{"file_path":"/contracts/AlowanceModule.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.7.0 <0.8.0;\n\nimport \"./Enum.sol\";\nimport \"./SignatureDecoder.sol\";\n\ninterface GnosisSafe {\n    /// @dev Allows a Module to execute a Safe transaction without any further confirmations.\n    /// @param to Destination address of module transaction.\n    /// @param value Ether value of module transaction.\n    /// @param data Data payload of module transaction.\n    /// @param operation Operation type of module transaction.\n    function execTransactionFromModule(address to, uint256 value, bytes calldata data, Enum.Operation operation)\n        external\n        returns (bool success);\n}\n\ncontract AllowanceModule is SignatureDecoder {\n\n    string public constant NAME = \"Allowance Module\";\n    string public constant VERSION = \"0.1.0\";\n\n    bytes32 public constant DOMAIN_SEPARATOR_TYPEHASH = 0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218;\n    // keccak256(\n    //     \"EIP712Domain(uint256 chainId,address verifyingContract)\"\n    // );\n\n    bytes32 public constant ALLOWANCE_TRANSFER_TYPEHASH = 0x80b006280932094e7cc965863eb5118dc07e5d272c6670c4a7c87299e04fceeb;\n    // keccak256(\n    //     \"AllowanceTransfer(address safe,address token,uint96 amount,address paymentToken,uint96 payment,uint16 nonce)\"\n    // );\n\n    // Safe -> Delegate -> Allowance\n    mapping(address => mapping (address => mapping(address => Allowance))) public allowances;\n    // Safe -> Delegate -> Tokens\n    mapping(address => mapping (address => address[])) public tokens;\n    // Safe -> Delegates double linked list entry points\n    mapping(address => uint48) public delegatesStart;\n    // Safe -> Delegates double linked list\n    mapping(address => mapping (uint48 => Delegate)) public delegates;\n\n    // We use a double linked list for the delegates. The id is the first 6 bytes. \n    // To double check the address in case of collision, the address is part of the struct.\n    struct Delegate {\n        address delegate;\n        uint48 prev;\n        uint48 next;\n    }\n\n    // The allowance info is optimized to fit into one word of storage.\n    struct Allowance {\n        uint96 amount;\n        uint96 spent;\n        uint16 resetTimeMin; // Maximum reset time span is 65k minutes\n        uint32 lastResetMin;\n        uint16 nonce;\n    }\n\n    event AddDelegate(address indexed safe, address delegate);\n    event RemoveDelegate(address indexed safe, address delegate);\n    event ExecuteAllowanceTransfer(address indexed safe, address delegate, address token, address to, uint96 value, uint16 nonce);\n    event PayAllowanceTransfer(address indexed safe, address delegate, address paymentToken, address paymentReceiver, uint96 payment);\n    event SetAllowance(address indexed safe, address delegate, address token, uint96 allowanceAmount, uint16 resetTime);\n    event ResetAllowance(address indexed safe, address delegate, address token);\n    event DeleteAllowance(address indexed safe, address delegate, address token);\n\n    /// @dev Allows to update the allowance for a specified token. This can only be done via a Safe transaction.\n    /// @param delegate Delegate whose allowance should be updated.\n    /// @param token Token contract address.\n    /// @param allowanceAmount allowance in smallest token unit.\n    /// @param resetTimeMin Time after which the allowance should reset\n    /// @param resetBaseMin Time based on which the reset time should be increased\n    function setAllowance(address delegate, address token, uint96 allowanceAmount, uint16 resetTimeMin, uint32 resetBaseMin)\n        public\n    {\n        require(delegate != address(0), \"delegate != address(0)\");\n        require(delegates[msg.sender][uint48(delegate)].delegate == delegate, \"delegates[msg.sender][uint48(delegate)].delegate == delegate\");\n        Allowance memory allowance = getAllowance(msg.sender, delegate, token);\n        if (allowance.nonce == 0) { // New token\n            // Nonce should never be 0 once allowance has been activated\n            allowance.nonce = 1;\n            tokens[msg.sender][delegate].push(token);\n        }\n        // Divide by 60 to get current time in minutes\n        // solium-disable-next-line security/no-block-members\n        uint32 currentMin = uint32(block.timestamp / 60);\n        if (resetBaseMin > 0) {\n            require(resetBaseMin <= currentMin, \"resetBaseMin <= currentMin\");\n            allowance.lastResetMin = currentMin - ((currentMin - resetBaseMin) % resetTimeMin);\n        } else if (allowance.lastResetMin == 0) {\n            allowance.lastResetMin = currentMin;\n        }\n        allowance.resetTimeMin = resetTimeMin;\n        allowance.amount = allowanceAmount;\n        updateAllowance(msg.sender, delegate, token, allowance);\n        emit SetAllowance(msg.sender, delegate, token, allowanceAmount, resetTimeMin);\n    }\n\n    function getAllowance(address safe, address delegate, address token) private view returns (Allowance memory allowance) {\n        allowance = allowances[safe][delegate][token];\n        // solium-disable-next-line security/no-block-members\n        uint32 currentMin = uint32(block.timestamp / 60);\n        // Check if we should reset the time. We do this on load to minimize storage read/ writes\n        if (allowance.resetTimeMin > 0 && allowance.lastResetMin <= currentMin - allowance.resetTimeMin) {\n            allowance.spent = 0;\n            // Resets happen in regular intervals and `lastResetMin` should be aligned to that\n            allowance.lastResetMin = currentMin - ((currentMin - allowance.lastResetMin) % allowance.resetTimeMin);\n        }\n        return allowance;\n    }\n\n    function updateAllowance(address safe, address delegate, address token, Allowance memory allowance) private {\n        allowances[safe][delegate][token] = allowance;\n    }\n\n    /// @dev Allows to reset the allowance for a specific delegate and token.\n    /// @param delegate Delegate whose allowance should be updated.\n    /// @param token Token contract address.\n    function resetAllowance(address delegate, address token) public {\n        Allowance memory allowance = getAllowance(msg.sender, delegate, token);\n        allowance.spent = 0;\n        updateAllowance(msg.sender, delegate, token, allowance);\n        emit ResetAllowance(msg.sender, delegate, token);\n    }\n\n    /// @dev Allows to remove the allowance for a specific delegate and token. This will set all values except the `nonce` to 0.\n    /// @param delegate Delegate whose allowance should be updated.\n    /// @param token Token contract address.\n    function deleteAllowance(address delegate, address token)\n        public\n    {\n        Allowance memory allowance = getAllowance(msg.sender, delegate, token);\n        allowance.amount = 0;\n        allowance.spent = 0;\n        allowance.resetTimeMin = 0;\n        allowance.lastResetMin = 0;\n        updateAllowance(msg.sender, delegate, token, allowance);\n        emit DeleteAllowance(msg.sender, delegate, token);\n    }\n\n    /// @dev Allows to use the allowance to perform a transfer.\n    /// @param safe The Safe whose funds should be used.\n    /// @param token Token contract address.\n    /// @param to Address that should receive the tokens.\n    /// @param amount Amount that should be transferred.\n    /// @param paymentToken Token that should be used to pay for the execution of the transfer.\n    /// @param payment Amount to should be paid for executing the transfer.\n    /// @param delegate Delegate whose allowance should be updated.\n    /// @param signature Signature generated by the delegate to authorize the transfer.\n    function executeAllowanceTransfer(\n        GnosisSafe safe,\n        address token,\n        address payable to,\n        uint96 amount,\n        address paymentToken,\n        uint96 payment,\n        address delegate,\n        bytes memory signature\n    ) public {\n        // Get current state\n        Allowance memory allowance = getAllowance(address(safe), delegate, token);\n        bytes memory transferHashData = generateTransferHashData(address(safe), token, to, amount, paymentToken, payment, allowance.nonce);\n\n        // Update state\n        allowance.nonce = allowance.nonce + 1;\n        uint96 newSpent = allowance.spent + amount;\n        // Check new spent amount and overflow\n        require(newSpent > allowance.spent && newSpent <= allowance.amount, \"newSpent > allowance.spent && newSpent <= allowance.amount\");\n        allowance.spent = newSpent;\n        if (payment > 0) {\n            // Use updated allowance if token and paymentToken are the same\n            Allowance memory paymentAllowance = paymentToken == token ? allowance : getAllowance(address(safe), delegate, paymentToken);\n            newSpent = paymentAllowance.spent + payment;\n            // Check new spent amount and overflow\n            require(newSpent > paymentAllowance.spent && newSpent <= paymentAllowance.amount, \"newSpent > paymentAllowance.spent && newSpent <= paymentAllowance.amount\");\n            paymentAllowance.spent = newSpent;\n            // Update payment allowance if different from allowance\n            if (paymentToken != token) updateAllowance(address(safe), delegate, paymentToken, paymentAllowance);\n        }\n        updateAllowance(address(safe), delegate, token, allowance);\n\n        // Perform external interactions\n        // Check signature\n        checkSignature(delegate, signature, transferHashData, safe);\n\n        if (payment > 0) {\n            // Transfer payment\n            // solium-disable-next-line security/no-tx-origin\n            transfer(safe, paymentToken, tx.origin, payment);\n            // solium-disable-next-line security/no-tx-origin\n            emit PayAllowanceTransfer(address(safe), delegate, paymentToken, tx.origin, payment);\n        }\n        // Transfer token\n        transfer(safe, token, to, amount);\n        emit ExecuteAllowanceTransfer(address(safe), delegate, token, to, amount, allowance.nonce - 1);\n    }\n\n    /// @dev Returns the chain id used by this contract.\n    function getChainId() public pure returns (uint256) {\n        uint256 id;\n        // solium-disable-next-line security/no-inline-assembly\n        assembly {\n            id := chainid()\n        }\n        return id;\n    }\n\n    /// @dev Generates the data for the transfer hash (required for signing)\n    function generateTransferHashData(\n        address safe,\n        address token,\n        address to,\n        uint96 amount,\n        address paymentToken,\n        uint96 payment,\n        uint16 nonce\n    ) private view returns (bytes memory) {\n        uint256 chainId = getChainId();\n        bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, chainId, this));\n        bytes32 transferHash = keccak256(\n            abi.encode(ALLOWANCE_TRANSFER_TYPEHASH, safe, token, to, amount, paymentToken, payment, nonce)\n        );\n        return abi.encodePacked(byte(0x19), byte(0x01), domainSeparator, transferHash);\n    }\n\n    /// @dev Generates the transfer hash that should be signed to authorize a transfer\n    function generateTransferHash(\n        address safe,\n        address token,\n        address to,\n        uint96 amount,\n        address paymentToken,\n        uint96 payment,\n        uint16 nonce\n    ) public view returns (bytes32) {\n        return keccak256(generateTransferHashData(\n            safe, token, to, amount, paymentToken, payment, nonce\n        ));\n    }\n\n    function checkSignature(address expectedDelegate, bytes memory signature, bytes memory transferHashData, GnosisSafe safe) private view {\n        address signer = recoverSignature(signature, transferHashData);\n        require(\n            expectedDelegate == signer && delegates[address(safe)][uint48(signer)].delegate == signer,\n            \"expectedDelegate == signer && delegates[address(safe)][uint48(signer)].delegate == signer\"\n        );\n    }\n\n    // We use the same format as used for the Safe contract, except that we only support exactly 1 signature and no contract signatures.\n    function recoverSignature(bytes memory signature, bytes memory transferHashData) private view returns (address owner) {\n        // If there is no signature data msg.sender should be used\n        if (signature.length == 0) return msg.sender;\n        // Check that the provided signature data is as long as 1 encoded ecsda signature\n        require(signature.length == 65, \"signatures.length == 65\");\n        uint8 v;\n        bytes32 r;\n        bytes32 s;\n        (v, r, s) = signatureSplit(signature, 0);\n        // If v is 0 then it is a contract signature\n        if (v == 0) {\n            revert(\"Contract signatures are not supported by this module\");\n        } else if (v == 1) {\n            // If v is 1 we also use msg.sender, this is so that we are compatible to the GnosisSafe signature scheme\n            owner = msg.sender;\n        } else if (v > 30) {\n            // To support eth_sign and similar we adjust v and hash the transferHashData with the Ethereum message prefix before applying ecrecover\n            owner = ecrecover(keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", keccak256(transferHashData))), v - 4, r, s);\n        } else {\n            // Use ecrecover with the messageHash for EOA signatures\n            owner = ecrecover(keccak256(transferHashData), v, r, s);\n        }\n        // 0 for the recovered owner indicates that an error happened.\n        require(owner != address(0), \"owner != address(0)\");\n    }\n\n    function transfer(GnosisSafe safe, address token, address payable to, uint96 amount) private {\n        if (token == address(0)) {\n            // solium-disable-next-line security/no-send\n            require(safe.execTransactionFromModule(to, amount, \"\", Enum.Operation.Call), \"Could not execute ether transfer\");\n        } else {\n            bytes memory data = abi.encodeWithSignature(\"transfer(address,uint256)\", to, amount);\n            require(safe.execTransactionFromModule(token, 0, data, Enum.Operation.Call), \"Could not execute token transfer\");\n        }\n    }\n\n    function getTokens(address safe, address delegate) public view returns (address[] memory) {\n        return tokens[safe][delegate];\n    }\n\n    function getTokenAllowance(address safe, address delegate, address token) public view returns (uint256[5] memory) {\n        Allowance memory allowance = getAllowance(safe, delegate, token);\n        return [\n            uint256(allowance.amount),\n            uint256(allowance.spent),\n            uint256(allowance.resetTimeMin),\n            uint256(allowance.lastResetMin),\n            uint256(allowance.nonce)\n        ];\n    }\n\n    /// @dev Allows to add a delegate.\n    /// @param delegate Delegate that should be added.\n    function addDelegate(address delegate) public {\n        uint48 index = uint48(delegate);\n        require(index != uint(0), \"index != uint(0)\");\n        address currentDelegate = delegates[msg.sender][index].delegate;\n        if(currentDelegate != address(0)) {\n            // We have a collision for the indices of delegates\n            require(currentDelegate == delegate, \"currentDelegate == delegate\");\n            // Delegate already exists, nothing to do\n            return;\n        }\n        uint48 startIndex = delegatesStart[msg.sender];\n        delegates[msg.sender][index] = Delegate(delegate, 0, startIndex);\n        delegates[msg.sender][startIndex].prev = index;\n        delegatesStart[msg.sender] = index;\n        emit AddDelegate(msg.sender, delegate);\n    }\n\n    /// @dev Allows to remove a delegate.\n    /// @param delegate Delegate that should be removed.\n    /// @param removeAllowances Indicator if allowances should also be removed. This should be set to `true` unless this causes an out of gas, in this case the allowances should be \"manually\" deleted via `deleteAllowance`.\n    function removeDelegate(address delegate, bool removeAllowances) public {\n        Delegate memory current = delegates[msg.sender][uint48(delegate)];\n        // Delegate doesn't exists, nothing to do\n        if(current.delegate == address(0)) return;\n        if (removeAllowances) {\n            address[] storage delegateTokens = tokens[msg.sender][delegate];\n            for (uint256 i = 0; i < delegateTokens.length; i++) {\n                address token = delegateTokens[i];\n                // Set all allowance params except the nonce to 0\n                Allowance memory allowance = getAllowance(msg.sender, delegate, token);\n                allowance.amount = 0;\n                allowance.spent = 0;\n                allowance.resetTimeMin = 0;\n                allowance.lastResetMin = 0;\n                updateAllowance(msg.sender, delegate, token, allowance);\n                emit DeleteAllowance(msg.sender, delegate, token);\n            }\n        }\n        if (current.prev == 0) {\n            delegatesStart[msg.sender] = current.next;\n        } else {\n            delegates[msg.sender][current.prev].next = current.next;\n        }\n        if (current.next != 0) {\n            delegates[msg.sender][current.next].prev = current.prev;\n        }\n        delete delegates[msg.sender][uint48(delegate)];\n        emit RemoveDelegate(msg.sender, delegate);\n    }\n\n    function getDelegates(address safe, uint48 start, uint8 pageSize) public view returns (address[] memory results, uint48 next) {\n        results = new address[](pageSize);\n        uint8 i = 0;\n        uint48 initialIndex = (start != 0) ? start : delegatesStart[safe];\n        Delegate memory current = delegates[safe][initialIndex];\n        while(current.delegate != address(0) && i < pageSize) {\n            results[i] = current.delegate;\n            i++;\n            current = delegates[safe][current.next];\n        }\n        next = uint48(current.delegate);\n        // Set the length of the array the number that has been used.\n        // solium-disable-next-line security/no-inline-assembly\n        assembly {\n            mstore(results, i)\n        }\n    }\n}","deployed_bytecode":"0x608060405234801561001057600080fd5b50600436106101215760003560e01c8063b713c9d4116100ad578063dd43a79f11610071578063dd43a79f1461093c578063e71bdf411461098c578063eb37abe0146109d0578063f56e81fa14610a97578063ffa1ad7414610b2f57610121565b8063b713c9d4146105cc578063beaeb388146106aa578063c19bf50e14610744578063ce60c692146107a8578063d626e0431461084657610121565b80634515641a116100f45780634515641a146101e0578063885133e31461036c5780638d0e8e1d146103d057806394b31fbd14610489578063a3f4df7e1461054957610121565b80631db61b5414610126578063310a3bb1146101445780633408e470146101a457806343abf5fe146101c2575b600080fd5b61012e610bb2565b6040518082815260200191505060405180910390f35b6101866004803603602081101561015a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bd9565b604051808265ffffffffffff16815260200191505060405180910390f35b6101ac610bfe565b6040518082815260200191505060405180910390f35b6101ca610c0b565b6040518082815260200191505060405180910390f35b61036a60048036036101008110156101f757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080356bffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080356bffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156102e457600080fd5b8201836020820111156102f657600080fd5b8035906020019184600183028401116401000000008311171561031857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610c32565b005b6103ce6004803603604081101561038257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506110a1565b005b610432600480360360408110156103e657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506111c9565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561047557808201518184015260208101905061045a565b505050509050019250505060405180910390f35b61050b6004803603606081101561049f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506112d4565b6040518082600560200280838360005b8381101561053657808201518184015260208101905061051b565b5050505090500191505060405180910390f35b610551611360565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610591578082015181840152602081019050610576565b50505050905090810190601f1680156105be5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61064e600480360360608110156105e257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611399565b60405180866bffffffffffffffffffffffff168152602001856bffffffffffffffffffffffff1681526020018461ffff1681526020018363ffffffff1681526020018261ffff1681526020019550505050505060405180910390f35b610742600480360360a08110156106c057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080356bffffffffffffffffffffffff169060200190929190803561ffff169060200190929190803563ffffffff169060200190929190505050611445565b005b6107a66004803603604081101561075a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506118fe565b005b6107fc600480360360408110156107be57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803565ffffffffffff1690602001909291905050506119cf565b604051808473ffffffffffffffffffffffffffffffffffffffff1681526020018365ffffffffffff1681526020018265ffffffffffff168152602001935050505060405180910390f35b610926600480360360e081101561085c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080356bffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080356bffffffffffffffffffffffff169060200190929190803561ffff169060200190929190505050611a4a565b6040518082815260200191505060405180910390f35b61098a6004803603604081101561095257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803515159060200190929190505050611a6f565b005b6109ce600480360360208110156109a257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506120ae565b005b610a31600480360360608110156109e657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803565ffffffffffff169060200190929190803560ff169060200190929190505050612581565b60405180806020018365ffffffffffff168152602001828103825284818151815260200191508051906020019060200280838360005b83811015610a82578082015181840152602081019050610a67565b50505050905001935050505060405180910390f35b610b0360048036036060811015610aad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061293d565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610b37612998565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610b77578082015181840152602081019050610b5c565b50505050905090810190601f168015610ba45780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b7f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a7946921860001b81565b60026020528060005260406000206000915054906101000a900465ffffffffffff1681565b6000804690508091505090565b7f80b006280932094e7cc965863eb5118dc07e5d272c6670c4a7c87299e04fceeb60001b81565b610c3a613858565b610c4589848a6129d1565b90506060610c5c8a8a8a8a8a8a8860800151612c2f565b90506001826080015101826080019061ffff16908161ffff1681525050600087836020015101905082602001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff16118015610cd3575082600001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff1611155b610d28576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603a8152602001806139b0603a913960400191505060405180910390fd5b8083602001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff16815250506000866bffffffffffffffffffffffff161115610ecd57610d6f613858565b8a73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614610db257610dad8c878a6129d1565b610db4565b835b905086816020015101915080602001516bffffffffffffffffffffffff16826bffffffffffffffffffffffff16118015610e0e575080600001516bffffffffffffffffffffffff16826bffffffffffffffffffffffff1611155b610e63576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526048815260200180613a1e6048913960600191505060405180910390fd5b8181602001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff16815250508a73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614610ecb57610eca8c878a84612e43565b5b505b610ed98b868c86612e43565b610ee58585848e612fe0565b6000866bffffffffffffffffffffffff161115610fbf57610f088b883289613133565b8a73ffffffffffffffffffffffffffffffffffffffff167fad71d7a737da41277b5ade17fd65b00671e3ab35f23778a98c8d925dc66e3d9d8689328a604051808573ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff168152602001826bffffffffffffffffffffffff16815260200194505050505060405180910390a25b610fcb8b8b8b8b613133565b8a73ffffffffffffffffffffffffffffffffffffffff167fa11cca2c2027e28ab0046aab4d4040f59d8b06e819ccd974c1e53e86aa814c19868c8c8c6001896080015103604051808673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff168152602001836bffffffffffffffffffffffff1681526020018261ffff1681526020019550505050505060405180910390a25050505050505050505050565b6110a9613858565b6110b43384846129d1565b9050600081600001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff1681525050600081602001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff16815250506000816040019061ffff16908161ffff16815250506000816060019063ffffffff16908163ffffffff168152505061114233848484612e43565b3373ffffffffffffffffffffffffffffffffffffffff167f9a9bc79dd7e42545ba12d5659704d73a9364d4a18e0a98ca1c992a3bc999d2718484604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a2505050565b6060600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054806020026020016040519081016040528092919081815260200182805480156112c757602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001906001019080831161127d575b5050505050905092915050565b6112dc6138b1565b6112e4613858565b6112ef8585856129d1565b90506040518060a0016040528082600001516bffffffffffffffffffffffff16815260200182602001516bffffffffffffffffffffffff168152602001826040015161ffff168152602001826060015163ffffffff168152602001826080015161ffff168152509150509392505050565b6040518060400160405280601081526020017f416c6c6f77616e6365204d6f64756c650000000000000000000000000000000081525081565b600060205282600052604060002060205281600052604060002060205280600052604060002060009250925050508060000160009054906101000a90046bffffffffffffffffffffffff169080600001600c9054906101000a90046bffffffffffffffffffffffff16908060000160189054906101000a900461ffff169080600001601a9054906101000a900463ffffffff169080600001601e9054906101000a900461ffff16905085565b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614156114e8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f64656c656761746520213d20616464726573732830290000000000000000000081525060200191505060405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff16600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008765ffffffffffff1665ffffffffffff16815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146115ef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603c81526020018061391b603c913960400191505060405180910390fd5b6115f7613858565b6116023387876129d1565b90506000816080015161ffff161415611708576001816080019061ffff16908161ffff1681525050600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020859080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b6000603c428161171457fe5b04905060008363ffffffff1611156117dc578063ffffffff168363ffffffff1611156117a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f7265736574426173654d696e203c3d2063757272656e744d696e00000000000081525060200191505060405180910390fd5b8361ffff1683820363ffffffff16816117bd57fe5b068103826060019063ffffffff16908163ffffffff1681525050611809565b6000826060015163ffffffff1614156118085780826060019063ffffffff16908163ffffffff16815250505b5b83826040019061ffff16908161ffff16815250508482600001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff168152505061185133888885612e43565b3373ffffffffffffffffffffffffffffffffffffffff167f49caa04c5e1e168069c09df7f88c07ca87be980b0bf4570ab77fe9aae3ca7eba88888888604051808573ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff168152602001836bffffffffffffffffffffffff1681526020018261ffff16815260200194505050505060405180910390a250505050505050565b611906613858565b6119113384846129d1565b9050600081602001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff168152505061194833848484612e43565b3373ffffffffffffffffffffffffffffffffffffffff167fa39af38687a2c1e52c987a84d807fd238b83b08a9da657f184a72fcd2b71360c8484604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a2505050565b6003602052816000526040600020602052806000526040600020600091509150508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060000160149054906101000a900465ffffffffffff169080600001601a9054906101000a900465ffffffffffff16905083565b6000611a5b88888888888888612c2f565b805190602001209050979650505050505050565b611a776138d3565b600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008465ffffffffffff1665ffffffffffff1681526020019081526020016000206040518060600160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050600073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff161415611bd157506120aa565b8115611dd6576000600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060005b8180549050811015611dd3576000828281548110611c7457fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050611ca9613858565b611cb43388846129d1565b9050600081600001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff1681525050600081602001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff16815250506000816040019061ffff16908161ffff16815250506000816060019063ffffffff16908163ffffffff1681525050611d4233888484612e43565b3373ffffffffffffffffffffffffffffffffffffffff167f9a9bc79dd7e42545ba12d5659704d73a9364d4a18e0a98ca1c992a3bc999d2718884604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a250508080600101915050611c5a565b50505b6000816020015165ffffffffffff161415611e56578060400151600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548165ffffffffffff021916908365ffffffffffff160217905550611ee5565b8060400151600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000836020015165ffffffffffff1665ffffffffffff168152602001908152602001600020600001601a6101000a81548165ffffffffffff021916908365ffffffffffff1602179055505b6000816040015165ffffffffffff1614611f88578060200151600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000836040015165ffffffffffff1665ffffffffffff16815260200190815260200160002060000160146101000a81548165ffffffffffff021916908365ffffffffffff1602179055505b600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008465ffffffffffff1665ffffffffffff168152602001908152602001600020600080820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556000820160146101000a81549065ffffffffffff021916905560008201601a6101000a81549065ffffffffffff021916905550503373ffffffffffffffffffffffffffffffffffffffff167fdccc2d936ded24d2153d2760581a7f0dcb23ec71190c9726b3584cdd700214d484604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a2505b5050565b600081905060008165ffffffffffff161415612132576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f696e64657820213d2075696e742830290000000000000000000000000000000081525060200191505060405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008365ffffffffffff1665ffffffffffff16815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612296578273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461228f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f63757272656e7444656c6567617465203d3d2064656c6567617465000000000081525060200191505060405180910390fd5b505061257e565b6000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900465ffffffffffff16905060405180606001604052808573ffffffffffffffffffffffffffffffffffffffff168152602001600065ffffffffffff1681526020018265ffffffffffff16815250600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008565ffffffffffff1665ffffffffffff16815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548165ffffffffffff021916908365ffffffffffff160217905550604082015181600001601a6101000a81548165ffffffffffff021916908365ffffffffffff16021790555090505082600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008365ffffffffffff1665ffffffffffff16815260200190815260200160002060000160146101000a81548165ffffffffffff021916908365ffffffffffff16021790555082600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548165ffffffffffff021916908365ffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff167f2fd5b26f00131bd8ca0fc556207292b85a6bec241341df82724333227458e63085604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a25050505b50565b606060008260ff1667ffffffffffffffff8111801561259f57600080fd5b506040519080825280602002602001820160405280156125ce5781602001602082028036833780820191505090505b509150600080808665ffffffffffff16141561263b57600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900465ffffffffffff1661263d565b855b90506126476138d3565b600360008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008365ffffffffffff1665ffffffffffff1681526020019081526020016000206040518060600160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff168152505090505b600073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff16141580156127a957508560ff168360ff16105b15612928578060000151858460ff16815181106127c257fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508280600101935050600360008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000826040015165ffffffffffff1665ffffffffffff1681526020019081526020016000206040518060600160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050612763565b80600001519350828552505050935093915050565b6001602052826000526040600020602052816000526040600020818154811061296557600080fd5b90600052602060002001600092509250509054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6040518060400160405280600581526020017f302e312e3000000000000000000000000000000000000000000000000000000081525081565b6129d9613858565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060a00160405290816000820160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160008201600c9054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff1681526020016000820160189054906101000a900461ffff1661ffff1661ffff16815260200160008201601a9054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201601e9054906101000a900461ffff1661ffff1661ffff168152505090506000603c4281612b8c57fe5b0490506000826040015161ffff16118015612bc15750816040015161ffff16810363ffffffff16826060015163ffffffff1611155b15612c2757600082602001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff1681525050816040015161ffff168260600151820363ffffffff1681612c0c57fe5b068103826060019063ffffffff16908163ffffffff16815250505b509392505050565b60606000612c3b610bfe565b905060007f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a7946921860001b8230604051602001808481526020018381526020018273ffffffffffffffffffffffffffffffffffffffff168152602001935050505060405160208183030381529060405280519060200120905060007f80b006280932094e7cc965863eb5118dc07e5d272c6670c4a7c87299e04fceeb60001b8b8b8b8b8b8b8b604051602001808981526020018873ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff168152602001856bffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff168152602001836bffffffffffffffffffffffff1681526020018261ffff16815260200198505050505050505050604051602081830303815290604052805190602001209050601960f81b600160f81b838360405160200180857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101847effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018381526020018281526020019450505050506040516020818303038152906040529350505050979650505050505050565b806000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555060408201518160000160186101000a81548161ffff021916908361ffff160217905550606082015181600001601a6101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001601e6101000a81548161ffff021916908361ffff16021790555090505050505050565b6000612fec8484613527565b90508073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480156130d757508073ffffffffffffffffffffffffffffffffffffffff16600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008365ffffffffffff1665ffffffffffff16815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b61312c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260598152602001806139576059913960600191505060405180910390fd5b5050505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156132c1578373ffffffffffffffffffffffffffffffffffffffff1663468721a7838360006040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff168152602001836bffffffffffffffffffffffff168152602001806020018360018111156131db57fe5b8152602001828103825260008152602001602001945050505050602060405180830381600087803b15801561320f57600080fd5b505af1158015613223573d6000803e3d6000fd5b505050506040513d602081101561323957600080fd5b81019080805190602001909291905050506132bc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f436f756c64206e6f742065786563757465206574686572207472616e7366657281525060200191505060405180910390fd5b613521565b60608282604051602401808373ffffffffffffffffffffffffffffffffffffffff168152602001826bffffffffffffffffffffffff168152602001925050506040516020818303038152906040527fa9059cbb000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090508473ffffffffffffffffffffffffffffffffffffffff1663468721a78560008460006040518563ffffffff1660e01b8152600401808573ffffffffffffffffffffffffffffffffffffffff168152602001848152602001806020018360018111156133e657fe5b8152602001828103825284818151815260200191508051906020019080838360005b83811015613423578082015181840152602081019050613408565b50505050905090810190601f1680156134505780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b15801561347257600080fd5b505af1158015613486573d6000803e3d6000fd5b505050506040513d602081101561349c57600080fd5b810190808051906020019092919050505061351f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f436f756c64206e6f74206578656375746520746f6b656e207472616e7366657281525060200191505060405180910390fd5b505b50505050565b6000808351141561353a57339050613823565b60418351146135b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f7369676e6174757265732e6c656e677468203d3d20363500000000000000000081525060200191505060405180910390fd5b60008060006135c1866000613829565b80935081945082955050505060008360ff16141561362a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260348152602001806139ea6034913960400191505060405180910390fd5b60018360ff16141561363e5733935061377c565b601e8360ff16111561370d576001858051906020012060405160200180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c018281526020019150506040516020818303038152906040528051906020012060048503848460405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156136fc573d6000803e3d6000fd5b50505060206040510351935061377b565b6001858051906020012084848460405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa15801561376e573d6000803e3d6000fd5b5050506020604051035193505b5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141561381f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f6f776e657220213d20616464726573732830290000000000000000000000000081525060200191505060405180910390fd5b5050505b92915050565b60008060008360410260208101860151925060408101860151915060ff60418201870151169350509250925092565b6040518060a0016040528060006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff168152602001600061ffff168152602001600063ffffffff168152602001600061ffff1681525090565b6040518060a00160405280600590602082028036833780820191505090505090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600065ffffffffffff168152602001600065ffffffffffff168152509056fe64656c6567617465735b6d73672e73656e6465725d5b75696e7434382864656c6567617465295d2e64656c6567617465203d3d2064656c6567617465657870656374656444656c6567617465203d3d207369676e65722026262064656c6567617465735b616464726573732873616665295d5b75696e743438287369676e6572295d2e64656c6567617465203d3d207369676e65726e65775370656e74203e20616c6c6f77616e63652e7370656e74202626206e65775370656e74203c3d20616c6c6f77616e63652e616d6f756e74436f6e7472616374207369676e61747572657320617265206e6f7420737570706f727465642062792074686973206d6f64756c656e65775370656e74203e207061796d656e74416c6c6f77616e63652e7370656e74202626206e65775370656e74203c3d207061796d656e74416c6c6f77616e63652e616d6f756e74a264697066735822122083d9f6894d7a4d179c3b27cf9fe7af6ef17e6bfc147016c85c378cea015db76964736f6c63430007040033","optimization_enabled":false,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"istanbul","libraries":{},"metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":false,"runs":200},"remappings":[]},"optimization_runs":null,"sourcify_repo_url":null,"decoded_constructor_args":null,"compiler_version":"0.7.4+commit.3f05b770","is_verified_via_verifier_alliance":true,"verified_at":"2024-02-25T22:33:53.877515Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x608060405234801561001057600080fd5b50613a9b806100206000396000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c8063b713c9d4116100ad578063dd43a79f11610071578063dd43a79f1461093c578063e71bdf411461098c578063eb37abe0146109d0578063f56e81fa14610a97578063ffa1ad7414610b2f57610121565b8063b713c9d4146105cc578063beaeb388146106aa578063c19bf50e14610744578063ce60c692146107a8578063d626e0431461084657610121565b80634515641a116100f45780634515641a146101e0578063885133e31461036c5780638d0e8e1d146103d057806394b31fbd14610489578063a3f4df7e1461054957610121565b80631db61b5414610126578063310a3bb1146101445780633408e470146101a457806343abf5fe146101c2575b600080fd5b61012e610bb2565b6040518082815260200191505060405180910390f35b6101866004803603602081101561015a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bd9565b604051808265ffffffffffff16815260200191505060405180910390f35b6101ac610bfe565b6040518082815260200191505060405180910390f35b6101ca610c0b565b6040518082815260200191505060405180910390f35b61036a60048036036101008110156101f757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080356bffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080356bffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156102e457600080fd5b8201836020820111156102f657600080fd5b8035906020019184600183028401116401000000008311171561031857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610c32565b005b6103ce6004803603604081101561038257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506110a1565b005b610432600480360360408110156103e657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506111c9565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561047557808201518184015260208101905061045a565b505050509050019250505060405180910390f35b61050b6004803603606081101561049f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506112d4565b6040518082600560200280838360005b8381101561053657808201518184015260208101905061051b565b5050505090500191505060405180910390f35b610551611360565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610591578082015181840152602081019050610576565b50505050905090810190601f1680156105be5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61064e600480360360608110156105e257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611399565b60405180866bffffffffffffffffffffffff168152602001856bffffffffffffffffffffffff1681526020018461ffff1681526020018363ffffffff1681526020018261ffff1681526020019550505050505060405180910390f35b610742600480360360a08110156106c057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080356bffffffffffffffffffffffff169060200190929190803561ffff169060200190929190803563ffffffff169060200190929190505050611445565b005b6107a66004803603604081101561075a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506118fe565b005b6107fc600480360360408110156107be57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803565ffffffffffff1690602001909291905050506119cf565b604051808473ffffffffffffffffffffffffffffffffffffffff1681526020018365ffffffffffff1681526020018265ffffffffffff168152602001935050505060405180910390f35b610926600480360360e081101561085c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080356bffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080356bffffffffffffffffffffffff169060200190929190803561ffff169060200190929190505050611a4a565b6040518082815260200191505060405180910390f35b61098a6004803603604081101561095257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803515159060200190929190505050611a6f565b005b6109ce600480360360208110156109a257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506120ae565b005b610a31600480360360608110156109e657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803565ffffffffffff169060200190929190803560ff169060200190929190505050612581565b60405180806020018365ffffffffffff168152602001828103825284818151815260200191508051906020019060200280838360005b83811015610a82578082015181840152602081019050610a67565b50505050905001935050505060405180910390f35b610b0360048036036060811015610aad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061293d565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610b37612998565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610b77578082015181840152602081019050610b5c565b50505050905090810190601f168015610ba45780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b7f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a7946921860001b81565b60026020528060005260406000206000915054906101000a900465ffffffffffff1681565b6000804690508091505090565b7f80b006280932094e7cc965863eb5118dc07e5d272c6670c4a7c87299e04fceeb60001b81565b610c3a613858565b610c4589848a6129d1565b90506060610c5c8a8a8a8a8a8a8860800151612c2f565b90506001826080015101826080019061ffff16908161ffff1681525050600087836020015101905082602001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff16118015610cd3575082600001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff1611155b610d28576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603a8152602001806139b0603a913960400191505060405180910390fd5b8083602001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff16815250506000866bffffffffffffffffffffffff161115610ecd57610d6f613858565b8a73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614610db257610dad8c878a6129d1565b610db4565b835b905086816020015101915080602001516bffffffffffffffffffffffff16826bffffffffffffffffffffffff16118015610e0e575080600001516bffffffffffffffffffffffff16826bffffffffffffffffffffffff1611155b610e63576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526048815260200180613a1e6048913960600191505060405180910390fd5b8181602001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff16815250508a73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614610ecb57610eca8c878a84612e43565b5b505b610ed98b868c86612e43565b610ee58585848e612fe0565b6000866bffffffffffffffffffffffff161115610fbf57610f088b883289613133565b8a73ffffffffffffffffffffffffffffffffffffffff167fad71d7a737da41277b5ade17fd65b00671e3ab35f23778a98c8d925dc66e3d9d8689328a604051808573ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff168152602001826bffffffffffffffffffffffff16815260200194505050505060405180910390a25b610fcb8b8b8b8b613133565b8a73ffffffffffffffffffffffffffffffffffffffff167fa11cca2c2027e28ab0046aab4d4040f59d8b06e819ccd974c1e53e86aa814c19868c8c8c6001896080015103604051808673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff168152602001836bffffffffffffffffffffffff1681526020018261ffff1681526020019550505050505060405180910390a25050505050505050505050565b6110a9613858565b6110b43384846129d1565b9050600081600001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff1681525050600081602001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff16815250506000816040019061ffff16908161ffff16815250506000816060019063ffffffff16908163ffffffff168152505061114233848484612e43565b3373ffffffffffffffffffffffffffffffffffffffff167f9a9bc79dd7e42545ba12d5659704d73a9364d4a18e0a98ca1c992a3bc999d2718484604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a2505050565b6060600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054806020026020016040519081016040528092919081815260200182805480156112c757602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001906001019080831161127d575b5050505050905092915050565b6112dc6138b1565b6112e4613858565b6112ef8585856129d1565b90506040518060a0016040528082600001516bffffffffffffffffffffffff16815260200182602001516bffffffffffffffffffffffff168152602001826040015161ffff168152602001826060015163ffffffff168152602001826080015161ffff168152509150509392505050565b6040518060400160405280601081526020017f416c6c6f77616e6365204d6f64756c650000000000000000000000000000000081525081565b600060205282600052604060002060205281600052604060002060205280600052604060002060009250925050508060000160009054906101000a90046bffffffffffffffffffffffff169080600001600c9054906101000a90046bffffffffffffffffffffffff16908060000160189054906101000a900461ffff169080600001601a9054906101000a900463ffffffff169080600001601e9054906101000a900461ffff16905085565b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614156114e8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f64656c656761746520213d20616464726573732830290000000000000000000081525060200191505060405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff16600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008765ffffffffffff1665ffffffffffff16815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146115ef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603c81526020018061391b603c913960400191505060405180910390fd5b6115f7613858565b6116023387876129d1565b90506000816080015161ffff161415611708576001816080019061ffff16908161ffff1681525050600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020859080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b6000603c428161171457fe5b04905060008363ffffffff1611156117dc578063ffffffff168363ffffffff1611156117a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f7265736574426173654d696e203c3d2063757272656e744d696e00000000000081525060200191505060405180910390fd5b8361ffff1683820363ffffffff16816117bd57fe5b068103826060019063ffffffff16908163ffffffff1681525050611809565b6000826060015163ffffffff1614156118085780826060019063ffffffff16908163ffffffff16815250505b5b83826040019061ffff16908161ffff16815250508482600001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff168152505061185133888885612e43565b3373ffffffffffffffffffffffffffffffffffffffff167f49caa04c5e1e168069c09df7f88c07ca87be980b0bf4570ab77fe9aae3ca7eba88888888604051808573ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff168152602001836bffffffffffffffffffffffff1681526020018261ffff16815260200194505050505060405180910390a250505050505050565b611906613858565b6119113384846129d1565b9050600081602001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff168152505061194833848484612e43565b3373ffffffffffffffffffffffffffffffffffffffff167fa39af38687a2c1e52c987a84d807fd238b83b08a9da657f184a72fcd2b71360c8484604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a2505050565b6003602052816000526040600020602052806000526040600020600091509150508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060000160149054906101000a900465ffffffffffff169080600001601a9054906101000a900465ffffffffffff16905083565b6000611a5b88888888888888612c2f565b805190602001209050979650505050505050565b611a776138d3565b600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008465ffffffffffff1665ffffffffffff1681526020019081526020016000206040518060600160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050600073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff161415611bd157506120aa565b8115611dd6576000600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060005b8180549050811015611dd3576000828281548110611c7457fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050611ca9613858565b611cb43388846129d1565b9050600081600001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff1681525050600081602001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff16815250506000816040019061ffff16908161ffff16815250506000816060019063ffffffff16908163ffffffff1681525050611d4233888484612e43565b3373ffffffffffffffffffffffffffffffffffffffff167f9a9bc79dd7e42545ba12d5659704d73a9364d4a18e0a98ca1c992a3bc999d2718884604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a250508080600101915050611c5a565b50505b6000816020015165ffffffffffff161415611e56578060400151600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548165ffffffffffff021916908365ffffffffffff160217905550611ee5565b8060400151600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000836020015165ffffffffffff1665ffffffffffff168152602001908152602001600020600001601a6101000a81548165ffffffffffff021916908365ffffffffffff1602179055505b6000816040015165ffffffffffff1614611f88578060200151600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000836040015165ffffffffffff1665ffffffffffff16815260200190815260200160002060000160146101000a81548165ffffffffffff021916908365ffffffffffff1602179055505b600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008465ffffffffffff1665ffffffffffff168152602001908152602001600020600080820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556000820160146101000a81549065ffffffffffff021916905560008201601a6101000a81549065ffffffffffff021916905550503373ffffffffffffffffffffffffffffffffffffffff167fdccc2d936ded24d2153d2760581a7f0dcb23ec71190c9726b3584cdd700214d484604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a2505b5050565b600081905060008165ffffffffffff161415612132576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f696e64657820213d2075696e742830290000000000000000000000000000000081525060200191505060405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008365ffffffffffff1665ffffffffffff16815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612296578273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461228f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f63757272656e7444656c6567617465203d3d2064656c6567617465000000000081525060200191505060405180910390fd5b505061257e565b6000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900465ffffffffffff16905060405180606001604052808573ffffffffffffffffffffffffffffffffffffffff168152602001600065ffffffffffff1681526020018265ffffffffffff16815250600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008565ffffffffffff1665ffffffffffff16815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548165ffffffffffff021916908365ffffffffffff160217905550604082015181600001601a6101000a81548165ffffffffffff021916908365ffffffffffff16021790555090505082600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008365ffffffffffff1665ffffffffffff16815260200190815260200160002060000160146101000a81548165ffffffffffff021916908365ffffffffffff16021790555082600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548165ffffffffffff021916908365ffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff167f2fd5b26f00131bd8ca0fc556207292b85a6bec241341df82724333227458e63085604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a25050505b50565b606060008260ff1667ffffffffffffffff8111801561259f57600080fd5b506040519080825280602002602001820160405280156125ce5781602001602082028036833780820191505090505b509150600080808665ffffffffffff16141561263b57600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900465ffffffffffff1661263d565b855b90506126476138d3565b600360008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008365ffffffffffff1665ffffffffffff1681526020019081526020016000206040518060600160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff168152505090505b600073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff16141580156127a957508560ff168360ff16105b15612928578060000151858460ff16815181106127c257fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508280600101935050600360008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000826040015165ffffffffffff1665ffffffffffff1681526020019081526020016000206040518060600160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050612763565b80600001519350828552505050935093915050565b6001602052826000526040600020602052816000526040600020818154811061296557600080fd5b90600052602060002001600092509250509054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6040518060400160405280600581526020017f302e312e3000000000000000000000000000000000000000000000000000000081525081565b6129d9613858565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060a00160405290816000820160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160008201600c9054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff1681526020016000820160189054906101000a900461ffff1661ffff1661ffff16815260200160008201601a9054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201601e9054906101000a900461ffff1661ffff1661ffff168152505090506000603c4281612b8c57fe5b0490506000826040015161ffff16118015612bc15750816040015161ffff16810363ffffffff16826060015163ffffffff1611155b15612c2757600082602001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff1681525050816040015161ffff168260600151820363ffffffff1681612c0c57fe5b068103826060019063ffffffff16908163ffffffff16815250505b509392505050565b60606000612c3b610bfe565b905060007f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a7946921860001b8230604051602001808481526020018381526020018273ffffffffffffffffffffffffffffffffffffffff168152602001935050505060405160208183030381529060405280519060200120905060007f80b006280932094e7cc965863eb5118dc07e5d272c6670c4a7c87299e04fceeb60001b8b8b8b8b8b8b8b604051602001808981526020018873ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff168152602001856bffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff168152602001836bffffffffffffffffffffffff1681526020018261ffff16815260200198505050505050505050604051602081830303815290604052805190602001209050601960f81b600160f81b838360405160200180857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101847effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018381526020018281526020019450505050506040516020818303038152906040529350505050979650505050505050565b806000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555060408201518160000160186101000a81548161ffff021916908361ffff160217905550606082015181600001601a6101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001601e6101000a81548161ffff021916908361ffff16021790555090505050505050565b6000612fec8484613527565b90508073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480156130d757508073ffffffffffffffffffffffffffffffffffffffff16600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008365ffffffffffff1665ffffffffffff16815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b61312c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260598152602001806139576059913960600191505060405180910390fd5b5050505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156132c1578373ffffffffffffffffffffffffffffffffffffffff1663468721a7838360006040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff168152602001836bffffffffffffffffffffffff168152602001806020018360018111156131db57fe5b8152602001828103825260008152602001602001945050505050602060405180830381600087803b15801561320f57600080fd5b505af1158015613223573d6000803e3d6000fd5b505050506040513d602081101561323957600080fd5b81019080805190602001909291905050506132bc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f436f756c64206e6f742065786563757465206574686572207472616e7366657281525060200191505060405180910390fd5b613521565b60608282604051602401808373ffffffffffffffffffffffffffffffffffffffff168152602001826bffffffffffffffffffffffff168152602001925050506040516020818303038152906040527fa9059cbb000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090508473ffffffffffffffffffffffffffffffffffffffff1663468721a78560008460006040518563ffffffff1660e01b8152600401808573ffffffffffffffffffffffffffffffffffffffff168152602001848152602001806020018360018111156133e657fe5b8152602001828103825284818151815260200191508051906020019080838360005b83811015613423578082015181840152602081019050613408565b50505050905090810190601f1680156134505780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b15801561347257600080fd5b505af1158015613486573d6000803e3d6000fd5b505050506040513d602081101561349c57600080fd5b810190808051906020019092919050505061351f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f436f756c64206e6f74206578656375746520746f6b656e207472616e7366657281525060200191505060405180910390fd5b505b50505050565b6000808351141561353a57339050613823565b60418351146135b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f7369676e6174757265732e6c656e677468203d3d20363500000000000000000081525060200191505060405180910390fd5b60008060006135c1866000613829565b80935081945082955050505060008360ff16141561362a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260348152602001806139ea6034913960400191505060405180910390fd5b60018360ff16141561363e5733935061377c565b601e8360ff16111561370d576001858051906020012060405160200180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c018281526020019150506040516020818303038152906040528051906020012060048503848460405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156136fc573d6000803e3d6000fd5b50505060206040510351935061377b565b6001858051906020012084848460405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa15801561376e573d6000803e3d6000fd5b5050506020604051035193505b5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141561381f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f6f776e657220213d20616464726573732830290000000000000000000000000081525060200191505060405180910390fd5b5050505b92915050565b60008060008360410260208101860151925060408101860151915060ff60418201870151169350509250925092565b6040518060a0016040528060006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff168152602001600061ffff168152602001600063ffffffff168152602001600061ffff1681525090565b6040518060a00160405280600590602082028036833780820191505090505090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600065ffffffffffff168152602001600065ffffffffffff168152509056fe64656c6567617465735b6d73672e73656e6465725d5b75696e7434382864656c6567617465295d2e64656c6567617465203d3d2064656c6567617465657870656374656444656c6567617465203d3d207369676e65722026262064656c6567617465735b616464726573732873616665295d5b75696e743438287369676e6572295d2e64656c6567617465203d3d207369676e65726e65775370656e74203e20616c6c6f77616e63652e7370656e74202626206e65775370656e74203c3d20616c6c6f77616e63652e616d6f756e74436f6e7472616374207369676e61747572657320617265206e6f7420737570706f727465642062792074686973206d6f64756c656e65775370656e74203e207061796d656e74416c6c6f77616e63652e7370656e74202626206e65775370656e74203c3d207061796d656e74416c6c6f77616e63652e616d6f756e74a264697066735822122083d9f6894d7a4d179c3b27cf9fe7af6ef17e6bfc147016c85c378cea015db76964736f6c63430007040033","name":"AllowanceModule","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"istanbul","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"/contracts/Enum.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.7.0 <0.8.0;\n\n/// @title Enum - Collection of enums\n/// @author Richard Meissner - <richard@gnosis.pm>\ncontract Enum {\n    enum Operation {\n        Call,\n        DelegateCall\n    }\n}\n"},{"file_path":"/contracts/SignatureDecoder.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.7.0 <0.8.0;\n\n/// @title SignatureDecoder - Decodes signatures that a encoded as bytes\n/// @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)\n/// @author Richard Meissner - <richard@gnosis.pm>\ncontract SignatureDecoder {\n    \n    /// @dev Recovers address who signed the message\n    /// @param messageHash operation ethereum signed message hash\n    /// @param messageSignature message `txHash` signature\n    /// @param pos which signature to read\n    function recoverKey (\n        bytes32 messageHash,\n        bytes memory messageSignature,\n        uint256 pos\n    )\n        internal\n        pure\n        returns (address)\n    {\n        uint8 v;\n        bytes32 r;\n        bytes32 s;\n        (v, r, s) = signatureSplit(messageSignature, pos);\n        return ecrecover(messageHash, v, r, s);\n    }\n\n    /// @dev divides bytes signature into `uint8 v, bytes32 r, bytes32 s`.\n    /// @notice Make sure to peform a bounds check for @param pos, to avoid out of bounds access on @param signatures\n    /// @param pos which signature to read. A prior bounds check of this parameter should be performed, to avoid out of bounds access\n    /// @param signatures concatenated rsv signatures\n    function signatureSplit(bytes memory signatures, uint256 pos)\n        internal\n        pure\n        returns (uint8 v, bytes32 r, bytes32 s)\n    {\n        // The signature format is a compact form of:\n        //   {bytes32 r}{bytes32 s}{uint8 v}\n        // Compact means, uint8 is not padded to 32 bytes.\n        // solium-disable-next-line security/no-inline-assembly\n        assembly {\n            let signaturePos := mul(0x41, pos)\n            r := mload(add(signatures, add(signaturePos, 0x20)))\n            s := mload(add(signatures, add(signaturePos, 0x40)))\n            // Here we are loading the last 32 bytes, including 31 bytes\n            // of 's'. There is no 'mload8' to do this.\n            //\n            // 'byte' is not working due to the Solidity parser, so lets\n            // use the second best option, 'and'\n            v := and(mload(add(signatures, add(signaturePos, 0x41))), 0xff)\n        }\n    }\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"safe","type":"address"},{"indexed":false,"internalType":"address","name":"delegate","type":"address"}],"name":"AddDelegate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"safe","type":"address"},{"indexed":false,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"}],"name":"DeleteAllowance","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"safe","type":"address"},{"indexed":false,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint96","name":"value","type":"uint96"},{"indexed":false,"internalType":"uint16","name":"nonce","type":"uint16"}],"name":"ExecuteAllowanceTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"safe","type":"address"},{"indexed":false,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"address","name":"paymentToken","type":"address"},{"indexed":false,"internalType":"address","name":"paymentReceiver","type":"address"},{"indexed":false,"internalType":"uint96","name":"payment","type":"uint96"}],"name":"PayAllowanceTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"safe","type":"address"},{"indexed":false,"internalType":"address","name":"delegate","type":"address"}],"name":"RemoveDelegate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"safe","type":"address"},{"indexed":false,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"}],"name":"ResetAllowance","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"safe","type":"address"},{"indexed":false,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint96","name":"allowanceAmount","type":"uint96"},{"indexed":false,"internalType":"uint16","name":"resetTime","type":"uint16"}],"name":"SetAllowance","type":"event"},{"inputs":[],"name":"ALLOWANCE_TRANSFER_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegate","type":"address"}],"name":"addDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowances","outputs":[{"internalType":"uint96","name":"amount","type":"uint96"},{"internalType":"uint96","name":"spent","type":"uint96"},{"internalType":"uint16","name":"resetTimeMin","type":"uint16"},{"internalType":"uint32","name":"lastResetMin","type":"uint32"},{"internalType":"uint16","name":"nonce","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint48","name":"","type":"uint48"}],"name":"delegates","outputs":[{"internalType":"address","name":"delegate","type":"address"},{"internalType":"uint48","name":"prev","type":"uint48"},{"internalType":"uint48","name":"next","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"delegatesStart","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegate","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"deleteAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract GnosisSafe","name":"safe","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address payable","name":"to","type":"address"},{"internalType":"uint96","name":"amount","type":"uint96"},{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"uint96","name":"payment","type":"uint96"},{"internalType":"address","name":"delegate","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"executeAllowanceTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"safe","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint96","name":"amount","type":"uint96"},{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"uint96","name":"payment","type":"uint96"},{"internalType":"uint16","name":"nonce","type":"uint16"}],"name":"generateTransferHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"safe","type":"address"},{"internalType":"uint48","name":"start","type":"uint48"},{"internalType":"uint8","name":"pageSize","type":"uint8"}],"name":"getDelegates","outputs":[{"internalType":"address[]","name":"results","type":"address[]"},{"internalType":"uint48","name":"next","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"safe","type":"address"},{"internalType":"address","name":"delegate","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"getTokenAllowance","outputs":[{"internalType":"uint256[5]","name":"","type":"uint256[5]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"safe","type":"address"},{"internalType":"address","name":"delegate","type":"address"}],"name":"getTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegate","type":"address"},{"internalType":"bool","name":"removeAllowances","type":"bool"}],"name":"removeDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegate","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"resetAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegate","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint96","name":"allowanceAmount","type":"uint96"},{"internalType":"uint16","name":"resetTimeMin","type":"uint16"},{"internalType":"uint32","name":"resetBaseMin","type":"uint32"}],"name":"setAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":null}