Transaction Hash:
Block:
12321924 at Apr-27-2021 10:41:27 AM +UTC
Transaction Fee:
0.0086553705 ETH
$21.14
Gas Used:
186,137 Gas / 46.5 Gwei
Emitted Events:
166 |
REDP.Approval( _owner=[Sender] 0xeadc2dfa080bc004d11771bd2f7d20d256217252, _spender=[Receiver] FixedOrderSandNftSale, _value=115792089237316195423570985008687907853269984665640564039454584007913129639935 )
|
167 |
REDP.Transfer( _from=[Sender] 0xeadc2dfa080bc004d11771bd2f7d20d256217252, _to=0x324736aaAc94EDA00bec66Fbaf3adfFBCc10584f, _value=3000000000000000000 )
|
168 |
AdminUpgradeabilityProxy.0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb( 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb, 0x000000000000000000000000ec21427cc1deb6fd0727d7a777dda9a9f5540b3c, 0x0000000000000000000000005a79e65f48e07a6751cef24428d4a9917f822190, 0x000000000000000000000000eadc2dfa080bc004d11771bd2f7d20d256217252, 0000000000000000000000000000000000000000000000000000000000000040, 00000000000000000000000000000000000000000000000000000000000000c0, 0000000000000000000000000000000000000000000000000000000000000003, 7a9fe22691c811ea339d9b73150e6911a5343dca00000000000000000a003804, 7a9fe22691c811ea339d9b73150e6911a5343dca00000000000000000a003804, 7a9fe22691c811ea339d9b73150e6911a5343dca00000000000000000b801000, 0000000000000000000000000000000000000000000000000000000000000003, 0000000000000000000000000000000000000000000000000000000000000001, 0000000000000000000000000000000000000000000000000000000000000001, 0000000000000000000000000000000000000000000000000000000000000001 )
|
169 |
FixedOrderSandNftSale.Purchase( purchaser=[Sender] 0xeadc2dfa080bc004d11771bd2f7d20d256217252, recipient=[Sender] 0xeadc2dfa080bc004d11771bd2f7d20d256217252, token=REDP, sku=5245445053414E44424F584E4654000000000000000000000000000000000000, quantity=3, userData=0x, totalPrice=3000000000000000000, extData=0x7A9FE22691C811EA339D9B73150E6911A5343DCA00000000000000000A0038047A9FE22691C811EA339D9B73150E6911A5343DCA00000000000000000A0038047A9FE22691C811EA339D9B73150E6911A5343DCA00000000000000000B801000 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x2840A084...84Bc1e6D0 | |||||
0xa342f5D8...7f4478dB5 | |||||
0xc365c331...C4058C8E1
Miner
| (Binance Pool) | 7,160.017909656835038146 Eth | 7,160.026565027335038146 Eth | 0.0086553705 | |
0xeadc2DfA...256217252 |
0.119728727074736447 Eth
Nonce: 104
|
0.111073356574736447 Eth
Nonce: 105
| 0.0086553705 | ||
0xeC21427c...9F5540B3c |
Execution Trace
FixedOrderSandNftSale.purchaseFor( recipient=0xeadc2DfA080Bc004D11771bD2f7d20d256217252, token=0x2840A0844310Fc22292FE336e96aB1884Bc1e6D0, sku=5245445053414E44424F584E4654000000000000000000000000000000000000, quantity=3, userData=0x )
-
REDP.transferFrom( sender=0xeadc2DfA080Bc004D11771bD2f7d20d256217252, recipient=0x324736aaAc94EDA00bec66Fbaf3adfFBCc10584f, amount=3000000000000000000 ) => ( True )
AdminUpgradeabilityProxy.2eb2c2d6( )
-
Asset.safeBatchTransferFrom( from=0x5a79E65f48e07A6751Cef24428d4a9917f822190, to=0xeadc2DfA080Bc004D11771bD2f7d20d256217252, ids=[55464657044963196816950587289035428064568320970692304673817341489687556012036, 55464657044963196816950587289035428064568320970692304673817341489687556012036, 55464657044963196816950587289035428064568320970692304673817341489687581167616], values=[1, 1, 1], data=0x )
-
purchaseFor[Sale (ln:1540)]
_msgSender[Sale (ln:1548)]
_purchaseFor[Sale (ln:1555)]
File 1 of 4: FixedOrderSandNftSale
File 2 of 4: REDP
File 3 of 4: AdminUpgradeabilityProxy
File 4 of 4: Asset
// Sources flattened with hardhat v2.1.2 https://hardhat.org // File @animoca/ethereum-contracts-erc20_base-4.0.0/contracts/token/ERC20/[email protected] /* https://github.com/OpenZeppelin/openzeppelin-contracts The MIT License (MIT) Copyright (c) 2016-2019 zOS Global Limited Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // SPDX-License-Identifier: MIT pragma solidity 0.6.8; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed _from, address indexed _to, uint256 _value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed _owner, address indexed _spender, uint256 _value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); } // File @animoca/ethereum-contracts-core_library-5.0.0/contracts/algo/[email protected] /* https://github.com/OpenZeppelin/openzeppelin-contracts The MIT License (MIT) Copyright (c) 2016-2019 zOS Global Limited Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ pragma solidity 0.6.8; /** * @dev Library for managing an enumerable variant of Solidity's * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] * type. * * Maps have the following properties: * * - Entries are added, removed, and checked for existence in constant time * (O(1)). * - Entries are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumMap for EnumMap.Map; * * // Declare a set state variable * EnumMap.Map private myMap; * } * ``` */ library EnumMap { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Map type with // bytes32 keys and values. // This means that we can only create new EnumMaps for types that fit // in bytes32. struct MapEntry { bytes32 key; bytes32 value; } struct Map { // Storage of map keys and values MapEntry[] entries; // Position of the entry defined by a key in the `entries` array, plus 1 // because index 0 means a key is not in the map. mapping(bytes32 => uint256) indexes; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set( Map storage map, bytes32 key, bytes32 value ) internal returns (bool) { // We read and store the key's index to prevent multiple reads from the same storage slot uint256 keyIndex = map.indexes[key]; if (keyIndex == 0) { // Equivalent to !contains(map, key) map.entries.push(MapEntry({key: key, value: value})); // The entry is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value map.indexes[key] = map.entries.length; return true; } else { map.entries[keyIndex - 1].value = value; return false; } } /** * @dev Removes a key-value pair from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(Map storage map, bytes32 key) internal returns (bool) { // We read and store the key's index to prevent multiple reads from the same storage slot uint256 keyIndex = map.indexes[key]; if (keyIndex != 0) { // Equivalent to contains(map, key) // To delete a key-value pair from the entries array in O(1), we swap the entry to delete with the last one // in the array, and then remove the last entry (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = keyIndex - 1; uint256 lastIndex = map.entries.length - 1; // When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. MapEntry storage lastEntry = map.entries[lastIndex]; // Move the last entry to the index where the entry to delete is map.entries[toDeleteIndex] = lastEntry; // Update the index for the moved entry map.indexes[lastEntry.key] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved entry was stored map.entries.pop(); // Delete the index for the deleted slot delete map.indexes[key]; return true; } else { return false; } } /** * @dev Returns true if the key is in the map. O(1). */ function contains(Map storage map, bytes32 key) internal view returns (bool) { return map.indexes[key] != 0; } /** * @dev Returns the number of key-value pairs in the map. O(1). */ function length(Map storage map) internal view returns (uint256) { return map.entries.length; } /** * @dev Returns the key-value pair stored at position `index` in the map. O(1). * * Note that there are no guarantees on the ordering of entries inside the * array, and it may change when more entries are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Map storage map, uint256 index) internal view returns (bytes32, bytes32) { require(map.entries.length > index, "EnumMap: index out of bounds"); MapEntry storage entry = map.entries[index]; return (entry.key, entry.value); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(Map storage map, bytes32 key) internal view returns (bytes32) { uint256 keyIndex = map.indexes[key]; require(keyIndex != 0, "EnumMap: nonexistent key"); // Equivalent to contains(map, key) return map.entries[keyIndex - 1].value; // All indexes are 1-based } } // File @animoca/ethereum-contracts-core_library-5.0.0/contracts/algo/[email protected] /* https://github.com/OpenZeppelin/openzeppelin-contracts The MIT License (MIT) Copyright (c) 2016-2019 zOS Global Limited Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ pragma solidity 0.6.8; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumSet for EnumSet.Set; * * // Declare a set state variable * EnumSet.Set private mySet; * } * ``` */ library EnumSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Set storage set, bytes32 value) internal returns (bool) { if (!contains(set, value)) { set.values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set.indexes[value] = set.values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Set storage set, bytes32 value) internal returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set.indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set.values.length - 1; // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. bytes32 lastvalue = set.values[lastIndex]; // Move the last value to the index where the value to delete is set.values[toDeleteIndex] = lastvalue; // Update the index for the moved value set.indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved value was stored set.values.pop(); // Delete the index for the deleted slot delete set.indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Set storage set, bytes32 value) internal view returns (bool) { return set.indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function length(Set storage set) internal view returns (uint256) { return set.values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Set storage set, uint256 index) internal view returns (bytes32) { require(set.values.length > index, "EnumSet: index out of bounds"); return set.values[index]; } } // File @openzeppelin/contracts/GSN/[email protected] pragma solidity >=0.6.0 <0.8.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } // File @openzeppelin/contracts/access/[email protected] pragma solidity >=0.6.0 <0.8.0; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(_owner == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } // File @animoca/ethereum-contracts-core_library-5.0.0/contracts/payment/[email protected] pragma solidity 0.6.8; /** @title PayoutWallet @dev adds support for a payout wallet Note: . */ contract PayoutWallet is Ownable { event PayoutWalletSet(address payoutWallet_); address payable public payoutWallet; constructor(address payoutWallet_) internal { setPayoutWallet(payoutWallet_); } function setPayoutWallet(address payoutWallet_) public onlyOwner { require(payoutWallet_ != address(0), "Payout: zero address"); require(payoutWallet_ != address(this), "Payout: this contract as payout"); require(payoutWallet_ != payoutWallet, "Payout: same payout wallet"); payoutWallet = payable(payoutWallet_); emit PayoutWalletSet(payoutWallet); } } // File @animoca/ethereum-contracts-core_library-5.0.0/contracts/utils/[email protected] pragma solidity 0.6.8; /** * Contract module which allows derived contracts to implement a mechanism for * activating, or 'starting', a contract. * * This module is used through inheritance. It will make available the modifiers * `whenNotStarted` and `whenStarted`, which can be applied to the functions of * your contract. Those functions will only be 'startable' once the modifiers * are put in place. */ contract Startable is Context { event Started(address account); uint256 private _startedAt; /** * Modifier to make a function callable only when the contract has not started. */ modifier whenNotStarted() { require(_startedAt == 0, "Startable: started"); _; } /** * Modifier to make a function callable only when the contract has started. */ modifier whenStarted() { require(_startedAt != 0, "Startable: not started"); _; } /** * Constructor. */ constructor() internal {} /** * Returns the timestamp when the contract entered the started state. * @return The timestamp when the contract entered the started state. */ function startedAt() public view returns (uint256) { return _startedAt; } /** * Triggers the started state. * @dev Emits the Started event when the function is successfully called. */ function _start() internal virtual whenNotStarted { _startedAt = now; emit Started(_msgSender()); } } // File @openzeppelin/contracts/utils/[email protected] pragma solidity >=0.6.0 <0.8.0; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor () internal { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!_paused, "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(_paused, "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } } // File @openzeppelin/contracts/utils/[email protected] pragma solidity >=0.6.2 <0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // File @openzeppelin/contracts/math/[email protected] pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File @animoca/ethereum-contracts-sale_base-8.0.0/contracts/sale/interfaces/[email protected] pragma solidity 0.6.8; /** * @title ISale * * An interface for a contract which allows merchants to display products and customers to purchase them. * * Products, designated as SKUs, are represented by bytes32 identifiers so that an identifier can carry an * explicit name under the form of a fixed-length string. Each SKU can be priced via up to several payment * tokens which can be ETH and/or ERC20(s). ETH token is represented by the magic value TOKEN_ETH, which means * this value can be used as the 'token' argument of the purchase-related functions to indicate ETH payment. * * The total available supply for a SKU is fixed at its creation. The magic value SUPPLY_UNLIMITED is used * to represent a SKU with an infinite, never-decreasing supply. An optional purchase notifications receiver * contract address can be set for a SKU at its creation: if the value is different from the zero address, * the function `onPurchaseNotificationReceived` will be called on this address upon every purchase of the SKU. * * This interface is designed to be consistent while managing a variety of implementation scenarios. It is * also intended to be developer-friendly: all vital information is consistently deductible from the events * (backend-oriented), as well as retrievable through calls to public functions (frontend-oriented). */ interface ISale { /** * Event emitted to notify about the magic values necessary for interfacing with this contract. * @param names An array of names for the magic values used by the contract. * @param values An array of values for the magic values used by the contract. */ event MagicValues(bytes32[] names, bytes32[] values); /** * Event emitted to notify about the creation of a SKU. * @param sku The identifier of the created SKU. * @param totalSupply The initial total supply for sale. * @param maxQuantityPerPurchase The maximum allowed quantity for a single purchase. * @param notificationsReceiver If not the zero address, the address of a contract on which `onPurchaseNotificationReceived` will be called after * each purchase. If this is the zero address, the call is not enabled. */ event SkuCreation(bytes32 sku, uint256 totalSupply, uint256 maxQuantityPerPurchase, address notificationsReceiver); /** * Event emitted to notify about a change in the pricing of a SKU. * @dev `tokens` and `prices` arrays MUST have the same length. * @param sku The identifier of the updated SKU. * @param tokens An array of updated payment tokens. If empty, interpret as all payment tokens being disabled. * @param prices An array of updated prices for each of the payment tokens. * Zero price values are used for payment tokens being disabled. */ event SkuPricingUpdate(bytes32 indexed sku, address[] tokens, uint256[] prices); /** * Event emitted to notify about a purchase. * @param purchaser The initiater and buyer of the purchase. * @param recipient The recipient of the purchase. * @param token The token used as the currency for the payment. * @param sku The identifier of the purchased SKU. * @param quantity The purchased quantity. * @param userData Optional extra user input data. * @param totalPrice The amount of `token` paid. * @param extData Implementation-specific extra purchase data, such as * details about discounts applied, conversion rates, purchase receipts, etc. */ event Purchase( address indexed purchaser, address recipient, address indexed token, bytes32 indexed sku, uint256 quantity, bytes userData, uint256 totalPrice, bytes extData ); /** * Returns the magic value used to represent the ETH payment token. * @dev MUST NOT be the zero address. * @return the magic value used to represent the ETH payment token. */ // solhint-disable-next-line func-name-mixedcase function TOKEN_ETH() external pure returns (address); /** * Returns the magic value used to represent an infinite, never-decreasing SKU's supply. * @dev MUST NOT be zero. * @return the magic value used to represent an infinite, never-decreasing SKU's supply. */ // solhint-disable-next-line func-name-mixedcase function SUPPLY_UNLIMITED() external pure returns (uint256); /** * Performs a purchase. * @dev Reverts if `recipient` is the zero address. * @dev Reverts if `token` is the address zero. * @dev Reverts if `quantity` is zero. * @dev Reverts if `quantity` is greater than the maximum purchase quantity. * @dev Reverts if `quantity` is greater than the remaining supply. * @dev Reverts if `sku` does not exist. * @dev Reverts if `sku` exists but does not have a price set for `token`. * @dev Emits the Purchase event. * @param recipient The recipient of the purchase. * @param token The token to use as the payment currency. * @param sku The identifier of the SKU to purchase. * @param quantity The quantity to purchase. * @param userData Optional extra user input data. */ function purchaseFor( address payable recipient, address token, bytes32 sku, uint256 quantity, bytes calldata userData ) external payable; /** * Estimates the computed final total amount to pay for a purchase, including any potential discount. * @dev This function MUST compute the same price as `purchaseFor` would in identical conditions (same arguments, same point in time). * @dev If an implementer contract uses the `pricingData` field, it SHOULD document how to interpret the values. * @dev Reverts if `recipient` is the zero address. * @dev Reverts if `token` is the zero address. * @dev Reverts if `quantity` is zero. * @dev Reverts if `quantity` is greater than the maximum purchase quantity. * @dev Reverts if `quantity` is greater than the remaining supply. * @dev Reverts if `sku` does not exist. * @dev Reverts if `sku` exists but does not have a price set for `token`. * @param recipient The recipient of the purchase used to calculate the total price amount. * @param token The payment token used to calculate the total price amount. * @param sku The identifier of the SKU used to calculate the total price amount. * @param quantity The quantity used to calculate the total price amount. * @param userData Optional extra user input data. * @return totalPrice The computed total price to pay. * @return pricingData Implementation-specific extra pricing data, such as details about discounts applied. * If not empty, the implementer MUST document how to interepret the values. */ function estimatePurchase( address payable recipient, address token, bytes32 sku, uint256 quantity, bytes calldata userData ) external view returns (uint256 totalPrice, bytes32[] memory pricingData); /** * Returns the information relative to a SKU. * @dev WARNING: it is the responsibility of the implementer to ensure that the * number of payment tokens is bounded, so that this function does not run out of gas. * @dev Reverts if `sku` does not exist. * @param sku The SKU identifier. * @return totalSupply The initial total supply for sale. * @return remainingSupply The remaining supply for sale. * @return maxQuantityPerPurchase The maximum allowed quantity for a single purchase. * @return notificationsReceiver The address of a contract on which to call the `onPurchaseNotificationReceived` function. * @return tokens The list of supported payment tokens. * @return prices The list of associated prices for each of the `tokens`. */ function getSkuInfo(bytes32 sku) external view returns ( uint256 totalSupply, uint256 remainingSupply, uint256 maxQuantityPerPurchase, address notificationsReceiver, address[] memory tokens, uint256[] memory prices ); /** * Returns the list of created SKU identifiers. * @dev WARNING: it is the responsibility of the implementer to ensure that the * number of SKUs is bounded, so that this function does not run out of gas. * @return skus the list of created SKU identifiers. */ function getSkus() external view returns (bytes32[] memory skus); } // File @animoca/ethereum-contracts-sale_base-8.0.0/contracts/sale/interfaces/[email protected] pragma solidity 0.6.8; /** * @title IPurchaseNotificationsReceiver * Interface for any contract that wants to support purchase notifications from a Sale contract. */ interface IPurchaseNotificationsReceiver { /** * Handles the receipt of a purchase notification. * @dev This function MUST return the function selector, otherwise the caller will revert the transaction. * The selector to be returned can be obtained as `this.onPurchaseNotificationReceived.selector` * @dev This function MAY throw. * @param purchaser The purchaser of the purchase. * @param recipient The recipient of the purchase. * @param token The token to use as the payment currency. * @param sku The identifier of the SKU to purchase. * @param quantity The quantity to purchase. * @param userData Optional extra user input data. * @param totalPrice The total price paid. * @param pricingData Implementation-specific extra pricing data, such as details about discounts applied. * @param paymentData Implementation-specific extra payment data, such as conversion rates. * @param deliveryData Implementation-specific extra delivery data, such as purchase receipts. * @return `bytes4(keccak256( * "onPurchaseNotificationReceived(address,address,address,bytes32,uint256,bytes,uint256,bytes32[],bytes32[],bytes32[])"))` */ function onPurchaseNotificationReceived( address purchaser, address recipient, address token, bytes32 sku, uint256 quantity, bytes calldata userData, uint256 totalPrice, bytes32[] calldata pricingData, bytes32[] calldata paymentData, bytes32[] calldata deliveryData ) external returns (bytes4); } // File @animoca/ethereum-contracts-sale_base-8.0.0/contracts/sale/abstract/[email protected] pragma solidity 0.6.8; /** * @title PurchaseLifeCycles * An abstract contract which define the life cycles for a purchase implementer. */ abstract contract PurchaseLifeCycles { /** * Wrapper for the purchase data passed as argument to the life cycle functions and down to their step functions. */ struct PurchaseData { address payable purchaser; address payable recipient; address token; bytes32 sku; uint256 quantity; bytes userData; uint256 totalPrice; bytes32[] pricingData; bytes32[] paymentData; bytes32[] deliveryData; } /* Internal Life Cycle Functions */ /** * `estimatePurchase` lifecycle. * @param purchase The purchase conditions. */ function _estimatePurchase(PurchaseData memory purchase) internal view virtual returns (uint256 totalPrice, bytes32[] memory pricingData) { _validation(purchase); _pricing(purchase); totalPrice = purchase.totalPrice; pricingData = purchase.pricingData; } /** * `purchaseFor` lifecycle. * @param purchase The purchase conditions. */ function _purchaseFor(PurchaseData memory purchase) internal virtual { _validation(purchase); _pricing(purchase); _payment(purchase); _delivery(purchase); _notification(purchase); } /* Internal Life Cycle Step Functions */ /** * Lifecycle step which validates the purchase pre-conditions. * @dev Responsibilities: * - Ensure that the purchase pre-conditions are met and revert if not. * @param purchase The purchase conditions. */ function _validation(PurchaseData memory purchase) internal view virtual; /** * Lifecycle step which computes the purchase price. * @dev Responsibilities: * - Computes the pricing formula, including any discount logic and price conversion; * - Set the value of `purchase.totalPrice`; * - Add any relevant extra data related to pricing in `purchase.pricingData` and document how to interpret it. * @param purchase The purchase conditions. */ function _pricing(PurchaseData memory purchase) internal view virtual; /** * Lifecycle step which manages the transfer of funds from the purchaser. * @dev Responsibilities: * - Ensure the payment reaches destination in the expected output token; * - Handle any token swap logic; * - Add any relevant extra data related to payment in `purchase.paymentData` and document how to interpret it. * @param purchase The purchase conditions. */ function _payment(PurchaseData memory purchase) internal virtual; /** * Lifecycle step which delivers the purchased SKUs to the recipient. * @dev Responsibilities: * - Ensure the product is delivered to the recipient, if that is the contract's responsibility. * - Handle any internal logic related to the delivery, including the remaining supply update; * - Add any relevant extra data related to delivery in `purchase.deliveryData` and document how to interpret it. * @param purchase The purchase conditions. */ function _delivery(PurchaseData memory purchase) internal virtual; /** * Lifecycle step which notifies of the purchase. * @dev Responsibilities: * - Manage after-purchase event(s) emission. * - Handle calls to the notifications receiver contract's `onPurchaseNotificationReceived` function, if applicable. * @param purchase The purchase conditions. */ function _notification(PurchaseData memory purchase) internal virtual; } // File @animoca/ethereum-contracts-sale_base-8.0.0/contracts/sale/abstract/[email protected] pragma solidity 0.6.8; /** * @title Sale * An abstract base sale contract with a minimal implementation of ISale and administration functions. * A minimal implementation of the `_validation`, `_delivery` and `notification` life cycle step functions * are provided, but the inheriting contract must implement `_pricing` and `_payment`. */ abstract contract Sale is PurchaseLifeCycles, ISale, PayoutWallet, Startable, Pausable { using Address for address; using SafeMath for uint256; using EnumSet for EnumSet.Set; using EnumMap for EnumMap.Map; struct SkuInfo { uint256 totalSupply; uint256 remainingSupply; uint256 maxQuantityPerPurchase; address notificationsReceiver; EnumMap.Map prices; } address public constant override TOKEN_ETH = address(0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee); uint256 public constant override SUPPLY_UNLIMITED = type(uint256).max; EnumSet.Set internal _skus; mapping(bytes32 => SkuInfo) internal _skuInfos; uint256 internal immutable _skusCapacity; uint256 internal immutable _tokensPerSkuCapacity; /** * Constructor. * @dev Emits the `MagicValues` event. * @dev Emits the `Paused` event. * @param payoutWallet_ the payout wallet. * @param skusCapacity the cap for the number of managed SKUs. * @param tokensPerSkuCapacity the cap for the number of tokens managed per SKU. */ constructor( address payoutWallet_, uint256 skusCapacity, uint256 tokensPerSkuCapacity ) internal PayoutWallet(payoutWallet_) { _skusCapacity = skusCapacity; _tokensPerSkuCapacity = tokensPerSkuCapacity; bytes32[] memory names = new bytes32[](2); bytes32[] memory values = new bytes32[](2); (names[0], values[0]) = ("TOKEN_ETH", bytes32(uint256(TOKEN_ETH))); (names[1], values[1]) = ("SUPPLY_UNLIMITED", bytes32(uint256(SUPPLY_UNLIMITED))); emit MagicValues(names, values); _pause(); } /* Public Admin Functions */ /** * Actvates, or 'starts', the contract. * @dev Emits the `Started` event. * @dev Emits the `Unpaused` event. * @dev Reverts if called by any other than the contract owner. * @dev Reverts if the contract has already been started. * @dev Reverts if the contract is not paused. */ function start() public virtual onlyOwner { _start(); _unpause(); } /** * Pauses the contract. * @dev Emits the `Paused` event. * @dev Reverts if called by any other than the contract owner. * @dev Reverts if the contract has not been started yet. * @dev Reverts if the contract is already paused. */ function pause() public virtual onlyOwner whenStarted { _pause(); } /** * Resumes the contract. * @dev Emits the `Unpaused` event. * @dev Reverts if called by any other than the contract owner. * @dev Reverts if the contract has not been started yet. * @dev Reverts if the contract is not paused. */ function unpause() public virtual onlyOwner whenStarted { _unpause(); } /** * Sets the token prices for the specified product SKU. * @dev Reverts if called by any other than the contract owner. * @dev Reverts if `tokens` and `prices` have different lengths. * @dev Reverts if `sku` does not exist. * @dev Reverts if one of the `tokens` is the zero address. * @dev Reverts if the update results in too many tokens for the SKU. * @dev Emits the `SkuPricingUpdate` event. * @param sku The identifier of the SKU. * @param tokens The list of payment tokens to update. * If empty, disable all the existing payment tokens. * @param prices The list of prices to apply for each payment token. * Zero price values are used to disable a payment token. */ function updateSkuPricing( bytes32 sku, address[] memory tokens, uint256[] memory prices ) public virtual onlyOwner { uint256 length = tokens.length; // solhint-disable-next-line reason-string require(length == prices.length, "Sale: tokens/prices lengths mismatch"); SkuInfo storage skuInfo = _skuInfos[sku]; require(skuInfo.totalSupply != 0, "Sale: non-existent sku"); EnumMap.Map storage tokenPrices = skuInfo.prices; if (length == 0) { uint256 currentLength = tokenPrices.length(); for (uint256 i = 0; i < currentLength; ++i) { // TODO add a clear function in EnumMap and EnumSet and use it (bytes32 token, ) = tokenPrices.at(0); tokenPrices.remove(token); } } else { _setTokenPrices(tokenPrices, tokens, prices); } emit SkuPricingUpdate(sku, tokens, prices); } /* ISale Public Functions */ /** * Performs a purchase. * @dev Reverts if the sale has not started. * @dev Reverts if the sale is paused. * @dev Reverts if `recipient` is the zero address. * @dev Reverts if `token` is the zero address. * @dev Reverts if `quantity` is zero. * @dev Reverts if `quantity` is greater than the maximum purchase quantity. * @dev Reverts if `quantity` is greater than the remaining supply. * @dev Reverts if `sku` does not exist. * @dev Reverts if `sku` exists but does not have a price set for `token`. * @dev Emits the Purchase event. * @param recipient The recipient of the purchase. * @param token The token to use as the payment currency. * @param sku The identifier of the SKU to purchase. * @param quantity The quantity to purchase. * @param userData Optional extra user input data. */ function purchaseFor( address payable recipient, address token, bytes32 sku, uint256 quantity, bytes calldata userData ) external payable virtual override whenStarted whenNotPaused { PurchaseData memory purchase; purchase.purchaser = _msgSender(); purchase.recipient = recipient; purchase.token = token; purchase.sku = sku; purchase.quantity = quantity; purchase.userData = userData; _purchaseFor(purchase); } /** * Estimates the computed final total amount to pay for a purchase, including any potential discount. * @dev This function MUST compute the same price as `purchaseFor` would in identical conditions (same arguments, same point in time). * @dev If an implementer contract uses the `pricingData` field, it SHOULD document how to interpret the values. * @dev Reverts if the sale has not started. * @dev Reverts if the sale is paused. * @dev Reverts if `recipient` is the zero address. * @dev Reverts if `token` is the zero address. * @dev Reverts if `quantity` is zero. * @dev Reverts if `quantity` is greater than the maximum purchase quantity. * @dev Reverts if `quantity` is greater than the remaining supply. * @dev Reverts if `sku` does not exist. * @dev Reverts if `sku` exists but does not have a price set for `token`. * @param recipient The recipient of the purchase used to calculate the total price amount. * @param token The payment token used to calculate the total price amount. * @param sku The identifier of the SKU used to calculate the total price amount. * @param quantity The quantity used to calculate the total price amount. * @param userData Optional extra user input data. * @return totalPrice The computed total price. * @return pricingData Implementation-specific extra pricing data, such as details about discounts applied. * If not empty, the implementer MUST document how to interepret the values. */ function estimatePurchase( address payable recipient, address token, bytes32 sku, uint256 quantity, bytes calldata userData ) external view virtual override whenStarted whenNotPaused returns (uint256 totalPrice, bytes32[] memory pricingData) { PurchaseData memory purchase; purchase.purchaser = _msgSender(); purchase.recipient = recipient; purchase.token = token; purchase.sku = sku; purchase.quantity = quantity; purchase.userData = userData; return _estimatePurchase(purchase); } /** * Returns the information relative to a SKU. * @dev WARNING: it is the responsibility of the implementer to ensure that the * number of payment tokens is bounded, so that this function does not run out of gas. * @dev Reverts if `sku` does not exist. * @param sku The SKU identifier. * @return totalSupply The initial total supply for sale. * @return remainingSupply The remaining supply for sale. * @return maxQuantityPerPurchase The maximum allowed quantity for a single purchase. * @return notificationsReceiver The address of a contract on which to call the `onPurchaseNotificationReceived` function. * @return tokens The list of supported payment tokens. * @return prices The list of associated prices for each of the `tokens`. */ function getSkuInfo(bytes32 sku) external view override returns ( uint256 totalSupply, uint256 remainingSupply, uint256 maxQuantityPerPurchase, address notificationsReceiver, address[] memory tokens, uint256[] memory prices ) { SkuInfo storage skuInfo = _skuInfos[sku]; uint256 length = skuInfo.prices.length(); totalSupply = skuInfo.totalSupply; require(totalSupply != 0, "Sale: non-existent sku"); remainingSupply = skuInfo.remainingSupply; maxQuantityPerPurchase = skuInfo.maxQuantityPerPurchase; notificationsReceiver = skuInfo.notificationsReceiver; tokens = new address[](length); prices = new uint256[](length); for (uint256 i = 0; i < length; ++i) { (bytes32 token, bytes32 price) = skuInfo.prices.at(i); tokens[i] = address(uint256(token)); prices[i] = uint256(price); } } /** * Returns the list of created SKU identifiers. * @return skus the list of created SKU identifiers. */ function getSkus() external view override returns (bytes32[] memory skus) { skus = _skus.values; } /* Internal Utility Functions */ /** * Creates an SKU. * @dev Reverts if `totalSupply` is zero. * @dev Reverts if `sku` already exists. * @dev Reverts if `notificationsReceiver` is not the zero address and is not a contract address. * @dev Reverts if the update results in too many SKUs. * @dev Emits the `SkuCreation` event. * @param sku the SKU identifier. * @param totalSupply the initial total supply. * @param maxQuantityPerPurchase The maximum allowed quantity for a single purchase. * @param notificationsReceiver The purchase notifications receiver contract address. * If set to the zero address, the notification is not enabled. */ function _createSku( bytes32 sku, uint256 totalSupply, uint256 maxQuantityPerPurchase, address notificationsReceiver ) internal virtual { require(totalSupply != 0, "Sale: zero supply"); require(_skus.length() < _skusCapacity, "Sale: too many skus"); require(_skus.add(sku), "Sale: sku already created"); if (notificationsReceiver != address(0)) { // solhint-disable-next-line reason-string require(notificationsReceiver.isContract(), "Sale: receiver is not a contract"); } SkuInfo storage skuInfo = _skuInfos[sku]; skuInfo.totalSupply = totalSupply; skuInfo.remainingSupply = totalSupply; skuInfo.maxQuantityPerPurchase = maxQuantityPerPurchase; skuInfo.notificationsReceiver = notificationsReceiver; emit SkuCreation(sku, totalSupply, maxQuantityPerPurchase, notificationsReceiver); } /** * Updates SKU token prices. * @dev Reverts if one of the `tokens` is the zero address. * @dev Reverts if the update results in too many tokens for the SKU. * @param tokenPrices Storage pointer to a mapping of SKU token prices to update. * @param tokens The list of payment tokens to update. * @param prices The list of prices to apply for each payment token. * Zero price values are used to disable a payment token. */ function _setTokenPrices( EnumMap.Map storage tokenPrices, address[] memory tokens, uint256[] memory prices ) internal virtual { for (uint256 i = 0; i < tokens.length; ++i) { address token = tokens[i]; require(token != address(0), "Sale: zero address token"); uint256 price = prices[i]; if (price == 0) { tokenPrices.remove(bytes32(uint256(token))); } else { tokenPrices.set(bytes32(uint256(token)), bytes32(price)); } } require(tokenPrices.length() <= _tokensPerSkuCapacity, "Sale: too many tokens"); } /* Internal Life Cycle Step Functions */ /** * Lifecycle step which validates the purchase pre-conditions. * @dev Responsibilities: * - Ensure that the purchase pre-conditions are met and revert if not. * @dev Reverts if `purchase.recipient` is the zero address. * @dev Reverts if `purchase.token` is the zero address. * @dev Reverts if `purchase.quantity` is zero. * @dev Reverts if `purchase.quantity` is greater than the SKU's `maxQuantityPerPurchase`. * @dev Reverts if `purchase.quantity` is greater than the available supply. * @dev Reverts if `purchase.sku` does not exist. * @dev Reverts if `purchase.sku` exists but does not have a price set for `purchase.token`. * @dev If this function is overriden, the implementer SHOULD super call this before. * @param purchase The purchase conditions. */ function _validation(PurchaseData memory purchase) internal view virtual override { require(purchase.recipient != address(0), "Sale: zero address recipient"); require(purchase.token != address(0), "Sale: zero address token"); require(purchase.quantity != 0, "Sale: zero quantity purchase"); SkuInfo storage skuInfo = _skuInfos[purchase.sku]; require(skuInfo.totalSupply != 0, "Sale: non-existent sku"); require(skuInfo.maxQuantityPerPurchase >= purchase.quantity, "Sale: above max quantity"); if (skuInfo.totalSupply != SUPPLY_UNLIMITED) { require(skuInfo.remainingSupply >= purchase.quantity, "Sale: insufficient supply"); } bytes32 priceKey = bytes32(uint256(purchase.token)); require(skuInfo.prices.contains(priceKey), "Sale: non-existent sku token"); } /** * Lifecycle step which delivers the purchased SKUs to the recipient. * @dev Responsibilities: * - Ensure the product is delivered to the recipient, if that is the contract's responsibility. * - Handle any internal logic related to the delivery, including the remaining supply update; * - Add any relevant extra data related to delivery in `purchase.deliveryData` and document how to interpret it. * @dev Reverts if there is not enough available supply. * @dev If this function is overriden, the implementer SHOULD super call it. * @param purchase The purchase conditions. */ function _delivery(PurchaseData memory purchase) internal virtual override { SkuInfo memory skuInfo = _skuInfos[purchase.sku]; if (skuInfo.totalSupply != SUPPLY_UNLIMITED) { _skuInfos[purchase.sku].remainingSupply = skuInfo.remainingSupply.sub(purchase.quantity); } } /** * Lifecycle step which notifies of the purchase. * @dev Responsibilities: * - Manage after-purchase event(s) emission. * - Handle calls to the notifications receiver contract's `onPurchaseNotificationReceived` function, if applicable. * @dev Reverts if `onPurchaseNotificationReceived` throws or returns an incorrect value. * @dev Emits the `Purchase` event. The values of `purchaseData` are the concatenated values of `priceData`, `paymentData` * and `deliveryData`. If not empty, the implementer MUST document how to interpret these values. * @dev If this function is overriden, the implementer SHOULD super call it. * @param purchase The purchase conditions. */ function _notification(PurchaseData memory purchase) internal virtual override { emit Purchase( purchase.purchaser, purchase.recipient, purchase.token, purchase.sku, purchase.quantity, purchase.userData, purchase.totalPrice, abi.encodePacked(purchase.pricingData, purchase.paymentData, purchase.deliveryData) ); address notificationsReceiver = _skuInfos[purchase.sku].notificationsReceiver; if (notificationsReceiver != address(0)) { // solhint-disable-next-line reason-string require( IPurchaseNotificationsReceiver(notificationsReceiver).onPurchaseNotificationReceived( purchase.purchaser, purchase.recipient, purchase.token, purchase.sku, purchase.quantity, purchase.userData, purchase.totalPrice, purchase.pricingData, purchase.paymentData, purchase.deliveryData ) == IPurchaseNotificationsReceiver(address(0)).onPurchaseNotificationReceived.selector, // TODO precompute return value "Sale: wrong receiver return value" ); } } } // File @animoca/ethereum-contracts-sale_base-8.0.0/contracts/sale/[email protected] pragma solidity 0.6.8; /** * @title FixedPricesSale * An Sale which implements a fixed prices strategy. * The final implementer is responsible for implementing any additional pricing and/or delivery logic. */ contract FixedPricesSale is Sale { /** * Constructor. * @dev Emits the `MagicValues` event. * @dev Emits the `Paused` event. * @param payoutWallet_ the payout wallet. * @param skusCapacity the cap for the number of managed SKUs. * @param tokensPerSkuCapacity the cap for the number of tokens managed per SKU. */ constructor( address payoutWallet_, uint256 skusCapacity, uint256 tokensPerSkuCapacity ) internal Sale(payoutWallet_, skusCapacity, tokensPerSkuCapacity) {} /* Internal Life Cycle Functions */ /** * Lifecycle step which computes the purchase price. * @dev Responsibilities: * - Computes the pricing formula, including any discount logic and price conversion; * - Set the value of `purchase.totalPrice`; * - Add any relevant extra data related to pricing in `purchase.pricingData` and document how to interpret it. * @dev Reverts if `purchase.sku` does not exist. * @dev Reverts if `purchase.token` is not supported by the SKU. * @dev Reverts in case of price overflow. * @param purchase The purchase conditions. */ function _pricing(PurchaseData memory purchase) internal view virtual override { SkuInfo storage skuInfo = _skuInfos[purchase.sku]; require(skuInfo.totalSupply != 0, "Sale: unsupported SKU"); EnumMap.Map storage prices = skuInfo.prices; uint256 unitPrice = _unitPrice(purchase, prices); purchase.totalPrice = unitPrice.mul(purchase.quantity); } /** * Lifecycle step which manages the transfer of funds from the purchaser. * @dev Responsibilities: * - Ensure the payment reaches destination in the expected output token; * - Handle any token swap logic; * - Add any relevant extra data related to payment in `purchase.paymentData` and document how to interpret it. * @dev Reverts in case of payment failure. * @param purchase The purchase conditions. */ function _payment(PurchaseData memory purchase) internal virtual override { if (purchase.token == TOKEN_ETH) { require(msg.value >= purchase.totalPrice, "Sale: insufficient ETH provided"); payoutWallet.transfer(purchase.totalPrice); uint256 change = msg.value.sub(purchase.totalPrice); if (change != 0) { purchase.purchaser.transfer(change); } } else { require(IERC20(purchase.token).transferFrom(_msgSender(), payoutWallet, purchase.totalPrice), "Sale: ERC20 payment failed"); } } /* Internal Utility Functions */ /** * Retrieves the unit price of a SKU for the specified payment token. * @dev Reverts if the specified payment token is unsupported. * @param purchase The purchase conditions specifying the payment token with which the unit price will be retrieved. * @param prices Storage pointer to a mapping of SKU token prices to retrieve the unit price from. * @return unitPrice The unit price of a SKU for the specified payment token. */ function _unitPrice(PurchaseData memory purchase, EnumMap.Map storage prices) internal view virtual returns (uint256 unitPrice) { unitPrice = uint256(prices.get(bytes32(uint256(purchase.token)))); require(unitPrice != 0, "Sale: unsupported payment token"); } } // File @animoca/ethereum-contracts-sale_base-8.0.0/contracts/sale/[email protected] pragma solidity 0.6.8; /** * @title FixedOrderInventorySale * A FixedPricesSale contract that handles the purchase of NFTs of an inventory contract to a * receipient. The provisioning of the NFTs occurs in a sequential order defined by a token list. * Only a single SKU is supported. */ contract FixedOrderInventorySale is FixedPricesSale { address public immutable inventory; uint256 public tokenIndex; uint256[] public tokenList; /** * Constructor. * @dev Reverts if `inventory_` is the zero address. * @dev Emits the `MagicValues` event. * @dev Emits the `Paused` event. * @param inventory_ The inventory contract from which the NFT sale supply is attributed from. * @param payoutWallet The payout wallet. * @param tokensPerSkuCapacity the cap for the number of tokens managed per SKU. */ constructor( address inventory_, address payoutWallet, uint256 tokensPerSkuCapacity ) public FixedPricesSale( payoutWallet, 1, // single SKU tokensPerSkuCapacity ) { // solhint-disable-next-line reason-string require(inventory_ != address(0), "FixedOrderInventorySale: zero address inventory"); inventory = inventory_; } /** * Adds additional tokens to the sale supply. * @dev Reverts if called by any other than the contract owner. * @dev Reverts if `tokens` is empty. * @dev Reverts if any of `tokens` are zero. * @dev The list of tokens specified (in sequence) will be appended to the end of the ordered * sale supply list. * @param tokens The list of tokens to add. */ function addSupply(uint256[] memory tokens) public virtual onlyOwner { uint256 numTokens = tokens.length; // solhint-disable-next-line reason-string require(numTokens != 0, "FixedOrderInventorySale: empty tokens to add"); for (uint256 i = 0; i != numTokens; ++i) { uint256 token = tokens[i]; // solhint-disable-next-line reason-string require(token != 0, "FixedOrderInventorySale: adding zero token"); tokenList.push(token); } if (_skus.length() != 0) { bytes32 sku = _skus.at(0); SkuInfo storage skuInfo = _skuInfos[sku]; skuInfo.totalSupply += numTokens; skuInfo.remainingSupply += numTokens; } } /** * Sets the tokens of the ordered sale supply list. * @dev Reverts if called by any other than the contract owner. * @dev Reverts if called when the contract is not paused. * @dev Reverts if the sale supply is empty. * @dev Reverts if the lengths of `indexes` and `tokens` do not match. * @dev Reverts if `indexes` is zero length. * @dev Reverts if any of `indexes` are less than `tokenIndex`. * @dev Reverts if any of `indexes` are out-of-bounds. * @dev Reverts it `tokens` is zero length. * @dev Reverts if any of `tokens` are zero. * @dev Does not allow resizing of the sale supply, only the re-ordering or replacment of * existing tokens. * @dev Because the elements of `indexes` and `tokens` are processed in sequence, duplicate * entries in either array are permitted, which allows for ordered operations to be performed * on the ordered sale supply list in the same transaction. * @param indexes The list of indexes in the ordered sale supply list whose element values * will be set. * @param tokens The new tokens to set in the ordered sale supply list at the corresponding * positions provided by `indexes`. */ function setSupply(uint256[] memory indexes, uint256[] memory tokens) public virtual onlyOwner whenPaused { uint256 tokenListLength = tokenList.length; // solhint-disable-next-line reason-string require(tokenListLength != 0, "FixedOrderInventorySale: empty token list"); uint256 numIndexes = indexes.length; // solhint-disable-next-line reason-string require(numIndexes != 0, "FixedOrderInventorySale: empty indexes"); uint256 numTokens = tokens.length; // solhint-disable-next-line reason-string require(numIndexes == numTokens, "FixedOrderInventorySale: array length mismatch"); uint256 tokenIndex_ = tokenIndex; for (uint256 i = 0; i != numIndexes; ++i) { uint256 index = indexes[i]; // solhint-disable-next-line reason-string require(index >= tokenIndex_, "FixedOrderInventorySale: invalid index"); // solhint-disable-next-line reason-string require(index < tokenListLength, "FixedOrderInventorySale: index out-of-bounds"); uint256 token = tokens[i]; // solhint-disable-next-line reason-string require(token != 0, "FixedOrderInventorySale: zero token"); tokenList[index] = token; } } /** * Retrieves the amount of total sale supply. * @return The amount of total sale supply. */ function getTotalSupply() public view virtual returns (uint256) { return tokenList.length; } /** * Lifecycle step which delivers the purchased SKUs to the recipient. * @dev Responsibilities: * - Ensure the product is delivered to the recipient, if that is the contract's responsibility. * - Handle any internal logic related to the delivery, including the remaining supply update. * - Add any relevant extra data related to delivery in `purchase.deliveryData` and document how to interpret it. * @dev Reverts if there is not enough available supply. * @dev Updates `purchase.deliveryData` with the list of tokens allocated from `tokenList` for * this purchase. * @param purchase The purchase conditions. */ function _delivery(PurchaseData memory purchase) internal virtual override { super._delivery(purchase); purchase.deliveryData = new bytes32[](purchase.quantity); uint256 tokenCount = 0; uint256 tokenIndex_ = tokenIndex; while (tokenCount != purchase.quantity) { purchase.deliveryData[tokenCount] = bytes32(tokenList[tokenIndex_]); ++tokenCount; ++tokenIndex_; } tokenIndex = tokenIndex_; } } // File contracts/sale/FixedOrderSandNftSale.sol pragma solidity 0.6.8; /** * @title FixedOrderSandNftSale * A FixedOrderInventorySale contract implementation that handles the purchases of Sandbox NFTs * track NFTs from a holder account to the recipient. The provisioning of the NFTs from the holder * account occurs in a sequential order defined by a token list. Only a single SKU is supported. */ contract FixedOrderSandNftSale is FixedOrderInventorySale { address public immutable tokenHolder; /** * Constructor. * @dev Reverts if `inventory` is the zero address. * @dev Reverts if `tokenHolder` is the zero address. * @dev Emits the `MagicValues` event. * @dev Emits the `Paused` event. * @param inventory The inventory contract from which the NFT sale supply is attributed from. * @param tokenHolder_ The account holding the pool of sale inventory NFTs. * @param payoutWallet The payout wallet. * @param tokensPerSkuCapacity the cap for the number of tokens managed per SKU. */ constructor( address inventory, address tokenHolder_, address payoutWallet, uint256 tokensPerSkuCapacity ) public FixedOrderInventorySale(inventory, payoutWallet, tokensPerSkuCapacity) { // solhint-disable-next-line reason-string require(tokenHolder_ != address(0), "FixedOrderSandNftSale: zero address token holder"); tokenHolder = tokenHolder_; } /** * Creates an SKU. * @dev Reverts if called by any other than the contract owner. * @dev Reverts if called when the contract is not paused. * @dev Reverts if the initial sale supply is empty. * @dev Reverts if `sku` already exists. * @dev Reverts if `notificationsReceiver` is not the zero address and is not a contract address. * @dev Reverts if the update results in too many SKUs. * @dev Emits the `SkuCreation` event. * @param sku the SKU identifier. * @param maxQuantityPerPurchase The maximum allowed quantity for a single purchase. * @param notificationsReceiver The purchase notifications receiver contract address. * If set to the zero address, the notification is not enabled. */ function createSku( bytes32 sku, uint256 maxQuantityPerPurchase, address notificationsReceiver ) external onlyOwner whenPaused { _createSku(sku, tokenList.length, maxQuantityPerPurchase, notificationsReceiver); } /** * Lifecycle step which delivers the purchased SKUs to the recipient. * @dev Responsibilities: * - Ensure the product is delivered to the recipient, if that is the contract's responsibility. * - Handle any internal logic related to the delivery, including the remaining supply update. * - Add any relevant extra data related to delivery in `purchase.deliveryData` and document how to interpret it. * @dev Reverts if there is not enough available supply. * @dev Reverts if this contract does not have the minter role on the inventory contract. * @dev Updates `purchase.deliveryData` with the list of tokens allocated from `tokenList` for * this purchase. * @dev Mints the tokens allocated in `purchase.deliveryData` to the purchase recipient. * @param purchase The purchase conditions. */ function _delivery(PurchaseData memory purchase) internal virtual override { super._delivery(purchase); uint256[] memory ids = new uint256[](purchase.quantity); uint256[] memory values = new uint256[](purchase.quantity); for (uint256 index = 0; index != purchase.quantity; ++index) { ids[index] = uint256(purchase.deliveryData[index]); values[index] = 1; } IFixedOrderInventoryTransferable(inventory).safeBatchTransferFrom(tokenHolder, purchase.recipient, ids, values, ""); } } /** * @dev Interface for the transfer function of the NFT inventory contract. */ interface IFixedOrderInventoryTransferable { /** * @notice Transfers `values` amount(s) of `ids` from the `from` address to the `to` address specified (with safety call). * @dev Caller must be approved to manage the tokens being transferred out of the `from` account (see "Approval" section of the standard). * MUST revert if `to` is the zero address. * MUST revert if length of `ids` is not the same as length of `values`. * MUST revert if any of the balance(s) of the holder(s) for token(s) in `ids` is lower than the respective amount(s) in `values` sent to the * recipient. * MUST revert on any other error. * MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see "Safe Transfer Rules" section of * the standard). * Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc). * After the above conditions for the transfer(s) in the batch are met, this function MUST check if `to` is a smart contract * (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `to` and act appropriately (see "Safe Transfer * Rules" section of the standard). * @param from Source address * @param to Target address * @param ids IDs of each token type (order and length must match _values array) * @param values Transfer amounts per token type (order and length must match _ids array) * @param data Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `to` */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external; }
File 2 of 4: REDP
// Sources flattened with hardhat v2.0.3 https://hardhat.org // File @openzeppelin/contracts/GSN/[email protected] // SPDX-License-Identifier: MIT pragma solidity ^0.6.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } // File @openzeppelin/contracts/access/[email protected] pragma solidity ^0.6.0; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(_owner == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } // File @animoca/ethereum-contracts-core_library/contracts/access/[email protected] pragma solidity 0.6.8; contract WhitelistedOperators is Ownable { mapping(address => bool) internal _whitelistedOperators; event WhitelistedOperator(address operator, bool enabled); /// @notice Enable or disable address operator access /// @param operator address that will be given/removed operator right. /// @param enabled set whether the operator is enabled or disabled. function whitelistOperator(address operator, bool enabled) external onlyOwner { _whitelistedOperators[operator] = enabled; emit WhitelistedOperator(operator, enabled); } /// @notice check whether address `who` is given operator rights. /// @param who The address to query. /// @return whether the address is whitelisted operator function isOperator(address who) public view returns (bool) { return _whitelistedOperators[who]; } } // File @openzeppelin/contracts/introspection/[email protected] pragma solidity ^0.6.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } // File @openzeppelin/contracts/introspection/[email protected] pragma solidity ^0.6.0; /** * @dev Implementation of the {IERC165} interface. * * Contracts may inherit from this and call {_registerInterface} to declare * their support of an interface. */ contract ERC165 is IERC165 { /* * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 */ bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; /** * @dev Mapping of interface ids to whether or not it's supported. */ mapping(bytes4 => bool) private _supportedInterfaces; constructor () internal { // Derived contracts need only register support for their own interfaces, // we register support for ERC165 itself here _registerInterface(_INTERFACE_ID_ERC165); } /** * @dev See {IERC165-supportsInterface}. * * Time complexity O(1), guaranteed to always use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) public view override returns (bool) { return _supportedInterfaces[interfaceId]; } /** * @dev Registers the contract as an implementer of the interface defined by * `interfaceId`. Support of the actual ERC165 interface is automatic and * registering its interface id is not required. * * See {IERC165-supportsInterface}. * * Requirements: * * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). */ function _registerInterface(bytes4 interfaceId) internal virtual { require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); _supportedInterfaces[interfaceId] = true; } } // File @openzeppelin/contracts/math/[email protected] pragma solidity ^0.6.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File @openzeppelin/contracts/utils/[email protected] pragma solidity ^0.6.2; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies in extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); return _functionCallWithValue(target, data, value, errorMessage); } function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) { require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: weiValue }(data); if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // File @animoca/ethereum-contracts-erc20_base/contracts/token/ERC20/[email protected] /* https://github.com/OpenZeppelin/openzeppelin-contracts The MIT License (MIT) Copyright (c) 2016-2019 zOS Global Limited Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ pragma solidity 0.6.8; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer( address indexed _from, address indexed _to, uint256 _value ); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval( address indexed _owner, address indexed _spender, uint256 _value ); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); } // File @animoca/ethereum-contracts-erc20_base/contracts/token/ERC20/[email protected] /* https://github.com/OpenZeppelin/openzeppelin-contracts The MIT License (MIT) Copyright (c) 2016-2019 zOS Global Limited Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ pragma solidity 0.6.8; /** * @dev Interface for commonly used additional ERC20 interfaces */ interface IERC20Detailed { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() external view returns (string memory); /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() external view returns (uint8); } // File @animoca/ethereum-contracts-erc20_base/contracts/token/ERC20/[email protected] pragma solidity 0.6.8; /** * @dev Interface for additional ERC20 allowance features */ interface IERC20Allowance { /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) external returns (bool); /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); } // File @animoca/ethereum-contracts-erc20_base/contracts/token/ERC20/[email protected] /* https://github.com/OpenZeppelin/openzeppelin-contracts The MIT License (MIT) Copyright (c) 2016-2019 zOS Global Limited Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ pragma solidity 0.6.8; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20MinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ abstract contract ERC20 is ERC165, Context, IERC20, IERC20Detailed, IERC20Allowance { using SafeMath for uint256; using Address for address; mapping (address => uint256) internal _balances; mapping (address => mapping (address => uint256)) internal _allowances; uint256 internal _totalSupply; constructor() internal { _registerInterface(type(IERC20).interfaceId); _registerInterface(type(IERC20Detailed).interfaceId); _registerInterface(type(IERC20Allowance).interfaceId); // ERC20Name interfaceId: bytes4(keccak256("name()")) _registerInterface(0x06fdde03); // ERC20Symbol interfaceId: bytes4(keccak256("symbol()")) _registerInterface(0x95d89b41); // ERC20Decimals interfaceId: bytes4(keccak256("decimals()")) _registerInterface(0x313ce567); } /////////////////////////////////////////// ERC20 /////////////////////////////////////// /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /////////////////////////////////////////// ERC20Allowance /////////////////////////////////////// /** * @dev See {IERC20Allowance-increaseAllowance}. */ function increaseAllowance( address spender, uint256 addedValue ) public virtual override returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev See {IERC20Allowance-decreaseAllowance}. */ function decreaseAllowance( address spender, uint256 subtractedValue ) public virtual override returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /////////////////////////////////////////// Internal Functions /////////////////////////////////////// /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /////////////////////////////////////////// Hooks /////////////////////////////////////// /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } } // File @animoca/ethereum-contracts-erc20_base/contracts/token/ERC20/[email protected] pragma solidity 0.6.8; abstract contract ERC20WithOperators is ERC20, WhitelistedOperators { /** * NOTICE * This override will allow *any* whitelisted operator to be able to * transfer unresitricted amounts of ERC20WithOperators-based tokens from 'sender' * to 'recipient'. Care must be taken to ensure to integrity of the * whitelisted operator list. */ function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) { address msgSender = _msgSender(); // bypass the internal allowance manipulation and checks for the // whitelisted operator (i.e. _msgSender()). as a side-effect, the // 'Approval' event will not be emitted since the allowance was not // updated. if (!isOperator(msgSender)) { _approve(sender, msgSender, allowance(sender, msgSender).sub(amount)); } _transfer(sender, recipient, amount); return true; } function allowance(address owner, address spender) public override view returns (uint256) { if (isOperator(spender)) { // allow the front-end to determine whether or not an approval is // necessary, given that the whitelisted operator status of the // spender is unknown. A call to WhitelistedOperators::isOperator() // is more direct, but we want to expose a mechanism by which to // check through the ERC20 interface. return type(uint256).max; } else { return super.allowance(owner, spender); } } function increaseAllowance(address spender, uint256 addedValue) public override returns (bool) { if (isOperator(spender)) { // bypass the internal allowance manipulation and checks for the // whitelisted operator (i.e. spender). as a side-effect, the // 'Approval' event will not be emitted since the allowance was not // updated. return true; } else { return super.increaseAllowance(spender, addedValue); } } function decreaseAllowance(address spender, uint256 subtractedValue) public override returns (bool) { if (isOperator(spender)) { // bypass the internal allowance manipulation and checks for the // whitelisted operator (i.e. spender). as a side-effect, the // 'Approval' event will not be emitted since the allowance was not // updated. return true; } else { return super.decreaseAllowance(spender, subtractedValue); } } function _approve(address owner, address spender, uint256 value) internal override { if (isOperator(spender)) { // bypass the internal allowance manipulation and checks for the // whitelisted operator (i.e. spender). as a side-effect, the // 'Approval' event will not be emitted since the allowance was not // updated. return; } else { super._approve(owner, spender, value); } } } // File @openzeppelin/contracts/utils/[email protected] pragma solidity ^0.6.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256` * (`UintSet`) are supported. */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping (bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { require(set._values.length > index, "EnumerableSet: index out of bounds"); return set._values[index]; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(value))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(value))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(value))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint256(_at(set._inner, index))); } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } } // File @openzeppelin/contracts/access/[email protected] pragma solidity ^0.6.0; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. */ abstract contract AccessControl is Context { using EnumerableSet for EnumerableSet.AddressSet; using Address for address; struct RoleData { EnumerableSet.AddressSet members; bytes32 adminRole; } mapping (bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view returns (bool) { return _roles[role].members.contains(account); } /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) public view returns (uint256) { return _roles[role].members.length(); } /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) public view returns (address) { return _roles[role].members.at(index); } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) public virtual { require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant"); _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) public virtual { require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke"); _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) public virtual { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { emit RoleAdminChanged(role, _roles[role].adminRole, adminRole); _roles[role].adminRole = adminRole; } function _grantRole(bytes32 role, address account) private { if (_roles[role].members.add(account)) { emit RoleGranted(role, account, _msgSender()); } } function _revokeRole(bytes32 role, address account) private { if (_roles[role].members.remove(account)) { emit RoleRevoked(role, account, _msgSender()); } } } // File @animoca/ethereum-contracts-core_library/contracts/access/[email protected] pragma solidity 0.6.8; /** * Contract module which allows derived contracts access control over token * minting operations. * * This module is used through inheritance. It will make available the modifier * `onlyMinter`, which can be applied to the minting functions of your contract. * Those functions will only be accessible to accounts with the minter role * once the modifer is put in place. */ contract MinterRole is AccessControl { event MinterAdded(address indexed account); event MinterRemoved(address indexed account); /** * Modifier to make a function callable only by accounts with the minter role. */ modifier onlyMinter() { require(isMinter(_msgSender()), "MinterRole: caller does not have the Minter role"); _; } /** * Constructor. */ constructor () internal { _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); emit MinterAdded(_msgSender()); } /** * Validates whether or not the given account has been granted the minter role. * @param account The account to validate. * @return True if the account has been granted the minter role, false otherwise. */ function isMinter(address account) public view returns (bool) { require(account != address(0), "MinterRole: address zero cannot be minter"); return hasRole(DEFAULT_ADMIN_ROLE, account); } /** * Grants the minter role to a non-minter. * @param account The account to grant the minter role to. */ function addMinter(address account) public onlyMinter { require(!isMinter(account), "MinterRole: add an account already minter"); grantRole(DEFAULT_ADMIN_ROLE, account); emit MinterAdded(account); } /** * Renounces the granted minter role. */ function renounceMinter() public onlyMinter { renounceRole(DEFAULT_ADMIN_ROLE, _msgSender()); emit MinterRemoved(_msgSender()); } } // File contracts/solc-0.6/token/ERC20/REDP.sol pragma solidity 0.6.8; /** * @title REDP */ contract REDP is ERC20WithOperators, MinterRole { // solhint-disable-next-line const-name-snakecase string public constant override name = "REDP"; // solhint-disable-next-line const-name-snakecase string public constant override symbol = "REDP"; // solhint-disable-next-line const-name-snakecase uint8 public constant override decimals = 18; function mint(address holder, uint256 amount) public onlyMinter { _mint(holder, amount); } function batchMint(address[] memory holders, uint256[] memory amounts) public onlyMinter { require(holders.length == amounts.length, "REDP: inconsistent arrays"); for (uint256 i = 0; i < holders.length; ++i) { _mint(holders[i], amounts[i]); } } /** * @dev Destroys `amount` tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 amount) public virtual { _burn(_msgSender(), amount); } /** * @dev Destroys `amount` tokens from `account`, deducting from the caller's * allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for ``accounts``'s tokens of at least * `amount`. */ function burnFrom(address account, uint256 amount) public virtual { uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "REDP: not enough allowance"); _approve(account, _msgSender(), decreasedAllowance); _burn(account, amount); } }
File 3 of 4: AdminUpgradeabilityProxy
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; import './UpgradeabilityProxy.sol'; /** * @title AdminUpgradeabilityProxy * @dev This contract combines an upgradeability proxy with an authorization * mechanism for administrative tasks. * All external functions in this contract must be guarded by the * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity * feature proposal that would enable this to be done automatically. */ contract AdminUpgradeabilityProxy is UpgradeabilityProxy { /** * Contract constructor. * @param _logic address of the initial implementation. * @param _admin Address of the proxy administrator. * @param _data Data to send as msg.data to the implementation to initialize the proxied contract. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped. */ constructor(address _logic, address _admin, bytes memory _data) UpgradeabilityProxy(_logic, _data) public payable { assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)); _setAdmin(_admin); } /** * @dev Emitted when the administration has been transferred. * @param previousAdmin Address of the previous admin. * @param newAdmin Address of the new admin. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Modifier to check whether the `msg.sender` is the admin. * If it is, it will run the function. Otherwise, it will delegate the call * to the implementation. */ modifier ifAdmin() { if (msg.sender == _admin()) { _; } else { _fallback(); } } /** * @return The address of the proxy admin. */ function admin() external ifAdmin returns (address) { return _admin(); } /** * @return The address of the implementation. */ function implementation() external ifAdmin returns (address) { return _implementation(); } /** * @dev Changes the admin of the proxy. * Only the current admin can call this function. * @param newAdmin Address to transfer proxy administration to. */ function changeAdmin(address newAdmin) external ifAdmin { require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address"); emit AdminChanged(_admin(), newAdmin); _setAdmin(newAdmin); } /** * @dev Upgrade the backing implementation of the proxy. * Only the admin can call this function. * @param newImplementation Address of the new implementation. */ function upgradeTo(address newImplementation) external ifAdmin { _upgradeTo(newImplementation); } /** * @dev Upgrade the backing implementation of the proxy and call a function * on the new implementation. * This is useful to initialize the proxied contract. * @param newImplementation Address of the new implementation. * @param data Data to send as msg.data in the low level call. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. */ function upgradeToAndCall(address newImplementation, bytes calldata data) payable external ifAdmin { _upgradeTo(newImplementation); (bool success,) = newImplementation.delegatecall(data); require(success); } /** * @return adm The admin slot. */ function _admin() internal view returns (address adm) { bytes32 slot = ADMIN_SLOT; assembly { adm := sload(slot) } } /** * @dev Sets the address of the proxy admin. * @param newAdmin Address of the new proxy admin. */ function _setAdmin(address newAdmin) internal { bytes32 slot = ADMIN_SLOT; assembly { sstore(slot, newAdmin) } } /** * @dev Only fall back when the sender is not the admin. */ function _willFallback() internal override virtual { require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin"); super._willFallback(); } } // SPDX-License-Identifier: MIT pragma solidity ^0.6.0; import './Proxy.sol'; import '@openzeppelin/contracts/utils/Address.sol'; /** * @title UpgradeabilityProxy * @dev This contract implements a proxy that allows to change the * implementation address to which it will delegate. * Such a change is called an implementation upgrade. */ contract UpgradeabilityProxy is Proxy { /** * @dev Contract constructor. * @param _logic Address of the initial implementation. * @param _data Data to send as msg.data to the implementation to initialize the proxied contract. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped. */ constructor(address _logic, bytes memory _data) public payable { assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)); _setImplementation(_logic); if(_data.length > 0) { (bool success,) = _logic.delegatecall(_data); require(success); } } /** * @dev Emitted when the implementation is upgraded. * @param implementation Address of the new implementation. */ event Upgraded(address indexed implementation); /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Returns the current implementation. * @return impl Address of the current implementation */ function _implementation() internal override view returns (address impl) { bytes32 slot = IMPLEMENTATION_SLOT; assembly { impl := sload(slot) } } /** * @dev Upgrades the proxy to a new implementation. * @param newImplementation Address of the new implementation. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Sets the implementation address of the proxy. * @param newImplementation Address of the new implementation. */ function _setImplementation(address newImplementation) internal { require(Address.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address"); bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, newImplementation) } } } // SPDX-License-Identifier: MIT pragma solidity ^0.6.0; /** * @title Proxy * @dev Implements delegation of calls to other contracts, with proper * forwarding of return values and bubbling of failures. * It defines a fallback function that delegates all calls to the address * returned by the abstract _implementation() internal function. */ abstract contract Proxy { /** * @dev Fallback function. * Implemented entirely in `_fallback`. */ fallback () payable external { _fallback(); } /** * @dev Receive function. * Implemented entirely in `_fallback`. */ receive () payable external { _fallback(); } /** * @return The Address of the implementation. */ function _implementation() internal virtual view returns (address); /** * @dev Delegates execution to an implementation contract. * This is a low level function that doesn't return to its internal call site. * It will return to the external caller whatever the implementation returns. * @param implementation Address to delegate. */ function _delegate(address implementation) internal { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } /** * @dev Function that is run as the first thing in the fallback function. * Can be redefined in derived contracts to add functionality. * Redefinitions must call super._willFallback(). */ function _willFallback() internal virtual { } /** * @dev fallback implementation. * Extracted to enable manual triggering. */ function _fallback() internal { _willFallback(); _delegate(_implementation()); } } // SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
File 4 of 4: Asset
pragma solidity 0.5.9; import "./Asset/ERC1155ERC721.sol"; contract Asset is ERC1155ERC721 {} pragma solidity 0.5.9; import "../contracts_common/Interfaces/ERC1155.sol"; import "../contracts_common/Interfaces/ERC1155TokenReceiver.sol"; import "../contracts_common/Libraries/AddressUtils.sol"; import "../contracts_common/Libraries/ObjectLib32.sol"; import "../contracts_common/Interfaces/ERC721.sol"; import "../contracts_common/Interfaces/ERC721TokenReceiver.sol"; import "../contracts_common/BaseWithStorage/SuperOperators.sol"; contract ERC1155ERC721 is SuperOperators, ERC1155, ERC721 { using AddressUtils for address; using ObjectLib32 for ObjectLib32.Operations; using ObjectLib32 for uint256; bytes4 private constant ERC1155_IS_RECEIVER = 0x4e2312e0; bytes4 private constant ERC1155_RECEIVED = 0xf23a6e61; bytes4 private constant ERC1155_BATCH_RECEIVED = 0xbc197c81; bytes4 private constant ERC721_RECEIVED = 0x150b7a02; uint256 private constant CREATOR_OFFSET_MULTIPLIER = uint256(2)**(256 - 160); uint256 private constant IS_NFT_OFFSET_MULTIPLIER = uint256(2)**(256 - 160 - 1); uint256 private constant PACK_ID_OFFSET_MULTIPLIER = uint256(2)**(256 - 160 - 1 - 32 - 40); uint256 private constant PACK_NUM_FT_TYPES_OFFSET_MULTIPLIER = uint256(2)**(256 - 160 - 1 - 32 - 40 - 12); uint256 private constant NFT_INDEX_OFFSET = 63; uint256 private constant IS_NFT = 0x0000000000000000000000000000000000000000800000000000000000000000; uint256 private constant NOT_IS_NFT = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFFFFFF; uint256 private constant NFT_INDEX = 0x00000000000000000000000000000000000000007FFFFFFF8000000000000000; uint256 private constant NOT_NFT_INDEX = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF800000007FFFFFFFFFFFFFFF; uint256 private constant URI_ID = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000007FFFFFFFFFFFF800; uint256 private constant PACK_ID = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000007FFFFFFFFF800000; uint256 private constant PACK_INDEX = 0x00000000000000000000000000000000000000000000000000000000000007FF; uint256 private constant PACK_NUM_FT_TYPES = 0x00000000000000000000000000000000000000000000000000000000007FF800; uint256 private constant MAX_SUPPLY = uint256(2)**32 - 1; uint256 private constant MAX_PACK_SIZE = uint256(2)**11; event CreatorshipTransfer( address indexed original, address indexed from, address indexed to ); mapping(address => uint256) private _numNFTPerAddress; // erc721 mapping(uint256 => uint256) private _owners; // erc721 mapping(address => mapping(uint256 => uint256)) private _packedTokenBalance; // erc1155 mapping(address => mapping(address => bool)) private _operatorsForAll; // erc721 and erc1155 mapping(uint256 => address) private _erc721operators; // erc721 mapping(uint256 => bytes32) private _metadataHash; // erc721 and erc1155 mapping(uint256 => bytes) private _rarityPacks; // rarity configuration per packs (2 bits per Asset) mapping(uint256 => uint32) private _nextCollectionIndex; // extraction mapping(address => address) private _creatorship; // creatorship transfer mapping(address => bool) private _bouncers; // the contracts allowed to mint mapping(address => bool) private _metaTransactionContracts; // native meta-transaction support address private _bouncerAdmin; bool internal _init; function init( address metaTransactionContract, address admin, address bouncerAdmin ) public { require(!_init, "ALREADY_INITIALISED"); _init = true; _metaTransactionContracts[metaTransactionContract] = true; _admin = admin; _bouncerAdmin = bouncerAdmin; emit MetaTransactionProcessor(metaTransactionContract, true); } event BouncerAdminChanged(address oldBouncerAdmin, address newBouncerAdmin); /// @notice Returns the current administrator in charge of minting rights. /// @return the current minting administrator in charge of minting rights. function getBouncerAdmin() external view returns(address) { return _bouncerAdmin; } /// @notice Change the minting administrator to be `newBouncerAdmin`. /// @param newBouncerAdmin address of the new minting administrator. function changeBouncerAdmin(address newBouncerAdmin) external { require( msg.sender == _bouncerAdmin, "only bouncerAdmin can change itself" ); emit BouncerAdminChanged(_bouncerAdmin, newBouncerAdmin); _bouncerAdmin = newBouncerAdmin; } event Bouncer(address bouncer, bool enabled); /// @notice Enable or disable the ability of `bouncer` to mint tokens (minting bouncer rights). /// @param bouncer address that will be given/removed minting bouncer rights. /// @param enabled set whether the address is enabled or disabled as a minting bouncer. function setBouncer(address bouncer, bool enabled) external { require( msg.sender == _bouncerAdmin, "only bouncerAdmin can setup bouncers" ); _bouncers[bouncer] = enabled; emit Bouncer(bouncer, enabled); } /// @notice check whether address `who` is given minting bouncer rights. /// @param who The address to query. /// @return whether the address has minting rights. function isBouncer(address who) external view returns(bool) { return _bouncers[who]; } event MetaTransactionProcessor(address metaTransactionProcessor, bool enabled); /// @notice Enable or disable the ability of `metaTransactionProcessor` to perform meta-tx (metaTransactionProcessor rights). /// @param metaTransactionProcessor address that will be given/removed metaTransactionProcessor rights. /// @param enabled set whether the metaTransactionProcessor is enabled or disabled. function setMetaTransactionProcessor(address metaTransactionProcessor, bool enabled) external { require( msg.sender == _admin, "only admin can setup metaTransactionProcessors" ); _metaTransactionContracts[metaTransactionProcessor] = enabled; emit MetaTransactionProcessor(metaTransactionProcessor, enabled); } /// @notice check whether address `who` is given meta-transaction execution rights. /// @param who The address to query. /// @return whether the address has meta-transaction execution rights. function isMetaTransactionProcessor(address who) external view returns(bool) { return _metaTransactionContracts[who]; } /// @notice Mint a token type for `creator` on slot `packId`. /// @param creator address of the creator of the token. /// @param packId unique packId for that token. /// @param hash hash of an IPFS cidv1 folder that contains the metadata of the token type in the file 0.json. /// @param supply number of tokens minted for that token type. /// @param rarity rarity power of the token. /// @param owner address that will receive the tokens. /// @param data extra data to accompany the minting call. /// @return the id of the newly minted token type. function mint( address creator, uint40 packId, bytes32 hash, uint256 supply, uint8 rarity, address owner, bytes calldata data ) external returns (uint256 id) { require(hash != 0, "hash is zero"); require(_bouncers[msg.sender], "only bouncer allowed to mint"); require(owner != address(0), "destination is zero address"); id = generateTokenId(creator, supply, packId, supply == 1 ? 0 : 1, 0); _mint( hash, supply, rarity, msg.sender, owner, id, data, false ); } function generateTokenId( address creator, uint256 supply, uint40 packId, uint16 numFTs, uint16 packIndex ) internal pure returns (uint256) { require(supply > 0 && supply <= MAX_SUPPLY, "invalid supply"); return uint256(creator) * CREATOR_OFFSET_MULTIPLIER + // CREATOR (supply == 1 ? uint256(1) * IS_NFT_OFFSET_MULTIPLIER : 0) + // minted as NFT (1) or FT (0) // IS_NFT uint256(packId) * PACK_ID_OFFSET_MULTIPLIER + // packId (unique pack) // PACk_ID numFTs * PACK_NUM_FT_TYPES_OFFSET_MULTIPLIER + // number of fungible token in the pack // PACK_NUM_FT_TYPES packIndex; // packIndex (position in the pack) // PACK_INDEX } function _mint( bytes32 hash, uint256 supply, uint8 rarity, address operator, address owner, uint256 id, bytes memory data, bool extraction ) internal { uint256 uriId = id & URI_ID; if (!extraction) { require(uint256(_metadataHash[uriId]) == 0, "id already used"); _metadataHash[uriId] = hash; require(rarity < 4, "rarity >= 4"); bytes memory pack = new bytes(1); pack[0] = bytes1(rarity * 64); _rarityPacks[uriId] = pack; } if (supply == 1) { // ERC721 _numNFTPerAddress[owner]++; _owners[id] = uint256(owner); emit Transfer(address(0), owner, id); } else { (uint256 bin, uint256 index) = id.getTokenBinIndex(); _packedTokenBalance[owner][bin] = _packedTokenBalance[owner][bin] .updateTokenBalance( index, supply, ObjectLib32.Operations.REPLACE ); } emit TransferSingle(operator, address(0), owner, id, supply); require( _checkERC1155AndCallSafeTransfer( operator, address(0), owner, id, supply, data, false, false ), "transfer rejected" ); } /// @notice Mint multiple token types for `creator` on slot `packId`. /// @param creator address of the creator of the tokens. /// @param packId unique packId for the tokens. /// @param hash hash of an IPFS cidv1 folder that contains the metadata of each token type in the files: 0.json, 1.json, 2.json, etc... /// @param supplies number of tokens minted for each token type. /// @param rarityPack rarity power of each token types packed into 2 bits each. /// @param owner address that will receive the tokens. /// @param data extra data to accompany the minting call. /// @return the ids of each newly minted token types. function mintMultiple( address creator, uint40 packId, bytes32 hash, uint256[] calldata supplies, bytes calldata rarityPack, address owner, bytes calldata data ) external returns (uint256[] memory ids) { require(hash != 0, "hash is zero"); require(_bouncers[msg.sender], "only bouncer allowed to mint"); require(owner != address(0), "destination is zero address"); uint16 numNFTs; (ids, numNFTs) = allocateIds( creator, supplies, rarityPack, packId, hash ); _mintBatches(supplies, owner, ids, numNFTs); completeMultiMint(msg.sender, owner, ids, supplies, data); } function allocateIds( address creator, uint256[] memory supplies, bytes memory rarityPack, uint40 packId, bytes32 hash ) internal returns (uint256[] memory ids, uint16 numNFTs) { require(supplies.length > 0, "supplies.length == 0"); require(supplies.length <= MAX_PACK_SIZE, "too big batch"); (ids, numNFTs) = generateTokenIds(creator, supplies, packId); uint256 uriId = ids[0] & URI_ID; require(uint256(_metadataHash[uriId]) == 0, "id already used"); _metadataHash[uriId] = hash; _rarityPacks[uriId] = rarityPack; } function generateTokenIds( address creator, uint256[] memory supplies, uint40 packId ) internal pure returns (uint256[] memory, uint16) { uint16 numTokenTypes = uint16(supplies.length); uint256[] memory ids = new uint256[](numTokenTypes); uint16 numNFTs = 0; for (uint16 i = 0; i < numTokenTypes; i++) { if (numNFTs == 0) { if (supplies[i] == 1) { numNFTs = uint16(numTokenTypes - i); } } else { require(supplies[i] == 1, "NFTs need to be put at the end"); } } uint16 numFTs = numTokenTypes - numNFTs; for (uint16 i = 0; i < numTokenTypes; i++) { ids[i] = generateTokenId(creator, supplies[i], packId, numFTs, i); } return (ids, numNFTs); } function completeMultiMint( address operator, address owner, uint256[] memory ids, uint256[] memory supplies, bytes memory data ) internal { emit TransferBatch(operator, address(0), owner, ids, supplies); require( _checkERC1155AndCallSafeBatchTransfer( operator, address(0), owner, ids, supplies, data ), "transfer rejected" ); } function _mintBatches( uint256[] memory supplies, address owner, uint256[] memory ids, uint16 numNFTs ) internal { uint16 offset = 0; while (offset < supplies.length - numNFTs) { _mintBatch(offset, supplies, owner, ids); offset += 8; } // deal with NFT last. they do not care of balance packing if (numNFTs > 0) { _mintNFTs( uint16(supplies.length - numNFTs), numNFTs, owner, ids ); } } function _mintNFTs( uint16 offset, uint32 numNFTs, address owner, uint256[] memory ids ) internal { for (uint16 i = 0; i < numNFTs; i++) { uint256 id = ids[i + offset]; _owners[id] = uint256(owner); emit Transfer(address(0), owner, id); } _numNFTPerAddress[owner] += numNFTs; } function _mintBatch( uint16 offset, uint256[] memory supplies, address owner, uint256[] memory ids ) internal { uint256 firstId = ids[offset]; (uint256 bin, uint256 index) = firstId.getTokenBinIndex(); uint256 balances = _packedTokenBalance[owner][bin]; for (uint256 i = 0; i < 8 && offset + i < supplies.length; i++) { uint256 j = offset + i; if (supplies[j] > 1) { balances = balances.updateTokenBalance( index + i, supplies[j], ObjectLib32.Operations.REPLACE ); } else { break; } } _packedTokenBalance[owner][bin] = balances; } function _transferFrom( address from, address to, uint256 id, uint256 value ) internal returns (bool metaTx) { require(to != address(0), "destination is zero address"); require(from != address(0), "from is zero address"); metaTx = _metaTransactionContracts[msg.sender]; bool authorized = from == msg.sender || metaTx || _superOperators[msg.sender] || _operatorsForAll[from][msg.sender]; if (id & IS_NFT > 0) { require( authorized || _erc721operators[id] == msg.sender, "Operator not approved" ); if(value > 0) { require(value == 1, "cannot transfer nft if amount not 1"); _numNFTPerAddress[from]--; _numNFTPerAddress[to]++; _owners[id] = uint256(to); if (_erc721operators[id] != address(0)) { // TODO operatorEnabled flag optimization (like in ERC721BaseToken) _erc721operators[id] = address(0); } emit Transfer(from, to, id); } } else { require(authorized, "Operator not approved"); if(value > 0) { // if different owners it will fails (uint256 bin, uint256 index) = id.getTokenBinIndex(); _packedTokenBalance[from][bin] = _packedTokenBalance[from][bin] .updateTokenBalance(index, value, ObjectLib32.Operations.SUB); _packedTokenBalance[to][bin] = _packedTokenBalance[to][bin] .updateTokenBalance(index, value, ObjectLib32.Operations.ADD); } } emit TransferSingle( metaTx ? from : msg.sender, from, to, id, value ); } /// @notice Transfers `value` tokens of type `id` from `from` to `to` (with safety call). /// @param from address from which tokens are transfered. /// @param to address to which the token will be transfered. /// @param id the token type transfered. /// @param value amount of token transfered. /// @param data aditional data accompanying the transfer. function safeTransferFrom( address from, address to, uint256 id, uint256 value, bytes calldata data ) external { if (id & IS_NFT > 0) { require(_ownerOf(id) == from, "not owner"); } bool metaTx = _transferFrom(from, to, id, value); require( _checkERC1155AndCallSafeTransfer( metaTx ? from : msg.sender, from, to, id, value, data, false, false ), "erc1155 transfer rejected" ); } /// @notice Transfers `values` tokens of type `ids` from `from` to `to` (with safety call). /// @dev call data should be optimized to order ids so packedBalance can be used efficiently. /// @param from address from which tokens are transfered. /// @param to address to which the token will be transfered. /// @param ids ids of each token type transfered. /// @param values amount of each token type transfered. /// @param data aditional data accompanying the transfer. function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external { require( ids.length == values.length, "Inconsistent array length between args" ); require(to != address(0), "destination is zero address"); require(from != address(0), "from is zero address"); bool metaTx = _metaTransactionContracts[msg.sender]; bool authorized = from == msg.sender || metaTx || _superOperators[msg.sender] || _operatorsForAll[from][msg.sender]; // solium-disable-line max-len _batchTransferFrom(from, to, ids, values, authorized); emit TransferBatch( metaTx ? from : msg.sender, from, to, ids, values ); require( _checkERC1155AndCallSafeBatchTransfer( metaTx ? from : msg.sender, from, to, ids, values, data ), "erc1155 transfer rejected" ); } function _batchTransferFrom( address from, address to, uint256[] memory ids, uint256[] memory values, bool authorized ) internal { uint256 numItems = ids.length; uint256 bin; uint256 index; uint256 balFrom; uint256 balTo; uint256 lastBin; uint256 numNFTs = 0; for (uint256 i = 0; i < numItems; i++) { if (ids[i] & IS_NFT > 0) { require( authorized || _erc721operators[ids[i]] == msg.sender, "Operator not approved" ); if(values[i] > 0) { require(values[i] == 1, "cannot transfer nft if amount not 1"); require(_ownerOf(ids[i]) == from, "not owner"); numNFTs++; _owners[ids[i]] = uint256(to); if (_erc721operators[ids[i]] != address(0)) { // TODO operatorEnabled flag optimization (like in ERC721BaseToken) _erc721operators[ids[i]] = address(0); } emit Transfer(from, to, ids[i]); } } else { require(authorized, "Operator not approved"); if (from == to) { _checkEnoughBalance(from, ids[i], values[i]); } else if(values[i] > 0) { (bin, index) = ids[i].getTokenBinIndex(); if (lastBin == 0) { lastBin = bin; balFrom = ObjectLib32.updateTokenBalance( _packedTokenBalance[from][bin], index, values[i], ObjectLib32.Operations.SUB ); balTo = ObjectLib32.updateTokenBalance( _packedTokenBalance[to][bin], index, values[i], ObjectLib32.Operations.ADD ); } else { if (bin != lastBin) { _packedTokenBalance[from][lastBin] = balFrom; _packedTokenBalance[to][lastBin] = balTo; balFrom = _packedTokenBalance[from][bin]; balTo = _packedTokenBalance[to][bin]; lastBin = bin; } balFrom = balFrom.updateTokenBalance( index, values[i], ObjectLib32.Operations.SUB ); balTo = balTo.updateTokenBalance( index, values[i], ObjectLib32.Operations.ADD ); } } } } if (numNFTs > 0 && from != to) { _numNFTPerAddress[from] -= numNFTs; _numNFTPerAddress[to] += numNFTs; } if (bin != 0 && from != to) { _packedTokenBalance[from][bin] = balFrom; _packedTokenBalance[to][bin] = balTo; } } function _checkEnoughBalance(address from, uint256 id, uint256 value) internal { (uint256 bin, uint256 index) = id.getTokenBinIndex(); require(_packedTokenBalance[from][bin].getValueInBin(index) >= value, "can't substract more than there is"); } /// @notice Get the balance of `owner` for the token type `id`. /// @param owner The address of the token holder. /// @param id the token type of which to get the balance of. /// @return the balance of `owner` for the token type `id`. function balanceOf(address owner, uint256 id) public view returns (uint256) { // do not check for existence, balance is zero if never minted // require(wasEverMinted(id), "token was never minted"); if (id & IS_NFT > 0) { if (_ownerOf(id) == owner) { return 1; } else { return 0; } } (uint256 bin, uint256 index) = id.getTokenBinIndex(); return _packedTokenBalance[owner][bin].getValueInBin(index); } /// @notice Get the balance of `owners` for each token type `ids`. /// @param owners the addresses of the token holders queried. /// @param ids ids of each token type to query. /// @return the balance of each `owners` for each token type `ids`. function balanceOfBatch( address[] calldata owners, uint256[] calldata ids ) external view returns (uint256[] memory) { require( owners.length == ids.length, "Inconsistent array length between args" ); uint256[] memory balances = new uint256[](ids.length); for (uint256 i = 0; i < ids.length; i++) { balances[i] = balanceOf(owners[i], ids[i]); } return balances; } /// @notice Get the creator of the token type `id`. /// @param id the id of the token to get the creator of. /// @return the creator of the token type `id`. function creatorOf(uint256 id) external view returns (address) { require(wasEverMinted(id), "token was never minted"); address originalCreator = address(id / CREATOR_OFFSET_MULTIPLIER); address newCreator = _creatorship[originalCreator]; if (newCreator != address(0)) { return newCreator; } return originalCreator; } /// @notice Transfers creatorship of `original` from `sender` to `to`. /// @param sender address of current registered creator. /// @param original address of the original creator whose creation are saved in the ids themselves. /// @param to address which will be given creatorship for all tokens originally minted by `original`. function transferCreatorship( address sender, address original, address to ) external { require( msg.sender == sender || _metaTransactionContracts[msg.sender] || _superOperators[msg.sender], "require meta approval" ); require(sender != address(0), "sender is zero address"); require(to != address(0), "destination is zero address"); address current = _creatorship[original]; if (current == address(0)) { current = original; } require(current != to, "current == to"); require(current == sender, "current != sender"); if (to == original) { _creatorship[original] = address(0); } else { _creatorship[original] = to; } emit CreatorshipTransfer(original, current, to); } /// @notice Enable or disable approval for `operator` to manage all `sender`'s tokens. /// @dev used for Meta Transaction (from metaTransactionContract). /// @param sender address which grant approval. /// @param operator address which will be granted rights to transfer all token owned by `sender`. /// @param approved whether to approve or revoke. function setApprovalForAllFor( address sender, address operator, bool approved ) external { require( msg.sender == sender || _metaTransactionContracts[msg.sender] || _superOperators[msg.sender], "require meta approval" ); _setApprovalForAll(sender, operator, approved); } /// @notice Enable or disable approval for `operator` to manage all of the caller's tokens. /// @param operator address which will be granted rights to transfer all tokens of the caller. /// @param approved whether to approve or revoke function setApprovalForAll(address operator, bool approved) external { _setApprovalForAll(msg.sender, operator, approved); } function _setApprovalForAll( address sender, address operator, bool approved ) internal { require(sender != address(0), "sender is zero address"); require(sender != operator, "sender = operator"); require(operator != address(0), "operator is zero address"); require( !_superOperators[operator], "super operator can't have their approvalForAll changed" ); _operatorsForAll[sender][operator] = approved; emit ApprovalForAll(sender, operator, approved); } /// @notice Queries the approval status of `operator` for owner `owner`. /// @param owner the owner of the tokens. /// @param operator address of authorized operator. /// @return true if the operator is approved, false if not. function isApprovedForAll(address owner, address operator) external view returns (bool isOperator) { require(owner != address(0), "owner is zero address"); require(operator != address(0), "operator is zero address"); return _operatorsForAll[owner][operator] || _superOperators[operator]; } /// @notice Count all NFTs assigned to `owner`. /// @param owner address for whom to query the balance. /// @return the number of NFTs owned by `owner`, possibly zero. function balanceOf(address owner) external view returns (uint256 balance) { require(owner != address(0), "owner is zero address"); return _numNFTPerAddress[owner]; } /// @notice Find the owner of an NFT. /// @param id the identifier for an NFT. /// @return the address of the owner of the NFT. function ownerOf(uint256 id) external view returns (address owner) { owner = _ownerOf(id); require(owner != address(0), "NFT does not exist"); } function _ownerOf(uint256 id) internal view returns (address) { return address(_owners[id]); } /// @notice Change or reaffirm the approved address for an NFT for `sender`. /// @dev used for Meta Transaction (from metaTransactionContract). /// @param sender the sender granting control. /// @param operator the address to approve as NFT controller. /// @param id the NFT to approve. function approveFor(address sender, address operator, uint256 id) external { address owner = _ownerOf(id); require(sender != address(0), "sender is zero address"); require( msg.sender == sender || _metaTransactionContracts[msg.sender] || _superOperators[msg.sender] || _operatorsForAll[sender][msg.sender], "require operators" ); // solium-disable-line max-len require(owner == sender, "not owner"); _erc721operators[id] = operator; emit Approval(owner, operator, id); } /// @notice Change or reaffirm the approved address for an NFT. /// @param operator the address to approve as NFT controller. /// @param id the id of the NFT to approve. function approve(address operator, uint256 id) external { address owner = _ownerOf(id); require(owner != address(0), "NFT does not exist"); require( owner == msg.sender || _superOperators[msg.sender] || _operatorsForAll[owner][msg.sender], "not authorized" ); _erc721operators[id] = operator; emit Approval(owner, operator, id); } /// @notice Get the approved address for a single NFT. /// @param id the NFT to find the approved address for. /// @return the approved address for this NFT, or the zero address if there is none. function getApproved(uint256 id) external view returns (address operator) { require(_ownerOf(id) != address(0), "NFT does not exist"); return _erc721operators[id]; } /// @notice Transfers ownership of an NFT. /// @param from the current owner of the NFT. /// @param to the new owner. /// @param id the NFT to transfer. function transferFrom(address from, address to, uint256 id) external { require(_ownerOf(id) == from, "not owner"); bool metaTx = _transferFrom(from, to, id, 1); require( _checkERC1155AndCallSafeTransfer( metaTx ? from : msg.sender, from, to, id, 1, "", true, false ), "erc1155 transfer rejected" ); } /// @notice Transfers the ownership of an NFT from one address to another address. /// @param from the current owner of the NFT. /// @param to the new owner. /// @param id the NFT to transfer. function safeTransferFrom(address from, address to, uint256 id) external { safeTransferFrom(from, to, id, ""); } /// @notice Transfers the ownership of an NFT from one address to another address. /// @param from the current owner of the NFT. /// @param to the new owner. /// @param id the NFT to transfer. /// @param data additional data with no specified format, sent in call to `to`. function safeTransferFrom( address from, address to, uint256 id, bytes memory data ) public { require(_ownerOf(id) == from, "not owner"); bool metaTx = _transferFrom(from, to, id, 1); require( _checkERC1155AndCallSafeTransfer( metaTx ? from : msg.sender, from, to, id, 1, data, true, true ), "erc721/erc1155 transfer rejected" ); } /// @notice A descriptive name for the collection of tokens in this contract. /// @return the name of the tokens. function name() external pure returns (string memory _name) { return "Sandbox's ASSETs"; } /// @notice An abbreviated name for the collection of tokens in this contract. /// @return the symbol of the tokens. function symbol() external pure returns (string memory _symbol) { return "ASSET"; } /// @notice Gives the rarity power of a particular token type. /// @param id the token type to get the rarity of. /// @return the rarity power(between 0 and 3). function rarity(uint256 id) public view returns (uint256) { require(wasEverMinted(id), "token was never minted"); bytes storage rarityPack = _rarityPacks[id & URI_ID]; uint256 packIndex = id & PACK_INDEX; if (packIndex / 4 >= rarityPack.length) { return 0; } else { uint8 pack = uint8(rarityPack[packIndex / 4]); uint8 i = (3 - uint8(packIndex % 4)) * 2; return (pack / (uint8(2)**i)) % 4; } } /// @notice Gives the collection a specific token belongs to. /// @param id the token to get the collection of. /// @return the collection the NFT is part of. function collectionOf(uint256 id) public view returns (uint256) { require(_ownerOf(id) != address(0), "NFT does not exist"); uint256 collectionId = id & NOT_NFT_INDEX & NOT_IS_NFT; require(wasEverMinted(collectionId), "no collection ever minted for that token"); return collectionId; } /// @notice Return wether the id is a collection /// @param id collectionId to check. /// @return whether the id is a collection. function isCollection(uint256 id) public view returns (bool) { uint256 collectionId = id & NOT_NFT_INDEX & NOT_IS_NFT; return wasEverMinted(collectionId); } /// @notice Gives the index at which an NFT was minted in a collection : first of a collection get the zero index. /// @param id the token to get the index of. /// @return the index/order at which the token `id` was minted in a collection. function collectionIndexOf(uint256 id) public view returns (uint256) { collectionOf(id); // this check if id and collection indeed was ever minted return uint32((id & NFT_INDEX) >> NFT_INDEX_OFFSET); } function toFullURI(bytes32 hash, uint256 id) internal pure returns (string memory) { return string( abi.encodePacked( "ipfs://bafybei", hash2base32(hash), "/", uint2str(id & PACK_INDEX), ".json" ) ); } function wasEverMinted(uint256 id) public view returns(bool) { if ((id & IS_NFT) > 0) { return _owners[id] != 0; } else { return ((id & PACK_INDEX) < ((id & PACK_NUM_FT_TYPES) / PACK_NUM_FT_TYPES_OFFSET_MULTIPLIER)) && _metadataHash[id & URI_ID] != 0; } } /// @notice check whether a packId/numFT tupple has been used /// @param creator for which creator /// @param packId the packId to check /// @param numFTs number of Fungible Token in that pack (can reuse packId if different) /// @return whether the pack has already been used function isPackIdUsed(address creator, uint40 packId, uint16 numFTs) external returns(bool) { uint256 uriId = uint256(creator) * CREATOR_OFFSET_MULTIPLIER + // CREATOR uint256(packId) * PACK_ID_OFFSET_MULTIPLIER + // packId (unique pack) // PACk_ID numFTs * PACK_NUM_FT_TYPES_OFFSET_MULTIPLIER; // number of fungible token in the pack // PACK_NUM_FT_TYPES return _metadataHash[uriId] != 0; } /// @notice A distinct Uniform Resource Identifier (URI) for a given token. /// @param id token to get the uri of. /// @return URI string function uri(uint256 id) public view returns (string memory) { require(wasEverMinted(id), "token was never minted"); // prevent returning invalid uri return toFullURI(_metadataHash[id & URI_ID], id); } /// @notice A distinct Uniform Resource Identifier (URI) for a given asset. /// @param id token to get the uri of. /// @return URI string function tokenURI(uint256 id) public view returns (string memory) { require(_ownerOf(id) != address(0), "NFT does not exist"); return toFullURI(_metadataHash[id & URI_ID], id); } bytes32 private constant base32Alphabet = 0x6162636465666768696A6B6C6D6E6F707172737475767778797A323334353637; // solium-disable-next-line security/no-assign-params function hash2base32(bytes32 hash) private pure returns (string memory _uintAsString) { uint256 _i = uint256(hash); uint256 k = 52; bytes memory bstr = new bytes(k); bstr[--k] = base32Alphabet[uint8((_i % 8) << 2)]; // uint8 s = uint8((256 - skip) % 5); // (_i % (2**s)) << (5-s) _i /= 8; while (k > 0) { bstr[--k] = base32Alphabet[_i % 32]; _i /= 32; } return string(bstr); } // solium-disable-next-line security/no-assign-params function uint2str(uint256 _i) private pure returns (string memory _uintAsString) { if (_i == 0) { return "0"; } uint256 j = _i; uint256 len; while (j != 0) { len++; j /= 10; } bytes memory bstr = new bytes(len); uint256 k = len - 1; while (_i != 0) { bstr[k--] = bytes1(uint8(48 + (_i % 10))); _i /= 10; } return string(bstr); } /// @notice Query if a contract implements interface `id`. /// @param id the interface identifier, as specified in ERC-165. /// @return `true` if the contract implements `id`. function supportsInterface(bytes4 id) external view returns (bool) { return id == 0x01ffc9a7 || //ERC165 id == 0xd9b67a26 || // ERC1155 id == 0x80ac58cd || // ERC721 id == 0x5b5e139f || // ERC721 metadata id == 0x0e89341c; // ERC1155 metadata } bytes4 constant ERC165ID = 0x01ffc9a7; function checkIsERC1155Receiver(address _contract) internal view returns (bool) { bool success; bool result; bytes memory call_data = abi.encodeWithSelector( ERC165ID, ERC1155_IS_RECEIVER ); // solium-disable-next-line security/no-inline-assembly assembly { let call_ptr := add(0x20, call_data) let call_size := mload(call_data) let output := mload(0x40) // Find empty storage location using "free memory pointer" mstore(output, 0x0) success := staticcall( 10000, _contract, call_ptr, call_size, output, 0x20 ) // 32 bytes result := mload(output) } // (10000 / 63) "not enough for supportsInterface(...)" // consume all gas, so caller can potentially know that there was not enough gas assert(gasleft() > 158); return success && result; } function _checkERC1155AndCallSafeTransfer( address operator, address from, address to, uint256 id, uint256 value, bytes memory data, bool erc721, bool erc721Safe ) internal returns (bool) { if (!to.isContract()) { return true; } if (erc721) { if (!checkIsERC1155Receiver(to)) { if (erc721Safe) { return _checkERC721AndCallSafeTransfer( operator, from, to, id, data ); } else { return true; } } } return ERC1155TokenReceiver(to).onERC1155Received( operator, from, id, value, data ) == ERC1155_RECEIVED; } function _checkERC1155AndCallSafeBatchTransfer( address operator, address from, address to, uint256[] memory ids, uint256[] memory values, bytes memory data ) internal returns (bool) { if (!to.isContract()) { return true; } bytes4 retval = ERC1155TokenReceiver(to).onERC1155BatchReceived( operator, from, ids, values, data ); return (retval == ERC1155_BATCH_RECEIVED); } function _checkERC721AndCallSafeTransfer( address operator, address from, address to, uint256 id, bytes memory data ) internal returns (bool) { // following not required as this function is always called as part of ERC1155 checks that include such check already // if (!to.isContract()) { // return true; // } return (ERC721TokenReceiver(to).onERC721Received( operator, from, id, data ) == ERC721_RECEIVED); } event Extraction(uint256 indexed fromId, uint256 toId); event AssetUpdate(uint256 indexed fromId, uint256 toId); function _burnERC1155( address operator, address from, uint256 id, uint32 amount ) internal { (uint256 bin, uint256 index) = (id).getTokenBinIndex(); _packedTokenBalance[from][bin] = _packedTokenBalance[from][bin] .updateTokenBalance(index, amount, ObjectLib32.Operations.SUB); emit TransferSingle(operator, from, address(0), id, amount); } function _burnERC721(address operator, address from, uint256 id) internal { require(from == _ownerOf(id), "not owner"); _owners[id] = 2**160; // equivalent to zero address when casted but ensure we track minted status _numNFTPerAddress[from]--; emit Transfer(from, address(0), id); emit TransferSingle(operator, from, address(0), id, 1); } /// @notice Burns `amount` tokens of type `id`. /// @param id token type which will be burnt. /// @param amount amount of token to burn. function burn(uint256 id, uint256 amount) external { _burn(msg.sender, id, amount); } /// @notice Burns `amount` tokens of type `id` from `from`. /// @param from address whose token is to be burnt. /// @param id token type which will be burnt. /// @param amount amount of token to burn. function burnFrom(address from, uint256 id, uint256 amount) external { require(from != address(0), "from is zero address"); require( msg.sender == from || _metaTransactionContracts[msg.sender] || _superOperators[msg.sender] || _operatorsForAll[from][msg.sender], "require meta approval" ); _burn(from, id, amount); } function _burn(address from, uint256 id, uint256 amount) internal { if ((id & IS_NFT) > 0) { require(amount == 1, "can only burn one NFT"); _burnERC721( _metaTransactionContracts[msg.sender] ? from : msg.sender, from, id ); } else { require(amount > 0 && amount <= MAX_SUPPLY, "invalid amount"); _burnERC1155( _metaTransactionContracts[msg.sender] ? from : msg.sender, from, id, uint32(amount) ); } } /// @notice Upgrades an NFT with new metadata and rarity. /// @param from address which own the NFT to be upgraded. /// @param id the NFT that will be burnt to be upgraded. /// @param packId unqiue packId for the token. /// @param hash hash of an IPFS cidv1 folder that contains the metadata of the new token type in the file 0.json. /// @param newRarity rarity power of the new NFT. /// @param to address which will receive the NFT. /// @param data bytes to be transmitted as part of the minted token. /// @return the id of the newly minted NFT. function updateERC721( address from, uint256 id, uint40 packId, bytes32 hash, uint8 newRarity, address to, bytes calldata data ) external returns(uint256) { require(hash != 0, "hash is zero"); require( _bouncers[msg.sender], "only bouncer allowed to mint via update" ); require(to != address(0), "destination is zero address"); require(from != address(0), "from is zero address"); _burnERC721(msg.sender, from, id); uint256 newId = generateTokenId(from, 1, packId, 0, 0); _mint(hash, 1, newRarity, msg.sender, to, newId, data, false); emit AssetUpdate(id, newId); return newId; } /// @notice Extracts an EIP-721 NFT from an EIP-1155 token. /// @param id the token type to extract from. /// @param to address which will receive the token. /// @return the id of the newly minted NFT. function extractERC721(uint256 id, address to) external returns (uint256 newId) { return _extractERC721From(msg.sender, msg.sender, id, to); } /// @notice Extracts an EIP-721 NFT from an EIP-1155 token. /// @param sender address which own the token to be extracted. /// @param id the token type to extract from. /// @param to address which will receive the token. /// @return the id of the newly minted NFT. function extractERC721From(address sender, uint256 id, address to) external returns (uint256 newId) { bool metaTx = _metaTransactionContracts[msg.sender]; require( msg.sender == sender || metaTx || _superOperators[msg.sender] || _operatorsForAll[sender][msg.sender], "require meta approval" ); return _extractERC721From(metaTx ? sender : msg.sender, sender, id, to); } function _extractERC721From(address operator, address sender, uint256 id, address to) internal returns (uint256 newId) { require(to != address(0), "destination is zero address"); require(id & IS_NFT == 0, "Not an ERC1155 Token"); uint32 tokenCollectionIndex = _nextCollectionIndex[id]; newId = id + IS_NFT + (tokenCollectionIndex) * 2**NFT_INDEX_OFFSET; _nextCollectionIndex[id] = tokenCollectionIndex + 1; _burnERC1155(operator, sender, id, 1); _mint( _metadataHash[id & URI_ID], 1, 0, operator, to, newId, "", true ); emit Extraction(id, newId); } } pragma solidity ^0.5.2; contract Admin { address internal _admin; event AdminChanged(address oldAdmin, address newAdmin); /// @notice gives the current administrator of this contract. /// @return the current administrator of this contract. function getAdmin() external view returns (address) { return _admin; } /// @notice change the administrator to be `newAdmin`. /// @param newAdmin address of the new administrator. function changeAdmin(address newAdmin) external { require(msg.sender == _admin, "only admin can change admin"); emit AdminChanged(_admin, newAdmin); _admin = newAdmin; } modifier onlyAdmin() { require (msg.sender == _admin, "only admin allowed"); _; } } pragma solidity ^0.5.2; import "./Admin.sol"; contract SuperOperators is Admin { mapping(address => bool) internal _superOperators; event SuperOperator(address superOperator, bool enabled); /// @notice Enable or disable the ability of `superOperator` to transfer tokens of all (superOperator rights). /// @param superOperator address that will be given/removed superOperator right. /// @param enabled set whether the superOperator is enabled or disabled. function setSuperOperator(address superOperator, bool enabled) external { require( msg.sender == _admin, "only admin is allowed to add super operators" ); _superOperators[superOperator] = enabled; emit SuperOperator(superOperator, enabled); } /// @notice check whether address `who` is given superOperator rights. /// @param who The address to query. /// @return whether the address has superOperator rights. function isSuperOperator(address who) public view returns (bool) { return _superOperators[who]; } } pragma solidity ^0.5.2; /** @title ERC-1155 Multi Token Standard @dev See https://eips.ethereum.org/EIPS/eip-1155 Note: The ERC-165 identifier for this interface is 0xd9b67a26. */ interface ERC1155 { event TransferSingle( address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value ); event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); event ApprovalForAll( address indexed owner, address indexed operator, bool approved ); event URI(string value, uint256 indexed id); /** @notice Transfers `value` amount of an `id` from `from` to `to` (with safety call). @dev Caller must be approved to manage the tokens being transferred out of the `from` account (see "Approval" section of the standard). MUST revert if `to` is the zero address. MUST revert if balance of holder for token `id` is lower than the `value` sent. MUST revert on any other error. MUST emit the `TransferSingle` event to reflect the balance change (see "Safe Transfer Rules" section of the standard). After the above conditions are met, this function MUST check if `to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `to` and act appropriately (see "Safe Transfer Rules" section of the standard). @param from Source address @param to Target address @param id ID of the token type @param value Transfer amount @param data Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `to` */ function safeTransferFrom( address from, address to, uint256 id, uint256 value, bytes calldata data ) external; /** @notice Transfers `values` amount(s) of `ids` from the `from` address to the `to` address specified (with safety call). @dev Caller must be approved to manage the tokens being transferred out of the `from` account (see "Approval" section of the standard). MUST revert if `to` is the zero address. MUST revert if length of `ids` is not the same as length of `values`. MUST revert if any of the balance(s) of the holder(s) for token(s) in `ids` is lower than the respective amount(s) in `values` sent to the recipient. MUST revert on any other error. MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see "Safe Transfer Rules" section of the standard). Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc). After the above conditions for the transfer(s) in the batch are met, this function MUST check if `to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `to` and act appropriately (see "Safe Transfer Rules" section of the standard). @param from Source address @param to Target address @param ids IDs of each token type (order and length must match _values array) @param values Transfer amounts per token type (order and length must match _ids array) @param data Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `to` */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external; /** @notice Get the balance of an account's tokens. @param owner The address of the token holder @param id ID of the token @return The _owner's balance of the token type requested */ function balanceOf(address owner, uint256 id) external view returns (uint256); /** @notice Get the balance of multiple account/token pairs @param owners The addresses of the token holders @param ids ID of the tokens @return The _owner's balance of the token types requested (i.e. balance for each (owner, id) pair) */ function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) external view returns (uint256[] memory); /** @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. @dev MUST emit the ApprovalForAll event on success. @param operator Address to add to the set of authorized operators @param approved True if the operator is approved, false to revoke approval */ function setApprovalForAll(address operator, bool approved) external; /** @notice Queries the approval status of an operator for a given owner. @param owner The owner of the tokens @param operator Address of authorized operator @return True if the operator is approved, false if not */ function isApprovedForAll(address owner, address operator) external view returns (bool); } pragma solidity ^0.5.2; /** Note: The ERC-165 identifier for this interface is 0x4e2312e0. */ interface ERC1155TokenReceiver { /** @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 MUST return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` (i.e. 0xf23a6e61) if it accepts the transfer. This function MUST revert if it rejects the transfer. Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller. @param operator The address which initiated the transfer (i.e. msg.sender) @param from The address which previously owned the token @param id The ID of the token being transferred @param value 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 value, 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 MUST return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` (i.e. 0xbc197c81) if it accepts the transfer(s). This function MUST revert if it rejects the transfer(s). Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller. @param operator The address which initiated the batch transfer (i.e. msg.sender) @param from The address which previously owned the token @param ids An array containing ids of each token being transferred (order and length must match _values array) @param values An array containing amounts of each token being transferred (order and length must match _ids array) @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 values, bytes calldata data ) external returns (bytes4); } pragma solidity ^0.5.2; /** * @title ERC165 * @dev https://eips.ethereum.org/EIPS/eip-165 */ interface ERC165 { /** * @notice Query if a contract implements interface `interfaceId` * @param interfaceId The interface identifier, as specified in ERC-165 * @dev Interface identification is specified in ERC-165. This function * uses less than 30,000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } pragma solidity ^0.5.2; import "./ERC165.sol"; import "./ERC721Events.sol"; /** * @title ERC721 Non-Fungible Token Standard basic interface * @dev see https://eips.ethereum.org/EIPS/eip-721 */ /*interface*/ contract ERC721 is ERC165, ERC721Events { function balanceOf(address owner) external view returns (uint256 balance); function ownerOf(uint256 tokenId) external view returns (address owner); // function exists(uint256 tokenId) external view returns (bool exists); function approve(address to, uint256 tokenId) external; function getApproved(uint256 tokenId) external view returns (address operator); function setApprovalForAll(address operator, bool approved) external; function isApprovedForAll(address owner, address operator) external view returns (bool); function transferFrom(address from, address to, uint256 tokenId) external; function safeTransferFrom(address from, address to, uint256 tokenId) external; function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; } pragma solidity ^0.5.2; /** * @title ERC721 Non-Fungible Token Standard basic interface * @dev see https://eips.ethereum.org/EIPS/eip-721 */ interface ERC721Events { event Transfer( address indexed _from, address indexed _to, uint256 indexed _tokenId ); event Approval( address indexed _owner, address indexed _approved, uint256 indexed _tokenId ); event ApprovalForAll( address indexed _owner, address indexed _operator, bool _approved ); } /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This code has not been reviewed. * Do not use or deploy this code before reviewing it personally first. */ // solhint-disable-next-line compiler-fixed pragma solidity ^0.5.2; interface ERC721TokenReceiver { function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); } pragma solidity ^0.5.2; library AddressUtils { function toPayable(address _address) internal pure returns (address payable _payable) { return address(uint160(_address)); } function isContract(address addr) internal view returns (bool) { // for accounts without code, i.e. `keccak256('')`: bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; bytes32 codehash; // solium-disable-next-line security/no-inline-assembly assembly { codehash := extcodehash(addr) } return (codehash != 0x0 && codehash != accountHash); } } pragma solidity ^0.5.2; import "./SafeMathWithRequire.sol"; library ObjectLib32 { using SafeMathWithRequire for uint256; enum Operations {ADD, SUB, REPLACE} // Constants regarding bin or chunk sizes for balance packing uint256 constant TYPES_BITS_SIZE = 32; // Max size of each object uint256 constant TYPES_PER_UINT256 = 256 / TYPES_BITS_SIZE; // Number of types per uint256 // // Objects and Tokens Functions // /** * @dev Return the bin number and index within that bin where ID is * @param tokenId Object type * @return (Bin number, ID's index within that bin) */ function getTokenBinIndex(uint256 tokenId) internal pure returns (uint256 bin, uint256 index) { bin = (tokenId * TYPES_BITS_SIZE) / 256; index = tokenId % TYPES_PER_UINT256; return (bin, index); } /** * @dev update the balance of a type provided in binBalances * @param binBalances Uint256 containing the balances of objects * @param index Index of the object in the provided bin * @param amount Value to update the type balance * @param operation Which operation to conduct : * Operations.REPLACE : Replace type balance with amount * Operations.ADD : ADD amount to type balance * Operations.SUB : Substract amount from type balance */ function updateTokenBalance( uint256 binBalances, uint256 index, uint256 amount, Operations operation ) internal pure returns (uint256 newBinBalance) { uint256 objectBalance = 0; if (operation == Operations.ADD) { objectBalance = getValueInBin(binBalances, index); newBinBalance = writeValueInBin( binBalances, index, objectBalance.add(amount) ); } else if (operation == Operations.SUB) { objectBalance = getValueInBin(binBalances, index); require(objectBalance >= amount, "can't substract more than there is"); newBinBalance = writeValueInBin( binBalances, index, objectBalance.sub(amount) ); } else if (operation == Operations.REPLACE) { newBinBalance = writeValueInBin(binBalances, index, amount); } else { revert("Invalid operation"); // Bad operation } return newBinBalance; } /* * @dev return value in binValue at position index * @param binValue uint256 containing the balances of TYPES_PER_UINT256 types * @param index index at which to retrieve value * @return Value at given index in bin */ function getValueInBin(uint256 binValue, uint256 index) internal pure returns (uint256) { // Mask to retrieve data for a given binData uint256 mask = (uint256(1) << TYPES_BITS_SIZE) - 1; // Shift amount uint256 rightShift = 256 - TYPES_BITS_SIZE * (index + 1); return (binValue >> rightShift) & mask; } /** * @dev return the updated binValue after writing amount at index * @param binValue uint256 containing the balances of TYPES_PER_UINT256 types * @param index Index at which to retrieve value * @param amount Value to store at index in bin * @return Value at given index in bin */ function writeValueInBin(uint256 binValue, uint256 index, uint256 amount) internal pure returns (uint256) { require( amount < 2**TYPES_BITS_SIZE, "Amount to write in bin is too large" ); // Mask to retrieve data for a given binData uint256 mask = (uint256(1) << TYPES_BITS_SIZE) - 1; // Shift amount uint256 leftShift = 256 - TYPES_BITS_SIZE * (index + 1); return (binValue & ~(mask << leftShift)) | (amount << leftShift); } } pragma solidity ^0.5.2; /** * @title SafeMath * @dev Math operations with safety checks that revert */ library SafeMathWithRequire { /** * @dev Multiplies two numbers, throws on overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { // Gas optimization: this is cheaper than asserting 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (a == 0) { return 0; } c = a * b; require(c / a == b, "overflow"); return c; } /** * @dev Integer division of two numbers, truncating the quotient. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // assert(b > 0); // Solidity automatically throws when dividing by 0 // uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return a / b; } /** * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "undeflow"); return a - b; } /** * @dev Adds two numbers, throws on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256 c) { c = a + b; require(c >= a, "overflow"); return c; } }