Address Contract Verified
Address
0x7ca89d81329b02f1a63C7f73BA3de3acb73164BE
Balance
0 ETH
Nonce
1
Code Size
7605 bytes
Creator
0xc7F669BE...5e87 at tx 0x9b6ef788...c052bb
Indexed Transactions
0
Contract Bytecode
7605 bytes
0x608060405234801561001057600080fd5b506004361061010b5760003560e01c80636a148217116100a2578063bc197c8111610071578063bc197c81146102ca578063d2a453c2146102fa578063dbdfb45214610316578063f23a6e6114610332578063f2fde38b146103625761010b565b80636a148217146102565780636c0c712b14610286578063715018a6146102a25780638da5cb5b146102ac5761010b565b806319e3c5ad116100de57806319e3c5ad146101a85780631fa54479146101d85780632b4dd1cc146102085780632c58cd17146102265761010b565b806301ffc9a7146101105780630c908a0c1461014057806313c444551461015c57806318c7229514610178575b600080fd5b61012a6004803603810190610125919061145a565b61037e565b6040516101379190611703565b60405180910390f35b61015a600480360381019061015591906113ac565b6103f8565b005b6101766004803603810190610171919061132b565b610738565b005b610192600480360381019061018d9190611487565b6107df565b60405161019f9190611703565b60405180910390f35b6101c260048036038101906101bd9190611487565b610809565b6040516101cf9190611703565b60405180910390f35b6101f260048036038101906101ed9190611487565b610829565b6040516101ff9190611703565b60405180910390f35b610210610849565b60405161021d9190611739565b60405180910390f35b610240600480360381019061023b91906112eb565b61086f565b60405161024d9190611854565b60405180910390f35b610270600480360381019061026b9190611487565b610894565b60405161027d9190611703565b60405180910390f35b6102a0600480360381019061029b9190611158565b6108be565b005b6102aa61090a565b005b6102b461091e565b6040516102c19190611667565b60405180910390f35b6102e460048036038101906102df9190611185565b610947565b6040516102f1919061171e565b60405180910390f35b610314600480360381019061030f91906113ac565b61095c565b005b610330600480360381019061032b919061132b565b610c41565b005b61034c60048036038101906103479190611254565b610ce8565b604051610359919061171e565b60405180910390f35b61037c60048036038101906103779190611158565b610cfd565b005b60007f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806103f157506103f082610d81565b5b9050919050565b60005b8484905081101561073157600085858381811061041b5761041a611aff565b5b905060200201359050600084848481811061043957610438611aff565b5b9050602002013590506001600083815260200190815260200160002060009054906101000a900460ff166104a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161049990611774565b60405180910390fd5b600081116104e5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104dc906117b4565b60405180910390fd5b80600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1662fdd58e33856040518363ffffffff1660e01b81526004016105429291906116da565b60206040518083038186803b15801561055a57600080fd5b505afa15801561056e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059291906114b4565b10156105d3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ca90611754565b60405180910390fd5b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f242432a333085856040518563ffffffff1660e01b81526004016106349493929190611682565b600060405180830381600087803b15801561064e57600080fd5b505af1158015610662573d6000803e3d6000fd5b505050506000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002054905081816106c79190611913565b600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600085815260200190815260200160002081905550505050808061072990611a87565b9150506103fb565b5050505050565b610740610deb565b60005b848490508110156107d857600085858381811061076357610762611aff565b5b905060200201359050600084848481811061078157610780611aff565b5b9050602002016020810190610796919061142d565b9050806001600084815260200190815260200160002060006101000a81548160ff021916908315150217905550505080806107d090611a87565b915050610743565b5050505050565b60006002600083815260200190815260200160002060009054906101000a900460ff169050919050565b60016020528060005260406000206000915054906101000a900460ff1681565b60026020528060005260406000206000915054906101000a900460ff1681565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6003602052816000526040600020602052806000526040600020600091509150505481565b60006001600083815260200190815260200160002060009054906101000a900460ff169050919050565b6108c6610deb565b80600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b610912610deb565b61091c6000610e69565b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600063bc197c8160e01b905095945050505050565b60005b84849050811015610c3a57600085858381811061097f5761097e611aff565b5b905060200201359050600084848481811061099d5761099c611aff565b5b9050602002013590506002600083815260200190815260200160002060009054906101000a900460ff16610a06576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109fd90611834565b60405180910390fd5b60008111610a49576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a40906117f4565b60405180910390fd5b80600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000848152602001908152602001600020541015610adc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ad3906117d4565b60405180910390fd5b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f242432a303385856040518563ffffffff1660e01b8152600401610b3d9493929190611682565b600060405180830381600087803b158015610b5757600080fd5b505af1158015610b6b573d6000803e3d6000fd5b505050506000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008481526020019081526020016000205490508181610bd09190611969565b600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000858152602001908152602001600020819055505050508080610c3290611a87565b91505061095f565b5050505050565b610c49610deb565b60005b84849050811015610ce1576000858583818110610c6c57610c6b611aff565b5b9050602002013590506000848484818110610c8a57610c89611aff565b5b9050602002016020810190610c9f919061142d565b9050806002600084815260200190815260200160002060006101000a81548160ff02191690831515021790555050508080610cd990611a87565b915050610c4c565b5050505050565b600063f23a6e6160e01b905095945050505050565b610d05610deb565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610d75576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d6c90611794565b60405180910390fd5b610d7e81610e69565b50565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b610df3610f2d565b73ffffffffffffffffffffffffffffffffffffffff16610e1161091e565b73ffffffffffffffffffffffffffffffffffffffff1614610e67576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e5e90611814565b60405180910390fd5b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600033905090565b6000610f48610f4384611894565b61186f565b90508083825260208201905082856020860282011115610f6b57610f6a611b67565b5b60005b85811015610f9b5781610f81888261112e565b845260208401935060208301925050600181019050610f6e565b5050509392505050565b6000610fb8610fb3846118c0565b61186f565b905082815260208101848484011115610fd457610fd3611b6c565b5b610fdf848285611a47565b509392505050565b600081359050610ff681611d23565b92915050565b60008083601f84011261101257611011611b62565b5b8235905067ffffffffffffffff81111561102f5761102e611b5d565b5b60208301915083602082028301111561104b5761104a611b67565b5b9250929050565b60008083601f84011261106857611067611b62565b5b8235905067ffffffffffffffff81111561108557611084611b5d565b5b6020830191508360208202830111156110a1576110a0611b67565b5b9250929050565b600082601f8301126110bd576110bc611b62565b5b81356110cd848260208601610f35565b91505092915050565b6000813590506110e581611d3a565b92915050565b6000813590506110fa81611d51565b92915050565b600082601f83011261111557611114611b62565b5b8135611125848260208601610fa5565b91505092915050565b60008135905061113d81611d68565b92915050565b60008151905061115281611d68565b92915050565b60006020828403121561116e5761116d611b76565b5b600061117c84828501610fe7565b91505092915050565b600080600080600060a086880312156111a1576111a0611b76565b5b60006111af88828901610fe7565b95505060206111c088828901610fe7565b945050604086013567ffffffffffffffff8111156111e1576111e0611b71565b5b6111ed888289016110a8565b935050606086013567ffffffffffffffff81111561120e5761120d611b71565b5b61121a888289016110a8565b925050608086013567ffffffffffffffff81111561123b5761123a611b71565b5b61124788828901611100565b9150509295509295909350565b600080600080600060a086880312156112705761126f611b76565b5b600061127e88828901610fe7565b955050602061128f88828901610fe7565b94505060406112a08882890161112e565b93505060606112b18882890161112e565b925050608086013567ffffffffffffffff8111156112d2576112d1611b71565b5b6112de88828901611100565b9150509295509295909350565b6000806040838503121561130257611301611b76565b5b600061131085828601610fe7565b92505060206113218582860161112e565b9150509250929050565b6000806000806040858703121561134557611344611b76565b5b600085013567ffffffffffffffff81111561136357611362611b71565b5b61136f87828801611052565b9450945050602085013567ffffffffffffffff81111561139257611391611b71565b5b61139e87828801610ffc565b925092505092959194509250565b600080600080604085870312156113c6576113c5611b76565b5b600085013567ffffffffffffffff8111156113e4576113e3611b71565b5b6113f087828801611052565b9450945050602085013567ffffffffffffffff81111561141357611412611b71565b5b61141f87828801611052565b925092505092959194509250565b60006020828403121561144357611442611b76565b5b6000611451848285016110d6565b91505092915050565b6000602082840312156114705761146f611b76565b5b600061147e848285016110eb565b91505092915050565b60006020828403121561149d5761149c611b76565b5b60006114ab8482850161112e565b91505092915050565b6000602082840312156114ca576114c9611b76565b5b60006114d884828501611143565b91505092915050565b6114ea8161199d565b82525050565b6114f9816119af565b82525050565b611508816119bb565b82525050565b61151781611a11565b82525050565b600061152a601983611902565b915061153582611b8c565b602082019050919050565b600061154d602483611902565b915061155882611bb5565b604082019050919050565b6000611570602683611902565b915061157b82611c04565b604082019050919050565b6000611593600e83611902565b915061159e82611c53565b602082019050919050565b60006115b6601f83611902565b91506115c182611c7c565b602082019050919050565b60006115d9601083611902565b91506115e482611ca5565b602082019050919050565b60006115fc602083611902565b915061160782611cce565b602082019050919050565b600061161f601583611902565b915061162a82611cf7565b602082019050919050565b60006116426000836118f1565b915061164d82611d20565b600082019050919050565b61166181611a07565b82525050565b600060208201905061167c60008301846114e1565b92915050565b600060a08201905061169760008301876114e1565b6116a460208301866114e1565b6116b16040830185611658565b6116be6060830184611658565b81810360808301526116cf81611635565b905095945050505050565b60006040820190506116ef60008301856114e1565b6116fc6020830184611658565b9392505050565b600060208201905061171860008301846114f0565b92915050565b600060208201905061173360008301846114ff565b92915050565b600060208201905061174e600083018461150e565b92915050565b6000602082019050818103600083015261176d8161151d565b9050919050565b6000602082019050818103600083015261178d81611540565b9050919050565b600060208201905081810360008301526117ad81611563565b9050919050565b600060208201905081810360008301526117cd81611586565b9050919050565b600060208201905081810360008301526117ed816115a9565b9050919050565b6000602082019050818103600083015261180d816115cc565b9050919050565b6000602082019050818103600083015261182d816115ef565b9050919050565b6000602082019050818103600083015261184d81611612565b9050919050565b60006020820190506118696000830184611658565b92915050565b600061187961188a565b90506118858282611a56565b919050565b6000604051905090565b600067ffffffffffffffff8211156118af576118ae611b2e565b5b602082029050602081019050919050565b600067ffffffffffffffff8211156118db576118da611b2e565b5b6118e482611b7b565b9050602081019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600061191e82611a07565b915061192983611a07565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111561195e5761195d611ad0565b5b828201905092915050565b600061197482611a07565b915061197f83611a07565b92508282101561199257611991611ad0565b5b828203905092915050565b60006119a8826119e7565b9050919050565b60008115159050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b6000611a1c82611a23565b9050919050565b6000611a2e82611a35565b9050919050565b6000611a40826119e7565b9050919050565b82818337600083830152505050565b611a5f82611b7b565b810181811067ffffffffffffffff82111715611a7e57611a7d611b2e565b5b80604052505050565b6000611a9282611a07565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611ac557611ac4611ad0565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f496e73756666696369656e7420706173732062616c616e636500000000000000600082015250565b7f5374616b696e6720666f7220746869732063686170746572204e6f7420656e6160008201527f626c656400000000000000000000000000000000000000000000000000000000602082015250565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b7f43616e6e6f74207374616b652030000000000000000000000000000000000000600082015250565b7f4e6f7420656e6f7567682070726f64756365722070617373207374616b656400600082015250565b7f43616e6e6f7420756e7374616b65203000000000000000000000000000000000600082015250565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b7f556e7374616b696e67206e6f7420656e61626c65640000000000000000000000600082015250565b50565b611d2c8161199d565b8114611d3757600080fd5b50565b611d43816119af565b8114611d4e57600080fd5b50565b611d5a816119bb565b8114611d6557600080fd5b50565b611d7181611a07565b8114611d7c57600080fd5b5056fea264697066735822122019f818de7e432775cfcd754d73f885011ea5926c36000c5328392d00278b066964736f6c63430008070033
Verified Source Code Full Match
Compiler: v0.8.7+commit.e28d00a7
EVM: london
Optimization: No
IERC1155Receiver.sol 58 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev _Available since v3.1._
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @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)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @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)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
Strings.sol 70 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
Context.sol 24 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^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 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) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
IERC1155MetadataURI.sol 22 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)
pragma solidity ^0.8.0;
import "../IERC1155.sol";
/**
* @dev Interface of the optional ERC1155MetadataExtension interface, as defined
* in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
*
* _Available since v3.1._
*/
interface IERC1155MetadataURI is IERC1155 {
/**
* @dev Returns the URI for token type `id`.
*
* If the `\{id\}` substring is present in the URI, it must be replaced by
* clients with the actual token type ID.
*/
function uri(uint256 id) external view returns (string memory);
}
ERC1155Holder.sol 36 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/utils/ERC1155Holder.sol)
pragma solidity ^0.8.0;
import "./ERC1155Receiver.sol";
/**
* Simple implementation of `ERC1155Receiver` that will allow a contract to hold ERC1155 tokens.
*
* IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be
* stuck.
*
* @dev _Available since v3.1._
*/
contract ERC1155Holder is ERC1155Receiver {
function onERC1155Received(
address,
address,
uint256,
uint256,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address,
address,
uint256[] memory,
uint256[] memory,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155BatchReceived.selector;
}
}
Ownable.sol 83 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @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() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
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 {
_transferOwnership(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");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
ERC1155Supply.sol 64 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC1155/extensions/ERC1155Supply.sol)
pragma solidity ^0.8.0;
import "../ERC1155.sol";
/**
* @dev Extension of ERC1155 that adds tracking of total supply per id.
*
* Useful for scenarios where Fungible and Non-fungible tokens have to be
* clearly identified. Note: While a totalSupply of 1 might mean the
* corresponding is an NFT, there is no guarantees that no other token with the
* same id are not going to be minted.
*/
abstract contract ERC1155Supply is ERC1155 {
mapping(uint256 => uint256) private _totalSupply;
/**
* @dev Total amount of tokens in with a given id.
*/
function totalSupply(uint256 id) public view virtual returns (uint256) {
return _totalSupply[id];
}
/**
* @dev Indicates whether any token exist with a given id, or not.
*/
function exists(uint256 id) public view virtual returns (bool) {
return ERC1155Supply.totalSupply(id) > 0;
}
/**
* @dev See {ERC1155-_beforeTokenTransfer}.
*/
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual override {
super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
if (from == address(0)) {
for (uint256 i = 0; i < ids.length; ++i) {
_totalSupply[ids[i]] += amounts[i];
}
}
if (to == address(0)) {
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 supply = _totalSupply[id];
require(supply >= amount, "ERC1155: burn amount exceeds totalSupply");
unchecked {
_totalSupply[id] = supply - amount;
}
}
}
}
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.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);
}
ProducerPassStaking.sol 131 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import "./WhiteRabbitProducerPass.sol";
/*
* This contract allows users to stake and unstake producer passes
* independent of any chapter in the White Rabbit IP
*/
contract ProducerPassStaking is Ownable, ERC1155Holder {
mapping(uint256 => bool) public isProducerPassStakingEnabledForId;
mapping(uint256 => bool) public isProducerPassUnstakingEnabledForId;
mapping(address => mapping(uint256 => uint256))
public stakedProducerPassesFromUser;
ERC1155 public producerPassContract;
function isStakingEnabledForChapter(uint256 chapter)
public
view
virtual
returns (bool)
{
return isProducerPassStakingEnabledForId[chapter];
}
function isUnstakingEnabledForChapter(uint256 chapter)
public
view
virtual
returns (bool)
{
return isProducerPassUnstakingEnabledForId[chapter];
}
function setProducerPassContract(address add) external onlyOwner {
producerPassContract = ERC1155(add);
}
function setProducerPassStakingEnabledForIds(
uint256[] calldata chapterIds,
bool[] calldata enabled
) external onlyOwner {
for (uint256 i = 0; i < chapterIds.length; i++) {
uint256 chapterId = chapterIds[i];
bool enable = enabled[i];
isProducerPassStakingEnabledForId[chapterId] = enable;
}
}
function setProducerPassUnstakingEnabledForIds(
uint256[] calldata chapterIds,
bool[] calldata enabled
) external onlyOwner {
for (uint256 i = 0; i < chapterIds.length; i++) {
uint256 chapterId = chapterIds[i];
bool enable = enabled[i];
isProducerPassUnstakingEnabledForId[chapterId] = enable;
}
}
function stakeProducerPasses(
uint256[] calldata chapterIds,
uint256[] calldata amounts
) public {
for (uint256 i = 0; i < chapterIds.length; i++) {
uint256 chapterId = chapterIds[i];
uint256 amount = amounts[i];
require(
isProducerPassStakingEnabledForId[chapterId],
"Staking for this chapter Not enabled"
);
require(amount > 0, "Cannot stake 0");
require(
producerPassContract.balanceOf(msg.sender, chapterId) >= amount,
"Insufficient pass balance"
);
producerPassContract.safeTransferFrom(
msg.sender,
address(this),
chapterId,
amount,
""
);
uint256 previousStakedAmount = stakedProducerPassesFromUser[
msg.sender
][chapterId];
stakedProducerPassesFromUser[msg.sender][chapterId] =
previousStakedAmount +
amount;
}
}
function unstakeProducerPasses(
uint256[] calldata chapterIds,
uint256[] calldata amounts
) public {
for (uint256 i = 0; i < chapterIds.length; i++) {
uint256 chapterId = chapterIds[i];
uint256 amount = amounts[i];
require(
isProducerPassUnstakingEnabledForId[chapterId],
"Unstaking not enabled"
);
require(amount > 0, "Cannot unstake 0");
require(
stakedProducerPassesFromUser[msg.sender][chapterId] >= amount,
"Not enough producer pass staked"
);
producerPassContract.safeTransferFrom(
address(this),
msg.sender,
chapterId,
amount,
""
);
uint256 previousStakedAmount = stakedProducerPassesFromUser[
msg.sender
][chapterId];
stakedProducerPassesFromUser[msg.sender][chapterId] =
previousStakedAmount -
amount;
}
}
}
WhiteRabbitProducerPass.sol 340 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
struct ProducerPass {
uint256 price;
uint256 episodeId;
uint256 maxSupply;
uint256 maxPerWallet;
uint256 openMintTimestamp; // unix timestamp in seconds
bytes32 merkleRoot;
}
contract WhiteRabbitProducerPass is ERC1155, ERC1155Supply, Ownable {
using Strings for uint256;
// The name of the token ("White Rabbit Producer Pass")
string public name;
// The token symbol ("WRPP")
string public symbol;
// The wallet addresses of the two artists creating the film
address payable private artistAddress1;
address payable private artistAddress2;
// The wallet addresses of the three developers managing the film
address payable private devAddress1;
address payable private devAddress2;
address payable private devAddress3;
// The royalty percentages for the artists and developers
uint256 private constant ARTIST_ROYALTY_PERCENTAGE = 60;
uint256 private constant DEV_ROYALTY_PERCENTAGE = 40;
// A mapping of the number of Producer Passes minted per episodeId per user
// userPassesMintedPerTokenId[msg.sender][episodeId] => number of minted passes
mapping(address => mapping(uint256 => uint256))
private userPassesMintedPerTokenId;
// A mapping from episodeId to its Producer Pass
mapping(uint256 => ProducerPass) private episodeToProducerPass;
// Event emitted when a Producer Pass is bought
event ProducerPassBought(
uint256 episodeId,
address indexed account,
uint256 amount
);
/**
* @dev Initializes the contract by setting the name and the token symbol
*/
constructor(string memory baseURI) ERC1155(baseURI) {
name = "White Rabbit Producer Pass";
symbol = "WRPP";
}
/**
* @dev Checks if the provided Merkle Proof is valid for the given root hash.
*/
function isValidMerkleProof(bytes32[] calldata merkleProof, bytes32 root)
internal
view
returns (bool)
{
return
MerkleProof.verify(
merkleProof,
root,
keccak256(abi.encodePacked(msg.sender))
);
}
/**
* @dev Retrieves the Producer Pass for a given episode.
*/
function getEpisodeToProducerPass(uint256 episodeId)
external
view
returns (ProducerPass memory)
{
return episodeToProducerPass[episodeId];
}
/**
* @dev Contracts the metadata URI for the Producer Pass of the given episodeId.
*
* Requirements:
*
* - The Producer Pass exists for the given episode
*/
function uri(uint256 episodeId)
public
view
override
returns (string memory)
{
require(
episodeToProducerPass[episodeId].episodeId != 0,
"Invalid episode"
);
return
string(
abi.encodePacked(
super.uri(episodeId),
episodeId.toString(),
".json"
)
);
}
/**
* Owner-only methods
*/
/**
* @dev Sets the base URI for the Producer Pass metadata.
*/
function setBaseURI(string memory baseURI) external onlyOwner {
_setURI(baseURI);
}
/**
* @dev Sets the parameters on the Producer Pass struct for the given episode.
*/
function setProducerPass(
uint256 price,
uint256 episodeId,
uint256 maxSupply,
uint256 maxPerWallet,
uint256 openMintTimestamp,
bytes32 merkleRoot
) external onlyOwner {
episodeToProducerPass[episodeId] = ProducerPass(
price,
episodeId,
maxSupply,
maxPerWallet,
openMintTimestamp,
merkleRoot
);
}
/**
* @dev Withdraws the balance and distributes it to the artists and developers
* based on the `ARTIST_ROYALTY_PERCENTAGE` and `DEV_ROYALTY_PERCENTAGE`.
*/
function withdraw() external onlyOwner {
uint256 balance = address(this).balance;
uint256 artistBalance = (balance * ARTIST_ROYALTY_PERCENTAGE) / 100;
uint256 balancePerArtist = artistBalance / 2;
uint256 devBalance = (balance * DEV_ROYALTY_PERCENTAGE) / 100;
uint256 balancePerDev = devBalance / 3;
bool success;
// Transfer artist balances
(success, ) = artistAddress1.call{value: balancePerArtist}("");
require(success, "Withdraw unsuccessful");
(success, ) = artistAddress2.call{value: balancePerArtist}("");
require(success, "Withdraw unsuccessful");
// Transfer dev balances
(success, ) = devAddress1.call{value: balancePerDev}("");
require(success, "Withdraw unsuccessful");
(success, ) = devAddress2.call{value: balancePerDev}("");
require(success, "Withdraw unsuccessful");
(success, ) = devAddress3.call{value: balancePerDev}("");
require(success, "Withdraw unsuccessful");
}
/**
* @dev Sets the royalty addresses for the two artists and three developers.
*/
function setRoyaltyAddresses(
address _a1,
address _a2,
address _d1,
address _d2,
address _d3
) external onlyOwner {
artistAddress1 = payable(_a1);
artistAddress2 = payable(_a2);
devAddress1 = payable(_d1);
devAddress2 = payable(_d2);
devAddress3 = payable(_d3);
}
/**
* @dev Creates a reserve of Producer Passes to set aside for gifting.
*
* Requirements:
*
* - There are enough Producer Passes to mint for the given episode
* - The supply for the given episode does not exceed the maxSupply of the Producer Pass
*/
function reserveProducerPassesForGifting(
uint256 episodeId,
uint256 amountEachAddress,
address[] calldata addresses
) public onlyOwner {
ProducerPass memory pass = episodeToProducerPass[episodeId];
require(amountEachAddress > 0, "Amount cannot be 0");
require(totalSupply(episodeId) < pass.maxSupply, "No passes to mint");
require(
totalSupply(episodeId) + amountEachAddress * addresses.length <=
pass.maxSupply,
"Cannot mint that many"
);
require(addresses.length > 0, "Need addresses");
for (uint256 i = 0; i < addresses.length; i++) {
address add = addresses[i];
_mint(add, episodeId, amountEachAddress, "");
}
}
/**
* @dev Mints a set number of Producer Passes for a given episode.
*
* Emits a `ProducerPassBought` event indicating the Producer Pass was minted successfully.
*
* Requirements:
*
* - The current time is within the minting window for the given episode
* - There are Producer Passes available to mint for the given episode
* - The user is not trying to mint more than the maxSupply
* - The user is not trying to mint more than the maxPerWallet
* - The user has enough ETH for the transaction
*/
function mintProducerPass(uint256 episodeId, uint256 amount)
external
payable
{
ProducerPass memory pass = episodeToProducerPass[episodeId];
require(
block.timestamp >= pass.openMintTimestamp,
"Mint is not available"
);
require(totalSupply(episodeId) < pass.maxSupply, "Sold out");
require(
totalSupply(episodeId) + amount <= pass.maxSupply,
"Cannot mint that many"
);
uint256 totalMintedPasses = userPassesMintedPerTokenId[msg.sender][
episodeId
];
require(
totalMintedPasses + amount <= pass.maxPerWallet,
"Exceeding maximum per wallet"
);
require(msg.value == pass.price * amount, "Not enough eth");
userPassesMintedPerTokenId[msg.sender][episodeId] =
totalMintedPasses +
amount;
_mint(msg.sender, episodeId, amount, "");
emit ProducerPassBought(episodeId, msg.sender, amount);
}
/**
* @dev For those on with early access (on the whitelist),
* mints a set number of Producer Passes for a given episode.
*
* Emits a `ProducerPassBought` event indicating the Producer Pass was minted successfully.
*
* Requirements:
*
* - Provides a valid Merkle proof, indicating the user is on the whitelist
* - There are Producer Passes available to mint for the given episode
* - The user is not trying to mint more than the maxSupply
* - The user is not trying to mint more than the maxPerWallet
* - The user has enough ETH for the transaction
*/
function earlyMintProducerPass(
uint256 episodeId,
uint256 amount,
bytes32[] calldata merkleProof
) external payable {
ProducerPass memory pass = episodeToProducerPass[episodeId];
require(
isValidMerkleProof(merkleProof, pass.merkleRoot),
"Not authorized to mint"
);
require(totalSupply(episodeId) < pass.maxSupply, "Sold out");
require(
totalSupply(episodeId) + amount <= pass.maxSupply,
"Cannot mint that many"
);
uint256 totalMintedPasses = userPassesMintedPerTokenId[msg.sender][
episodeId
];
require(
totalMintedPasses + amount <= pass.maxPerWallet,
"Exceeding maximum per wallet"
);
require(msg.value == pass.price * amount, "Not enough eth");
userPassesMintedPerTokenId[msg.sender][episodeId] =
totalMintedPasses +
amount;
_mint(msg.sender, episodeId, amount, "");
emit ProducerPassBought(episodeId, msg.sender, amount);
}
/**
* @dev Retrieves the number of Producer Passes a user has minted by episodeId.
*/
function userPassesMintedByEpisodeId(uint256 episodeId)
external
view
returns (uint256)
{
return userPassesMintedPerTokenId[msg.sender][episodeId];
}
/**
* @dev Boilerplate override for `_beforeTokenTransfer`
*/
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual override(ERC1155, ERC1155Supply) {
super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
}
}
ERC1155Receiver.sol 19 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/utils/ERC1155Receiver.sol)
pragma solidity ^0.8.0;
import "../IERC1155Receiver.sol";
import "../../../utils/introspection/ERC165.sol";
/**
* @dev _Available since v3.1._
*/
abstract contract ERC1155Receiver is ERC165, IERC1155Receiver {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
}
}
IERC1155.sol 125 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
external
view
returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}
Math.sol 345 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}
ERC1155.sol 517 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol)
pragma solidity ^0.8.0;
import "./IERC1155.sol";
import "./IERC1155Receiver.sol";
import "./extensions/IERC1155MetadataURI.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of the basic standard multi-token.
* See https://eips.ethereum.org/EIPS/eip-1155
* Originally based on code by Enjin: https://github.com/enjin/erc-1155
*
* _Available since v3.1._
*/
contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
using Address for address;
// Mapping from token ID to account balances
mapping(uint256 => mapping(address => uint256)) private _balances;
// Mapping from account to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
// Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
string private _uri;
/**
* @dev See {_setURI}.
*/
constructor(string memory uri_) {
_setURI(uri_);
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC1155MetadataURI-uri}.
*
* This implementation returns the same URI for *all* token types. It relies
* on the token type ID substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* Clients calling this function must replace the `\{id\}` substring with the
* actual token type ID.
*/
function uri(uint256) public view virtual override returns (string memory) {
return _uri;
}
/**
* @dev See {IERC1155-balanceOf}.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
require(account != address(0), "ERC1155: address zero is not a valid owner");
return _balances[id][account];
}
/**
* @dev See {IERC1155-balanceOfBatch}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
public
view
virtual
override
returns (uint256[] memory)
{
require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");
uint256[] memory batchBalances = new uint256[](accounts.length);
for (uint256 i = 0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts[i], ids[i]);
}
return batchBalances;
}
/**
* @dev See {IERC1155-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual override {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC1155-isApprovedForAll}.
*/
function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
return _operatorApprovals[account][operator];
}
/**
* @dev See {IERC1155-safeTransferFrom}.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
_safeTransferFrom(from, to, id, amount, data);
}
/**
* @dev See {IERC1155-safeBatchTransferFrom}.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
_safeBatchTransferFrom(from, to, ids, amounts, data);
}
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
emit TransferSingle(operator, from, to, id, amount);
_afterTokenTransfer(operator, from, to, ids, amounts, data);
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function _safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
require(to != address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
}
emit TransferBatch(operator, from, to, ids, amounts);
_afterTokenTransfer(operator, from, to, ids, amounts, data);
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
}
/**
* @dev Sets a new URI for all token types, by relying on the token type ID
* substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* By this mechanism, any occurrence of the `\{id\}` substring in either the
* URI or any of the amounts in the JSON file at said URI will be replaced by
* clients with the token type ID.
*
* For example, the `https://token-cdn-domain/\{id\}.json` URI would be
* interpreted by clients as
* `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
* for token type ID 0x4cce0.
*
* See {uri}.
*
* Because these URIs cannot be meaningfully represented by the {URI} event,
* this function emits no events.
*/
function _setURI(string memory newuri) internal virtual {
_uri = newuri;
}
/**
* @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _mint(
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
_balances[id][to] += amount;
emit TransferSingle(operator, address(0), to, id, amount);
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
_doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function _mintBatch(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; i++) {
_balances[ids[i]][to] += amounts[i];
}
emit TransferBatch(operator, address(0), to, ids, amounts);
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
_doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
}
/**
* @dev Destroys `amount` tokens of token type `id` from `from`
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `from` must have at least `amount` tokens of token type `id`.
*/
function _burn(
address from,
uint256 id,
uint256 amount
) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
emit TransferSingle(operator, from, address(0), id, amount);
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
*/
function _burnBatch(
address from,
uint256[] memory ids,
uint256[] memory amounts
) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
for (uint256 i = 0; i < ids.length; i++) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
}
emit TransferBatch(operator, from, address(0), ids, amounts);
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Emits an {ApprovalForAll} event.
*/
function _setApprovalForAll(
address owner,
address operator,
bool approved
) internal virtual {
require(owner != operator, "ERC1155: setting approval status for self");
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Hook that is called before any token transfer. This includes minting
* and burning, as well as batched variants.
*
* The same hook is called on both single and batched variants. For single
* transfers, the length of the `ids` and `amounts` arrays will be 1.
*
* Calling conditions (for each `id` and `amount` pair):
*
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* of token type `id` will be transferred to `to`.
* - When `from` is zero, `amount` tokens of token type `id` will be minted
* for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
* will be burned.
* - `from` and `to` are never both zero.
* - `ids` and `amounts` have the same, non-zero length.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
/**
* @dev Hook that is called after any token transfer. This includes minting
* and burning, as well as batched variants.
*
* The same hook is called on both single and batched variants. For single
* transfers, the length of the `id` and `amount` arrays will be 1.
*
* Calling conditions (for each `id` and `amount` pair):
*
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* of token type `id` will be transferred to `to`.
* - When `from` is zero, `amount` tokens of token type `id` will be minted
* for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
* will be burned.
* - `from` and `to` are never both zero.
* - `ids` and `amounts` have the same, non-zero length.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
function _doSafeTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
if (response != IERC1155Receiver.onERC1155Received.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
function _doSafeBatchTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
bytes4 response
) {
if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
uint256[] memory array = new uint256[](1);
array[0] = element;
return array;
}
}
MerkleProof.sol 223 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/MerkleProof.sol)
pragma solidity ^0.8.0;
/**
* @dev These functions deal with verification of Merkle Tree proofs.
*
* The tree and the proofs can be generated using our
* https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
* You will find a quickstart guide in the readme.
*
* WARNING: You should avoid using leaf values that are 64 bytes long prior to
* hashing, or use a hash function other than keccak256 for hashing leaves.
* This is because the concatenation of a sorted pair of internal nodes in
* the merkle tree could be reinterpreted as a leaf value.
* OpenZeppelin's JavaScript library generates merkle trees that are safe
* against this attack out of the box.
*/
library MerkleProof {
/**
* @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
* defined by `root`. For this, a `proof` must be provided, containing
* sibling hashes on the branch from the leaf to the root of the tree. Each
* pair of leaves and each pair of pre-images are assumed to be sorted.
*/
function verify(
bytes32[] memory proof,
bytes32 root,
bytes32 leaf
) internal pure returns (bool) {
return processProof(proof, leaf) == root;
}
/**
* @dev Calldata version of {verify}
*
* _Available since v4.7._
*/
function verifyCalldata(
bytes32[] calldata proof,
bytes32 root,
bytes32 leaf
) internal pure returns (bool) {
return processProofCalldata(proof, leaf) == root;
}
/**
* @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
* from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
* hash matches the root of the tree. When processing the proof, the pairs
* of leafs & pre-images are assumed to be sorted.
*
* _Available since v4.4._
*/
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
/**
* @dev Calldata version of {processProof}
*
* _Available since v4.7._
*/
function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
/**
* @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by
* `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/
function multiProofVerify(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProof(proof, proofFlags, leaves) == root;
}
/**
* @dev Calldata version of {multiProofVerify}
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/
function multiProofVerifyCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProofCalldata(proof, proofFlags, leaves) == root;
}
/**
* @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
* proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
* leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
* respectively.
*
* CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
* is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
* tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
*
* _Available since v4.7._
*/
function processMultiProof(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
// the merkle tree.
uint256 leavesLen = leaves.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.
require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
// At each step, we compute the next hash using two values:
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
// get the next hash.
// - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
// `proof` array.
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
return hashes[totalHashes - 1];
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
/**
* @dev Calldata version of {processMultiProof}.
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/
function processMultiProofCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
// the merkle tree.
uint256 leavesLen = leaves.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.
require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
// At each step, we compute the next hash using two values:
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
// get the next hash.
// - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
// `proof` array.
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
return hashes[totalHashes - 1];
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
}
function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}
Address.sol 244 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @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
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 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");
(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 functionCallWithValue(target, data, 0, "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");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// 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
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
ERC165.sol 29 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
Read Contract
isProducerPassStakingEnabledForId 0x19e3c5ad → bool
isProducerPassUnstakingEnabledForId 0x1fa54479 → bool
isStakingEnabledForChapter 0x6a148217 → bool
isUnstakingEnabledForChapter 0x18c72295 → bool
owner 0x8da5cb5b → address
producerPassContract 0x2b4dd1cc → address
stakedProducerPassesFromUser 0x2c58cd17 → uint256
supportsInterface 0x01ffc9a7 → bool
Write Contract 9 functions
These functions modify contract state and require a wallet transaction to execute.
onERC1155BatchReceived 0xbc197c81
address
address
uint256[]
uint256[]
bytes
returns: bytes4
onERC1155Received 0xf23a6e61
address
address
uint256
uint256
bytes
returns: bytes4
renounceOwnership 0x715018a6
No parameters
setProducerPassContract 0x6c0c712b
address add
setProducerPassStakingEnabledForIds 0x13c44455
uint256[] chapterIds
bool[] enabled
setProducerPassUnstakingEnabledForIds 0xdbdfb452
uint256[] chapterIds
bool[] enabled
stakeProducerPasses 0x0c908a0c
uint256[] chapterIds
uint256[] amounts
transferOwnership 0xf2fde38b
address newOwner
unstakeProducerPasses 0xd2a453c2
uint256[] chapterIds
uint256[] amounts
Recent Transactions
No transactions found for this address