Contract Name:
MonetCardToken
Contract Source Code:
pragma solidity >=0.5.0;
interface IERC1155TokenReceiver {
/**
* @notice Handle the receipt of a single ERC1155 token type
* @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated
* This function MAY throw to revert and reject the transfer
* Return of other amount than the magic value MUST result in the transaction being reverted
* Note: The token contract address is always the message sender
* @param _operator The address which called the `safeTransferFrom` function
* @param _from The address which previously owned the token
* @param _id The id of the token being transferred
* @param _amount The amount of tokens being transferred
* @param _data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
*/
function onERC1155Received(address _operator, address _from, uint256 _id, uint256 _amount, bytes calldata _data) external returns(bytes4);
/**
* @notice Handle the receipt of multiple ERC1155 token types
* @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated
* This function MAY throw to revert and reject the transfer
* Return of other amount than the magic value WILL result in the transaction being reverted
* Note: The token contract address is always the message sender
* @param _operator The address which called the `safeBatchTransferFrom` function
* @param _from The address which previously owned the token
* @param _ids An array containing ids of each token being transferred
* @param _amounts An array containing amounts of each token being transferred
* @param _data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
*/
function onERC1155BatchReceived(address _operator, address _from, uint256[] calldata _ids, uint256[] calldata _amounts, bytes calldata _data) external returns(bytes4);
}
pragma solidity =0.5.16;
import "./libraries/Address.sol";
import "./libraries/SafeMath.sol";
import "./interfaces/IERC1155TokenReceiver.sol";
import "./Minter.sol";
contract MonetCardToken is Minter {
using Address for address;
using SafeMath for uint256;
bytes4 private constant ERC1155_RECEIVED_VALUE = 0xf23a6e61;
bytes4 private constant ERC1155_BATCH_RECEIVED_VALUE = 0xbc197c81;
bytes4 private constant ERC1155_INTERFACE_ID = 0xd9b67a26;
mapping(address => mapping(uint256 => uint256)) internal _balances;
mapping(address => mapping(address => bool)) internal _operators;
mapping(uint256 => uint256) internal _totalSupplies;
// VIEW
function isApprovedForAll(address _owner, address _operator) public view returns (bool) {
return _operators[_owner][_operator];
}
function totalSupply(uint256 _id) public view returns (uint256) {
return _totalSupplies[_id];
}
function balanceOf(address _owner, uint256 _id) external view returns (uint256) {
return _balances[_owner][_id];
}
function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) external view returns (uint256[] memory) {
require(_owners.length == _ids.length, "INVALID_ARRAY_LENGTH");
uint256[] memory batchBalances = new uint256[](_owners.length);
for (uint256 i = 0; i < _owners.length; i++) {
batchBalances[i] = _balances[_owners[i]][_ids[i]];
}
return batchBalances;
}
function cardsNumOf(address _owner, uint256 _level,uint256 _carry) public view returns (uint256 nums) {
for (uint256 i = 0; i < 4; i++) {
uint256 num = _balances[_owner][_level.mul(10).add(i)];
nums = nums.add((_carry**(3 - i)).mul(num));
}
return nums;
}
function cardsNumOfAll(address _owner, uint256 _carry) public view returns (uint256[10] memory nums) {
uint256 levelMax = 10;
for (uint256 i = 0; i < levelMax; i++) {
nums[i] = cardsNumOf(_owner, levelMax.sub(i), _carry);
}
}
function cardsTotalSupply() public view returns (uint256[40] memory nums) {
uint256 idx;
for (uint256 i = 10; i > 0; i--) {
for (uint256 j = 0; j < 4; j++) {
nums[idx++] = _totalSupplies[i.mul(10).add(j)];
}
}
}
function supportsInterface(bytes4 _interfaceID) external pure returns (bool) {
return _interfaceID == ERC1155_INTERFACE_ID;
}
// PRIVATE
function _mintBatch(address _to, uint256[] memory _ids, uint256[] memory _values) private {
require(_to != address(0), "INVALID_RECIPIENT");
uint256 size = _ids.length;
for (uint256 i = 0; i < size; i++) {
_totalSupplies[_ids[i]] = _totalSupplies[_ids[i]].add(_values[i]);
_balances[_to][_ids[i]] = _balances[_to][_ids[i]].add(_values[i]);
}
emit TransferBatch(msg.sender, address(0), _to, _ids, _values);
}
function _safeBatchBurnFrom(address _from, uint256[] memory _ids, uint256[] memory _values ) private {
require(_ids.length == _values.length, "INVALID_ARRAYS_LENGTH");
uint256 size = _ids.length;
for (uint256 i = 0; i < size; i++) {
_balances[_from][_ids[i]] = _balances[_from][_ids[i]].sub(
_values[i]
);
_totalSupplies[_ids[i]] = _totalSupplies[_ids[i]].sub(_values[i]);
}
emit TransferBatch(msg.sender, _from, address(0), _ids, _values);
}
function _safeTransferFrom(address _from, address _to, uint256 _id, uint256 _amount) private {
_balances[_from][_id] = _balances[_from][_id].sub(_amount); // Subtract amount
_balances[_to][_id] = _balances[_to][_id].add(_amount); // Add amount
emit TransferSingle(msg.sender, _from, _to, _id, _amount);
}
function _safeBatchTransferFrom(
address _from,
address _to,
uint256[] memory _ids,
uint256[] memory _amounts
) private {
require(_ids.length == _amounts.length, "INVALID_ARRAYS_LENGTH");
uint256 size = _ids.length;
for (uint256 i = 0; i < size; i++) {
_balances[_from][_ids[i]] = _balances[_from][_ids[i]].sub(
_amounts[i]
);
_balances[_to][_ids[i]] = _balances[_to][_ids[i]].add(_amounts[i]);
}
emit TransferBatch(msg.sender, _from, _to, _ids, _amounts);
}
function _callonERC1155Received(address _from, address _to, uint256 _id, uint256 _amount, bytes memory _data) private {
if (_to.isContract()) {
bytes4 retval = IERC1155TokenReceiver(_to).onERC1155Received(msg.sender, _from, _id, _amount, _data);
require(retval == ERC1155_RECEIVED_VALUE, "INVALID_ON_RECEIVE_MESSAGE");
}
}
function _callonERC1155BatchReceived(address _from, address _to, uint256[] memory _ids, uint256[] memory _amounts, bytes memory _data) private {
if (_to.isContract()) {
bytes4 retval = IERC1155TokenReceiver(_to).onERC1155BatchReceived(msg.sender, _from, _ids, _amounts, _data );
require(retval == ERC1155_BATCH_RECEIVED_VALUE, "INVALID_ON_RECEIVE_MESSAGE");
}
}
// EXTERNAL
function safeBatchMint(address _to, uint256[] calldata _ids, uint256[] calldata _values) external onlyMinter {
require(_ids.length == _values.length, "INVALID_ARRAYS_LENGTH");
_mintBatch(_to, _ids, _values);
}
function safeBatchBurnFrom(address _from, uint256[] calldata _ids, uint256[] calldata _amounts) external {
require((msg.sender == _from) || isApprovedForAll(_from, msg.sender));
_safeBatchBurnFrom(_from, _ids, _amounts);
}
function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _amount, bytes calldata _data) external {
require((msg.sender == _from) || isApprovedForAll(_from, msg.sender));
require(_to != address(0), "INVALID_RECIPIENT");
_safeTransferFrom(_from, _to, _id, _amount);
_callonERC1155Received(_from, _to, _id, _amount, _data);
}
function safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _amounts, bytes calldata _data) external {
require((msg.sender == _from) || isApprovedForAll(_from, msg.sender));
require(_to != address(0), "INVALID_RECIPIENT");
_safeBatchTransferFrom(_from, _to, _ids, _amounts);
_callonERC1155BatchReceived(_from, _to, _ids, _amounts, _data);
}
function cardsBatchMint(address _to, uint256[] calldata _cards) external onlyMinter {
uint256[] memory _ids = new uint256[](_cards.length);
uint256[] memory _values = new uint256[](_cards.length);
for (uint256 i = 0; i < _cards.length; i++) {
_ids[i] = _cards[i] % 1000;
_values[i] = _cards[i] / 1000;
}
_mintBatch(_to, _ids, _values);
}
function cardsBatchBurnFrom(address _from, uint256[] calldata _cards) external {
require((msg.sender == _from) || isApprovedForAll(_from, msg.sender));
uint256[] memory _ids = new uint256[](_cards.length);
uint256[] memory _values = new uint256[](_cards.length);
for (uint256 i = 0; i < _cards.length; i++) {
_ids[i] = _cards[i] % 1000;
_values[i] = _cards[i] / 1000;
}
_safeBatchBurnFrom(_from, _ids, _values);
}
function setApprovalForAll(address _operator, bool _approved) external {
_operators[msg.sender][_operator] = _approved;
emit ApprovalForAll(msg.sender, _operator, _approved);
}
// EVENT
event TransferSingle(address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _amount);
event TransferBatch(address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _amounts);
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
event URI(string _amount, uint256 indexed _id);
}
pragma solidity =0.5.16;
library Address {
/**
* Returns whether the target address is a contract
* @dev This function will return false if invoked during the constructor of a contract,
* as the code is not actually created until after the constructor finishes.
* @param account address of the account to check
* @return whether the target address is a contract
*/
function isContract(address account) internal view returns (bool) {
uint256 size;
// XXX Currently there is no better way to check if there is a contract in an address
// than to check the size of the code at that address.
// See https://ethereum.stackexchange.com/a/14016/36603
// for more details about how this works.
// TODO Check this again before the Serenity release, because all addresses will be
// contracts then.
// solium-disable-next-line security/no-inline-assembly
assembly { size := extcodesize(account) }
return size > 0;
}
}
pragma solidity =0.5.16;
// a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)
library SafeMath {
function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x, 'ds-math-add-overflow');
}
function sub(uint x, uint y) internal pure returns (uint z) {
require((z = x - y) <= x, 'ds-math-sub-underflow');
}
function mul(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow');
}
function div(uint a, uint b) internal pure returns (uint z) {
require(b > 0);
return a / b;
}
}
pragma solidity =0.5.16;
import './Ownable.sol';
contract Minter is Ownable {
mapping(address => bool) private _minters;
event MinterChanged(address indexed minter, bool approved);
modifier onlyMinter {
require(isMinter(), "Minter: caller is not the minter");
_;
}
function isMinter() public view returns (bool){
return _minters[msg.sender];
}
function setMinter(address _minter,bool _approved) external onlyOwner {
_minters[_minter] = _approved;
emit MinterChanged(_minter,_approved);
}
}
pragma solidity =0.5.16;
contract Ownable {
address private _owner;
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
constructor() internal {
_owner = msg.sender;
emit OwnershipTransferred(address(0), _owner);
}
function owner() public view returns (address) {
return _owner;
}
modifier onlyOwner() {
require(isOwner(), "Ownable: caller is not the owner");
_;
}
function isOwner() public view returns (bool) {
return msg.sender == _owner;
}
function transferOwnership(address newOwner) public onlyOwner {
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}