ETH Price: $2,534.39 (-0.30%)

Transaction Decoder

Block:
14501653 at Apr-01-2022 05:16:44 PM +UTC
Transaction Fee:
0.015284201422811796 ETH $38.74
Gas Used:
106,086 Gas / 144.073689486 Gwei

Emitted Events:

174 Sand.Transfer( from=[Receiver] MultiGiveaway, to=[Sender] 0xc84ff195c904fcb2ee5ba8e70f8b84b2635a1bf2, value=1000000000000000000000 )
175 MultiGiveaway.ClaimedMultipleTokens( to=[Sender] 0xc84ff195c904fcb2ee5ba8e70f8b84b2635a1bf2, erc1155=, erc721=, erc20=[{name:amounts, type:uint256[], order:1, indexed:false, value:[1000000000000000000000], valueString:[1000000000000000000000]}, {name:contractAddresses, type:address[], order:2, indexed:false, value:[0x3845badAde8e6dFF049820680d1F14bD3903a5d0], valueString:[0x3845badAde8e6dFF049820680d1F14bD3903a5d0]}] )

Account State Difference:

  Address   Before After State Difference Code
0x3845badA...D3903a5d0
0xa21342f7...F8f83A9e4
0xC84FF195...2635a1bF2
0.0294 Eth
Nonce: 0
0.014115798577188204 Eth
Nonce: 1
0.015284201422811796
(Ethermine)
911.56900231156334165 Eth911.56916144056334165 Eth0.000159129

Execution Trace

MultiGiveaway.claimMultipleTokens( )
  • Sand.transferFrom( from=0xa21342f796996954284B8DC6AAe7ecBF8f83A9e4, to=0xC84FF195c904fCB2Ee5ba8E70F8B84B2635a1bF2, amount=1000000000000000000000 ) => ( success=True )
    claimMultipleTokens[MultiGiveaway (ln:60)]
    File 1 of 2: MultiGiveaway
    //SPDX-License-Identifier: MIT
    pragma solidity 0.8.2;
    import "@openzeppelin/contracts-0.8/token/ERC721/IERC721Receiver.sol";
    import "@openzeppelin/contracts-0.8/token/ERC1155/IERC1155Receiver.sol";
    import "./ClaimERC1155ERC721ERC20.sol";
    import "../../common/BaseWithStorage/WithAdmin.sol";
    /// @title MultiGiveaway contract.
    /// @notice This contract manages claims for multiple token types.
    contract MultiGiveaway is WithAdmin, ClaimERC1155ERC721ERC20 {
        ///////////////////////////////  Data //////////////////////////////
        bytes4 private constant ERC1155_RECEIVED = 0xf23a6e61;
        bytes4 private constant ERC1155_BATCH_RECEIVED = 0xbc197c81;
        bytes4 internal constant ERC721_RECEIVED = 0x150b7a02;
        bytes4 internal constant ERC721_BATCH_RECEIVED = 0x4b808c46;
        mapping(address => mapping(bytes32 => bool)) public claimed;
        mapping(bytes32 => uint256) internal _expiryTime;
        ///////////////////////////////  Events //////////////////////////////
        event NewGiveaway(bytes32 merkleRoot, uint256 expiryTime);
        ///////////////////////////////  Constructor /////////////////////////
        constructor(address admin) {
            _admin = admin;
        }
        ///////////////////////////////  Functions ///////////////////////////
        /// @notice Function to add a new giveaway.
        /// @param merkleRoot The merkle root hash of the claim data.
        /// @param expiryTime The expiry time for the giveaway.
        function addNewGiveaway(bytes32 merkleRoot, uint256 expiryTime) external onlyAdmin {
            _expiryTime[merkleRoot] = expiryTime;
            emit NewGiveaway(merkleRoot, expiryTime);
        }
        /// @notice Function to check which giveaways have been claimed by a particular user.
        /// @param user The user (intended token destination) address.
        /// @param rootHashes The array of giveaway root hashes to check.
        /// @return claimedGiveaways The array of bools confirming whether or not the giveaways relating to the root hashes provided have been claimed.
        function getClaimedStatus(address user, bytes32[] calldata rootHashes) external view returns (bool[] memory) {
            bool[] memory claimedGiveaways = new bool[](rootHashes.length);
            for (uint256 i = 0; i < rootHashes.length; i++) {
                claimedGiveaways[i] = claimed[user][rootHashes[i]];
            }
            return claimedGiveaways;
        }
        /// @notice Function to permit the claiming of multiple tokens from multiple giveaways to a reserved address.
        /// @param claims The array of claim structs, each containing a destination address, the giveaway items to be claimed and an optional salt param.
        /// @param proofs The proofs submitted for verification.
        function claimMultipleTokensFromMultipleMerkleTree(
            bytes32[] calldata rootHashes,
            Claim[] memory claims,
            bytes32[][] calldata proofs
        ) external {
            require(claims.length == rootHashes.length, "INVALID_INPUT");
            require(claims.length == proofs.length, "INVALID_INPUT");
            for (uint256 i = 0; i < rootHashes.length; i++) {
                claimMultipleTokens(rootHashes[i], claims[i], proofs[i]);
            }
        }
        /// @dev Public function used to perform validity checks and progress to claim multiple token types in one claim.
        /// @param merkleRoot The merkle root hash for the specific set of items being claimed.
        /// @param claim The claim struct containing the destination address, all items to be claimed and optional salt param.
        /// @param proof The proof provided by the user performing the claim function.
        function claimMultipleTokens(
            bytes32 merkleRoot,
            Claim memory claim,
            bytes32[] calldata proof
        ) public {
            uint256 giveawayExpiryTime = _expiryTime[merkleRoot];
            require(claim.to != address(0), "INVALID_TO_ZERO_ADDRESS");
            require(claim.to != address(this), "DESTINATION_MULTIGIVEAWAY_CONTRACT");
            require(giveawayExpiryTime != 0, "GIVEAWAY_DOES_NOT_EXIST");
            require(block.timestamp < giveawayExpiryTime, "CLAIM_PERIOD_IS_OVER");
            require(claimed[claim.to][merkleRoot] == false, "DESTINATION_ALREADY_CLAIMED");
            claimed[claim.to][merkleRoot] = true;
            _claimERC1155ERC721ERC20(merkleRoot, claim, proof);
        }
        function onERC721Received(
            address, /*operator*/
            address, /*from*/
            uint256, /*id*/
            bytes calldata /*data*/
        ) external pure returns (bytes4) {
            return ERC721_RECEIVED;
        }
        function onERC721BatchReceived(
            address, /*operator*/
            address, /*from*/
            uint256[] calldata, /*ids*/
            bytes calldata /*data*/
        ) external pure returns (bytes4) {
            return ERC721_BATCH_RECEIVED;
        }
        function onERC1155Received(
            address, /*operator*/
            address, /*from*/
            uint256, /*id*/
            uint256, /*value*/
            bytes calldata /*data*/
        ) external pure returns (bytes4) {
            return ERC1155_RECEIVED;
        }
        function onERC1155BatchReceived(
            address, /*operator*/
            address, /*from*/
            uint256[] calldata, /*ids*/
            uint256[] calldata, /*values*/
            bytes calldata /*data*/
        ) external pure returns (bytes4) {
            return ERC1155_BATCH_RECEIVED;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @title ERC721 token receiver interface
     * @dev Interface for any contract that wants to support safeTransfers
     * from ERC721 asset contracts.
     */
    interface IERC721Receiver {
        /**
         * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
         * by `operator` from `from`, this function is called.
         *
         * It must return its Solidity selector to confirm the token transfer.
         * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
         *
         * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
         */
        function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "../../utils/introspection/IERC165.sol";
    /**
     * _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.
            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. 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);
    }
    //SPDX-License-Identifier: MIT
    pragma solidity 0.8.2;
    import "@openzeppelin/contracts-0.8/token/ERC1155/IERC1155.sol";
    import "@openzeppelin/contracts-0.8/token/ERC20/IERC20.sol";
    import "@openzeppelin/contracts-0.8/token/ERC20/utils/SafeERC20.sol";
    import "../../common/interfaces/IERC721Extended.sol";
    import "../../common/Libraries/Verify.sol";
    contract ClaimERC1155ERC721ERC20 {
        ///////////////////////////////  Libs //////////////////////////////
        using SafeERC20 for IERC20;
        ///////////////////////////////  Data //////////////////////////////
        struct Claim {
            address to;
            ERC1155Claim[] erc1155;
            ERC721Claim[] erc721;
            ERC20Claim erc20;
            bytes32 salt;
        }
        struct ERC1155Claim {
            uint256[] ids;
            uint256[] values;
            address contractAddress;
        }
        struct ERC721Claim {
            uint256[] ids;
            address contractAddress;
        }
        struct ERC20Claim {
            uint256[] amounts;
            address[] contractAddresses;
        }
        ///////////////////////////////  Events //////////////////////////////
        /// @dev Emits when a successful claim occurs.
        /// @param to The destination address for the claimed ERC1155, ERC721 and ERC20 tokens.
        /// @param erc1155 The array of ERC1155Claim structs containing the ids, values and ERC1155 contract address.
        /// @param erc721 The array of ERC721Claim structs containing the ids and ERC721 contract address.
        /// @param erc20 The ERC20Claim struct containing the amounts and ERC20 contract addresses.
        event ClaimedMultipleTokens(address to, ERC1155Claim[] erc1155, ERC721Claim[] erc721, ERC20Claim erc20);
        ///////////////////////////////  Functions ///////////////////////////
        /// @dev Internal function used to claim multiple token types in one claim.
        /// @param merkleRoot The merkle root hash for the specific set of items being claimed.
        /// @param claim The claim struct containing the destination address, all items to be claimed and optional salt param.
        /// @param proof The proof provided by the user performing the claim function.
        function _claimERC1155ERC721ERC20(
            bytes32 merkleRoot,
            Claim memory claim,
            bytes32[] calldata proof
        ) internal {
            _checkValidity(merkleRoot, claim, proof);
            for (uint256 i = 0; i < claim.erc1155.length; i++) {
                require(claim.erc1155[i].ids.length == claim.erc1155[i].values.length, "INVALID_INPUT");
                _transferERC1155(claim.to, claim.erc1155[i].ids, claim.erc1155[i].values, claim.erc1155[i].contractAddress);
            }
            for (uint256 i = 0; i < claim.erc721.length; i++) {
                _transferERC721(claim.to, claim.erc721[i].ids, claim.erc721[i].contractAddress);
            }
            if (claim.erc20.amounts.length != 0) {
                require(claim.erc20.amounts.length == claim.erc20.contractAddresses.length, "INVALID_INPUT");
                _transferERC20(claim.to, claim.erc20.amounts, claim.erc20.contractAddresses);
            }
            emit ClaimedMultipleTokens(claim.to, claim.erc1155, claim.erc721, claim.erc20);
        }
        /// @dev Private function used to check the validity of a specific claim.
        /// @param merkleRoot The merkle root hash for the specific set of items being claimed.
        /// @param claim The claim struct containing the destination address, all items to be claimed and optional salt param.
        /// @param proof The proof provided by the user performing the claim function.
        function _checkValidity(
            bytes32 merkleRoot,
            Claim memory claim,
            bytes32[] memory proof
        ) private pure {
            bytes32 leaf = _generateClaimHash(claim);
            require(Verify.doesComputedHashMatchMerkleRootHash(merkleRoot, proof, leaf), "INVALID_CLAIM");
        }
        /// @dev Private function used to generate a hash from an encoded claim.
        /// @param claim The claim struct.
        function _generateClaimHash(Claim memory claim) private pure returns (bytes32) {
            return keccak256(abi.encode(claim));
        }
        /// @dev Private function used to transfer the ERC1155 tokens specified in a specific claim.
        /// @param to The destination address for the claimed tokens.
        /// @param ids The array of ERC1155 ids.
        /// @param values The amount of ERC1155 tokens of each id to be transferred.
        /// @param contractAddress The ERC1155 token contract address.
        function _transferERC1155(
            address to,
            uint256[] memory ids,
            uint256[] memory values,
            address contractAddress
        ) private {
            require(contractAddress != address(0), "INVALID_CONTRACT_ZERO_ADDRESS");
            IERC1155(contractAddress).safeBatchTransferFrom(address(this), to, ids, values, "");
        }
        /// @dev Private function used to transfer the ERC721tokens specified in a specific claim.
        /// @param to The destination address for the claimed tokens.
        /// @param ids The array of ERC721 ids.
        /// @param contractAddress The ERC721 token contract address.
        function _transferERC721(
            address to,
            uint256[] memory ids,
            address contractAddress
        ) private {
            require(contractAddress != address(0), "INVALID_CONTRACT_ZERO_ADDRESS");
            IERC721Extended(contractAddress).safeBatchTransferFrom(address(this), to, ids, "");
        }
        /// @dev Private function used to transfer the ERC20 tokens specified in a specific claim.
        /// @param to The destination address for the claimed tokens.
        /// @param amounts The array of amounts of ERC20 tokens to be transferred.
        /// @param contractAddresses The array of ERC20 token contract addresses.
        function _transferERC20(
            address to,
            uint256[] memory amounts,
            address[] memory contractAddresses
        ) private {
            for (uint256 i = 0; i < amounts.length; i++) {
                address erc20ContractAddress = contractAddresses[i];
                uint256 erc20Amount = amounts[i];
                require(erc20ContractAddress != address(0), "INVALID_CONTRACT_ZERO_ADDRESS");
                IERC20(erc20ContractAddress).safeTransferFrom(address(this), to, erc20Amount);
            }
        }
    }
    //SPDX-License-Identifier: MIT
    // solhint-disable-next-line compiler-version
    pragma solidity 0.8.2;
    contract WithAdmin {
        address internal _admin;
        /// @dev Emits when the contract administrator is changed.
        /// @param oldAdmin The address of the previous administrator.
        /// @param newAdmin The address of the new administrator.
        event AdminChanged(address oldAdmin, address newAdmin);
        modifier onlyAdmin() {
            require(msg.sender == _admin, "ADMIN_ONLY");
            _;
        }
        /// @dev Get the current administrator of this contract.
        /// @return The current administrator of this contract.
        function getAdmin() external view returns (address) {
            return _admin;
        }
        /// @dev Change the administrator to be `newAdmin`.
        /// @param newAdmin The address of the new administrator.
        function changeAdmin(address newAdmin) external {
            require(msg.sender == _admin, "ADMIN_ACCESS_DENIED");
            emit AdminChanged(_admin, newAdmin);
            _admin = newAdmin;
        }
    }
    // SPDX-License-Identifier: MIT
    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);
    }
    // SPDX-License-Identifier: MIT
    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 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.
         */
        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;
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev Interface of the ERC20 standard as defined in the EIP.
     */
    interface IERC20 {
        /**
         * @dev Returns the amount of tokens in existence.
         */
        function totalSupply() external view returns (uint256);
        /**
         * @dev Returns the amount of tokens owned by `account`.
         */
        function balanceOf(address account) external view returns (uint256);
        /**
         * @dev Moves `amount` tokens from the caller's account to `recipient`.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transfer(address recipient, uint256 amount) external returns (bool);
        /**
         * @dev Returns the remaining number of tokens that `spender` will be
         * allowed to spend on behalf of `owner` through {transferFrom}. This is
         * zero by default.
         *
         * This value changes when {approve} or {transferFrom} are called.
         */
        function allowance(address owner, address spender) external view returns (uint256);
        /**
         * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * IMPORTANT: Beware that changing an allowance with this method brings the risk
         * that someone may use both the old and the new allowance by unfortunate
         * transaction ordering. One possible solution to mitigate this race
         * condition is to first reduce the spender's allowance to 0 and set the
         * desired value afterwards:
         * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
         *
         * Emits an {Approval} event.
         */
        function approve(address spender, uint256 amount) external returns (bool);
        /**
         * @dev Moves `amount` tokens from `sender` to `recipient` using the
         * allowance mechanism. `amount` is then deducted from the caller's
         * allowance.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
        /**
         * @dev Emitted when `value` tokens are moved from one account (`from`) to
         * another (`to`).
         *
         * Note that `value` may be zero.
         */
        event Transfer(address indexed from, address indexed to, uint256 value);
        /**
         * @dev Emitted when the allowance of a `spender` for an `owner` is set by
         * a call to {approve}. `value` is the new allowance.
         */
        event Approval(address indexed owner, address indexed spender, uint256 value);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "../IERC20.sol";
    import "../../../utils/Address.sol";
    /**
     * @title SafeERC20
     * @dev Wrappers around ERC20 operations that throw on failure (when the token
     * contract returns false). Tokens that return no value (and instead revert or
     * throw on failure) are also supported, non-reverting calls are assumed to be
     * successful.
     * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
     * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
     */
    library SafeERC20 {
        using Address for address;
        function safeTransfer(IERC20 token, address to, uint256 value) internal {
            _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
        }
        function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
            _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
        }
        /**
         * @dev Deprecated. This function has issues similar to the ones found in
         * {IERC20-approve}, and its usage is discouraged.
         *
         * Whenever possible, use {safeIncreaseAllowance} and
         * {safeDecreaseAllowance} instead.
         */
        function safeApprove(IERC20 token, address spender, uint256 value) internal {
            // safeApprove should only be called when setting an initial allowance,
            // or when resetting it to zero. To increase and decrease it, use
            // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
            // solhint-disable-next-line max-line-length
            require((value == 0) || (token.allowance(address(this), spender) == 0),
                "SafeERC20: approve from non-zero to non-zero allowance"
            );
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
        }
        function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
            uint256 newAllowance = token.allowance(address(this), spender) + value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
        function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
            unchecked {
                uint256 oldAllowance = token.allowance(address(this), spender);
                require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
                uint256 newAllowance = oldAllowance - value;
                _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
            }
        }
        /**
         * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
         * on the return value: the return value is optional (but if data is returned, it must not be false).
         * @param token The token targeted by the call.
         * @param data The call data (encoded using abi.encode or one of its variants).
         */
        function _callOptionalReturn(IERC20 token, bytes memory data) private {
            // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
            // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
            // the target address contains contract code and also asserts for success in the low-level call.
            bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
            if (returndata.length > 0) { // Return data is optional
                // solhint-disable-next-line max-line-length
                require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
            }
        }
    }
    //SPDX-License-Identifier: MIT
    pragma solidity 0.8.2;
    import "@openzeppelin/contracts-0.8/token/ERC721/IERC721.sol";
    interface IERC721Extended is IERC721 {
        function approveFor(
            address sender,
            address operator,
            uint256 id
        ) external;
        function batchTransferFrom(
            address from,
            address to,
            uint256[] calldata ids,
            bytes calldata data
        ) external;
        function safeBatchTransferFrom(
            address from,
            address to,
            uint256[] calldata ids,
            bytes calldata data
        ) external;
        function setApprovalForAllFor(
            address sender,
            address operator,
            bool approved
        ) external;
        function burn(uint256 id) external;
        function burnFrom(address from, uint256 id) external;
    }
    //SPDX-License-Identifier: MIT
    pragma solidity 0.8.2;
    /**
     * @title Verify
     * @dev Merkle root comparison function.
     */
    library Verify {
        /// @dev Check if the computedHash == comparisonHash.
        /// @param comparisonHash The merkle root hash passed to the function.
        /// @param proof The proof provided by the user.
        /// @param leaf The generated hash.
        /// @return Whether the computedHash == comparisonHash.
        function doesComputedHashMatchMerkleRootHash(
            bytes32 comparisonHash,
            bytes32[] memory proof,
            bytes32 leaf
        ) internal pure returns (bool) {
            bytes32 computedHash = leaf;
            for (uint256 i = 0; i < proof.length; i++) {
                bytes32 proofElement = proof[i];
                if (computedHash < proofElement) {
                    computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
                } else {
                    computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
                }
            }
            return computedHash == comparisonHash;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev Collection of functions related to the address type
     */
    library Address {
        /**
         * @dev Returns true if `account` is a contract.
         *
         * [IMPORTANT]
         * ====
         * It is unsafe to assume that an address for which this function returns
         * false is an externally-owned account (EOA) and not a contract.
         *
         * Among others, `isContract` will return false for the following
         * types of addresses:
         *
         *  - an externally-owned account
         *  - a contract in construction
         *  - an address where a contract will be created
         *  - an address where a contract lived, but was destroyed
         * ====
         */
        function isContract(address account) internal view returns (bool) {
            // This method relies on extcodesize, which returns 0 for contracts in
            // construction, since the code is only stored at the end of the
            // constructor execution.
            uint256 size;
            // solhint-disable-next-line no-inline-assembly
            assembly { size := extcodesize(account) }
            return size > 0;
        }
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, "Address: insufficient balance");
            // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
            (bool success, ) = recipient.call{ value: amount }("");
            require(success, "Address: unable to send value, recipient may have reverted");
        }
        /**
         * @dev Performs a Solidity function call using a low level `call`. A
         * plain`call` is an unsafe replacement for a function call: use this
         * function instead.
         *
         * If `target` reverts with a revert reason, it is bubbled up by this
         * function (like regular Solidity function calls).
         *
         * Returns the raw returned data. To convert to the expected return value,
         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
         *
         * Requirements:
         *
         * - `target` must be a contract.
         * - calling `target` with `data` must not revert.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
          return functionCall(target, data, "Address: low-level call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
         * `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
            return functionCallWithValue(target, data, 0, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
        }
        /**
         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
         * with `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
            require(address(this).balance >= value, "Address: insufficient balance for call");
            require(isContract(target), "Address: call to non-contract");
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.call{ value: value }(data);
            return _verifyCallResult(success, returndata, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
            return functionStaticCall(target, data, "Address: low-level static call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
            require(isContract(target), "Address: static call to non-contract");
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.staticcall(data);
            return _verifyCallResult(success, returndata, errorMessage);
        }
        /**
         * @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) {
            require(isContract(target), "Address: delegate call to non-contract");
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.delegatecall(data);
            return _verifyCallResult(success, returndata, errorMessage);
        }
        function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
            if (success) {
                return returndata;
            } else {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "../../utils/introspection/IERC165.sol";
    /**
     * @dev Required interface of an ERC721 compliant contract.
     */
    interface IERC721 is IERC165 {
        /**
         * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
         */
        event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
        /**
         * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
         */
        event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
        /**
         * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
         */
        event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
        /**
         * @dev Returns the number of tokens in ``owner``'s account.
         */
        function balanceOf(address owner) external view returns (uint256 balance);
        /**
         * @dev Returns the owner of the `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function ownerOf(uint256 tokenId) external view returns (address owner);
        /**
         * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
         * are aware of the ERC721 protocol to prevent tokens from being forever locked.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must exist and be owned by `from`.
         * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
         * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
         *
         * Emits a {Transfer} event.
         */
        function safeTransferFrom(address from, address to, uint256 tokenId) external;
        /**
         * @dev Transfers `tokenId` token from `from` to `to`.
         *
         * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must be owned by `from`.
         * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(address from, address to, uint256 tokenId) external;
        /**
         * @dev Gives permission to `to` to transfer `tokenId` token to another account.
         * The approval is cleared when the token is transferred.
         *
         * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
         *
         * Requirements:
         *
         * - The caller must own the token or be an approved operator.
         * - `tokenId` must exist.
         *
         * Emits an {Approval} event.
         */
        function approve(address to, uint256 tokenId) external;
        /**
         * @dev Returns the account approved for `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function getApproved(uint256 tokenId) external view returns (address operator);
        /**
         * @dev Approve or remove `operator` as an operator for the caller.
         * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
         *
         * Requirements:
         *
         * - The `operator` cannot be the caller.
         *
         * Emits an {ApprovalForAll} event.
         */
        function setApprovalForAll(address operator, bool _approved) external;
        /**
         * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
         *
         * See {setApprovalForAll}
         */
        function isApprovedForAll(address owner, address operator) external view returns (bool);
        /**
          * @dev Safely transfers `tokenId` token from `from` to `to`.
          *
          * Requirements:
          *
          * - `from` cannot be the zero address.
          * - `to` cannot be the zero address.
          * - `tokenId` token must exist and be owned by `from`.
          * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
          * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
          *
          * Emits a {Transfer} event.
          */
        function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
    }
    

    File 2 of 2: Sand
    pragma solidity ^0.5.2;
    contract Admin {
        address internal _admin;
        event AdminChanged(address oldAdmin, address newAdmin);
        /// @notice gives the current administrator of this contract.
        /// @return the current administrator of this contract.
        function getAdmin() external view returns (address) {
            return _admin;
        }
        /// @notice change the administrator to be `newAdmin`.
        /// @param newAdmin address of the new administrator.
        function changeAdmin(address newAdmin) external {
            require(msg.sender == _admin, "only admin can change admin");
            emit AdminChanged(_admin, newAdmin);
            _admin = newAdmin;
        }
    }
    pragma solidity ^0.5.2;
    import "./Admin.sol";
    contract SuperOperators is Admin {
        mapping(address => bool) internal _superOperators;
        event SuperOperator(address superOperator, bool enabled);
        /// @notice Enable or disable the ability of `superOperator` to transfer tokens of all (superOperator rights).
        /// @param superOperator address that will be given/removed superOperator right.
        /// @param enabled set whether the superOperator is enabled or disabled.
        function setSuperOperator(address superOperator, bool enabled) external {
            require(
                msg.sender == _admin,
                "only admin is allowed to add super operators"
            );
            _superOperators[superOperator] = enabled;
            emit SuperOperator(superOperator, enabled);
        }
        /// @notice check whether address `who` is given superOperator rights.
        /// @param who The address to query.
        /// @return whether the address has superOperator rights.
        function isSuperOperator(address who) public view returns (bool) {
            return _superOperators[who];
        }
    }
    pragma solidity ^0.5.2;
    /* interface */
    contract ERC20Events {
        event Transfer(address indexed from, address indexed to, uint256 value);
        event Approval(
            address indexed owner,
            address indexed spender,
            uint256 value
        );
    }
    pragma solidity ^0.5.2;
    library BytesUtil {
        function memcpy(uint256 dest, uint256 src, uint256 len) internal pure {
            // Copy word-length chunks while possible
            for (; len >= 32; len -= 32) {
                assembly {
                    mstore(dest, mload(src))
                }
                dest += 32;
                src += 32;
            }
            // Copy remaining bytes
            uint256 mask = 256**(32 - len) - 1;
            assembly {
                let srcpart := and(mload(src), not(mask))
                let destpart := and(mload(dest), mask)
                mstore(dest, or(destpart, srcpart))
            }
        }
        function pointerToBytes(uint256 src, uint256 len)
            internal
            pure
            returns (bytes memory)
        {
            bytes memory ret = new bytes(len);
            uint256 retptr;
            assembly {
                retptr := add(ret, 32)
            }
            memcpy(retptr, src, len);
            return ret;
        }
        function addressToBytes(address a) internal pure returns (bytes memory b) {
            assembly {
                let m := mload(0x40)
                mstore(
                    add(m, 20),
                    xor(0x140000000000000000000000000000000000000000, a)
                )
                mstore(0x40, add(m, 52))
                b := m
            }
        }
        function uint256ToBytes(uint256 a) internal pure returns (bytes memory b) {
            assembly {
                let m := mload(0x40)
                mstore(add(m, 32), a)
                mstore(0x40, add(m, 64))
                b := m
            }
        }
        function doFirstParamEqualsAddress(bytes memory data, address _address)
            internal
            pure
            returns (bool)
        {
            if (data.length < (36 + 32)) {
                return false;
            }
            uint256 value;
            assembly {
                value := mload(add(data, 36))
            }
            return value == uint256(_address);
        }
        function doParamEqualsUInt256(bytes memory data, uint256 i, uint256 value)
            internal
            pure
            returns (bool)
        {
            if (data.length < (36 + (i + 1) * 32)) {
                return false;
            }
            uint256 offset = 36 + i * 32;
            uint256 valuePresent;
            assembly {
                valuePresent := mload(add(data, offset))
            }
            return valuePresent == value;
        }
        function overrideFirst32BytesWithAddress(
            bytes memory data,
            address _address
        ) internal pure returns (bytes memory) {
            uint256 dest;
            assembly {
                dest := add(data, 48)
            } // 48 = 32 (offset) + 4 (func sig) + 12 (address is only 20 bytes)
            bytes memory addressBytes = addressToBytes(_address);
            uint256 src;
            assembly {
                src := add(addressBytes, 32)
            }
            memcpy(dest, src, 20);
            return data;
        }
        function overrideFirstTwo32BytesWithAddressAndInt(
            bytes memory data,
            address _address,
            uint256 _value
        ) internal pure returns (bytes memory) {
            uint256 dest;
            uint256 src;
            assembly {
                dest := add(data, 48)
            } // 48 = 32 (offset) + 4 (func sig) + 12 (address is only 20 bytes)
            bytes memory bbytes = addressToBytes(_address);
            assembly {
                src := add(bbytes, 32)
            }
            memcpy(dest, src, 20);
            assembly {
                dest := add(data, 68)
            } // 48 = 32 (offset) + 4 (func sig) + 32 (next slot)
            bbytes = uint256ToBytes(_value);
            assembly {
                src := add(bbytes, 32)
            }
            memcpy(dest, src, 32);
            return data;
        }
    }
    pragma solidity 0.5.9;
    import "./Sand/erc20/ERC20ExecuteExtension.sol";
    import "./Sand/erc20/ERC20BaseToken.sol";
    import "./Sand/erc20/ERC20BasicApproveExtension.sol";
    contract Sand is ERC20ExecuteExtension, ERC20BasicApproveExtension, ERC20BaseToken {
        constructor(address sandAdmin, address executionAdmin, address beneficiary) public {
            _admin = sandAdmin;
            _executionAdmin = executionAdmin;
            _mint(beneficiary, 3000000000000000000000000000);
        }
        /// @notice A descriptive name for the tokens
        /// @return name of the tokens
        function name() public view returns (string memory) {
            return "SAND";
        }
        /// @notice An abbreviated name for the tokens
        /// @return symbol of the tokens
        function symbol() public view returns (string memory) {
            return "SAND";
        }
    }
    pragma solidity 0.5.9;
    import "../../../contracts_common/src/Interfaces/ERC20Events.sol";
    import "../../../contracts_common/src/BaseWithStorage/SuperOperators.sol";
    contract ERC20BaseToken is SuperOperators, ERC20Events {
        uint256 internal _totalSupply;
        mapping(address => uint256) internal _balances;
        mapping(address => mapping(address => uint256)) internal _allowances;
        /// @notice Gets the total number of tokens in existence.
        /// @return the total number of tokens in existence.
        function totalSupply() public view returns (uint256) {
            return _totalSupply;
        }
        /// @notice Gets the balance of `owner`.
        /// @param owner The address to query the balance of.
        /// @return The amount owned by `owner`.
        function balanceOf(address owner) public view returns (uint256) {
            return _balances[owner];
        }
        /// @notice gets allowance of `spender` for `owner`'s tokens.
        /// @param owner address whose token is allowed.
        /// @param spender address allowed to transfer.
        /// @return the amount of token `spender` is allowed to transfer on behalf of `owner`.
        function allowance(address owner, address spender)
            public
            view
            returns (uint256 remaining)
        {
            return _allowances[owner][spender];
        }
        /// @notice returns the number of decimals for that token.
        /// @return the number of decimals.
        function decimals() public view returns (uint8) {
            return uint8(18);
        }
        /// @notice Transfer `amount` tokens to `to`.
        /// @param to the recipient address of the tokens transfered.
        /// @param amount the number of tokens transfered.
        /// @return true if success.
        function transfer(address to, uint256 amount)
            public
            returns (bool success)
        {
            _transfer(msg.sender, to, amount);
            return true;
        }
        /// @notice Transfer `amount` tokens from `from` to `to`.
        /// @param from whose token it is transferring from.
        /// @param to the recipient address of the tokens transfered.
        /// @param amount the number of tokens transfered.
        /// @return true if success.
        function transferFrom(address from, address to, uint256 amount)
            public
            returns (bool success)
        {
            if (msg.sender != from && !_superOperators[msg.sender]) {
                uint256 currentAllowance = _allowances[from][msg.sender];
                if (currentAllowance != (2**256) - 1) {
                    // save gas when allowance is maximal by not reducing it (see https://github.com/ethereum/EIPs/issues/717)
                    require(currentAllowance >= amount, "Not enough funds allowed");
                    _allowances[from][msg.sender] = currentAllowance - amount;
                }
            }
            _transfer(from, to, amount);
            return true;
        }
        /// @notice burn `amount` tokens.
        /// @param amount the number of tokens to burn.
        /// @return true if success.
        function burn(uint256 amount) external returns (bool) {
            _burn(msg.sender, amount);
            return true;
        }
        /// @notice burn `amount` tokens from `owner`.
        /// @param owner address whose token is to burn.
        /// @param amount the number of token to burn.
        /// @return true if success.
        function burnFor(address owner, uint256 amount) external returns (bool) {
            _burn(owner, amount);
            return true;
        }
        /// @notice approve `spender` to transfer `amount` tokens.
        /// @param spender address to be given rights to transfer.
        /// @param amount the number of tokens allowed.
        /// @return true if success.
        function approve(address spender, uint256 amount)
            public
            returns (bool success)
        {
            _approveFor(msg.sender, spender, amount);
            return true;
        }
        /// @notice approve `spender` to transfer `amount` tokens from `owner`.
        /// @param owner address whose token is allowed.
        /// @param spender  address to be given rights to transfer.
        /// @param amount the number of tokens allowed.
        /// @return true if success.
        function approveFor(address owner, address spender, uint256 amount)
            public
            returns (bool success)
        {
            require(
                msg.sender == owner || _superOperators[msg.sender],
                "msg.sender != owner && !superOperator"
            );
            _approveFor(owner, spender, amount);
            return true;
        }
        function addAllowanceIfNeeded(address owner, address spender, uint256 amountNeeded)
            public
            returns (bool success)
        {
            require(
                msg.sender == owner || _superOperators[msg.sender],
                "msg.sender != owner && !superOperator"
            );
            _addAllowanceIfNeeded(owner, spender, amountNeeded);
            return true;
        }
        function _addAllowanceIfNeeded(address owner, address spender, uint256 amountNeeded)
            internal
        {
            if(amountNeeded > 0 && !isSuperOperator(spender)) {
                uint256 currentAllowance = _allowances[owner][spender];
                if(currentAllowance < amountNeeded) {
                    _approveFor(owner, spender, amountNeeded);
                }
            }
        }
        function _approveFor(address owner, address spender, uint256 amount)
            internal
        {
            require(
                owner != address(0) && spender != address(0),
                "Cannot approve with 0x0"
            );
            _allowances[owner][spender] = amount;
            emit Approval(owner, spender, amount);
        }
        function _transfer(address from, address to, uint256 amount) internal {
            require(to != address(0), "Cannot send to 0x0");
            uint256 currentBalance = _balances[from];
            require(currentBalance >= amount, "not enough fund");
            _balances[from] = currentBalance - amount;
            _balances[to] += amount;
            emit Transfer(from, to, amount);
        }
        function _mint(address to, uint256 amount) internal {
            require(to != address(0), "Cannot mint to 0x0");
            require(amount > 0, "cannot mint 0 tokens");
            uint256 currentTotalSupply = _totalSupply;
            uint256 newTotalSupply = currentTotalSupply + amount;
            require(newTotalSupply > currentTotalSupply, "overflow");
            _totalSupply = newTotalSupply;
            _balances[to] += amount;
            emit Transfer(address(0), to, amount);
        }
        function _burn(address from, uint256 amount) internal {
            require(amount > 0, "cannot burn 0 tokens");
            if (msg.sender != from && !_superOperators[msg.sender]) {
                uint256 currentAllowance = _allowances[from][msg.sender];
                require(
                    currentAllowance >= amount,
                    "Not enough funds allowed"
                );
                if (currentAllowance != (2**256) - 1) {
                    // save gas when allowance is maximal by not reducing it (see https://github.com/ethereum/EIPs/issues/717)
                    _allowances[from][msg.sender] = currentAllowance - amount;
                }
            }
            uint256 currentBalance = _balances[from];
            require(currentBalance >= amount, "Not enough funds");
            _balances[from] = currentBalance - amount;
            _totalSupply -= amount;
            emit Transfer(from, address(0), amount);
        }
    }
    pragma solidity 0.5.9;
    import "../../../contracts_common/src/Libraries/BytesUtil.sol";
    contract ERC20BasicApproveExtension {
        /// @notice approve `target` to spend `amount` and call it with data.
        /// @param target address to be given rights to transfer and destination of the call.
        /// @param amount the number of tokens allowed.
        /// @param data bytes for the call.
        /// @return data of the call.
        function approveAndCall(
            address target,
            uint256 amount,
            bytes calldata data
        ) external payable returns (bytes memory) {
            require(
                BytesUtil.doFirstParamEqualsAddress(data, msg.sender),
                "first param != sender"
            );
            _approveFor(msg.sender, target, amount);
            // solium-disable-next-line security/no-call-value
            (bool success, bytes memory returnData) = target.call.value(msg.value)(data);
            require(success, string(returnData));
            return returnData;
        }
        /// @notice temporarly approve `target` to spend `amount` and call it with data. Previous approvals remains unchanged.
        /// @param target destination of the call, allowed to spend the amount specified
        /// @param amount the number of tokens allowed to spend.
        /// @param data bytes for the call.
        /// @return data of the call.
        function paidCall(
            address target,
            uint256 amount,
            bytes calldata data
        ) external payable returns (bytes memory) {
            require(
                BytesUtil.doFirstParamEqualsAddress(data, msg.sender),
                "first param != sender"
            );
            if (amount > 0) {
                _addAllowanceIfNeeded(msg.sender, target, amount);
            }
            // solium-disable-next-line security/no-call-value
            (bool success, bytes memory returnData) = target.call.value(msg.value)(data);
            require(success, string(returnData));
            return returnData;
        }
        function _approveFor(address owner, address target, uint256 amount) internal;
        function _addAllowanceIfNeeded(address owner, address spender, uint256 amountNeeded) internal;
    }
    pragma solidity 0.5.9;
    contract ERC20ExecuteExtension {
        /// @dev _executionAdmin != _admin so that this super power can be disabled independently
        address internal _executionAdmin;
        event ExecutionAdminAdminChanged(address oldAdmin, address newAdmin);
        /// @notice give the address responsible for adding execution rights.
        /// @return address of the execution administrator.
        function getExecutionAdmin() external view returns (address) {
            return _executionAdmin;
        }
        /// @notice change the execution adminstrator to be `newAdmin`.
        /// @param newAdmin address of the new administrator.
        function changeExecutionAdmin(address newAdmin) external {
            require(msg.sender == _executionAdmin, "only executionAdmin can change executionAdmin");
            emit ExecutionAdminAdminChanged(_executionAdmin, newAdmin);
            _executionAdmin = newAdmin;
        }
        mapping(address => bool) internal _executionOperators;
        event ExecutionOperator(address executionOperator, bool enabled);
        /// @notice set `executionOperator` as executionOperator: `enabled`.
        /// @param executionOperator address that will be given/removed executionOperator right.
        /// @param enabled set whether the executionOperator is enabled or disabled.
        function setExecutionOperator(address executionOperator, bool enabled) external {
            require(
                msg.sender == _executionAdmin,
                "only execution admin is allowed to add execution operators"
            );
            _executionOperators[executionOperator] = enabled;
            emit ExecutionOperator(executionOperator, enabled);
        }
        /// @notice check whether address `who` is given executionOperator rights.
        /// @param who The address to query.
        /// @return whether the address has executionOperator rights.
        function isExecutionOperator(address who) public view returns (bool) {
            return _executionOperators[who];
        }
        /// @notice execute on behalf of the contract.
        /// @param to destination address fo the call.
        /// @param gasLimit exact amount of gas to be passed to the call.
        /// @param data the bytes sent to the destination address.
        /// @return success whether the execution was successful.
        /// @return returnData data resulting from the execution.
        function executeWithSpecificGas(address to, uint256 gasLimit, bytes calldata data) external returns (bool success, bytes memory returnData) {
            require(_executionOperators[msg.sender], "only execution operators allowed to execute on SAND behalf");
            (success, returnData) = to.call.gas(gasLimit)(data);
            assert(gasleft() > gasLimit / 63); // not enough gas provided, assert to throw all gas // TODO use EIP-1930
        }
        /// @notice approve a specific amount of token for `from` and execute on behalf of the contract.
        /// @param from address of which token will be transfered.
        /// @param to destination address fo the call.
        /// @param amount number of tokens allowed that can be transfer by the code at `to`.
        /// @param gasLimit exact amount of gas to be passed to the call.
        /// @param data the bytes sent to the destination address.
        /// @return success whether the execution was successful.
        /// @return returnData data resulting from the execution.
        function approveAndExecuteWithSpecificGas(
            address from,
            address to,
            uint256 amount,
            uint256 gasLimit,
            bytes calldata data
        ) external returns (bool success, bytes memory returnData) {
            require(_executionOperators[msg.sender], "only execution operators allowed to execute on SAND behalf");
            return _approveAndExecuteWithSpecificGas(from, to, amount, gasLimit, data);
        }
        /// @dev the reason for this function is that charging for gas here is more gas-efficient than doing it in the caller.
        /// @notice approve a specific amount of token for `from` and execute on behalf of the contract. Plus charge the gas required to perform it.
        /// @param from address of which token will be transfered.
        /// @param to destination address fo the call.
        /// @param amount number of tokens allowed that can be transfer by the code at `to`.
        /// @param gasLimit exact amount of gas to be passed to the call.
        /// @param tokenGasPrice price in token for the gas to be charged.
        /// @param baseGasCharge amount of gas charged on top of the gas used for the call.
        /// @param tokenReceiver recipient address of the token charged for the gas used.
        /// @param data the bytes sent to the destination address.
        /// @return success whether the execution was successful.
        /// @return returnData data resulting from the execution.
        function approveAndExecuteWithSpecificGasAndChargeForIt(
            address from,
            address to,
            uint256 amount,
            uint256 gasLimit,
            uint256 tokenGasPrice,
            uint256 baseGasCharge,
            address tokenReceiver,
            bytes calldata data
        ) external returns (bool success, bytes memory returnData) {
            uint256 initialGas = gasleft();
            require(_executionOperators[msg.sender], "only execution operators allowed to execute on SAND behalf");
            (success, returnData) = _approveAndExecuteWithSpecificGas(from, to, amount, gasLimit, data);
            if (tokenGasPrice > 0) {
                _charge(from, gasLimit, tokenGasPrice, initialGas, baseGasCharge, tokenReceiver);
            }
        }
        /// @notice transfer 1amount1 token from `from` to `to` and charge the gas required to perform that transfer.
        /// @param from address of which token will be transfered.
        /// @param to destination address fo the call.
        /// @param amount number of tokens allowed that can be transfer by the code at `to`.
        /// @param gasLimit exact amount of gas to be passed to the call.
        /// @param tokenGasPrice price in token for the gas to be charged.
        /// @param baseGasCharge amount of gas charged on top of the gas used for the call.
        /// @param tokenReceiver recipient address of the token charged for the gas used.
        /// @return whether the transfer was successful.
        function transferAndChargeForGas(
            address from,
            address to,
            uint256 amount,
            uint256 gasLimit,
            uint256 tokenGasPrice,
            uint256 baseGasCharge,
            address tokenReceiver
        ) external returns (bool) {
            uint256 initialGas = gasleft();
            require(_executionOperators[msg.sender], "only execution operators allowed to perfrom transfer and charge");
            _transfer(from, to, amount);
            if (tokenGasPrice > 0) {
                _charge(from, gasLimit, tokenGasPrice, initialGas, baseGasCharge, tokenReceiver);
            }
            return true;
        }
        function _charge(
            address from,
            uint256 gasLimit,
            uint256 tokenGasPrice,
            uint256 initialGas,
            uint256 baseGasCharge,
            address tokenReceiver
        ) internal {
            uint256 gasCharge = initialGas - gasleft();
            if(gasCharge > gasLimit) {
                gasCharge = gasLimit;
            }
            gasCharge += baseGasCharge;
            uint256 tokensToCharge = gasCharge * tokenGasPrice;
            require(tokensToCharge / gasCharge == tokenGasPrice, "overflow");
            _transfer(from, tokenReceiver, tokensToCharge);
        }
        function _approveAndExecuteWithSpecificGas(
            address from,
            address to,
            uint256 amount,
            uint256 gasLimit,
            bytes memory data
        ) internal returns (bool success, bytes memory returnData) {
            if (amount > 0) {
                _addAllowanceIfNeeded(from, to, amount);
            }
            (success, returnData) = to.call.gas(gasLimit)(data);
            assert(gasleft() > gasLimit / 63); // not enough gas provided, assert to throw all gas // TODO use EIP-1930
        }
        function _transfer(address from, address to, uint256 amount) internal;
        function _addAllowanceIfNeeded(address owner, address spender, uint256 amountNeeded) internal;
    }