ETH Price: $2,517.84 (+0.09%)

Transaction Decoder

Block:
20864942 at Sep-30-2024 05:23:35 PM +UTC
Transaction Fee:
0.001026384623456928 ETH $2.58
Gas Used:
61,356 Gas / 16.728349688 Gwei

Emitted Events:

585 TetherToken.Transfer( from=Forwarder, to=[Receiver] WalletSimple, value=194052577 )

Account State Difference:

  Address   Before After State Difference Code
0x3AEB5831...7B805a107
1.359605165283571544 Eth
Nonce: 78552
1.358578780660114616 Eth
Nonce: 78553
0.001026384623456928
(Titan Builder)
13.811793733696251926 Eth13.811926710950614058 Eth0.000132977254362132
0xdAC17F95...13D831ec7

Execution Trace

WalletSimple.flushForwarderTokens( forwarderAddress=0xb5860e43ee7494174aeC1479e1f30116EE436d13, tokenContractAddress=0xdAC17F958D2ee523a2206206994597C13D831ec7 )
  • WalletSimple.flushForwarderTokens( forwarderAddress=0xb5860e43ee7494174aeC1479e1f30116EE436d13, tokenContractAddress=0xdAC17F958D2ee523a2206206994597C13D831ec7 )
    • Forwarder.flushTokens( tokenContractAddress=0xdAC17F958D2ee523a2206206994597C13D831ec7 )
      • Forwarder.flushTokens( tokenContractAddress=0xdAC17F958D2ee523a2206206994597C13D831ec7 )
        • TetherToken.balanceOf( who=0xb5860e43ee7494174aeC1479e1f30116EE436d13 ) => ( 194052577 )
        • TetherToken.transfer( _to=0x4F17f6a5650Ce334B7411dAEbcE92007E632250d, _value=194052577 )
          flushForwarderTokens[WalletSimple (ln:306)]
          File 1 of 5: WalletSimple
          // SPDX-License-Identifier: Apache-2.0
          pragma solidity 0.8.10;
          import './TransferHelper.sol';
          import './ERC20Interface.sol';
          import './IForwarder.sol';
          /** ERC721, ERC1155 imports */
          import '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol';
          import '@openzeppelin/contracts/token/ERC1155/utils/ERC1155Receiver.sol';
          /**
           *
           * WalletSimple
           * ============
           *
           * Basic multi-signer wallet designed for use in a co-signing environment where 2 signatures are required to move funds.
           * Typically used in a 2-of-3 signing configuration. Uses ecrecover to allow for 2 signatures in a single transaction.
           *
           * The first signature is created on the operation hash (see Data Formats) and passed to sendMultiSig/sendMultiSigToken
           * The signer is determined by verifyMultiSig().
           *
           * The second signature is created by the submitter of the transaction and determined by msg.signer.
           *
           * Data Formats
           * ============
           *
           * The signature is created with ethereumjs-util.ecsign(operationHash).
           * Like the eth_sign RPC call, it packs the values as a 65-byte array of [r, s, v].
           * Unlike eth_sign, the message is not prefixed.
           *
           * The operationHash the result of keccak256(prefix, toAddress, value, data, expireTime).
           * For ether transactions, `prefix` is "ETHER".
           * For token transaction, `prefix` is "ERC20" and `data` is the tokenContractAddress.
           *
           *
           */
          contract WalletSimple is IERC721Receiver, ERC1155Receiver {
            // Events
            event Deposited(address from, uint256 value, bytes data);
            event SafeModeActivated(address msgSender);
            event Transacted(
              address msgSender, // Address of the sender of the message initiating the transaction
              address otherSigner, // Address of the signer (second signature) used to initiate the transaction
              bytes32 operation, // Operation hash (see Data Formats)
              address toAddress, // The address the transaction was sent to
              uint256 value, // Amount of Wei sent to the address
              bytes data // Data sent when invoking the transaction
            );
            event BatchTransfer(address sender, address recipient, uint256 value);
            // this event shows the other signer and the operation hash that they signed
            // specific batch transfer events are emitted in Batcher
            event BatchTransacted(
              address msgSender, // Address of the sender of the message initiating the transaction
              address otherSigner, // Address of the signer (second signature) used to initiate the transaction
              bytes32 operation // Operation hash (see Data Formats)
            );
            // Public fields
            mapping(address => bool) public signers; // The addresses that can co-sign transactions on the wallet
            bool public safeMode = false; // When active, wallet may only send to signer addresses
            bool public initialized = false; // True if the contract has been initialized
            // Internal fields
            uint256 private constant MAX_SEQUENCE_ID_INCREASE = 10000;
            uint256 constant SEQUENCE_ID_WINDOW_SIZE = 10;
            uint256[SEQUENCE_ID_WINDOW_SIZE] recentSequenceIds;
            /**
             * Set up a simple multi-sig wallet by specifying the signers allowed to be used on this wallet.
             * 2 signers will be required to send a transaction from this wallet.
             * Note: The sender is NOT automatically added to the list of signers.
             * Signers CANNOT be changed once they are set
             *
             * @param allowedSigners An array of signers on the wallet
             */
            function init(address[] calldata allowedSigners) external onlyUninitialized {
              require(allowedSigners.length == 3, 'Invalid number of signers');
              for (uint8 i = 0; i < allowedSigners.length; i++) {
                require(allowedSigners[i] != address(0), 'Invalid signer');
                signers[allowedSigners[i]] = true;
              }
              initialized = true;
            }
            /**
             * Get the network identifier that signers must sign over
             * This provides protection signatures being replayed on other chains
             * This must be a virtual function because chain-specific contracts will need
             *    to override with their own network ids. It also can't be a field
             *    to allow this contract to be used by proxy with delegatecall, which will
             *    not pick up on state variables
             */
            function getNetworkId() internal virtual pure returns (string memory) {
              return 'ETHER';
            }
            /**
             * Get the network identifier that signers must sign over for token transfers
             * This provides protection signatures being replayed on other chains
             * This must be a virtual function because chain-specific contracts will need
             *    to override with their own network ids. It also can't be a field
             *    to allow this contract to be used by proxy with delegatecall, which will
             *    not pick up on state variables
             */
            function getTokenNetworkId() internal virtual pure returns (string memory) {
              return 'ERC20';
            }
            /**
             * Get the network identifier that signers must sign over for batch transfers
             * This provides protection signatures being replayed on other chains
             * This must be a virtual function because chain-specific contracts will need
             *    to override with their own network ids. It also can't be a field
             *    to allow this contract to be used by proxy with delegatecall, which will
             *    not pick up on state variables
             */
            function getBatchNetworkId() internal virtual pure returns (string memory) {
              return 'ETHER-Batch';
            }
            /**
             * Determine if an address is a signer on this wallet
             * @param signer address to check
             * returns boolean indicating whether address is signer or not
             */
            function isSigner(address signer) public view returns (bool) {
              return signers[signer];
            }
            /**
             * Modifier that will execute internal code block only if the sender is an authorized signer on this wallet
             */
            modifier onlySigner {
              require(isSigner(msg.sender), 'Non-signer in onlySigner method');
              _;
            }
            /**
             * Modifier that will execute internal code block only if the contract has not been initialized yet
             */
            modifier onlyUninitialized {
              require(!initialized, 'Contract already initialized');
              _;
            }
            /**
             * Gets called when a transaction is received with data that does not match any other method
             */
            fallback() external payable {
              if (msg.value > 0) {
                // Fire deposited event if we are receiving funds
                emit Deposited(msg.sender, msg.value, msg.data);
              }
            }
            /**
             * Gets called when a transaction is received with ether and no data
             */
            receive() external payable {
              if (msg.value > 0) {
                // Fire deposited event if we are receiving funds
                // message data is always empty for receive. If there is data it is sent to fallback function.
                emit Deposited(msg.sender, msg.value, '');
              }
            }
            /**
             * Execute a multi-signature transaction from this wallet using 2 signers: one from msg.sender and the other from ecrecover.
             * Sequence IDs are numbers starting from 1. They are used to prevent replay attacks and may not be repeated.
             *
             * @param toAddress the destination address to send an outgoing transaction
             * @param value the amount in Wei to be sent
             * @param data the data to send to the toAddress when invoking the transaction
             * @param expireTime the number of seconds since 1970 for which this transaction is valid
             * @param sequenceId the unique sequence id obtainable from getNextSequenceId
             * @param signature see Data Formats
             */
            function sendMultiSig(
              address toAddress,
              uint256 value,
              bytes calldata data,
              uint256 expireTime,
              uint256 sequenceId,
              bytes calldata signature
            ) external onlySigner {
              // Verify the other signer
              bytes32 operationHash = keccak256(
                abi.encodePacked(
                  getNetworkId(),
                  toAddress,
                  value,
                  data,
                  expireTime,
                  sequenceId
                )
              );
              address otherSigner = verifyMultiSig(
                toAddress,
                operationHash,
                signature,
                expireTime,
                sequenceId
              );
              // Success, send the transaction
              (bool success, ) = toAddress.call{ value: value }(data);
              require(success, 'Call execution failed');
              emit Transacted(
                msg.sender,
                otherSigner,
                operationHash,
                toAddress,
                value,
                data
              );
            }
            /**
             * Execute a batched multi-signature transaction from this wallet using 2 signers: one from msg.sender and the other from ecrecover.
             * Sequence IDs are numbers starting from 1. They are used to prevent replay attacks and may not be repeated.
             * The recipients and values to send are encoded in two arrays, where for index i, recipients[i] will be sent values[i].
             *
             * @param recipients The list of recipients to send to
             * @param values The list of values to send to
             * @param expireTime the number of seconds since 1970 for which this transaction is valid
             * @param sequenceId the unique sequence id obtainable from getNextSequenceId
             * @param signature see Data Formats
             */
            function sendMultiSigBatch(
              address[] calldata recipients,
              uint256[] calldata values,
              uint256 expireTime,
              uint256 sequenceId,
              bytes calldata signature
            ) external onlySigner {
              require(recipients.length != 0, 'Not enough recipients');
              require(
                recipients.length == values.length,
                'Unequal recipients and values'
              );
              require(recipients.length < 256, 'Too many recipients, max 255');
              // Verify the other signer
              bytes32 operationHash = keccak256(
                abi.encodePacked(
                  getBatchNetworkId(),
                  recipients,
                  values,
                  expireTime,
                  sequenceId
                )
              );
              // the first parameter (toAddress) is used to ensure transactions in safe mode only go to a signer
              // if in safe mode, we should use normal sendMultiSig to recover, so this check will always fail if in safe mode
              require(!safeMode, 'Batch in safe mode');
              address otherSigner = verifyMultiSig(
                address(0x0),
                operationHash,
                signature,
                expireTime,
                sequenceId
              );
              batchTransfer(recipients, values);
              emit BatchTransacted(msg.sender, otherSigner, operationHash);
            }
            /**
             * Transfer funds in a batch to each of recipients
             * @param recipients The list of recipients to send to
             * @param values The list of values to send to recipients.
             *  The recipient with index i in recipients array will be sent values[i].
             *  Thus, recipients and values must be the same length
             */
            function batchTransfer(
              address[] calldata recipients,
              uint256[] calldata values
            ) internal {
              for (uint256 i = 0; i < recipients.length; i++) {
                require(address(this).balance >= values[i], 'Insufficient funds');
                (bool success, ) = recipients[i].call{ value: values[i] }('');
                require(success, 'Call failed');
                emit BatchTransfer(msg.sender, recipients[i], values[i]);
              }
            }
            /**
             * Execute a multi-signature token transfer from this wallet using 2 signers: one from msg.sender and the other from ecrecover.
             * Sequence IDs are numbers starting from 1. They are used to prevent replay attacks and may not be repeated.
             *
             * @param toAddress the destination address to send an outgoing transaction
             * @param value the amount in tokens to be sent
             * @param tokenContractAddress the address of the erc20 token contract
             * @param expireTime the number of seconds since 1970 for which this transaction is valid
             * @param sequenceId the unique sequence id obtainable from getNextSequenceId
             * @param signature see Data Formats
             */
            function sendMultiSigToken(
              address toAddress,
              uint256 value,
              address tokenContractAddress,
              uint256 expireTime,
              uint256 sequenceId,
              bytes calldata signature
            ) external onlySigner {
              // Verify the other signer
              bytes32 operationHash = keccak256(
                abi.encodePacked(
                  getTokenNetworkId(),
                  toAddress,
                  value,
                  tokenContractAddress,
                  expireTime,
                  sequenceId
                )
              );
              verifyMultiSig(toAddress, operationHash, signature, expireTime, sequenceId);
              TransferHelper.safeTransfer(tokenContractAddress, toAddress, value);
            }
            /**
             * Execute a token flush from one of the forwarder addresses. This transfer needs only a single signature and can be done by any signer
             *
             * @param forwarderAddress the address of the forwarder address to flush the tokens from
             * @param tokenContractAddress the address of the erc20 token contract
             */
            function flushForwarderTokens(
              address payable forwarderAddress,
              address tokenContractAddress
            ) external onlySigner {
              IForwarder forwarder = IForwarder(forwarderAddress);
              forwarder.flushTokens(tokenContractAddress);
            }
            /**
             * Execute a ERC721 token flush from one of the forwarder addresses. This transfer needs only a single signature and can be done by any signer
             *
             * @param forwarderAddress the address of the forwarder address to flush the tokens from
             * @param tokenContractAddress the address of the erc20 token contract
             */
            function flushERC721ForwarderTokens(
              address payable forwarderAddress,
              address tokenContractAddress,
              uint256 tokenId
            ) external onlySigner {
              IForwarder forwarder = IForwarder(forwarderAddress);
              forwarder.flushERC721Token(tokenContractAddress, tokenId);
            }
            /**
             * Execute a ERC1155 batch token flush from one of the forwarder addresses.
             * This transfer needs only a single signature and can be done by any signer.
             *
             * @param forwarderAddress the address of the forwarder address to flush the tokens from
             * @param tokenContractAddress the address of the erc1155 token contract
             */
            function batchFlushERC1155ForwarderTokens(
              address payable forwarderAddress,
              address tokenContractAddress,
              uint256[] calldata tokenIds
            ) external onlySigner {
              IForwarder forwarder = IForwarder(forwarderAddress);
              forwarder.batchFlushERC1155Tokens(tokenContractAddress, tokenIds);
            }
            /**
             * Execute a ERC1155 token flush from one of the forwarder addresses.
             * This transfer needs only a single signature and can be done by any signer.
             *
             * @param forwarderAddress the address of the forwarder address to flush the tokens from
             * @param tokenContractAddress the address of the erc1155 token contract
             * @param tokenId the token id associated with the ERC1155
             */
            function flushERC1155ForwarderTokens(
              address payable forwarderAddress,
              address tokenContractAddress,
              uint256 tokenId
            ) external onlySigner {
              IForwarder forwarder = IForwarder(forwarderAddress);
              forwarder.flushERC1155Tokens(tokenContractAddress, tokenId);
            }
            /**
             * Sets the autoflush 721 parameter on the forwarder.
             *
             * @param forwarderAddress the address of the forwarder to toggle.
             * @param autoFlush whether to autoflush erc721 tokens
             */
            function setAutoFlush721(address forwarderAddress, bool autoFlush)
              external
              onlySigner
            {
              IForwarder forwarder = IForwarder(forwarderAddress);
              forwarder.setAutoFlush721(autoFlush);
            }
            /**
             * Sets the autoflush 721 parameter on the forwarder.
             *
             * @param forwarderAddress the address of the forwarder to toggle.
             * @param autoFlush whether to autoflush erc1155 tokens
             */
            function setAutoFlush1155(address forwarderAddress, bool autoFlush)
              external
              onlySigner
            {
              IForwarder forwarder = IForwarder(forwarderAddress);
              forwarder.setAutoFlush1155(autoFlush);
            }
            /**
             * Do common multisig verification for both eth sends and erc20token transfers
             *
             * @param toAddress the destination address to send an outgoing transaction
             * @param operationHash see Data Formats
             * @param signature see Data Formats
             * @param expireTime the number of seconds since 1970 for which this transaction is valid
             * @param sequenceId the unique sequence id obtainable from getNextSequenceId
             * returns address that has created the signature
             */
            function verifyMultiSig(
              address toAddress,
              bytes32 operationHash,
              bytes calldata signature,
              uint256 expireTime,
              uint256 sequenceId
            ) private returns (address) {
              address otherSigner = recoverAddressFromSignature(operationHash, signature);
              // Verify if we are in safe mode. In safe mode, the wallet can only send to signers
              require(!safeMode || isSigner(toAddress), 'External transfer in safe mode');
              // Verify that the transaction has not expired
              require(expireTime >= block.timestamp, 'Transaction expired');
              // Try to insert the sequence ID. Will revert if the sequence id was invalid
              tryInsertSequenceId(sequenceId);
              require(isSigner(otherSigner), 'Invalid signer');
              require(otherSigner != msg.sender, 'Signers cannot be equal');
              return otherSigner;
            }
            /**
             * ERC721 standard callback function for when a ERC721 is transfered.
             *
             * @param _operator The address of the nft contract
             * @param _from The address of the sender
             * @param _tokenId The token id of the nft
             * @param _data Additional data with no specified format, sent in call to `_to`
             */
            function onERC721Received(
              address _operator,
              address _from,
              uint256 _tokenId,
              bytes memory _data
            ) external virtual override returns (bytes4) {
              return this.onERC721Received.selector;
            }
            /**
             * @inheritdoc IERC1155Receiver
             */
            function onERC1155Received(
              address _operator,
              address _from,
              uint256 id,
              uint256 value,
              bytes calldata data
            ) external virtual override returns (bytes4) {
              return this.onERC1155Received.selector;
            }
            /**
             * @inheritdoc IERC1155Receiver
             */
            function onERC1155BatchReceived(
              address _operator,
              address _from,
              uint256[] calldata ids,
              uint256[] calldata values,
              bytes calldata data
            ) external virtual override returns (bytes4) {
              return this.onERC1155BatchReceived.selector;
            }
            /**
             * Irrevocably puts contract into safe mode. When in this mode, transactions may only be sent to signing addresses.
             */
            function activateSafeMode() external onlySigner {
              safeMode = true;
              emit SafeModeActivated(msg.sender);
            }
            /**
             * Gets signer's address using ecrecover
             * @param operationHash see Data Formats
             * @param signature see Data Formats
             * returns address recovered from the signature
             */
            function recoverAddressFromSignature(
              bytes32 operationHash,
              bytes memory signature
            ) private pure returns (address) {
              require(signature.length == 65, 'Invalid signature - wrong length');
              // We need to unpack the signature, which is given as an array of 65 bytes (like eth.sign)
              bytes32 r;
              bytes32 s;
              uint8 v;
              // solhint-disable-next-line
              assembly {
                r := mload(add(signature, 32))
                s := mload(add(signature, 64))
                v := and(mload(add(signature, 65)), 255)
              }
              if (v < 27) {
                v += 27; // Ethereum versions are 27 or 28 as opposed to 0 or 1 which is submitted by some signing libs
              }
              // protect against signature malleability
              // S value must be in the lower half orader
              // reference: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/051d340171a93a3d401aaaea46b4b62fa81e5d7c/contracts/cryptography/ECDSA.sol#L53
              require(
                uint256(s) <=
                  0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
                "ECDSA: invalid signature 's' value"
              );
              // note that this returns 0 if the signature is invalid
              // Since 0x0 can never be a signer, when the recovered signer address
              // is checked against our signer list, that 0x0 will cause an invalid signer failure
              return ecrecover(operationHash, v, r, s);
            }
            /**
             * Verify that the sequence id has not been used before and inserts it. Throws if the sequence ID was not accepted.
             * We collect a window of up to 10 recent sequence ids, and allow any sequence id that is not in the window and
             * greater than the minimum element in the window.
             * @param sequenceId to insert into array of stored ids
             */
            function tryInsertSequenceId(uint256 sequenceId) private onlySigner {
              // Keep a pointer to the lowest value element in the window
              uint256 lowestValueIndex = 0;
              // fetch recentSequenceIds into memory for function context to avoid unnecessary sloads
                uint256[SEQUENCE_ID_WINDOW_SIZE] memory _recentSequenceIds
               = recentSequenceIds;
              for (uint256 i = 0; i < SEQUENCE_ID_WINDOW_SIZE; i++) {
                require(_recentSequenceIds[i] != sequenceId, 'Sequence ID already used');
                if (_recentSequenceIds[i] < _recentSequenceIds[lowestValueIndex]) {
                  lowestValueIndex = i;
                }
              }
              // The sequence ID being used is lower than the lowest value in the window
              // so we cannot accept it as it may have been used before
              require(
                sequenceId > _recentSequenceIds[lowestValueIndex],
                'Sequence ID below window'
              );
              // Block sequence IDs which are much higher than the lowest value
              // This prevents people blocking the contract by using very large sequence IDs quickly
              require(
                sequenceId <=
                  (_recentSequenceIds[lowestValueIndex] + MAX_SEQUENCE_ID_INCREASE),
                'Sequence ID above maximum'
              );
              recentSequenceIds[lowestValueIndex] = sequenceId;
            }
            /**
             * Gets the next available sequence ID for signing when using executeAndConfirm
             * returns the sequenceId one higher than the highest currently stored
             */
            function getNextSequenceId() external view returns (uint256) {
              uint256 highestSequenceId = 0;
              for (uint256 i = 0; i < SEQUENCE_ID_WINDOW_SIZE; i++) {
                if (recentSequenceIds[i] > highestSequenceId) {
                  highestSequenceId = recentSequenceIds[i];
                }
              }
              return highestSequenceId + 1;
            }
          }
          // SPDX-License-Identifier: GPL-3.0-or-later
          // source: https://github.com/Uniswap/solidity-lib/blob/master/contracts/libraries/TransferHelper.sol
          pragma solidity 0.8.10;
          import '@openzeppelin/contracts/utils/Address.sol';
          // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
          library TransferHelper {
            function safeTransfer(
              address token,
              address to,
              uint256 value
            ) internal {
              // bytes4(keccak256(bytes('transfer(address,uint256)')));
              (bool success, bytes memory data) = token.call(
                abi.encodeWithSelector(0xa9059cbb, to, value)
              );
              require(
                success && (data.length == 0 || abi.decode(data, (bool))),
                'TransferHelper::safeTransfer: transfer failed'
              );
            }
            function safeTransferFrom(
              address token,
              address from,
              address to,
              uint256 value
            ) internal {
              // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
              (bool success, bytes memory returndata) = token.call(
                abi.encodeWithSelector(0x23b872dd, from, to, value)
              );
              Address.verifyCallResult(
                success,
                returndata,
                'TransferHelper::transferFrom: transferFrom failed'
              );
            }
          }
          // SPDX-License-Identifier: UNLICENSED
          pragma solidity 0.8.10;
          /**
           * Contract that exposes the needed erc20 token functions
           */
          abstract contract ERC20Interface {
            // Send _value amount of tokens to address _to
            function transfer(address _to, uint256 _value)
              public
              virtual
              returns (bool success);
            // Get the account balance of another account with address _owner
            function balanceOf(address _owner)
              public
              virtual
              view
              returns (uint256 balance);
          }
          pragma solidity ^0.8.0;
          import '@openzeppelin/contracts/utils/introspection/IERC165.sol';
          interface IForwarder is IERC165 {
            /**
             * Sets the autoflush721 parameter.
             *
             * @param autoFlush whether to autoflush erc721 tokens
             */
            function setAutoFlush721(bool autoFlush) external;
            /**
             * Sets the autoflush1155 parameter.
             *
             * @param autoFlush whether to autoflush erc1155 tokens
             */
            function setAutoFlush1155(bool autoFlush) external;
            /**
             * Execute a token transfer of the full balance from the forwarder token to the parent address
             *
             * @param tokenContractAddress the address of the erc20 token contract
             */
            function flushTokens(address tokenContractAddress) external;
            /**
             * Execute a nft transfer from the forwarder to the parent address
             *
             * @param tokenContractAddress the address of the ERC721 NFT contract
             * @param tokenId The token id of the nft
             */
            function flushERC721Token(address tokenContractAddress, uint256 tokenId)
              external;
            /**
             * Execute a nft transfer from the forwarder to the parent address.
             *
             * @param tokenContractAddress the address of the ERC1155 NFT contract
             * @param tokenId The token id of the nft
             */
            function flushERC1155Tokens(address tokenContractAddress, uint256 tokenId)
              external;
            /**
             * Execute a batch nft transfer from the forwarder to the parent address.
             *
             * @param tokenContractAddress the address of the ERC1155 NFT contract
             * @param tokenIds The token ids of the nfts
             */
            function batchFlushERC1155Tokens(
              address tokenContractAddress,
              uint256[] calldata tokenIds
            ) external;
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)
          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
          // OpenZeppelin Contracts v4.4.1 (token/ERC1155/utils/ERC1155Receiver.sol)
          pragma solidity ^0.8.0;
          import "../IERC1155Receiver.sol";
          import "../../../utils/introspection/ERC165.sol";
          /**
           * @dev _Available since v3.1._
           */
          abstract contract ERC1155Receiver is ERC165, IERC1155Receiver {
              /**
               * @dev See {IERC165-supportsInterface}.
               */
              function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
                  return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (utils/Address.sol)
          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;
                  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");
                  (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");
                  (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");
                  (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");
                  (bool success, bytes memory returndata) = target.delegatecall(data);
                  return verifyCallResult(success, returndata, errorMessage);
              }
              /**
               * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
               * revert reason using the provided one.
               *
               * _Available since v4.3._
               */
              function verifyCallResult(
                  bool success,
                  bytes memory returndata,
                  string memory errorMessage
              ) internal pure returns (bytes memory) {
                  if (success) {
                      return returndata;
                  } else {
                      // 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
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert(errorMessage);
                      }
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev Interface of the ERC165 standard, as defined in the
           * https://eips.ethereum.org/EIPS/eip-165[EIP].
           *
           * Implementers can declare support of contract interfaces, which can then be
           * queried by others ({ERC165Checker}).
           *
           * For an implementation, see {ERC165}.
           */
          interface IERC165 {
              /**
               * @dev Returns true if this contract implements the interface defined by
               * `interfaceId`. See the corresponding
               * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
               * to learn more about how these ids are created.
               *
               * This function call must use less than 30 000 gas.
               */
              function supportsInterface(bytes4 interfaceId) external view returns (bool);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155Receiver.sol)
          pragma solidity ^0.8.0;
          import "../../utils/introspection/IERC165.sol";
          /**
           * @dev _Available since v3.1._
           */
          interface IERC1155Receiver is IERC165 {
              /**
                  @dev Handles the receipt of a single ERC1155 token type. This function is
                  called at the end of a `safeTransferFrom` after the balance has been updated.
                  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
          // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
          pragma solidity ^0.8.0;
          import "./IERC165.sol";
          /**
           * @dev Implementation of the {IERC165} interface.
           *
           * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
           * for the additional interface id that will be supported. For example:
           *
           * ```solidity
           * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
           *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
           * }
           * ```
           *
           * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
           */
          abstract contract ERC165 is IERC165 {
              /**
               * @dev See {IERC165-supportsInterface}.
               */
              function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                  return interfaceId == type(IERC165).interfaceId;
              }
          }
          

          File 2 of 5: Forwarder
          // SPDX-License-Identifier: Apache-2.0
          pragma solidity 0.8.10;
          import '@openzeppelin/contracts/token/ERC1155/IERC1155.sol';
          import '@openzeppelin/contracts/token/ERC721/IERC721.sol';
          import '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol';
          import '@openzeppelin/contracts/token/ERC1155/utils/ERC1155Receiver.sol';
          import './ERC20Interface.sol';
          import './TransferHelper.sol';
          import './IForwarder.sol';
          /**
           * Contract that will forward any incoming Ether to the creator of the contract
           *
           */
          contract Forwarder is IERC721Receiver, ERC1155Receiver, IForwarder {
            // Address to which any funds sent to this contract will be forwarded
            address public parentAddress;
            bool public autoFlush721 = true;
            bool public autoFlush1155 = true;
            event ForwarderDeposited(address from, uint256 value, bytes data);
            /**
             * Initialize the contract, and sets the destination address to that of the creator
             */
            function init(
              address _parentAddress,
              bool _autoFlush721,
              bool _autoFlush1155
            ) external onlyUninitialized {
              parentAddress = _parentAddress;
              uint256 value = address(this).balance;
              // set whether we want to automatically flush erc721/erc1155 tokens or not
              autoFlush721 = _autoFlush721;
              autoFlush1155 = _autoFlush1155;
              if (value == 0) {
                return;
              }
              (bool success, ) = parentAddress.call{ value: value }('');
              require(success, 'Flush failed');
              // NOTE: since we are forwarding on initialization,
              // we don't have the context of the original sender.
              // We still emit an event about the forwarding but set
              // the sender to the forwarder itself
              emit ForwarderDeposited(address(this), value, msg.data);
            }
            /**
             * Modifier that will execute internal code block only if the sender is the parent address
             */
            modifier onlyParent {
              require(msg.sender == parentAddress, 'Only Parent');
              _;
            }
            /**
             * Modifier that will execute internal code block only if the contract has not been initialized yet
             */
            modifier onlyUninitialized {
              require(parentAddress == address(0x0), 'Already initialized');
              _;
            }
            /**
             * Default function; Gets called when data is sent but does not match any other function
             */
            fallback() external payable {
              flush();
            }
            /**
             * Default function; Gets called when Ether is deposited with no data, and forwards it to the parent address
             */
            receive() external payable {
              flush();
            }
            /**
             * @inheritdoc IForwarder
             */
            function setAutoFlush721(bool autoFlush)
              external
              virtual
              override
              onlyParent
            {
              autoFlush721 = autoFlush;
            }
            /**
             * @inheritdoc IForwarder
             */
            function setAutoFlush1155(bool autoFlush)
              external
              virtual
              override
              onlyParent
            {
              autoFlush1155 = autoFlush;
            }
            /**
             * ERC721 standard callback function for when a ERC721 is transfered. The forwarder will send the nft
             * to the base wallet once the nft contract invokes this method after transfering the nft.
             *
             * @param _operator The address which called `safeTransferFrom` function
             * @param _from The address of the sender
             * @param _tokenId The token id of the nft
             * @param data Additional data with no specified format, sent in call to `_to`
             */
            function onERC721Received(
              address _operator,
              address _from,
              uint256 _tokenId,
              bytes memory data
            ) external virtual override returns (bytes4) {
              if (autoFlush721) {
                IERC721 instance = IERC721(msg.sender);
                require(
                  instance.supportsInterface(type(IERC721).interfaceId),
                  'The caller does not support the ERC721 interface'
                );
                // this won't work for ERC721 re-entrancy
                instance.safeTransferFrom(address(this), parentAddress, _tokenId, data);
              }
              return this.onERC721Received.selector;
            }
            function callFromParent(
              address target,
              uint256 value,
              bytes calldata data
            ) external onlyParent returns (bytes memory) {
              (bool success, bytes memory returnedData) = target.call{ value: value }(
                data
              );
              require(success, 'Parent call execution failed');
              return returnedData;
            }
            /**
             * @inheritdoc IERC1155Receiver
             */
            function onERC1155Received(
              address _operator,
              address _from,
              uint256 id,
              uint256 value,
              bytes calldata data
            ) external virtual override returns (bytes4) {
              IERC1155 instance = IERC1155(msg.sender);
              require(
                instance.supportsInterface(type(IERC1155).interfaceId),
                'The caller does not support the IERC1155 interface'
              );
              if (autoFlush1155) {
                instance.safeTransferFrom(address(this), parentAddress, id, value, data);
              }
              return this.onERC1155Received.selector;
            }
            /**
             * @inheritdoc IERC1155Receiver
             */
            function onERC1155BatchReceived(
              address _operator,
              address _from,
              uint256[] calldata ids,
              uint256[] calldata values,
              bytes calldata data
            ) external virtual override returns (bytes4) {
              IERC1155 instance = IERC1155(msg.sender);
              require(
                instance.supportsInterface(type(IERC1155).interfaceId),
                'The caller does not support the IERC1155 interface'
              );
              if (autoFlush1155) {
                instance.safeBatchTransferFrom(
                  address(this),
                  parentAddress,
                  ids,
                  values,
                  data
                );
              }
              return this.onERC1155BatchReceived.selector;
            }
            /**
             * @inheritdoc IForwarder
             */
            function flushTokens(address tokenContractAddress)
              external
              virtual
              override
              onlyParent
            {
              ERC20Interface instance = ERC20Interface(tokenContractAddress);
              address forwarderAddress = address(this);
              uint256 forwarderBalance = instance.balanceOf(forwarderAddress);
              if (forwarderBalance == 0) {
                return;
              }
              TransferHelper.safeTransfer(
                tokenContractAddress,
                parentAddress,
                forwarderBalance
              );
            }
            /**
             * @inheritdoc IForwarder
             */
            function flushERC721Token(address tokenContractAddress, uint256 tokenId)
              external
              virtual
              override
              onlyParent
            {
              IERC721 instance = IERC721(tokenContractAddress);
              require(
                instance.supportsInterface(type(IERC721).interfaceId),
                'The tokenContractAddress does not support the ERC721 interface'
              );
              address ownerAddress = instance.ownerOf(tokenId);
              instance.transferFrom(ownerAddress, parentAddress, tokenId);
            }
            /**
             * @inheritdoc IForwarder
             */
            function flushERC1155Tokens(address tokenContractAddress, uint256 tokenId)
              external
              virtual
              override
              onlyParent
            {
              IERC1155 instance = IERC1155(tokenContractAddress);
              require(
                instance.supportsInterface(type(IERC1155).interfaceId),
                'The caller does not support the IERC1155 interface'
              );
              address forwarderAddress = address(this);
              uint256 forwarderBalance = instance.balanceOf(forwarderAddress, tokenId);
              instance.safeTransferFrom(
                forwarderAddress,
                parentAddress,
                tokenId,
                forwarderBalance,
                ''
              );
            }
            /**
             * @inheritdoc IForwarder
             */
            function batchFlushERC1155Tokens(
              address tokenContractAddress,
              uint256[] calldata tokenIds
            ) external virtual override onlyParent {
              IERC1155 instance = IERC1155(tokenContractAddress);
              require(
                instance.supportsInterface(type(IERC1155).interfaceId),
                'The caller does not support the IERC1155 interface'
              );
              address forwarderAddress = address(this);
              uint256[] memory amounts = new uint256[](tokenIds.length);
              for (uint256 i = 0; i < tokenIds.length; i++) {
                amounts[i] = instance.balanceOf(forwarderAddress, tokenIds[i]);
              }
              instance.safeBatchTransferFrom(
                forwarderAddress,
                parentAddress,
                tokenIds,
                amounts,
                ''
              );
            }
            /**
             * Flush the entire balance of the contract to the parent address.
             */
            function flush() public {
              uint256 value = address(this).balance;
              if (value == 0) {
                return;
              }
              (bool success, ) = parentAddress.call{ value: value }('');
              require(success, 'Flush failed');
              emit ForwarderDeposited(msg.sender, value, msg.data);
            }
            /**
             * @inheritdoc IERC165
             */
            function supportsInterface(bytes4 interfaceId)
              public
              virtual
              override(ERC1155Receiver, IERC165)
              view
              returns (bool)
            {
              return
                interfaceId == type(IForwarder).interfaceId ||
                super.supportsInterface(interfaceId);
            }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155.sol)
          pragma solidity ^0.8.0;
          import "../../utils/introspection/IERC165.sol";
          /**
           * @dev Required interface of an ERC1155 compliant contract, as defined in the
           * https://eips.ethereum.org/EIPS/eip-1155[EIP].
           *
           * _Available since v3.1._
           */
          interface IERC1155 is IERC165 {
              /**
               * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
               */
              event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
              /**
               * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
               * transfers.
               */
              event TransferBatch(
                  address indexed operator,
                  address indexed from,
                  address indexed to,
                  uint256[] ids,
                  uint256[] values
              );
              /**
               * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
               * `approved`.
               */
              event ApprovalForAll(address indexed account, address indexed operator, bool approved);
              /**
               * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
               *
               * If an {URI} event was emitted for `id`, the standard
               * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
               * returned by {IERC1155MetadataURI-uri}.
               */
              event URI(string value, uint256 indexed id);
              /**
               * @dev Returns the amount of tokens of token type `id` owned by `account`.
               *
               * Requirements:
               *
               * - `account` cannot be the zero address.
               */
              function balanceOf(address account, uint256 id) external view returns (uint256);
              /**
               * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
               *
               * Requirements:
               *
               * - `accounts` and `ids` must have the same length.
               */
              function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
                  external
                  view
                  returns (uint256[] memory);
              /**
               * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
               *
               * Emits an {ApprovalForAll} event.
               *
               * Requirements:
               *
               * - `operator` cannot be the caller.
               */
              function setApprovalForAll(address operator, bool approved) external;
              /**
               * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
               *
               * See {setApprovalForAll}.
               */
              function isApprovedForAll(address account, address operator) external view returns (bool);
              /**
               * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
               *
               * Emits a {TransferSingle} event.
               *
               * Requirements:
               *
               * - `to` cannot be the zero address.
               * - If the caller is not `from`, it must 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
          // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)
          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;
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)
          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
          // OpenZeppelin Contracts v4.4.1 (token/ERC1155/utils/ERC1155Receiver.sol)
          pragma solidity ^0.8.0;
          import "../IERC1155Receiver.sol";
          import "../../../utils/introspection/ERC165.sol";
          /**
           * @dev _Available since v3.1._
           */
          abstract contract ERC1155Receiver is ERC165, IERC1155Receiver {
              /**
               * @dev See {IERC165-supportsInterface}.
               */
              function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
                  return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
              }
          }
          // SPDX-License-Identifier: UNLICENSED
          pragma solidity 0.8.10;
          /**
           * Contract that exposes the needed erc20 token functions
           */
          abstract contract ERC20Interface {
            // Send _value amount of tokens to address _to
            function transfer(address _to, uint256 _value)
              public
              virtual
              returns (bool success);
            // Get the account balance of another account with address _owner
            function balanceOf(address _owner)
              public
              virtual
              view
              returns (uint256 balance);
          }
          // SPDX-License-Identifier: GPL-3.0-or-later
          // source: https://github.com/Uniswap/solidity-lib/blob/master/contracts/libraries/TransferHelper.sol
          pragma solidity 0.8.10;
          import '@openzeppelin/contracts/utils/Address.sol';
          // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
          library TransferHelper {
            function safeTransfer(
              address token,
              address to,
              uint256 value
            ) internal {
              // bytes4(keccak256(bytes('transfer(address,uint256)')));
              (bool success, bytes memory data) = token.call(
                abi.encodeWithSelector(0xa9059cbb, to, value)
              );
              require(
                success && (data.length == 0 || abi.decode(data, (bool))),
                'TransferHelper::safeTransfer: transfer failed'
              );
            }
            function safeTransferFrom(
              address token,
              address from,
              address to,
              uint256 value
            ) internal {
              // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
              (bool success, bytes memory returndata) = token.call(
                abi.encodeWithSelector(0x23b872dd, from, to, value)
              );
              Address.verifyCallResult(
                success,
                returndata,
                'TransferHelper::transferFrom: transferFrom failed'
              );
            }
          }
          pragma solidity ^0.8.0;
          import '@openzeppelin/contracts/utils/introspection/IERC165.sol';
          interface IForwarder is IERC165 {
            /**
             * Sets the autoflush721 parameter.
             *
             * @param autoFlush whether to autoflush erc721 tokens
             */
            function setAutoFlush721(bool autoFlush) external;
            /**
             * Sets the autoflush1155 parameter.
             *
             * @param autoFlush whether to autoflush erc1155 tokens
             */
            function setAutoFlush1155(bool autoFlush) external;
            /**
             * Execute a token transfer of the full balance from the forwarder token to the parent address
             *
             * @param tokenContractAddress the address of the erc20 token contract
             */
            function flushTokens(address tokenContractAddress) external;
            /**
             * Execute a nft transfer from the forwarder to the parent address
             *
             * @param tokenContractAddress the address of the ERC721 NFT contract
             * @param tokenId The token id of the nft
             */
            function flushERC721Token(address tokenContractAddress, uint256 tokenId)
              external;
            /**
             * Execute a nft transfer from the forwarder to the parent address.
             *
             * @param tokenContractAddress the address of the ERC1155 NFT contract
             * @param tokenId The token id of the nft
             */
            function flushERC1155Tokens(address tokenContractAddress, uint256 tokenId)
              external;
            /**
             * Execute a batch nft transfer from the forwarder to the parent address.
             *
             * @param tokenContractAddress the address of the ERC1155 NFT contract
             * @param tokenIds The token ids of the nfts
             */
            function batchFlushERC1155Tokens(
              address tokenContractAddress,
              uint256[] calldata tokenIds
            ) external;
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev Interface of the ERC165 standard, as defined in the
           * https://eips.ethereum.org/EIPS/eip-165[EIP].
           *
           * Implementers can declare support of contract interfaces, which can then be
           * queried by others ({ERC165Checker}).
           *
           * For an implementation, see {ERC165}.
           */
          interface IERC165 {
              /**
               * @dev Returns true if this contract implements the interface defined by
               * `interfaceId`. See the corresponding
               * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
               * to learn more about how these ids are created.
               *
               * This function call must use less than 30 000 gas.
               */
              function supportsInterface(bytes4 interfaceId) external view returns (bool);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155Receiver.sol)
          pragma solidity ^0.8.0;
          import "../../utils/introspection/IERC165.sol";
          /**
           * @dev _Available since v3.1._
           */
          interface IERC1155Receiver is IERC165 {
              /**
                  @dev Handles the receipt of a single ERC1155 token type. This function is
                  called at the end of a `safeTransferFrom` after the balance has been updated.
                  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
          // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
          pragma solidity ^0.8.0;
          import "./IERC165.sol";
          /**
           * @dev Implementation of the {IERC165} interface.
           *
           * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
           * for the additional interface id that will be supported. For example:
           *
           * ```solidity
           * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
           *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
           * }
           * ```
           *
           * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
           */
          abstract contract ERC165 is IERC165 {
              /**
               * @dev See {IERC165-supportsInterface}.
               */
              function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                  return interfaceId == type(IERC165).interfaceId;
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (utils/Address.sol)
          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;
                  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");
                  (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");
                  (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");
                  (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");
                  (bool success, bytes memory returndata) = target.delegatecall(data);
                  return verifyCallResult(success, returndata, errorMessage);
              }
              /**
               * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
               * revert reason using the provided one.
               *
               * _Available since v4.3._
               */
              function verifyCallResult(
                  bool success,
                  bytes memory returndata,
                  string memory errorMessage
              ) internal pure returns (bytes memory) {
                  if (success) {
                      return returndata;
                  } else {
                      // 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
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert(errorMessage);
                      }
                  }
              }
          }
          

          File 3 of 5: TetherToken
          pragma solidity ^0.4.17;
          
          /**
           * @title SafeMath
           * @dev Math operations with safety checks that throw on error
           */
          library SafeMath {
              function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                  if (a == 0) {
                      return 0;
                  }
                  uint256 c = a * b;
                  assert(c / a == b);
                  return c;
              }
          
              function div(uint256 a, uint256 b) internal pure returns (uint256) {
                  // assert(b > 0); // Solidity automatically throws when dividing by 0
                  uint256 c = a / b;
                  // assert(a == b * c + a % b); // There is no case in which this doesn't hold
                  return c;
              }
          
              function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                  assert(b <= a);
                  return a - b;
              }
          
              function add(uint256 a, uint256 b) internal pure returns (uint256) {
                  uint256 c = a + b;
                  assert(c >= a);
                  return c;
              }
          }
          
          /**
           * @title Ownable
           * @dev The Ownable contract has an owner address, and provides basic authorization control
           * functions, this simplifies the implementation of "user permissions".
           */
          contract Ownable {
              address public owner;
          
              /**
                * @dev The Ownable constructor sets the original `owner` of the contract to the sender
                * account.
                */
              function Ownable() public {
                  owner = msg.sender;
              }
          
              /**
                * @dev Throws if called by any account other than the owner.
                */
              modifier onlyOwner() {
                  require(msg.sender == owner);
                  _;
              }
          
              /**
              * @dev Allows the current owner to transfer control of the contract to a newOwner.
              * @param newOwner The address to transfer ownership to.
              */
              function transferOwnership(address newOwner) public onlyOwner {
                  if (newOwner != address(0)) {
                      owner = newOwner;
                  }
              }
          
          }
          
          /**
           * @title ERC20Basic
           * @dev Simpler version of ERC20 interface
           * @dev see https://github.com/ethereum/EIPs/issues/20
           */
          contract ERC20Basic {
              uint public _totalSupply;
              function totalSupply() public constant returns (uint);
              function balanceOf(address who) public constant returns (uint);
              function transfer(address to, uint value) public;
              event Transfer(address indexed from, address indexed to, uint value);
          }
          
          /**
           * @title ERC20 interface
           * @dev see https://github.com/ethereum/EIPs/issues/20
           */
          contract ERC20 is ERC20Basic {
              function allowance(address owner, address spender) public constant returns (uint);
              function transferFrom(address from, address to, uint value) public;
              function approve(address spender, uint value) public;
              event Approval(address indexed owner, address indexed spender, uint value);
          }
          
          /**
           * @title Basic token
           * @dev Basic version of StandardToken, with no allowances.
           */
          contract BasicToken is Ownable, ERC20Basic {
              using SafeMath for uint;
          
              mapping(address => uint) public balances;
          
              // additional variables for use if transaction fees ever became necessary
              uint public basisPointsRate = 0;
              uint public maximumFee = 0;
          
              /**
              * @dev Fix for the ERC20 short address attack.
              */
              modifier onlyPayloadSize(uint size) {
                  require(!(msg.data.length < size + 4));
                  _;
              }
          
              /**
              * @dev transfer token for a specified address
              * @param _to The address to transfer to.
              * @param _value The amount to be transferred.
              */
              function transfer(address _to, uint _value) public onlyPayloadSize(2 * 32) {
                  uint fee = (_value.mul(basisPointsRate)).div(10000);
                  if (fee > maximumFee) {
                      fee = maximumFee;
                  }
                  uint sendAmount = _value.sub(fee);
                  balances[msg.sender] = balances[msg.sender].sub(_value);
                  balances[_to] = balances[_to].add(sendAmount);
                  if (fee > 0) {
                      balances[owner] = balances[owner].add(fee);
                      Transfer(msg.sender, owner, fee);
                  }
                  Transfer(msg.sender, _to, sendAmount);
              }
          
              /**
              * @dev Gets the balance of the specified address.
              * @param _owner The address to query the the balance of.
              * @return An uint representing the amount owned by the passed address.
              */
              function balanceOf(address _owner) public constant returns (uint balance) {
                  return balances[_owner];
              }
          
          }
          
          /**
           * @title Standard ERC20 token
           *
           * @dev Implementation of the basic standard token.
           * @dev https://github.com/ethereum/EIPs/issues/20
           * @dev Based oncode by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
           */
          contract StandardToken is BasicToken, ERC20 {
          
              mapping (address => mapping (address => uint)) public allowed;
          
              uint public constant MAX_UINT = 2**256 - 1;
          
              /**
              * @dev Transfer tokens from one address to another
              * @param _from address The address which you want to send tokens from
              * @param _to address The address which you want to transfer to
              * @param _value uint the amount of tokens to be transferred
              */
              function transferFrom(address _from, address _to, uint _value) public onlyPayloadSize(3 * 32) {
                  var _allowance = allowed[_from][msg.sender];
          
                  // Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
                  // if (_value > _allowance) throw;
          
                  uint fee = (_value.mul(basisPointsRate)).div(10000);
                  if (fee > maximumFee) {
                      fee = maximumFee;
                  }
                  if (_allowance < MAX_UINT) {
                      allowed[_from][msg.sender] = _allowance.sub(_value);
                  }
                  uint sendAmount = _value.sub(fee);
                  balances[_from] = balances[_from].sub(_value);
                  balances[_to] = balances[_to].add(sendAmount);
                  if (fee > 0) {
                      balances[owner] = balances[owner].add(fee);
                      Transfer(_from, owner, fee);
                  }
                  Transfer(_from, _to, sendAmount);
              }
          
              /**
              * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
              * @param _spender The address which will spend the funds.
              * @param _value The amount of tokens to be spent.
              */
              function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
          
                  // To change the approve amount you first have to reduce the addresses`
                  //  allowance to zero by calling `approve(_spender, 0)` if it is not
                  //  already 0 to mitigate the race condition described here:
                  //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                  require(!((_value != 0) && (allowed[msg.sender][_spender] != 0)));
          
                  allowed[msg.sender][_spender] = _value;
                  Approval(msg.sender, _spender, _value);
              }
          
              /**
              * @dev Function to check the amount of tokens than an owner allowed to a spender.
              * @param _owner address The address which owns the funds.
              * @param _spender address The address which will spend the funds.
              * @return A uint specifying the amount of tokens still available for the spender.
              */
              function allowance(address _owner, address _spender) public constant returns (uint remaining) {
                  return allowed[_owner][_spender];
              }
          
          }
          
          
          /**
           * @title Pausable
           * @dev Base contract which allows children to implement an emergency stop mechanism.
           */
          contract Pausable is Ownable {
            event Pause();
            event Unpause();
          
            bool public paused = false;
          
          
            /**
             * @dev Modifier to make a function callable only when the contract is not paused.
             */
            modifier whenNotPaused() {
              require(!paused);
              _;
            }
          
            /**
             * @dev Modifier to make a function callable only when the contract is paused.
             */
            modifier whenPaused() {
              require(paused);
              _;
            }
          
            /**
             * @dev called by the owner to pause, triggers stopped state
             */
            function pause() onlyOwner whenNotPaused public {
              paused = true;
              Pause();
            }
          
            /**
             * @dev called by the owner to unpause, returns to normal state
             */
            function unpause() onlyOwner whenPaused public {
              paused = false;
              Unpause();
            }
          }
          
          contract BlackList is Ownable, BasicToken {
          
              /////// Getters to allow the same blacklist to be used also by other contracts (including upgraded Tether) ///////
              function getBlackListStatus(address _maker) external constant returns (bool) {
                  return isBlackListed[_maker];
              }
          
              function getOwner() external constant returns (address) {
                  return owner;
              }
          
              mapping (address => bool) public isBlackListed;
              
              function addBlackList (address _evilUser) public onlyOwner {
                  isBlackListed[_evilUser] = true;
                  AddedBlackList(_evilUser);
              }
          
              function removeBlackList (address _clearedUser) public onlyOwner {
                  isBlackListed[_clearedUser] = false;
                  RemovedBlackList(_clearedUser);
              }
          
              function destroyBlackFunds (address _blackListedUser) public onlyOwner {
                  require(isBlackListed[_blackListedUser]);
                  uint dirtyFunds = balanceOf(_blackListedUser);
                  balances[_blackListedUser] = 0;
                  _totalSupply -= dirtyFunds;
                  DestroyedBlackFunds(_blackListedUser, dirtyFunds);
              }
          
              event DestroyedBlackFunds(address _blackListedUser, uint _balance);
          
              event AddedBlackList(address _user);
          
              event RemovedBlackList(address _user);
          
          }
          
          contract UpgradedStandardToken is StandardToken{
              // those methods are called by the legacy contract
              // and they must ensure msg.sender to be the contract address
              function transferByLegacy(address from, address to, uint value) public;
              function transferFromByLegacy(address sender, address from, address spender, uint value) public;
              function approveByLegacy(address from, address spender, uint value) public;
          }
          
          contract TetherToken is Pausable, StandardToken, BlackList {
          
              string public name;
              string public symbol;
              uint public decimals;
              address public upgradedAddress;
              bool public deprecated;
          
              //  The contract can be initialized with a number of tokens
              //  All the tokens are deposited to the owner address
              //
              // @param _balance Initial supply of the contract
              // @param _name Token Name
              // @param _symbol Token symbol
              // @param _decimals Token decimals
              function TetherToken(uint _initialSupply, string _name, string _symbol, uint _decimals) public {
                  _totalSupply = _initialSupply;
                  name = _name;
                  symbol = _symbol;
                  decimals = _decimals;
                  balances[owner] = _initialSupply;
                  deprecated = false;
              }
          
              // Forward ERC20 methods to upgraded contract if this one is deprecated
              function transfer(address _to, uint _value) public whenNotPaused {
                  require(!isBlackListed[msg.sender]);
                  if (deprecated) {
                      return UpgradedStandardToken(upgradedAddress).transferByLegacy(msg.sender, _to, _value);
                  } else {
                      return super.transfer(_to, _value);
                  }
              }
          
              // Forward ERC20 methods to upgraded contract if this one is deprecated
              function transferFrom(address _from, address _to, uint _value) public whenNotPaused {
                  require(!isBlackListed[_from]);
                  if (deprecated) {
                      return UpgradedStandardToken(upgradedAddress).transferFromByLegacy(msg.sender, _from, _to, _value);
                  } else {
                      return super.transferFrom(_from, _to, _value);
                  }
              }
          
              // Forward ERC20 methods to upgraded contract if this one is deprecated
              function balanceOf(address who) public constant returns (uint) {
                  if (deprecated) {
                      return UpgradedStandardToken(upgradedAddress).balanceOf(who);
                  } else {
                      return super.balanceOf(who);
                  }
              }
          
              // Forward ERC20 methods to upgraded contract if this one is deprecated
              function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
                  if (deprecated) {
                      return UpgradedStandardToken(upgradedAddress).approveByLegacy(msg.sender, _spender, _value);
                  } else {
                      return super.approve(_spender, _value);
                  }
              }
          
              // Forward ERC20 methods to upgraded contract if this one is deprecated
              function allowance(address _owner, address _spender) public constant returns (uint remaining) {
                  if (deprecated) {
                      return StandardToken(upgradedAddress).allowance(_owner, _spender);
                  } else {
                      return super.allowance(_owner, _spender);
                  }
              }
          
              // deprecate current contract in favour of a new one
              function deprecate(address _upgradedAddress) public onlyOwner {
                  deprecated = true;
                  upgradedAddress = _upgradedAddress;
                  Deprecate(_upgradedAddress);
              }
          
              // deprecate current contract if favour of a new one
              function totalSupply() public constant returns (uint) {
                  if (deprecated) {
                      return StandardToken(upgradedAddress).totalSupply();
                  } else {
                      return _totalSupply;
                  }
              }
          
              // Issue a new amount of tokens
              // these tokens are deposited into the owner address
              //
              // @param _amount Number of tokens to be issued
              function issue(uint amount) public onlyOwner {
                  require(_totalSupply + amount > _totalSupply);
                  require(balances[owner] + amount > balances[owner]);
          
                  balances[owner] += amount;
                  _totalSupply += amount;
                  Issue(amount);
              }
          
              // Redeem tokens.
              // These tokens are withdrawn from the owner address
              // if the balance must be enough to cover the redeem
              // or the call will fail.
              // @param _amount Number of tokens to be issued
              function redeem(uint amount) public onlyOwner {
                  require(_totalSupply >= amount);
                  require(balances[owner] >= amount);
          
                  _totalSupply -= amount;
                  balances[owner] -= amount;
                  Redeem(amount);
              }
          
              function setParams(uint newBasisPoints, uint newMaxFee) public onlyOwner {
                  // Ensure transparency by hardcoding limit beyond which fees can never be added
                  require(newBasisPoints < 20);
                  require(newMaxFee < 50);
          
                  basisPointsRate = newBasisPoints;
                  maximumFee = newMaxFee.mul(10**decimals);
          
                  Params(basisPointsRate, maximumFee);
              }
          
              // Called when new token are issued
              event Issue(uint amount);
          
              // Called when tokens are redeemed
              event Redeem(uint amount);
          
              // Called when contract is deprecated
              event Deprecate(address newAddress);
          
              // Called if contract ever adds fees
              event Params(uint feeBasisPoints, uint maxFee);
          }

          File 4 of 5: WalletSimple
          // SPDX-License-Identifier: Apache-2.0
          pragma solidity 0.8.10;
          import './TransferHelper.sol';
          import './ERC20Interface.sol';
          import './IForwarder.sol';
          /** ERC721, ERC1155 imports */
          import '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol';
          import '@openzeppelin/contracts/token/ERC1155/utils/ERC1155Receiver.sol';
          /**
           *
           * WalletSimple
           * ============
           *
           * Basic multi-signer wallet designed for use in a co-signing environment where 2 signatures are required to move funds.
           * Typically used in a 2-of-3 signing configuration. Uses ecrecover to allow for 2 signatures in a single transaction.
           *
           * The first signature is created on the operation hash (see Data Formats) and passed to sendMultiSig/sendMultiSigToken
           * The signer is determined by verifyMultiSig().
           *
           * The second signature is created by the submitter of the transaction and determined by msg.signer.
           *
           * Data Formats
           * ============
           *
           * The signature is created with ethereumjs-util.ecsign(operationHash).
           * Like the eth_sign RPC call, it packs the values as a 65-byte array of [r, s, v].
           * Unlike eth_sign, the message is not prefixed.
           *
           * The operationHash the result of keccak256(prefix, toAddress, value, data, expireTime).
           * For ether transactions, `prefix` is "ETHER".
           * For token transaction, `prefix` is "ERC20" and `data` is the tokenContractAddress.
           *
           *
           */
          contract WalletSimple is IERC721Receiver, ERC1155Receiver {
            // Events
            event Deposited(address from, uint256 value, bytes data);
            event SafeModeActivated(address msgSender);
            event Transacted(
              address msgSender, // Address of the sender of the message initiating the transaction
              address otherSigner, // Address of the signer (second signature) used to initiate the transaction
              bytes32 operation, // Operation hash (see Data Formats)
              address toAddress, // The address the transaction was sent to
              uint256 value, // Amount of Wei sent to the address
              bytes data // Data sent when invoking the transaction
            );
            event BatchTransfer(address sender, address recipient, uint256 value);
            // this event shows the other signer and the operation hash that they signed
            // specific batch transfer events are emitted in Batcher
            event BatchTransacted(
              address msgSender, // Address of the sender of the message initiating the transaction
              address otherSigner, // Address of the signer (second signature) used to initiate the transaction
              bytes32 operation // Operation hash (see Data Formats)
            );
            // Public fields
            mapping(address => bool) public signers; // The addresses that can co-sign transactions on the wallet
            bool public safeMode = false; // When active, wallet may only send to signer addresses
            bool public initialized = false; // True if the contract has been initialized
            // Internal fields
            uint256 private constant MAX_SEQUENCE_ID_INCREASE = 10000;
            uint256 constant SEQUENCE_ID_WINDOW_SIZE = 10;
            uint256[SEQUENCE_ID_WINDOW_SIZE] recentSequenceIds;
            /**
             * Set up a simple multi-sig wallet by specifying the signers allowed to be used on this wallet.
             * 2 signers will be required to send a transaction from this wallet.
             * Note: The sender is NOT automatically added to the list of signers.
             * Signers CANNOT be changed once they are set
             *
             * @param allowedSigners An array of signers on the wallet
             */
            function init(address[] calldata allowedSigners) external onlyUninitialized {
              require(allowedSigners.length == 3, 'Invalid number of signers');
              for (uint8 i = 0; i < allowedSigners.length; i++) {
                require(allowedSigners[i] != address(0), 'Invalid signer');
                signers[allowedSigners[i]] = true;
              }
              initialized = true;
            }
            /**
             * Get the network identifier that signers must sign over
             * This provides protection signatures being replayed on other chains
             * This must be a virtual function because chain-specific contracts will need
             *    to override with their own network ids. It also can't be a field
             *    to allow this contract to be used by proxy with delegatecall, which will
             *    not pick up on state variables
             */
            function getNetworkId() internal virtual pure returns (string memory) {
              return 'ETHER';
            }
            /**
             * Get the network identifier that signers must sign over for token transfers
             * This provides protection signatures being replayed on other chains
             * This must be a virtual function because chain-specific contracts will need
             *    to override with their own network ids. It also can't be a field
             *    to allow this contract to be used by proxy with delegatecall, which will
             *    not pick up on state variables
             */
            function getTokenNetworkId() internal virtual pure returns (string memory) {
              return 'ERC20';
            }
            /**
             * Get the network identifier that signers must sign over for batch transfers
             * This provides protection signatures being replayed on other chains
             * This must be a virtual function because chain-specific contracts will need
             *    to override with their own network ids. It also can't be a field
             *    to allow this contract to be used by proxy with delegatecall, which will
             *    not pick up on state variables
             */
            function getBatchNetworkId() internal virtual pure returns (string memory) {
              return 'ETHER-Batch';
            }
            /**
             * Determine if an address is a signer on this wallet
             * @param signer address to check
             * returns boolean indicating whether address is signer or not
             */
            function isSigner(address signer) public view returns (bool) {
              return signers[signer];
            }
            /**
             * Modifier that will execute internal code block only if the sender is an authorized signer on this wallet
             */
            modifier onlySigner {
              require(isSigner(msg.sender), 'Non-signer in onlySigner method');
              _;
            }
            /**
             * Modifier that will execute internal code block only if the contract has not been initialized yet
             */
            modifier onlyUninitialized {
              require(!initialized, 'Contract already initialized');
              _;
            }
            /**
             * Gets called when a transaction is received with data that does not match any other method
             */
            fallback() external payable {
              if (msg.value > 0) {
                // Fire deposited event if we are receiving funds
                emit Deposited(msg.sender, msg.value, msg.data);
              }
            }
            /**
             * Gets called when a transaction is received with ether and no data
             */
            receive() external payable {
              if (msg.value > 0) {
                // Fire deposited event if we are receiving funds
                // message data is always empty for receive. If there is data it is sent to fallback function.
                emit Deposited(msg.sender, msg.value, '');
              }
            }
            /**
             * Execute a multi-signature transaction from this wallet using 2 signers: one from msg.sender and the other from ecrecover.
             * Sequence IDs are numbers starting from 1. They are used to prevent replay attacks and may not be repeated.
             *
             * @param toAddress the destination address to send an outgoing transaction
             * @param value the amount in Wei to be sent
             * @param data the data to send to the toAddress when invoking the transaction
             * @param expireTime the number of seconds since 1970 for which this transaction is valid
             * @param sequenceId the unique sequence id obtainable from getNextSequenceId
             * @param signature see Data Formats
             */
            function sendMultiSig(
              address toAddress,
              uint256 value,
              bytes calldata data,
              uint256 expireTime,
              uint256 sequenceId,
              bytes calldata signature
            ) external onlySigner {
              // Verify the other signer
              bytes32 operationHash = keccak256(
                abi.encodePacked(
                  getNetworkId(),
                  toAddress,
                  value,
                  data,
                  expireTime,
                  sequenceId
                )
              );
              address otherSigner = verifyMultiSig(
                toAddress,
                operationHash,
                signature,
                expireTime,
                sequenceId
              );
              // Success, send the transaction
              (bool success, ) = toAddress.call{ value: value }(data);
              require(success, 'Call execution failed');
              emit Transacted(
                msg.sender,
                otherSigner,
                operationHash,
                toAddress,
                value,
                data
              );
            }
            /**
             * Execute a batched multi-signature transaction from this wallet using 2 signers: one from msg.sender and the other from ecrecover.
             * Sequence IDs are numbers starting from 1. They are used to prevent replay attacks and may not be repeated.
             * The recipients and values to send are encoded in two arrays, where for index i, recipients[i] will be sent values[i].
             *
             * @param recipients The list of recipients to send to
             * @param values The list of values to send to
             * @param expireTime the number of seconds since 1970 for which this transaction is valid
             * @param sequenceId the unique sequence id obtainable from getNextSequenceId
             * @param signature see Data Formats
             */
            function sendMultiSigBatch(
              address[] calldata recipients,
              uint256[] calldata values,
              uint256 expireTime,
              uint256 sequenceId,
              bytes calldata signature
            ) external onlySigner {
              require(recipients.length != 0, 'Not enough recipients');
              require(
                recipients.length == values.length,
                'Unequal recipients and values'
              );
              require(recipients.length < 256, 'Too many recipients, max 255');
              // Verify the other signer
              bytes32 operationHash = keccak256(
                abi.encodePacked(
                  getBatchNetworkId(),
                  recipients,
                  values,
                  expireTime,
                  sequenceId
                )
              );
              // the first parameter (toAddress) is used to ensure transactions in safe mode only go to a signer
              // if in safe mode, we should use normal sendMultiSig to recover, so this check will always fail if in safe mode
              require(!safeMode, 'Batch in safe mode');
              address otherSigner = verifyMultiSig(
                address(0x0),
                operationHash,
                signature,
                expireTime,
                sequenceId
              );
              batchTransfer(recipients, values);
              emit BatchTransacted(msg.sender, otherSigner, operationHash);
            }
            /**
             * Transfer funds in a batch to each of recipients
             * @param recipients The list of recipients to send to
             * @param values The list of values to send to recipients.
             *  The recipient with index i in recipients array will be sent values[i].
             *  Thus, recipients and values must be the same length
             */
            function batchTransfer(
              address[] calldata recipients,
              uint256[] calldata values
            ) internal {
              for (uint256 i = 0; i < recipients.length; i++) {
                require(address(this).balance >= values[i], 'Insufficient funds');
                (bool success, ) = recipients[i].call{ value: values[i] }('');
                require(success, 'Call failed');
                emit BatchTransfer(msg.sender, recipients[i], values[i]);
              }
            }
            /**
             * Execute a multi-signature token transfer from this wallet using 2 signers: one from msg.sender and the other from ecrecover.
             * Sequence IDs are numbers starting from 1. They are used to prevent replay attacks and may not be repeated.
             *
             * @param toAddress the destination address to send an outgoing transaction
             * @param value the amount in tokens to be sent
             * @param tokenContractAddress the address of the erc20 token contract
             * @param expireTime the number of seconds since 1970 for which this transaction is valid
             * @param sequenceId the unique sequence id obtainable from getNextSequenceId
             * @param signature see Data Formats
             */
            function sendMultiSigToken(
              address toAddress,
              uint256 value,
              address tokenContractAddress,
              uint256 expireTime,
              uint256 sequenceId,
              bytes calldata signature
            ) external onlySigner {
              // Verify the other signer
              bytes32 operationHash = keccak256(
                abi.encodePacked(
                  getTokenNetworkId(),
                  toAddress,
                  value,
                  tokenContractAddress,
                  expireTime,
                  sequenceId
                )
              );
              verifyMultiSig(toAddress, operationHash, signature, expireTime, sequenceId);
              TransferHelper.safeTransfer(tokenContractAddress, toAddress, value);
            }
            /**
             * Execute a token flush from one of the forwarder addresses. This transfer needs only a single signature and can be done by any signer
             *
             * @param forwarderAddress the address of the forwarder address to flush the tokens from
             * @param tokenContractAddress the address of the erc20 token contract
             */
            function flushForwarderTokens(
              address payable forwarderAddress,
              address tokenContractAddress
            ) external onlySigner {
              IForwarder forwarder = IForwarder(forwarderAddress);
              forwarder.flushTokens(tokenContractAddress);
            }
            /**
             * Execute a ERC721 token flush from one of the forwarder addresses. This transfer needs only a single signature and can be done by any signer
             *
             * @param forwarderAddress the address of the forwarder address to flush the tokens from
             * @param tokenContractAddress the address of the erc20 token contract
             */
            function flushERC721ForwarderTokens(
              address payable forwarderAddress,
              address tokenContractAddress,
              uint256 tokenId
            ) external onlySigner {
              IForwarder forwarder = IForwarder(forwarderAddress);
              forwarder.flushERC721Token(tokenContractAddress, tokenId);
            }
            /**
             * Execute a ERC1155 batch token flush from one of the forwarder addresses.
             * This transfer needs only a single signature and can be done by any signer.
             *
             * @param forwarderAddress the address of the forwarder address to flush the tokens from
             * @param tokenContractAddress the address of the erc1155 token contract
             */
            function batchFlushERC1155ForwarderTokens(
              address payable forwarderAddress,
              address tokenContractAddress,
              uint256[] calldata tokenIds
            ) external onlySigner {
              IForwarder forwarder = IForwarder(forwarderAddress);
              forwarder.batchFlushERC1155Tokens(tokenContractAddress, tokenIds);
            }
            /**
             * Execute a ERC1155 token flush from one of the forwarder addresses.
             * This transfer needs only a single signature and can be done by any signer.
             *
             * @param forwarderAddress the address of the forwarder address to flush the tokens from
             * @param tokenContractAddress the address of the erc1155 token contract
             * @param tokenId the token id associated with the ERC1155
             */
            function flushERC1155ForwarderTokens(
              address payable forwarderAddress,
              address tokenContractAddress,
              uint256 tokenId
            ) external onlySigner {
              IForwarder forwarder = IForwarder(forwarderAddress);
              forwarder.flushERC1155Tokens(tokenContractAddress, tokenId);
            }
            /**
             * Sets the autoflush 721 parameter on the forwarder.
             *
             * @param forwarderAddress the address of the forwarder to toggle.
             * @param autoFlush whether to autoflush erc721 tokens
             */
            function setAutoFlush721(address forwarderAddress, bool autoFlush)
              external
              onlySigner
            {
              IForwarder forwarder = IForwarder(forwarderAddress);
              forwarder.setAutoFlush721(autoFlush);
            }
            /**
             * Sets the autoflush 721 parameter on the forwarder.
             *
             * @param forwarderAddress the address of the forwarder to toggle.
             * @param autoFlush whether to autoflush erc1155 tokens
             */
            function setAutoFlush1155(address forwarderAddress, bool autoFlush)
              external
              onlySigner
            {
              IForwarder forwarder = IForwarder(forwarderAddress);
              forwarder.setAutoFlush1155(autoFlush);
            }
            /**
             * Do common multisig verification for both eth sends and erc20token transfers
             *
             * @param toAddress the destination address to send an outgoing transaction
             * @param operationHash see Data Formats
             * @param signature see Data Formats
             * @param expireTime the number of seconds since 1970 for which this transaction is valid
             * @param sequenceId the unique sequence id obtainable from getNextSequenceId
             * returns address that has created the signature
             */
            function verifyMultiSig(
              address toAddress,
              bytes32 operationHash,
              bytes calldata signature,
              uint256 expireTime,
              uint256 sequenceId
            ) private returns (address) {
              address otherSigner = recoverAddressFromSignature(operationHash, signature);
              // Verify if we are in safe mode. In safe mode, the wallet can only send to signers
              require(!safeMode || isSigner(toAddress), 'External transfer in safe mode');
              // Verify that the transaction has not expired
              require(expireTime >= block.timestamp, 'Transaction expired');
              // Try to insert the sequence ID. Will revert if the sequence id was invalid
              tryInsertSequenceId(sequenceId);
              require(isSigner(otherSigner), 'Invalid signer');
              require(otherSigner != msg.sender, 'Signers cannot be equal');
              return otherSigner;
            }
            /**
             * ERC721 standard callback function for when a ERC721 is transfered.
             *
             * @param _operator The address of the nft contract
             * @param _from The address of the sender
             * @param _tokenId The token id of the nft
             * @param _data Additional data with no specified format, sent in call to `_to`
             */
            function onERC721Received(
              address _operator,
              address _from,
              uint256 _tokenId,
              bytes memory _data
            ) external virtual override returns (bytes4) {
              return this.onERC721Received.selector;
            }
            /**
             * @inheritdoc IERC1155Receiver
             */
            function onERC1155Received(
              address _operator,
              address _from,
              uint256 id,
              uint256 value,
              bytes calldata data
            ) external virtual override returns (bytes4) {
              return this.onERC1155Received.selector;
            }
            /**
             * @inheritdoc IERC1155Receiver
             */
            function onERC1155BatchReceived(
              address _operator,
              address _from,
              uint256[] calldata ids,
              uint256[] calldata values,
              bytes calldata data
            ) external virtual override returns (bytes4) {
              return this.onERC1155BatchReceived.selector;
            }
            /**
             * Irrevocably puts contract into safe mode. When in this mode, transactions may only be sent to signing addresses.
             */
            function activateSafeMode() external onlySigner {
              safeMode = true;
              emit SafeModeActivated(msg.sender);
            }
            /**
             * Gets signer's address using ecrecover
             * @param operationHash see Data Formats
             * @param signature see Data Formats
             * returns address recovered from the signature
             */
            function recoverAddressFromSignature(
              bytes32 operationHash,
              bytes memory signature
            ) private pure returns (address) {
              require(signature.length == 65, 'Invalid signature - wrong length');
              // We need to unpack the signature, which is given as an array of 65 bytes (like eth.sign)
              bytes32 r;
              bytes32 s;
              uint8 v;
              // solhint-disable-next-line
              assembly {
                r := mload(add(signature, 32))
                s := mload(add(signature, 64))
                v := and(mload(add(signature, 65)), 255)
              }
              if (v < 27) {
                v += 27; // Ethereum versions are 27 or 28 as opposed to 0 or 1 which is submitted by some signing libs
              }
              // protect against signature malleability
              // S value must be in the lower half orader
              // reference: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/051d340171a93a3d401aaaea46b4b62fa81e5d7c/contracts/cryptography/ECDSA.sol#L53
              require(
                uint256(s) <=
                  0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
                "ECDSA: invalid signature 's' value"
              );
              // note that this returns 0 if the signature is invalid
              // Since 0x0 can never be a signer, when the recovered signer address
              // is checked against our signer list, that 0x0 will cause an invalid signer failure
              return ecrecover(operationHash, v, r, s);
            }
            /**
             * Verify that the sequence id has not been used before and inserts it. Throws if the sequence ID was not accepted.
             * We collect a window of up to 10 recent sequence ids, and allow any sequence id that is not in the window and
             * greater than the minimum element in the window.
             * @param sequenceId to insert into array of stored ids
             */
            function tryInsertSequenceId(uint256 sequenceId) private onlySigner {
              // Keep a pointer to the lowest value element in the window
              uint256 lowestValueIndex = 0;
              // fetch recentSequenceIds into memory for function context to avoid unnecessary sloads
                uint256[SEQUENCE_ID_WINDOW_SIZE] memory _recentSequenceIds
               = recentSequenceIds;
              for (uint256 i = 0; i < SEQUENCE_ID_WINDOW_SIZE; i++) {
                require(_recentSequenceIds[i] != sequenceId, 'Sequence ID already used');
                if (_recentSequenceIds[i] < _recentSequenceIds[lowestValueIndex]) {
                  lowestValueIndex = i;
                }
              }
              // The sequence ID being used is lower than the lowest value in the window
              // so we cannot accept it as it may have been used before
              require(
                sequenceId > _recentSequenceIds[lowestValueIndex],
                'Sequence ID below window'
              );
              // Block sequence IDs which are much higher than the lowest value
              // This prevents people blocking the contract by using very large sequence IDs quickly
              require(
                sequenceId <=
                  (_recentSequenceIds[lowestValueIndex] + MAX_SEQUENCE_ID_INCREASE),
                'Sequence ID above maximum'
              );
              recentSequenceIds[lowestValueIndex] = sequenceId;
            }
            /**
             * Gets the next available sequence ID for signing when using executeAndConfirm
             * returns the sequenceId one higher than the highest currently stored
             */
            function getNextSequenceId() external view returns (uint256) {
              uint256 highestSequenceId = 0;
              for (uint256 i = 0; i < SEQUENCE_ID_WINDOW_SIZE; i++) {
                if (recentSequenceIds[i] > highestSequenceId) {
                  highestSequenceId = recentSequenceIds[i];
                }
              }
              return highestSequenceId + 1;
            }
          }
          // SPDX-License-Identifier: GPL-3.0-or-later
          // source: https://github.com/Uniswap/solidity-lib/blob/master/contracts/libraries/TransferHelper.sol
          pragma solidity 0.8.10;
          import '@openzeppelin/contracts/utils/Address.sol';
          // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
          library TransferHelper {
            function safeTransfer(
              address token,
              address to,
              uint256 value
            ) internal {
              // bytes4(keccak256(bytes('transfer(address,uint256)')));
              (bool success, bytes memory data) = token.call(
                abi.encodeWithSelector(0xa9059cbb, to, value)
              );
              require(
                success && (data.length == 0 || abi.decode(data, (bool))),
                'TransferHelper::safeTransfer: transfer failed'
              );
            }
            function safeTransferFrom(
              address token,
              address from,
              address to,
              uint256 value
            ) internal {
              // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
              (bool success, bytes memory returndata) = token.call(
                abi.encodeWithSelector(0x23b872dd, from, to, value)
              );
              Address.verifyCallResult(
                success,
                returndata,
                'TransferHelper::transferFrom: transferFrom failed'
              );
            }
          }
          // SPDX-License-Identifier: UNLICENSED
          pragma solidity 0.8.10;
          /**
           * Contract that exposes the needed erc20 token functions
           */
          abstract contract ERC20Interface {
            // Send _value amount of tokens to address _to
            function transfer(address _to, uint256 _value)
              public
              virtual
              returns (bool success);
            // Get the account balance of another account with address _owner
            function balanceOf(address _owner)
              public
              virtual
              view
              returns (uint256 balance);
          }
          pragma solidity ^0.8.0;
          import '@openzeppelin/contracts/utils/introspection/IERC165.sol';
          interface IForwarder is IERC165 {
            /**
             * Sets the autoflush721 parameter.
             *
             * @param autoFlush whether to autoflush erc721 tokens
             */
            function setAutoFlush721(bool autoFlush) external;
            /**
             * Sets the autoflush1155 parameter.
             *
             * @param autoFlush whether to autoflush erc1155 tokens
             */
            function setAutoFlush1155(bool autoFlush) external;
            /**
             * Execute a token transfer of the full balance from the forwarder token to the parent address
             *
             * @param tokenContractAddress the address of the erc20 token contract
             */
            function flushTokens(address tokenContractAddress) external;
            /**
             * Execute a nft transfer from the forwarder to the parent address
             *
             * @param tokenContractAddress the address of the ERC721 NFT contract
             * @param tokenId The token id of the nft
             */
            function flushERC721Token(address tokenContractAddress, uint256 tokenId)
              external;
            /**
             * Execute a nft transfer from the forwarder to the parent address.
             *
             * @param tokenContractAddress the address of the ERC1155 NFT contract
             * @param tokenId The token id of the nft
             */
            function flushERC1155Tokens(address tokenContractAddress, uint256 tokenId)
              external;
            /**
             * Execute a batch nft transfer from the forwarder to the parent address.
             *
             * @param tokenContractAddress the address of the ERC1155 NFT contract
             * @param tokenIds The token ids of the nfts
             */
            function batchFlushERC1155Tokens(
              address tokenContractAddress,
              uint256[] calldata tokenIds
            ) external;
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)
          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
          // OpenZeppelin Contracts v4.4.1 (token/ERC1155/utils/ERC1155Receiver.sol)
          pragma solidity ^0.8.0;
          import "../IERC1155Receiver.sol";
          import "../../../utils/introspection/ERC165.sol";
          /**
           * @dev _Available since v3.1._
           */
          abstract contract ERC1155Receiver is ERC165, IERC1155Receiver {
              /**
               * @dev See {IERC165-supportsInterface}.
               */
              function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
                  return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (utils/Address.sol)
          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;
                  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");
                  (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");
                  (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");
                  (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");
                  (bool success, bytes memory returndata) = target.delegatecall(data);
                  return verifyCallResult(success, returndata, errorMessage);
              }
              /**
               * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
               * revert reason using the provided one.
               *
               * _Available since v4.3._
               */
              function verifyCallResult(
                  bool success,
                  bytes memory returndata,
                  string memory errorMessage
              ) internal pure returns (bytes memory) {
                  if (success) {
                      return returndata;
                  } else {
                      // 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
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert(errorMessage);
                      }
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev Interface of the ERC165 standard, as defined in the
           * https://eips.ethereum.org/EIPS/eip-165[EIP].
           *
           * Implementers can declare support of contract interfaces, which can then be
           * queried by others ({ERC165Checker}).
           *
           * For an implementation, see {ERC165}.
           */
          interface IERC165 {
              /**
               * @dev Returns true if this contract implements the interface defined by
               * `interfaceId`. See the corresponding
               * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
               * to learn more about how these ids are created.
               *
               * This function call must use less than 30 000 gas.
               */
              function supportsInterface(bytes4 interfaceId) external view returns (bool);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155Receiver.sol)
          pragma solidity ^0.8.0;
          import "../../utils/introspection/IERC165.sol";
          /**
           * @dev _Available since v3.1._
           */
          interface IERC1155Receiver is IERC165 {
              /**
                  @dev Handles the receipt of a single ERC1155 token type. This function is
                  called at the end of a `safeTransferFrom` after the balance has been updated.
                  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
          // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
          pragma solidity ^0.8.0;
          import "./IERC165.sol";
          /**
           * @dev Implementation of the {IERC165} interface.
           *
           * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
           * for the additional interface id that will be supported. For example:
           *
           * ```solidity
           * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
           *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
           * }
           * ```
           *
           * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
           */
          abstract contract ERC165 is IERC165 {
              /**
               * @dev See {IERC165-supportsInterface}.
               */
              function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                  return interfaceId == type(IERC165).interfaceId;
              }
          }
          

          File 5 of 5: Forwarder
          // SPDX-License-Identifier: Apache-2.0
          pragma solidity 0.8.10;
          import '@openzeppelin/contracts/token/ERC1155/IERC1155.sol';
          import '@openzeppelin/contracts/token/ERC721/IERC721.sol';
          import '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol';
          import '@openzeppelin/contracts/token/ERC1155/utils/ERC1155Receiver.sol';
          import './ERC20Interface.sol';
          import './TransferHelper.sol';
          import './IForwarder.sol';
          /**
           * Contract that will forward any incoming Ether to the creator of the contract
           *
           */
          contract Forwarder is IERC721Receiver, ERC1155Receiver, IForwarder {
            // Address to which any funds sent to this contract will be forwarded
            address public parentAddress;
            bool public autoFlush721 = true;
            bool public autoFlush1155 = true;
            event ForwarderDeposited(address from, uint256 value, bytes data);
            /**
             * Initialize the contract, and sets the destination address to that of the creator
             */
            function init(
              address _parentAddress,
              bool _autoFlush721,
              bool _autoFlush1155
            ) external onlyUninitialized {
              parentAddress = _parentAddress;
              uint256 value = address(this).balance;
              // set whether we want to automatically flush erc721/erc1155 tokens or not
              autoFlush721 = _autoFlush721;
              autoFlush1155 = _autoFlush1155;
              if (value == 0) {
                return;
              }
              (bool success, ) = parentAddress.call{ value: value }('');
              require(success, 'Flush failed');
              // NOTE: since we are forwarding on initialization,
              // we don't have the context of the original sender.
              // We still emit an event about the forwarding but set
              // the sender to the forwarder itself
              emit ForwarderDeposited(address(this), value, msg.data);
            }
            /**
             * Modifier that will execute internal code block only if the sender is the parent address
             */
            modifier onlyParent {
              require(msg.sender == parentAddress, 'Only Parent');
              _;
            }
            /**
             * Modifier that will execute internal code block only if the contract has not been initialized yet
             */
            modifier onlyUninitialized {
              require(parentAddress == address(0x0), 'Already initialized');
              _;
            }
            /**
             * Default function; Gets called when data is sent but does not match any other function
             */
            fallback() external payable {
              flush();
            }
            /**
             * Default function; Gets called when Ether is deposited with no data, and forwards it to the parent address
             */
            receive() external payable {
              flush();
            }
            /**
             * @inheritdoc IForwarder
             */
            function setAutoFlush721(bool autoFlush)
              external
              virtual
              override
              onlyParent
            {
              autoFlush721 = autoFlush;
            }
            /**
             * @inheritdoc IForwarder
             */
            function setAutoFlush1155(bool autoFlush)
              external
              virtual
              override
              onlyParent
            {
              autoFlush1155 = autoFlush;
            }
            /**
             * ERC721 standard callback function for when a ERC721 is transfered. The forwarder will send the nft
             * to the base wallet once the nft contract invokes this method after transfering the nft.
             *
             * @param _operator The address which called `safeTransferFrom` function
             * @param _from The address of the sender
             * @param _tokenId The token id of the nft
             * @param data Additional data with no specified format, sent in call to `_to`
             */
            function onERC721Received(
              address _operator,
              address _from,
              uint256 _tokenId,
              bytes memory data
            ) external virtual override returns (bytes4) {
              if (autoFlush721) {
                IERC721 instance = IERC721(msg.sender);
                require(
                  instance.supportsInterface(type(IERC721).interfaceId),
                  'The caller does not support the ERC721 interface'
                );
                // this won't work for ERC721 re-entrancy
                instance.safeTransferFrom(address(this), parentAddress, _tokenId, data);
              }
              return this.onERC721Received.selector;
            }
            function callFromParent(
              address target,
              uint256 value,
              bytes calldata data
            ) external onlyParent returns (bytes memory) {
              (bool success, bytes memory returnedData) = target.call{ value: value }(
                data
              );
              require(success, 'Parent call execution failed');
              return returnedData;
            }
            /**
             * @inheritdoc IERC1155Receiver
             */
            function onERC1155Received(
              address _operator,
              address _from,
              uint256 id,
              uint256 value,
              bytes calldata data
            ) external virtual override returns (bytes4) {
              IERC1155 instance = IERC1155(msg.sender);
              require(
                instance.supportsInterface(type(IERC1155).interfaceId),
                'The caller does not support the IERC1155 interface'
              );
              if (autoFlush1155) {
                instance.safeTransferFrom(address(this), parentAddress, id, value, data);
              }
              return this.onERC1155Received.selector;
            }
            /**
             * @inheritdoc IERC1155Receiver
             */
            function onERC1155BatchReceived(
              address _operator,
              address _from,
              uint256[] calldata ids,
              uint256[] calldata values,
              bytes calldata data
            ) external virtual override returns (bytes4) {
              IERC1155 instance = IERC1155(msg.sender);
              require(
                instance.supportsInterface(type(IERC1155).interfaceId),
                'The caller does not support the IERC1155 interface'
              );
              if (autoFlush1155) {
                instance.safeBatchTransferFrom(
                  address(this),
                  parentAddress,
                  ids,
                  values,
                  data
                );
              }
              return this.onERC1155BatchReceived.selector;
            }
            /**
             * @inheritdoc IForwarder
             */
            function flushTokens(address tokenContractAddress)
              external
              virtual
              override
              onlyParent
            {
              ERC20Interface instance = ERC20Interface(tokenContractAddress);
              address forwarderAddress = address(this);
              uint256 forwarderBalance = instance.balanceOf(forwarderAddress);
              if (forwarderBalance == 0) {
                return;
              }
              TransferHelper.safeTransfer(
                tokenContractAddress,
                parentAddress,
                forwarderBalance
              );
            }
            /**
             * @inheritdoc IForwarder
             */
            function flushERC721Token(address tokenContractAddress, uint256 tokenId)
              external
              virtual
              override
              onlyParent
            {
              IERC721 instance = IERC721(tokenContractAddress);
              require(
                instance.supportsInterface(type(IERC721).interfaceId),
                'The tokenContractAddress does not support the ERC721 interface'
              );
              address ownerAddress = instance.ownerOf(tokenId);
              instance.transferFrom(ownerAddress, parentAddress, tokenId);
            }
            /**
             * @inheritdoc IForwarder
             */
            function flushERC1155Tokens(address tokenContractAddress, uint256 tokenId)
              external
              virtual
              override
              onlyParent
            {
              IERC1155 instance = IERC1155(tokenContractAddress);
              require(
                instance.supportsInterface(type(IERC1155).interfaceId),
                'The caller does not support the IERC1155 interface'
              );
              address forwarderAddress = address(this);
              uint256 forwarderBalance = instance.balanceOf(forwarderAddress, tokenId);
              instance.safeTransferFrom(
                forwarderAddress,
                parentAddress,
                tokenId,
                forwarderBalance,
                ''
              );
            }
            /**
             * @inheritdoc IForwarder
             */
            function batchFlushERC1155Tokens(
              address tokenContractAddress,
              uint256[] calldata tokenIds
            ) external virtual override onlyParent {
              IERC1155 instance = IERC1155(tokenContractAddress);
              require(
                instance.supportsInterface(type(IERC1155).interfaceId),
                'The caller does not support the IERC1155 interface'
              );
              address forwarderAddress = address(this);
              uint256[] memory amounts = new uint256[](tokenIds.length);
              for (uint256 i = 0; i < tokenIds.length; i++) {
                amounts[i] = instance.balanceOf(forwarderAddress, tokenIds[i]);
              }
              instance.safeBatchTransferFrom(
                forwarderAddress,
                parentAddress,
                tokenIds,
                amounts,
                ''
              );
            }
            /**
             * Flush the entire balance of the contract to the parent address.
             */
            function flush() public {
              uint256 value = address(this).balance;
              if (value == 0) {
                return;
              }
              (bool success, ) = parentAddress.call{ value: value }('');
              require(success, 'Flush failed');
              emit ForwarderDeposited(msg.sender, value, msg.data);
            }
            /**
             * @inheritdoc IERC165
             */
            function supportsInterface(bytes4 interfaceId)
              public
              virtual
              override(ERC1155Receiver, IERC165)
              view
              returns (bool)
            {
              return
                interfaceId == type(IForwarder).interfaceId ||
                super.supportsInterface(interfaceId);
            }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155.sol)
          pragma solidity ^0.8.0;
          import "../../utils/introspection/IERC165.sol";
          /**
           * @dev Required interface of an ERC1155 compliant contract, as defined in the
           * https://eips.ethereum.org/EIPS/eip-1155[EIP].
           *
           * _Available since v3.1._
           */
          interface IERC1155 is IERC165 {
              /**
               * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
               */
              event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
              /**
               * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
               * transfers.
               */
              event TransferBatch(
                  address indexed operator,
                  address indexed from,
                  address indexed to,
                  uint256[] ids,
                  uint256[] values
              );
              /**
               * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
               * `approved`.
               */
              event ApprovalForAll(address indexed account, address indexed operator, bool approved);
              /**
               * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
               *
               * If an {URI} event was emitted for `id`, the standard
               * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
               * returned by {IERC1155MetadataURI-uri}.
               */
              event URI(string value, uint256 indexed id);
              /**
               * @dev Returns the amount of tokens of token type `id` owned by `account`.
               *
               * Requirements:
               *
               * - `account` cannot be the zero address.
               */
              function balanceOf(address account, uint256 id) external view returns (uint256);
              /**
               * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
               *
               * Requirements:
               *
               * - `accounts` and `ids` must have the same length.
               */
              function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
                  external
                  view
                  returns (uint256[] memory);
              /**
               * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
               *
               * Emits an {ApprovalForAll} event.
               *
               * Requirements:
               *
               * - `operator` cannot be the caller.
               */
              function setApprovalForAll(address operator, bool approved) external;
              /**
               * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
               *
               * See {setApprovalForAll}.
               */
              function isApprovedForAll(address account, address operator) external view returns (bool);
              /**
               * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
               *
               * Emits a {TransferSingle} event.
               *
               * Requirements:
               *
               * - `to` cannot be the zero address.
               * - If the caller is not `from`, it must 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
          // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)
          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;
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)
          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
          // OpenZeppelin Contracts v4.4.1 (token/ERC1155/utils/ERC1155Receiver.sol)
          pragma solidity ^0.8.0;
          import "../IERC1155Receiver.sol";
          import "../../../utils/introspection/ERC165.sol";
          /**
           * @dev _Available since v3.1._
           */
          abstract contract ERC1155Receiver is ERC165, IERC1155Receiver {
              /**
               * @dev See {IERC165-supportsInterface}.
               */
              function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
                  return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
              }
          }
          // SPDX-License-Identifier: UNLICENSED
          pragma solidity 0.8.10;
          /**
           * Contract that exposes the needed erc20 token functions
           */
          abstract contract ERC20Interface {
            // Send _value amount of tokens to address _to
            function transfer(address _to, uint256 _value)
              public
              virtual
              returns (bool success);
            // Get the account balance of another account with address _owner
            function balanceOf(address _owner)
              public
              virtual
              view
              returns (uint256 balance);
          }
          // SPDX-License-Identifier: GPL-3.0-or-later
          // source: https://github.com/Uniswap/solidity-lib/blob/master/contracts/libraries/TransferHelper.sol
          pragma solidity 0.8.10;
          import '@openzeppelin/contracts/utils/Address.sol';
          // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
          library TransferHelper {
            function safeTransfer(
              address token,
              address to,
              uint256 value
            ) internal {
              // bytes4(keccak256(bytes('transfer(address,uint256)')));
              (bool success, bytes memory data) = token.call(
                abi.encodeWithSelector(0xa9059cbb, to, value)
              );
              require(
                success && (data.length == 0 || abi.decode(data, (bool))),
                'TransferHelper::safeTransfer: transfer failed'
              );
            }
            function safeTransferFrom(
              address token,
              address from,
              address to,
              uint256 value
            ) internal {
              // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
              (bool success, bytes memory returndata) = token.call(
                abi.encodeWithSelector(0x23b872dd, from, to, value)
              );
              Address.verifyCallResult(
                success,
                returndata,
                'TransferHelper::transferFrom: transferFrom failed'
              );
            }
          }
          pragma solidity ^0.8.0;
          import '@openzeppelin/contracts/utils/introspection/IERC165.sol';
          interface IForwarder is IERC165 {
            /**
             * Sets the autoflush721 parameter.
             *
             * @param autoFlush whether to autoflush erc721 tokens
             */
            function setAutoFlush721(bool autoFlush) external;
            /**
             * Sets the autoflush1155 parameter.
             *
             * @param autoFlush whether to autoflush erc1155 tokens
             */
            function setAutoFlush1155(bool autoFlush) external;
            /**
             * Execute a token transfer of the full balance from the forwarder token to the parent address
             *
             * @param tokenContractAddress the address of the erc20 token contract
             */
            function flushTokens(address tokenContractAddress) external;
            /**
             * Execute a nft transfer from the forwarder to the parent address
             *
             * @param tokenContractAddress the address of the ERC721 NFT contract
             * @param tokenId The token id of the nft
             */
            function flushERC721Token(address tokenContractAddress, uint256 tokenId)
              external;
            /**
             * Execute a nft transfer from the forwarder to the parent address.
             *
             * @param tokenContractAddress the address of the ERC1155 NFT contract
             * @param tokenId The token id of the nft
             */
            function flushERC1155Tokens(address tokenContractAddress, uint256 tokenId)
              external;
            /**
             * Execute a batch nft transfer from the forwarder to the parent address.
             *
             * @param tokenContractAddress the address of the ERC1155 NFT contract
             * @param tokenIds The token ids of the nfts
             */
            function batchFlushERC1155Tokens(
              address tokenContractAddress,
              uint256[] calldata tokenIds
            ) external;
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev Interface of the ERC165 standard, as defined in the
           * https://eips.ethereum.org/EIPS/eip-165[EIP].
           *
           * Implementers can declare support of contract interfaces, which can then be
           * queried by others ({ERC165Checker}).
           *
           * For an implementation, see {ERC165}.
           */
          interface IERC165 {
              /**
               * @dev Returns true if this contract implements the interface defined by
               * `interfaceId`. See the corresponding
               * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
               * to learn more about how these ids are created.
               *
               * This function call must use less than 30 000 gas.
               */
              function supportsInterface(bytes4 interfaceId) external view returns (bool);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155Receiver.sol)
          pragma solidity ^0.8.0;
          import "../../utils/introspection/IERC165.sol";
          /**
           * @dev _Available since v3.1._
           */
          interface IERC1155Receiver is IERC165 {
              /**
                  @dev Handles the receipt of a single ERC1155 token type. This function is
                  called at the end of a `safeTransferFrom` after the balance has been updated.
                  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
          // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
          pragma solidity ^0.8.0;
          import "./IERC165.sol";
          /**
           * @dev Implementation of the {IERC165} interface.
           *
           * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
           * for the additional interface id that will be supported. For example:
           *
           * ```solidity
           * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
           *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
           * }
           * ```
           *
           * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
           */
          abstract contract ERC165 is IERC165 {
              /**
               * @dev See {IERC165-supportsInterface}.
               */
              function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                  return interfaceId == type(IERC165).interfaceId;
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (utils/Address.sol)
          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;
                  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");
                  (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");
                  (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");
                  (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");
                  (bool success, bytes memory returndata) = target.delegatecall(data);
                  return verifyCallResult(success, returndata, errorMessage);
              }
              /**
               * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
               * revert reason using the provided one.
               *
               * _Available since v4.3._
               */
              function verifyCallResult(
                  bool success,
                  bytes memory returndata,
                  string memory errorMessage
              ) internal pure returns (bytes memory) {
                  if (success) {
                      return returndata;
                  } else {
                      // 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
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert(errorMessage);
                      }
                  }
              }
          }