// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/**
* @dev Collection of functions related to the address type
*/libraryAddress{
/**
* @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
* ====
*/functionisContract(address account) internalviewreturns (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-assemblyassembly {
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].
*/functionsendValue(addresspayable 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._
*/functionfunctionCall(address target, bytesmemory data)
internalreturns (bytesmemory)
{
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._
*/functionfunctionCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
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._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value
) internalreturns (bytesmemory) {
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._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value,
stringmemory errorMessage
) internalreturns (bytesmemory) {
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, bytesmemory 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._
*/functionfunctionStaticCall(address target, bytesmemory data)
internalviewreturns (bytesmemory)
{
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._
*/functionfunctionStaticCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalviewreturns (bytesmemory) {
require(isContract(target), "Address: static call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytesmemory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target, bytesmemory data)
internalreturns (bytesmemory)
{
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._
*/functionfunctionDelegateCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
require(isContract(target), "Address: delegate call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytesmemory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function_verifyCallResult(bool success,
bytesmemory returndata,
stringmemory errorMessage
) privatepurereturns (bytesmemory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if presentif (returndata.length>0) {
// The easiest way to bubble the revert reason is using memory via assembly// solhint-disable-next-line no-inline-assemblyassembly {
let returndata_size :=mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
Contract Source Code
File 2 of 12: Context.sol
// SPDX-License-Identifier: MITpragmasolidity ^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.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691returnmsg.data;
}
}
Contract Source Code
File 3 of 12: ERC1155.sol
// SPDX-License-Identifier: MITpragmasolidity ^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._
*/contractERC1155isContext, ERC165, IERC1155, IERC1155MetadataURI{
usingAddressforaddress;
// Mapping from token ID to account balancesmapping(uint256=>mapping(address=>uint256)) private _balances;
// Mapping from account to operator approvalsmapping(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}.jsonstringprivate _uri;
/**
* @dev See {_setURI}.
*/constructor(stringmemory uri_) {
_setURI(uri_);
}
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId)
publicviewvirtualoverride(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.
*/functionuri(uint256) publicviewvirtualoverridereturns (stringmemory) {
return _uri;
}
/**
* @dev See {IERC1155-balanceOf}.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/functionbalanceOf(address account, uint256 id)
publicviewvirtualoverridereturns (uint256)
{
require(
account !=address(0),
"ERC1155: balance query for the zero address"
);
return _balances[id][account];
}
/**
* @dev See {IERC1155-balanceOfBatch}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/functionbalanceOfBatch(address[] memory accounts, uint256[] memory ids)
publicviewvirtualoverridereturns (uint256[] memory)
{
require(
accounts.length== ids.length,
"ERC1155: accounts and ids length mismatch"
);
uint256[] memory batchBalances =newuint256[](accounts.length);
for (uint256 i =0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts[i], ids[i]);
}
return batchBalances;
}
/**
* @dev See {IERC1155-setApprovalForAll}.
*/functionsetApprovalForAll(address operator, bool approved)
publicvirtualoverride{
require(
_msgSender() != operator,
"ERC1155: setting approval status for self"
);
_operatorApprovals[_msgSender()][operator] = approved;
emit ApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC1155-isApprovedForAll}.
*/functionisApprovedForAll(address account, address operator)
publicviewvirtualoverridereturns (bool)
{
return _operatorApprovals[account][operator];
}
/**
* @dev See {IERC1155-safeTransferFrom}.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 id,
uint256 amount,
bytesmemory data
) publicvirtualoverride{
require(to !=address(0), "ERC1155: transfer to the zero address");
require(
from== _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not owner nor approved"
);
address operator = _msgSender();
_beforeTokenTransfer(
operator,
from,
to,
_asSingletonArray(id),
_asSingletonArray(amount),
data
);
uint256 fromBalance = _balances[id][from];
require(
fromBalance >= amount,
"ERC1155: insufficient balance for transfer"
);
_balances[id][from] = fromBalance - amount;
_balances[id][to] += amount;
emit TransferSingle(operator, from, to, id, amount);
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
}
/**
* @dev See {IERC1155-safeBatchTransferFrom}.
*/functionsafeBatchTransferFrom(addressfrom,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytesmemory data
) publicvirtualoverride{
require(
ids.length== amounts.length,
"ERC1155: ids and amounts length mismatch"
);
require(to !=address(0), "ERC1155: transfer to the zero address");
require(
from== _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: transfer caller is not owner nor approved"
);
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"
);
_balances[id][from] = fromBalance - amount;
_balances[id][to] += amount;
}
emit TransferBatch(operator, from, to, ids, amounts);
_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(stringmemory newuri) internalvirtual{
_uri = newuri;
}
/**
* @dev Creates `amount` tokens of token type `id`, and assigns them to `account`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - If `account` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/function_mint(address account,
uint256 id,
uint256 amount,
bytesmemory data
) internalvirtual{
require(account !=address(0), "ERC1155: mint to the zero address");
address operator = _msgSender();
_beforeTokenTransfer(
operator,
address(0),
account,
_asSingletonArray(id),
_asSingletonArray(amount),
data
);
_balances[id][account] += amount;
emit TransferSingle(operator, address(0), account, id, amount);
_doSafeTransferAcceptanceCheck(
operator,
address(0),
account,
id,
amount,
data
);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
*
* 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,
bytesmemory data
) internalvirtual{
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);
_doSafeBatchTransferAcceptanceCheck(
operator,
address(0),
to,
ids,
amounts,
data
);
}
/**
* @dev Destroys `amount` tokens of token type `id` from `account`
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens of token type `id`.
*/function_burn(address account,
uint256 id,
uint256 amount
) internalvirtual{
require(account !=address(0), "ERC1155: burn from the zero address");
address operator = _msgSender();
_beforeTokenTransfer(
operator,
account,
address(0),
_asSingletonArray(id),
_asSingletonArray(amount),
""
);
uint256 accountBalance = _balances[id][account];
require(
accountBalance >= amount,
"ERC1155: burn amount exceeds balance"
);
_balances[id][account] = accountBalance - amount;
emit TransferSingle(operator, account, address(0), id, amount);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
*/function_burnBatch(address account,
uint256[] memory ids,
uint256[] memory amounts
) internalvirtual{
require(account !=address(0), "ERC1155: burn from the zero address");
require(
ids.length== amounts.length,
"ERC1155: ids and amounts length mismatch"
);
address operator = _msgSender();
_beforeTokenTransfer(operator, account, address(0), ids, amounts, "");
for (uint256 i =0; i < ids.length; i++) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 accountBalance = _balances[id][account];
require(
accountBalance >= amount,
"ERC1155: burn amount exceeds balance"
);
_balances[id][account] = accountBalance - amount;
}
emit TransferBatch(operator, account, address(0), ids, amounts);
}
/**
* @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 `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_beforeTokenTransfer(address operator,
addressfrom,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytesmemory data
) internalvirtual{}
function_doSafeTransferAcceptanceCheck(address operator,
addressfrom,
address to,
uint256 id,
uint256 amount,
bytesmemory data
) private{
if (to.isContract()) {
try
IERC1155Receiver(to).onERC1155Received(
operator,
from,
id,
amount,
data
)
returns (bytes4 response) {
if (
response != IERC1155Receiver(to).onERC1155Received.selector
) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catchError(stringmemory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non ERC1155Receiver implementer");
}
}
}
function_doSafeBatchTransferAcceptanceCheck(address operator,
addressfrom,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytesmemory data
) private{
if (to.isContract()) {
try
IERC1155Receiver(to).onERC1155BatchReceived(
operator,
from,
ids,
amounts,
data
)
returns (bytes4 response) {
if (
response !=
IERC1155Receiver(to).onERC1155BatchReceived.selector
) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catchError(stringmemory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non ERC1155Receiver implementer");
}
}
}
function_asSingletonArray(uint256 element)
privatepurereturns (uint256[] memory)
{
uint256[] memory array =newuint256[](1);
array[0] = element;
return array;
}
}
Contract Source Code
File 4 of 12: ERC165.sol
// SPDX-License-Identifier: MITpragmasolidity ^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.
*/abstractcontractERC165isIERC165{
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId)
publicviewvirtualoverridereturns (bool)
{
return interfaceId ==type(IERC165).interfaceId;
}
}
Contract Source Code
File 5 of 12: IERC1155.sol
// SPDX-License-Identifier: MITpragmasolidity ^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._
*/interfaceIERC1155isIERC165{
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/eventTransferSingle(addressindexed operator,
addressindexedfrom,
addressindexed to,
uint256 id,
uint256 value
);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/eventTransferBatch(addressindexed operator,
addressindexedfrom,
addressindexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/eventApprovalForAll(addressindexed account,
addressindexed 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}.
*/eventURI(string value, uint256indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/functionbalanceOf(address account, uint256 id)
externalviewreturns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/functionbalanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
externalviewreturns (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.
*/functionsetApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/functionisApprovedForAll(address account, address operator)
externalviewreturns (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 be 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.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 id,
uint256 amount,
bytescalldata 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.
*/functionsafeBatchTransferFrom(addressfrom,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytescalldata data
) external;
}
Contract Source Code
File 6 of 12: IERC1155MetadataURI.sol
// SPDX-License-Identifier: MITpragmasolidity ^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._
*/interfaceIERC1155MetadataURIisIERC1155{
/**
* @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.
*/functionuri(uint256 id) externalviewreturns (stringmemory);
}
Contract Source Code
File 7 of 12: IERC1155Receiver.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"../utils/introspection/IERC165.sol";
/**
* @dev _Available since v3.1._
*/interfaceIERC1155ReceiverisIERC165{
/**
@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.
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
*/functiononERC1155Received(address operator,
addressfrom,
uint256 id,
uint256 value,
bytescalldata data
) externalreturns (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. 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
*/functiononERC1155BatchReceived(address operator,
addressfrom,
uint256[] calldata ids,
uint256[] calldata values,
bytescalldata data
) externalreturns (bytes4);
}
Contract Source Code
File 8 of 12: IERC165.sol
// SPDX-License-Identifier: MITpragmasolidity ^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}.
*/interfaceIERC165{
/**
* @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.
*/functionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
}
Contract Source Code
File 9 of 12: Ownable.sol
// SPDX-License-Identifier: MITpragmasolidity ^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.
*/abstractcontractOwnableisContext{
addressprivate _owner;
eventOwnershipTransferred(addressindexed previousOwner,
addressindexed newOwner
);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/constructor() {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
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.
*/functionrenounceOwnership() publicvirtualonlyOwner{
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.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
require(
newOwner !=address(0),
"Ownable: new owner is the zero address"
);
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
Contract Source Code
File 10 of 12: SignatureVerifier_V2.sol
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗// ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║// ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║// ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║// ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║// ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝// Copyright (C) 2021 zapper// Copyright (c) 2018 Tasuku Nakamura// This program is free software: you can redistribute it and/or modify// it under the terms of the GNU Affero General Public License as published by// the Free Software Foundation, either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU Affero General Public License for more details./////@author Zapper///@notice This contract checks if a message has been signed by a verified signer via personal_sign.// SPDX-License-Identifier: GPL-2.0pragmasolidity ^0.8.0;contractSignatureVerifier_V2{
addresspublic signer;
constructor(address _signer) {
signer = _signer;
}
functionverify(bytes32 messageHash, bytesmemory signature)
internalviewreturns (bool)
{
bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash);
return recoverSigner(ethSignedMessageHash, signature) == signer;
}
functiongetEthSignedMessageHash(bytes32 messageHash)
internalpurereturns (bytes32)
{
returnkeccak256(
abi.encodePacked(
"\x19Ethereum Signed Message:\n32",
messageHash
)
);
}
functionrecoverSigner(bytes32 _ethSignedMessageHash,
bytesmemory _signature
) internalpurereturns (address) {
(bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);
returnecrecover(_ethSignedMessageHash, v, r, s);
}
functionsplitSignature(bytesmemory signature)
internalpurereturns (bytes32 r,
bytes32 s,
uint8 v
)
{
require(signature.length==65, "invalid signature length");
assembly {
r :=mload(add(signature, 32))
s :=mload(add(signature, 64))
v :=byte(0, mload(add(signature, 96)))
}
}
}
Contract Source Code
File 11 of 12: Strings.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/**
* @dev String operations.
*/libraryStrings{
bytes16privateconstant _HEX_SYMBOLS ="0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/functiontoString(uint256 value) internalpurereturns (stringmemory) {
// Inspired by OraclizeAPI's implementation - MIT licence// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.solif (value ==0) {
return"0";
}
uint256 temp = value;
uint256 digits;
while (temp !=0) {
digits++;
temp /=10;
}
bytesmemory buffer =newbytes(digits);
while (value !=0) {
digits -=1;
buffer[digits] =bytes1(uint8(48+uint256(value %10)));
value /=10;
}
returnstring(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/functiontoHexString(uint256 value) internalpurereturns (stringmemory) {
if (value ==0) {
return"0x00";
}
uint256 temp = value;
uint256 length =0;
while (temp !=0) {
length++;
temp >>=8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/functiontoHexString(uint256 value, uint256 length)
internalpurereturns (stringmemory)
{
bytesmemory buffer =newbytes(2* length +2);
buffer[0] ="0";
buffer[1] ="x";
for (uint256 i =2* length +1; i >1; --i) {
buffer[i] = _HEX_SYMBOLS[value &0xf];
value >>=4;
}
require(value ==0, "Strings: hex length insufficient");
returnstring(buffer);
}
}
Contract Source Code
File 12 of 12: Zapper_NFT_V2.sol
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗// ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║// ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║// ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║// ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║// ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝// Copyright (C) 2021 zapper// This program is free software: you can redistribute it and/or modify// it under the terms of the GNU Affero General Public License as published by// the Free Software Foundation, either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU Affero General Public License for more details./////@author Zapper///@notice This contract manages Zapper V2 NFTs and Volts./// Volts can be claimed through quests in order to mint various NFTs./// Crafting combines NFTs of the same type into higher tier NFTs. NFTs/// can also be redemeed for Volts.// SPDX-License-Identifier: GPL-2.0pragmasolidity ^0.8.0;import"./ERC1155/ERC1155.sol";
import"./access/Ownable.sol";
import"./SignatureVerifier/SignatureVerifier_V2.sol";
import"./ERC1155/IERC1155.sol";
import"./utils/Strings.sol";
contractZapper_NFT_V2_0_1isERC1155, Ownable, SignatureVerifier_V2{
// Used in pausable modifierboolpublic paused;
// NFT namestringpublic name;
// NFT symbolstringpublic symbol;
// Season deadlineuint256public deadline;
// Modifier to apply to cost of NFT when redeeming in bpsuint256public redeemModifier =7500;
// Quantity of NFTs consumed per crafting eventuint256public craftingRequirement =3;
// Mapping from token ID to token supplymapping(uint256=>uint256) private tokenSupply;
// Mapping of accessory contracts that have permission to mintmapping(address=>bool) public accessoryContract;
// Total Volt supplyuint256public voltSupply;
// Mapping from account to Volt balancemapping(address=>uint256) public voltBalance;
// Mapping from token ID to token existencemapping(uint256=>bool) private exists;
// Mapping for the rarity classes for use in craftingmapping(uint256=>uint256) public nextRarity;
// Mapping from token ID to token cost in voltsmapping(uint256=>uint256) public cost;
// Mapping from account to noncemapping(address=>uint256) public nonces;
// Emitted when `account` claims VoltseventClaimVolts(addressindexed account,
uint256 voltsRecieved,
uint256 nonce
);
// Emitted when `account` burns VoltseventBurnVolts(addressindexed account, uint256 voltsBurned);
// Emitted when `account` mints one or more NFTs by spending VoltseventMint(addressindexed account, uint256 voltsSpent);
// Emitted when `account` redeems Volts by burning one or more NFTseventRedeem(addressindexed account, uint256 voltsRecieved);
// Emitted when `account` crafts one or more of the same NFTeventCraft(addressindexed account, uint256 craftID);
// Emitted when `account` crafts multiple different NFTseventCraftBatch(addressindexed account, uint256[] craftIDs);
// Emitted when a new NFT type is addedeventAdd(uint256 id, uint256 cost, uint256 nextRarity);
// Emitted when the baseURI is updatedeventupdateBaseURI(string uri);
modifierpausable{
require(!paused, "Paused");
_;
}
modifierbeforeDeadline{
require(block.timestamp<= deadline, "Deadline elapsed");
_;
}
constructor(stringmemory _name,
stringmemory _symbol,
stringmemory _uri,
address signer,
address manager,
uint256 _deadline
) ERC1155(_uri) SignatureVerifier_V2(signer) {
name = _name;
symbol = _symbol;
deadline = _deadline;
transferOwnership(manager);
}
/**
* @dev Adds a new NFT and initializes crafting params
* @param costs An array of the cost of each ID. 0 if it cannot
* be crafted
* @param nextRarities An array of higher rarity IDs which can be
* crafted from the ID. 0 if max rarity.
*/functionadd(uint256[] calldata ids,
uint256[] calldata costs,
uint256[] calldata nextRarities
) externalonlyOwner{
require(
ids.length== costs.length&& ids.length== nextRarities.length,
"Mismatched array lengths"
);
for (uint256 i =0; i < ids.length; i++) {
uint256 newId = ids[i];
require(!exists[newId], "ID already exists");
require(newId !=0, "Invalid ID");
exists[newId] =true;
cost[newId] = costs[i];
nextRarity[newId] = nextRarities[i];
emit Add(newId, costs[i], nextRarities[i]);
}
}
/**
* @notice Claims Volts earned through quests
* @param voltsEarned The quantity of Volts being awarded
* @param signature The signature granting msg.sender the volts
*/functionclaimVolts(uint256 voltsEarned, bytescalldata signature)
externalpausablebeforeDeadline{
bytes32 messageHash =
getMessageHash(msg.sender, voltsEarned, nonces[msg.sender]++);
require(verify(messageHash, signature), "Invalid Signature");
_createVolts(voltsEarned);
emit ClaimVolts(msg.sender, voltsEarned, nonces[msg.sender]);
}
/**
* @notice Burns Volts
* @param voltsBurned The quantity of Volts being burned
*/functionburnVolts(uint256 voltsBurned) externalpausable{
_burnVolts(voltsBurned);
emit BurnVolts(msg.sender, voltsBurned);
}
/**
* @notice Mints a desired quantity of a single NFT ID
* in exchange for Volts
* @param id The ID of the NFT to mint
* @param quantity The quantity of the NFT to mint
*/functionmint(uint256 id, uint256 quantity) externalpausable{
require(exists[id], "Invalid ID");
uint256 voltsSpent;
if (!accessoryContract[msg.sender]) {
require(cost[id] >0, "Price not set");
voltsSpent = cost[id] * quantity;
_burnVolts(voltsSpent);
}
_mint(msg.sender, id, quantity, newbytes(0));
emit Mint(msg.sender, voltsSpent);
}
/**
* @notice Batch Mints desired quantities of different NFT IDs
* in exchange for Volts
* @param ids An array consisting of the IDs of the NFTs to mint
* @param quantities An array consisting of the quantities of the NFTs to mint
*/functionmintBatch(uint256[] calldata ids, uint256[] calldata quantities)
externalpausable{
require(ids.length== quantities.length, "Mismatched array lengths");
uint256 voltsSpent;
if (!accessoryContract[msg.sender]) {
for (uint256 i =0; i < ids.length; i++) {
require(exists[ids[i]], "Invalid ID");
require(cost[ids[i]] >0, "Price not set");
voltsSpent += cost[ids[i]] * quantities[i];
}
_burnVolts(voltsSpent);
} else {
for (uint256 i =0; i < ids.length; i++) {
require(exists[ids[i]], "Invalid ID");
}
}
_mintBatch(msg.sender, ids, quantities, newbytes(0));
emit Mint(msg.sender, voltsSpent);
}
/**
* @notice Burns an NFT
* @dev Does not award Volts!
* @param id The ID of the NFT to burn
* @param quantity The quantity of the NFT to burn
*/functionburn(uint256 id, uint256 quantity) externalpausable{
_burn(msg.sender, id, quantity);
}
/**
* @notice Batch burns NFTs
* @dev Does not award Volts!
* @param ids An array consisting of the IDs of the NFTs to burn
* @param quantities An array consisting of the quantities
* of each NFT to burn
*/functionburnBatch(uint256[] calldata ids, uint256[] calldata quantities)
externalpausable{
_burnBatch(msg.sender, ids, quantities);
}
/**
* @notice Redeems an NFT for Volts. Redeeming NFTs is
* subject to a modifier which returns some percentage of
* the full cost of the NFT
* @param id ID of the NFT to redeem
* @param quantity The quantity of the NFT being redeemed
*/functionredeem(uint256 id, uint256 quantity) externalpausable{
require(cost[id] >0, "Cannot redeem this type");
_burn(msg.sender, id, quantity);
uint256 voltsRecieved = (cost[id] * quantity * redeemModifier) /10000;
_createVolts(voltsRecieved);
emit Redeem(msg.sender, voltsRecieved);
}
/**
* @notice Redeems multiple NFTs for Volts. Redeeming NFTs is
* subject to a modifier which returns some percentage of
* the full cost of the NFT
* @param ids An array consisting of the IDs of the NFTs to redeem
* @param quantities An array consisting of the quantities of
* each NFT to redeem
*/functionredeemBatch(uint256[] calldata ids, uint256[] calldata quantities)
externalpausable{
_burnBatch(msg.sender, ids, quantities);
uint256 voltsRecieved;
for (uint256 i =0; i < ids.length; i++) {
require(cost[ids[i]] >0, "Cannot redeem this type");
voltsRecieved +=
(cost[ids[i]] * quantities[i] * redeemModifier) /10000;
}
_createVolts(voltsRecieved);
emit Redeem(msg.sender, voltsRecieved);
}
/**
* @notice Crafts higher tier NFTs with lower tier NFTs
* @param id ID of the NFT used for crafting
* @param quantity The quantity of id to consume in crafting
*/functioncraft(uint256 id, uint256 quantity) externalpausable{
uint256 craftID = nextRarity[id];
require(craftID !=0, "Already maximum rarity");
require(
quantity % craftingRequirement ==0,
"Incorrect quantity for crafting"
);
_burn(msg.sender, id, quantity);
uint256 craftQuantity = quantity / craftingRequirement;
_mint(msg.sender, craftID, craftQuantity, newbytes(0));
emit Craft(msg.sender, craftID);
}
/**
* @notice Crafts multiple different higher tier NFTs with
* lower tier NFTs
* @param ids An array consisting of the IDs of the NFT used for crafting
* @param quantities An array consisting of the quantities of the NFT
* to consume in crafting
*/functioncraftBatch(uint256[] calldata ids, uint256[] calldata quantities)
externalpausable{
_burnBatch(msg.sender, ids, quantities);
uint256[] memory craftQuantities =newuint256[](quantities.length);
uint256[] memory craftIds =newuint256[](ids.length);
for (uint256 i =0; i < ids.length; i++) {
uint256 craftID = nextRarity[ids[i]];
require(craftID !=0, "Already maximum rarity");
require(
quantities[i] % craftingRequirement ==0,
"Incorrect quantity for crafting"
);
craftIds[i] = craftID;
craftQuantities[i] = quantities[i] / craftingRequirement;
}
_mintBatch(msg.sender, craftIds, craftQuantities, newbytes(0));
emit CraftBatch(msg.sender, craftIds);
}
/**
* @dev Function to set the URI for all NFT IDs
*/functionsetBaseURI(stringcalldata _uri) externalonlyOwner{
_setURI(_uri);
emit updateBaseURI(_uri);
}
/**
* @dev Returns the URI of a token given its ID
* @param id ID of the token to query
* @return uri of the token or an empty string if it does not exist
*/functionuri(uint256 id) publicviewoverridereturns (stringmemory) {
require(exists[id], "URI query for nonexistent token");
stringmemory baseUri =super.uri(0);
returnstring(abi.encodePacked(baseUri, Strings.toString(id)));
}
/**
* @notice Maps the rarity classes and Volt costs
* for use in crafting
* @param ids An array of the IDs being updated
* @param costs An array of the cost of each ID
* @param nextRarities An array of higher rarity IDs which
* can be crafted from the ID
*/functionupdateCraftingParameters(uint256[] calldata ids,
uint256[] calldata costs,
uint256[] calldata nextRarities
) externalonlyOwner{
require(
ids.length== costs.length&& ids.length== nextRarities.length,
"Mismatched array lengths"
);
for (uint256 i =0; i < ids.length; i++) {
require(exists[ids[i]], "ID does not exist");
cost[ids[i]] = costs[i];
nextRarity[ids[i]] = nextRarities[i];
}
}
/**
* @dev Updates the modifier which is used when redeeming
* NFTs for Volts
*/functionupdateRedeemModifier(uint256 _redeemModifier) externalonlyOwner{
redeemModifier = _redeemModifier;
}
/**
* @dev Updates the crafting requirement modifier which determines
* the quantity of NFTs that are burned in order to craft
* higher rarity NFTs
*/functionupdateCraftingRequirement(uint256 _craftingRequirement)
externalonlyOwner{
craftingRequirement = _craftingRequirement;
}
/**
* @dev Updates the mapping of accessory contracts which have
* special permssions to mint NFTs (lootbox, bridge, etc.)
*/functionupdateAccessoryContracts(address _accessoryContract, bool allowed)
externalonlyOwner{
accessoryContract[_accessoryContract] = allowed;
}
/**
* @dev Updates the deadline after which Volts can no longer be claimed
*/functionupdateDeadline(uint256 _deadline) externalonlyOwner{
deadline = _deadline;
}
/**
* @dev Returns the total quantity for a token ID
* @param id ID of the token to query
* @return amount of token in existence
*/functiontotalSupply(uint256 id) externalviewreturns (uint256) {
return tokenSupply[id];
}
/**
* @dev Pause or unpause the contract
*/functionpause() externalonlyOwner{
paused =!paused;
}
/**
* @dev Function to return the message hash that will be
* signed by the signer
*/functiongetMessageHash(address account,
uint256 volts,
uint256 nonce
) publicpurereturns (bytes32) {
returnkeccak256(abi.encodePacked(account, volts, nonce));
}
/**
* @dev Internal override function for minting an NFT
*/function_mint(address account,
uint256 id,
uint256 amount,
bytesmemory data
) internaloverride{
super._mint(account, id, amount, data);
tokenSupply[id] += amount;
}
/**
* @dev Internal override function for batch minting NFTs
*/function_mintBatch(address to,
uint256[] memory ids,
uint256[] memory amounts,
bytesmemory data
) internaloverride{
super._mintBatch(to, ids, amounts, data);
for (uint256 i =0; i < ids.length; i++) {
tokenSupply[ids[i]] += amounts[i];
}
}
/**
* @dev Internal override function for burning an NFT
*/function_burn(address account,
uint256 id,
uint256 amount
) internaloverride{
super._burn(account, id, amount);
tokenSupply[id] -= amount;
}
/**
* @dev Internal override function for batch burning NFTs
*/function_burnBatch(address account,
uint256[] memory ids,
uint256[] memory amounts
) internaloverride{
super._burnBatch(account, ids, amounts);
for (uint256 i; i < ids.length; i++) {
tokenSupply[ids[i]] -= amounts[i];
}
}
/**
* @dev Internal function to create volts
*/function_createVolts(uint256 quantity) internal{
voltBalance[msg.sender] += quantity;
voltSupply += quantity;
}
/**
* @dev Internal function to burn volts
*/function_burnVolts(uint256 quantity) internal{
require(
voltBalance[msg.sender] >= quantity,
"Insufficient Volt balance"
);
voltBalance[msg.sender] -= quantity;
voltSupply -= quantity;
}
}