Contract 0xf5719a5a5886054a889c116792913c607086aab8

 
 
Txn Hash
Method
Block
From
To
Value [Txn Fee]
0x9cd22758a8525bc273cb7793bd30fc968c20a98b2f1d739f916d97edbfa7a7b0Atomic Match_341690662022-10-10 13:05:29345 days 23 hrs ago0x5f6156e8f3e819a006ea79f4f6dfba91cdab08bd IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.006444432313 30.510087979
0x543ac3c2c6509a95148d8ee55c883717bef735a475999db2819c629de49b8717Atomic Match_341624092022-10-10 9:16:21346 days 2 hrs ago0xb6a052d3470c38cbbd4ff9fadff3ab1f7d91e3c3 IN  0xf5719a5a5886054a889c116792913c607086aab80.00006 MATIC0.01912098947 30.000014859
0xebe5404b3b1202cba42426a89df65c2614fbf40fb65dbafa77a4a6d08aec4accCancel Order_341593642022-10-10 7:24:52346 days 4 hrs ago0xf49f736c93f5a209bc86c3d1f0d13b2c90488237 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.002190150001 30.000000018
0xeee7014c674225152b7a5289cefc0dd99685a0ef979e3ebe6c6595831c0c0497Atomic Match_341577332022-10-10 6:28:42346 days 5 hrs ago0x20387e976dd8533911d0d97a63b33ab0ed8cce30 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.006124260003 30.000000017
0xf50e30d76b4c9f05390b16802787a8352fd35e3aa0538cf5d9a888351df2cafaCancel Order_341316842022-10-09 15:30:36346 days 20 hrs ago0x173745adfbf11d20623fd43a5e382cd35e897e73 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.00136665 30.000000016
0xc1ca04ff32679d428ac445655cc2d137e8b108401bdc5dcbbce415c1ea786f2aCancel Order_341316812022-10-09 15:30:30346 days 20 hrs ago0x173745adfbf11d20623fd43a5e382cd35e897e73 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.002189790001 30.000000014
0xd376c9a18f1589decd0ebf60d49468cc4c15adc88ce2b096818ce21faf116426Set Start Time341256852022-10-09 11:57:51347 days 9 mins ago0x0b050cc56200806746594294f798eabefeef368b IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.001568622432 34.752474296
0x558c3e18fc2ff539b68f628329606fb42a1d5d477d5080907cd765a90c10d23aSet Start Time341168902022-10-09 6:49:01347 days 5 hrs ago0xf49f736c93f5a209bc86c3d1f0d13b2c90488237 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.001373460502 30.428706002
0xc06fd4823229964741cc4859534b11af592e371a9371419aa2001e244bc43812Cancel Order_341165942022-10-09 6:38:49347 days 5 hrs ago0xd6ac9ec09e3cd1299574bec65db743c80eba89a7 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.002196990001 30.000000014
0x5fc0e05b20994b7038d3744bfe32f3ef523daa719f22aa41b1c7f90ac3895b58Cancel Order_341165652022-10-09 6:37:51347 days 5 hrs ago0xd6ac9ec09e3cd1299574bec65db743c80eba89a7 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.002197350001 30.000000016
0x024cb6bf1497375723fd6cebcd37b94f8fe1bfbdb1bb68127d2e692365bf652bCancel Order_341092022022-10-09 2:09:40347 days 9 hrs ago0xb91c19c5698e088b60c4d6a7c103f2271c09aa85 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.00219051 30.000000011
0x2b0b6db54e19baa77b62033e2402ccf1f81ee54992c23106e9c9e75f030b4f6eCancel Order_341090172022-10-09 2:03:18347 days 10 hrs ago0x173745adfbf11d20623fd43a5e382cd35e897e73 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.00219735 30.000000013
0x6a3c776c1171262c702f9f6e66d86a13357521a0bee237d13e20529727ac8959Atomic Match_336519602022-09-28 1:23:36358 days 10 hrs ago0x72d67a6f328c07bbbbf80623ceca639a067ec80a IN  0xf5719a5a5886054a889c116792913c607086aab80.3 MATIC0.005415780005 30.000000031
0xe47503452c311af8c4dda874f22f2c571c754b8259d681b7a437ba7c9b11ece6Atomic Match_336270142022-09-27 10:26:10359 days 1 hr ago0x173745adfbf11d20623fd43a5e382cd35e897e73 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.006259470006 30.000000032
0x53c3a263c498a31da56f081dbad18cb59dc47344c86f9472a0385c32a480e5f5Atomic Match_336267652022-09-27 10:15:28359 days 1 hr ago0x173745adfbf11d20623fd43a5e382cd35e897e73 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.0061357835 30.070000002
0x2f9ba8aaff21f5402fc09e590e833b69c3146a78e0b58c3f9a12243dd1666741Atomic Match_336267252022-09-27 10:14:04359 days 1 hr ago0xd6ac9ec09e3cd1299574bec65db743c80eba89a7 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.006124620004 30.000000023
0xa3917849635d73d5494eb8cfce58ac61338d81f07eee81465edf8e8e96ecb9d4Cancel Order_336266612022-09-27 10:11:52359 days 1 hr ago0xd6ac9ec09e3cd1299574bec65db743c80eba89a7 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.002190510005 30.00000007
0x6b7fc1927e5d47978f17d8324ba84f1195d870c5be23443eb8061f33bf19e93cCancel Order_336265362022-09-27 10:05:26359 days 2 hrs ago0x173745adfbf11d20623fd43a5e382cd35e897e73 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.002189790001 30.000000018
0xcc407930e94a8ab1a7cc32e2b5c634170eb048b4a14ab9370c46c6ee4dcf422cAtomic Match_336249132022-09-27 9:05:24359 days 3 hrs ago0x173745adfbf11d20623fd43a5e382cd35e897e73 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.006124980045 30.000000223
0x8afe68db954d6ecdda1f78be1dd56a9ed31def8f24d88094df89b0068181fccfAtomic Match_336219182022-09-27 7:18:06359 days 4 hrs ago0x173745adfbf11d20623fd43a5e382cd35e897e73 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.006124260004 30.000000024
0xcf48df6a6802ee5184c6aac4cc47fb371ed036c4d5003c83941fd3279b84cf0cCancel Order_336218352022-09-27 7:15:16359 days 4 hrs ago0x173745adfbf11d20623fd43a5e382cd35e897e73 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.002197350002 30.000000028
0x7502374d1058aeadd59fce6bcd9b7107a5b34674320d9ba447a1c199a84f4bd9Cancel Order_336217732022-09-27 7:13:08359 days 4 hrs ago0xd6ac9ec09e3cd1299574bec65db743c80eba89a7 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.002197350002 30.000000033
0xe056dd97b56dbef1cd2808646ff1166399245fc387b690d9b92db211bdd8b9caCancel Order_336217152022-09-27 7:11:08359 days 4 hrs ago0xd6ac9ec09e3cd1299574bec65db743c80eba89a7 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.002195550003 30.000000051
0x4912c2fec6195591b799eaedd19b92d66b754cadef97bba6855e13dec4d07a1cCancel Order_336216582022-09-27 7:09:10359 days 4 hrs ago0xd6ac9ec09e3cd1299574bec65db743c80eba89a7 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.002196990007 30.000000099
0x6bb7ba0637d4052b9b2c5b12b17462cf55b4059fe782c31d04a8d6a9b64f0b8aCancel Order_336215952022-09-27 7:06:59359 days 4 hrs ago0xd6ac9ec09e3cd1299574bec65db743c80eba89a7 IN  0xf5719a5a5886054a889c116792913c607086aab80 MATIC0.002196990011 30.000000156
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xc5ad0d6f91f51936a18ff4b98cbc406e5f33bc11dabdce1e9d7d765033273185348046002022-10-26 1:50:21330 days 10 hrs ago 0xf5719a5a5886054a889c116792913c607086aab80x5f6156e8f3e819a006ea79f4f6dfba91cdab08bd0.000009749 MATIC
0xc5ad0d6f91f51936a18ff4b98cbc406e5f33bc11dabdce1e9d7d765033273185348046002022-10-26 1:50:21330 days 10 hrs ago 0xf5719a5a5886054a889c116792913c607086aab8 0x8f949859b838f719ac8fe305239ca92391875fab0.00000025 MATIC
0xc5ad0d6f91f51936a18ff4b98cbc406e5f33bc11dabdce1e9d7d765033273185348046002022-10-26 1:50:21330 days 10 hrs ago 0xf5719a5a5886054a889c116792913c607086aab80x5f6156e8f3e819a006ea79f4f6dfba91cdab08bd0.000000001 MATIC
0xc5ad0d6f91f51936a18ff4b98cbc406e5f33bc11dabdce1e9d7d765033273185348046002022-10-26 1:50:21330 days 10 hrs ago 0x041aee0a4404603ef8de6f3380ffe52ddd082b43 0xf5719a5a5886054a889c116792913c607086aab80.00001 MATIC
0x2a93219c5c9ca8d02e23c143c4c245c01e53d800a2274498b501091f1850b633347888652022-10-25 16:40:39330 days 19 hrs ago 0xf5719a5a5886054a889c116792913c607086aab80x5f6156e8f3e819a006ea79f4f6dfba91cdab08bd0.000009749 MATIC
0x2a93219c5c9ca8d02e23c143c4c245c01e53d800a2274498b501091f1850b633347888652022-10-25 16:40:39330 days 19 hrs ago 0xf5719a5a5886054a889c116792913c607086aab8 0x8f949859b838f719ac8fe305239ca92391875fab0.00000025 MATIC
0x2a93219c5c9ca8d02e23c143c4c245c01e53d800a2274498b501091f1850b633347888652022-10-25 16:40:39330 days 19 hrs ago 0xf5719a5a5886054a889c116792913c607086aab80x5f6156e8f3e819a006ea79f4f6dfba91cdab08bd0.000000001 MATIC
0x2a93219c5c9ca8d02e23c143c4c245c01e53d800a2274498b501091f1850b633347888652022-10-25 16:40:39330 days 19 hrs ago 0x041aee0a4404603ef8de6f3380ffe52ddd082b43 0xf5719a5a5886054a889c116792913c607086aab80.00001 MATIC
0xb8ec747e47e99d38b79bb35e87f3879e0936bad9fba7e34b098d82e513c09d72341687752022-10-10 12:55:31345 days 23 hrs ago 0xf5719a5a5886054a889c116792913c607086aab80x45fb6d7df651f27871a1dc0e513430876b474d620.000009749 MATIC
0xb8ec747e47e99d38b79bb35e87f3879e0936bad9fba7e34b098d82e513c09d72341687752022-10-10 12:55:31345 days 23 hrs ago 0xf5719a5a5886054a889c116792913c607086aab8 0x8f949859b838f719ac8fe305239ca92391875fab0.00000025 MATIC
0xb8ec747e47e99d38b79bb35e87f3879e0936bad9fba7e34b098d82e513c09d72341687752022-10-10 12:55:31345 days 23 hrs ago 0xf5719a5a5886054a889c116792913c607086aab80x5f6156e8f3e819a006ea79f4f6dfba91cdab08bd0.000000001 MATIC
0xb8ec747e47e99d38b79bb35e87f3879e0936bad9fba7e34b098d82e513c09d72341687752022-10-10 12:55:31345 days 23 hrs ago 0xcc7f6d7b13e054022511e1608b6a6ed6b69b8057 0xf5719a5a5886054a889c116792913c607086aab80.00001 MATIC
0x543ac3c2c6509a95148d8ee55c883717bef735a475999db2819c629de49b8717341624092022-10-10 9:16:21346 days 2 hrs ago 0xf5719a5a5886054a889c116792913c607086aab80xe519f873a0c1a173adbb81907a7e1969afb0bd3c0.000058494 MATIC
0x543ac3c2c6509a95148d8ee55c883717bef735a475999db2819c629de49b8717341624092022-10-10 9:16:21346 days 2 hrs ago 0xf5719a5a5886054a889c116792913c607086aab8 0x8f949859b838f719ac8fe305239ca92391875fab0.0000015 MATIC
0x543ac3c2c6509a95148d8ee55c883717bef735a475999db2819c629de49b8717341624092022-10-10 9:16:21346 days 2 hrs ago 0xf5719a5a5886054a889c116792913c607086aab80x5f6156e8f3e819a006ea79f4f6dfba91cdab08bd0.000000006 MATIC
0xe2628d02a719525ca8412c9975bd0069c415849decdd26cc234ec5e111d6d7c1341616952022-10-10 8:51:49346 days 3 hrs ago 0xf5719a5a5886054a889c116792913c607086aab80x5f6156e8f3e819a006ea79f4f6dfba91cdab08bd0.000009749 MATIC
0xe2628d02a719525ca8412c9975bd0069c415849decdd26cc234ec5e111d6d7c1341616952022-10-10 8:51:49346 days 3 hrs ago 0xf5719a5a5886054a889c116792913c607086aab8 0x8f949859b838f719ac8fe305239ca92391875fab0.00000025 MATIC
0xe2628d02a719525ca8412c9975bd0069c415849decdd26cc234ec5e111d6d7c1341616952022-10-10 8:51:49346 days 3 hrs ago 0xf5719a5a5886054a889c116792913c607086aab80x5f6156e8f3e819a006ea79f4f6dfba91cdab08bd0.000000001 MATIC
0xe2628d02a719525ca8412c9975bd0069c415849decdd26cc234ec5e111d6d7c1341616952022-10-10 8:51:49346 days 3 hrs ago 0x45fb6d7df651f27871a1dc0e513430876b474d62 0xf5719a5a5886054a889c116792913c607086aab80.00001 MATIC
0x3a290fa9901d5c31ab3a39c99789a93f9648344115802365cf3e849034dcebd7341610762022-10-10 8:24:02346 days 3 hrs ago 0xf5719a5a5886054a889c116792913c607086aab80x5f6156e8f3e819a006ea79f4f6dfba91cdab08bd0.00000975 MATIC
0x3a290fa9901d5c31ab3a39c99789a93f9648344115802365cf3e849034dcebd7341610762022-10-10 8:24:02346 days 3 hrs ago 0xf5719a5a5886054a889c116792913c607086aab8 0x8f949859b838f719ac8fe305239ca92391875fab0.00000025 MATIC
0x3a290fa9901d5c31ab3a39c99789a93f9648344115802365cf3e849034dcebd7341610762022-10-10 8:24:02346 days 3 hrs ago 0x1c6182f2b9c511ab359b5f371a3851533872911b 0xf5719a5a5886054a889c116792913c607086aab80.00001 MATIC
0xcc8065145673a4ae41101af2ff02047d7e449e207453f9d27f216ed3ec2dd607341573132022-10-10 6:14:18346 days 5 hrs ago 0xf5719a5a5886054a889c116792913c607086aab80x75f062d99ccf767484c82728b7490b20b95083db0.00000975 MATIC
0xcc8065145673a4ae41101af2ff02047d7e449e207453f9d27f216ed3ec2dd607341573132022-10-10 6:14:18346 days 5 hrs ago 0xf5719a5a5886054a889c116792913c607086aab8 0x8f949859b838f719ac8fe305239ca92391875fab0.00000025 MATIC
0xcc8065145673a4ae41101af2ff02047d7e449e207453f9d27f216ed3ec2dd607341573132022-10-10 6:14:18346 days 5 hrs ago 0xd392d00d30c2885b4db2c5f53eca9e6402a33928 0xf5719a5a5886054a889c116792913c607086aab80.00001 MATIC
[ Download CSV Export 
Loading

Similar Match Source Code
This contract matches the deployed ByteCode of the Source Code for Contract 0x391E174769107fcE0E62FE4809f0B9646AB7237A
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
PlaNFTExchange

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 23 : PlaNFTExchange.sol
//SPDX-License-Identifier: MIT

pragma solidity ^0.8.13;

import "./Exchange.sol";

contract PlaNFTExchange is Exchange {
    string public constant codename = "Lambton Worm";

    /**
     * @dev Initialize a PlaNFTExchange instance
     * @param registryAddress Address of the registry instance which this Exchange instance will use
     * @param tokenAddress Address of the token used for protocol fees
     */
    constructor (
        string memory name,
        string memory version,
        uint256 chainId,
        bytes32 salt,
        ProxyRegistry registryAddress,
        TokenTransferProxy tokenTransferProxyAddress,
        ERC20 tokenAddress,
        address protocolFeeAddress,
        address rewardFeeRecipient
    ) Exchange(name, version, chainId, salt) {
        registry = registryAddress;
        tokenTransferProxy = tokenTransferProxyAddress;
        exchangeToken = tokenAddress;
        protocolFeeRecipient = protocolFeeAddress;
        _rewardFeeRecipient = rewardFeeRecipient;
    }
}

File 2 of 23 : Exchange.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.13;

import "./ExchangeCore.sol";

/**
 * @title Exchange
 * @author Project Wyvern Developers
 */
contract Exchange is ExchangeCore {
    constructor(
        string memory name,
        string memory version,
        uint256 chainId,
        bytes32 salt
    ) ExchangeCore(name, version, chainId, salt) {}

    /**
     * @dev Call guardedArrayReplace - library function exposed for testing.
     */
    function guardedArrayReplace(
        bytes memory array,
        bytes memory desired,
        bytes memory mask
    ) public pure returns (bytes memory) {
        ArrayUtils.guardedArrayReplace(array, desired, mask);
        return array;
    }

    /**
     * @dev Call calculateFinalPrice - library function exposed for testing.
     */
    function calculateFinalPrice(
        SaleKindInterface.Side side,
        SaleKindInterface.SaleKind saleKind,
        uint256 basePrice,
        uint256 extra,
        uint256 listingTime,
        uint256 expirationTime
    ) public view returns (uint256) {
        return SaleKindInterface.calculateFinalPrice(side, saleKind, basePrice, extra, listingTime, expirationTime);
    }

    /**
     * @dev Call hashOrder - Solidity ABI encoding limitation workaround, hopefully temporary.
     */
    function hashOrder_(
        address[7] memory addrs,
        uint256[9] memory uints,
        FeeMethod feeMethod,
        SaleKindInterface.Side side,
        SaleKindInterface.SaleKind saleKind,
        AuthenticatedProxy.HowToCall howToCall,
        bytes memory data,
        bytes memory replacementPattern,
        bytes memory staticExtradata
    ) public pure returns (bytes32) {
        return
            hashOrder(
                Order(
                    addrs[0],
                    addrs[1],
                    addrs[2],
                    uints[0],
                    uints[1],
                    uints[2],
                    uints[3],
                    addrs[3],
                    feeMethod,
                    side,
                    saleKind,
                    addrs[4],
                    howToCall,
                    data,
                    replacementPattern,
                    addrs[5],
                    staticExtradata,
                    addrs[6],
                    uints[4],
                    uints[5],
                    uints[6],
                    uints[7],
                    uints[8]
                )
            );
    }

    /**
     * @dev Call hashToSign - Solidity ABI encoding limitation workaround, hopefully temporary.
     */
    function hashToSign_(
        address[7] memory addrs,
        uint256[9] memory uints,
        FeeMethod feeMethod,
        SaleKindInterface.Side side,
        SaleKindInterface.SaleKind saleKind,
        AuthenticatedProxy.HowToCall howToCall,
        bytes memory data,
        bytes memory replacementPattern,
        bytes memory staticExtradata
    ) public view returns (bytes32) {
        return
            hashToSign(
                Order(
                    addrs[0],
                    addrs[1],
                    addrs[2],
                    uints[0],
                    uints[1],
                    uints[2],
                    uints[3],
                    addrs[3],
                    feeMethod,
                    side,
                    saleKind,
                    addrs[4],
                    howToCall,
                    data,
                    replacementPattern,
                    addrs[5],
                    staticExtradata,
                    addrs[6],
                    uints[4],
                    uints[5],
                    uints[6],
                    uints[7],
                    uints[8]
                )
            );
    }

    /**
     * @dev Call validateOrderParameters - Solidity ABI encoding limitation workaround, hopefully temporary.
     */
    function validateOrderParameters_(
        address[7] memory addrs,
        uint256[9] memory uints,
        FeeMethod feeMethod,
        SaleKindInterface.Side side,
        SaleKindInterface.SaleKind saleKind,
        AuthenticatedProxy.HowToCall howToCall,
        bytes memory data,
        bytes memory replacementPattern,
        bytes memory staticExtradata
    ) public view returns (bool) {
        return validateOrderParameters(Order(
            addrs[0],
            addrs[1],
            addrs[2],
            uints[0],
            uints[1],
            uints[2],
            uints[3],
            addrs[3],
            feeMethod,
            side,
            saleKind,
            addrs[4],
            howToCall,
            data,
            replacementPattern,
            addrs[5],
            staticExtradata,
            addrs[6],
            uints[4],
            uints[5],
            uints[6],
            uints[7],
            uints[8]
        ));
    }

    /**
     * @dev Call validateOrder - Solidity ABI encoding limitation workaround, hopefully temporary.
     */
    function validateOrder_(
        address[7] memory addrs,
        uint256[9] memory uints,
        FeeMethod feeMethod,
        SaleKindInterface.Side side,
        SaleKindInterface.SaleKind saleKind,
        AuthenticatedProxy.HowToCall howToCall,
        bytes memory data,
        bytes memory replacementPattern,
        bytes memory staticExtradata,
        bytes memory signature
    ) public view returns (bool) {
        Order memory order = Order(
            addrs[0],
            addrs[1],
            addrs[2],
            uints[0],
            uints[1],
            uints[2],
            uints[3],
            addrs[3],
            feeMethod,
            side,
            saleKind,
            addrs[4],
            howToCall,
            data,
            replacementPattern,
            addrs[5],
            staticExtradata,
            addrs[6],
            uints[4],
            uints[5],
            uints[6],
            uints[7],
            uints[8]
        );
        return validateOrder(hashToSign(order), order, signature);
    }

    /**
     * @dev Call approveOrder - Solidity ABI encoding limitation workaround, hopefully temporary.
     */
    function approveOrder_(
        address[7] memory addrs,
        uint256[9] memory uints,
        FeeMethod feeMethod,
        SaleKindInterface.Side side,
        SaleKindInterface.SaleKind saleKind,
        AuthenticatedProxy.HowToCall howToCall,
        bytes memory data,
        bytes memory replacementPattern,
        bytes memory staticExtradata,
        bool orderbookInclusionDesired
    ) public {
        Order memory order = Order(
            addrs[0],
            addrs[1],
            addrs[2],
            uints[0],
            uints[1],
            uints[2],
            uints[3],
            addrs[3],
            feeMethod,
            side,
            saleKind,
            addrs[4],
            howToCall,
            data,
            replacementPattern,
            addrs[5],
            staticExtradata,
            addrs[6],
            uints[4],
            uints[5],
            uints[6],
            uints[7],
            uints[8]
        );
        return approveOrder(order, orderbookInclusionDesired);
    }

    /**
     * @dev Call cancelOrder - Solidity ABI encoding limitation workaround, hopefully temporary.
     */
    function cancelOrder_(
        address[7] memory addrs,
        uint256[9] memory uints,
        FeeMethod feeMethod,
        SaleKindInterface.Side side,
        SaleKindInterface.SaleKind saleKind,
        AuthenticatedProxy.HowToCall howToCall,
        bytes memory data,
        bytes memory replacementPattern,
        bytes memory staticExtradata,
        bytes memory signature
    ) public {
        Order memory order = Order(
            addrs[0],
            addrs[1],
            addrs[2],
            uints[0],
            uints[1],
            uints[2],
            uints[3],
            addrs[3],
            feeMethod,
            side,
            saleKind,
            addrs[4],
            howToCall,
            data,
            replacementPattern,
            addrs[5],
            staticExtradata,
            addrs[6],
            uints[4],
            uints[5],
            uints[6],
            uints[7],
            uints[8]
        );
        return cancelOrder(order, signature);
    }

    /**
     * @dev Call cancelOrder, supplying a specific nonce — enables cancelling orders
     that were signed with nonces greater than the current nonce.
     */
    function cancelOrderWithNonce_(
        address[7] memory addrs,
        uint256[10] memory uints,
        FeeMethod feeMethod,
        SaleKindInterface.Side side,
        SaleKindInterface.SaleKind saleKind,
        AuthenticatedProxy.HowToCall howToCall,
        bytes memory data,
        bytes memory replacementPattern,
        bytes memory staticExtradata,
        bytes memory signature
    ) public {
        Order memory order = Order(
            addrs[0],
            addrs[1],
            addrs[2],
            uints[0],
            uints[1],
            uints[2],
            uints[3],
            addrs[3],
            feeMethod,
            side,
            saleKind,
            addrs[4],
            howToCall,
            data,
            replacementPattern,
            addrs[5],
            staticExtradata,
            addrs[6],
            uints[4],
            uints[5],
            uints[6],
            uints[7],
            uints[8]
        );
        return cancelOrder(order, signature);
    }

    /**
     * @dev Call calculateCurrentPrice - Solidity ABI encoding limitation workaround, hopefully temporary.
     */
    function calculateCurrentPrice_(
        address[7] memory addrs,
        uint256[9] memory uints,
        FeeMethod feeMethod,
        SaleKindInterface.Side side,
        SaleKindInterface.SaleKind saleKind,
        AuthenticatedProxy.HowToCall howToCall,
        bytes memory data,
        bytes memory replacementPattern,
        bytes memory staticExtradata
    ) public view returns (uint256) {
        return
            calculateCurrentPrice(
                Order(
                    addrs[0],
                    addrs[1],
                    addrs[2],
                    uints[0],
                    uints[1],
                    uints[2],
                    uints[3],
                    addrs[3],
                    feeMethod,
                    side,
                    saleKind,
                    addrs[4],
                    howToCall,
                    data,
                    replacementPattern,
                    addrs[5],
                    staticExtradata,
                    addrs[6],
                    uints[4],
                    uints[5],
                    uints[6],
                    uints[7],
                    uints[8]
                )
            );
    }

    /**
     * @dev Call ordersCanMatch - Solidity ABI encoding limitation workaround, hopefully temporary.
     */
    function ordersCanMatch_(
        address[14] memory addrs,
        uint256[18] memory uints,
        uint8[8] memory feeMethodsSidesKindsHowToCalls,
        bytes memory calldataBuy,
        bytes memory calldataSell,
        bytes memory replacementPatternBuy,
        bytes memory replacementPatternSell,
        bytes memory staticExtradataBuy,
        bytes memory staticExtradataSell
    ) public view returns (bool) {
        Order memory buy = Order(
            addrs[0],
            addrs[1],
            addrs[2],
            uints[0],
            uints[1],
            uints[2],
            uints[3],
            addrs[3],
            FeeMethod(feeMethodsSidesKindsHowToCalls[0]),
            SaleKindInterface.Side(feeMethodsSidesKindsHowToCalls[1]),
            SaleKindInterface.SaleKind(feeMethodsSidesKindsHowToCalls[2]),
            addrs[4],
            AuthenticatedProxy.HowToCall(feeMethodsSidesKindsHowToCalls[3]),
            calldataBuy,
            replacementPatternBuy,
            addrs[5],
            staticExtradataBuy,
            addrs[6],
            uints[4],
            uints[5],
            uints[6],
            uints[7],
            uints[8]
        );
        Order memory sell = Order(
            addrs[7],
            addrs[8],
            addrs[9],
            uints[9],
            uints[10],
            uints[11],
            uints[12],
            addrs[10],
            FeeMethod(feeMethodsSidesKindsHowToCalls[4]),
            SaleKindInterface.Side(feeMethodsSidesKindsHowToCalls[5]),
            SaleKindInterface.SaleKind(feeMethodsSidesKindsHowToCalls[6]),
            addrs[11],
            AuthenticatedProxy.HowToCall(feeMethodsSidesKindsHowToCalls[7]),
            calldataSell,
            replacementPatternSell,
            addrs[12],
            staticExtradataSell,
            addrs[13],
            uints[13],
            uints[14],
            uints[15],
            uints[16],
            uints[17]
        );
        return ordersCanMatch(buy, sell);
    }

    /**
     * @dev Return whether or not two orders' calldata specifications can match
     * @param buyCalldata Buy-side order calldata
     * @param buyReplacementPattern Buy-side order calldata replacement mask
     * @param sellCalldata Sell-side order calldata
     * @param sellReplacementPattern Sell-side order calldata replacement mask
     * @return Whether the orders' calldata can be matched
     */
    function orderCalldataCanMatch(
        bytes memory buyCalldata,
        bytes memory buyReplacementPattern,
        bytes memory sellCalldata,
        bytes memory sellReplacementPattern
    ) public pure returns (bool) {
        if (buyReplacementPattern.length > 0) {
            ArrayUtils.guardedArrayReplace(buyCalldata, sellCalldata, buyReplacementPattern);
        }
        if (sellReplacementPattern.length > 0) {
            ArrayUtils.guardedArrayReplace(sellCalldata, buyCalldata, sellReplacementPattern);
        }
        return ArrayUtils.arrayEq(buyCalldata, sellCalldata);
    }

    /**
     * @dev Call calculateMatchPrice - Solidity ABI encoding limitation workaround, hopefully temporary.
     */
    function calculateMatchPrice_(
        address[14] memory addrs,
        uint256[18] memory uints,
        uint8[8] memory feeMethodsSidesKindsHowToCalls,
        bytes memory calldataBuy,
        bytes memory calldataSell,
        bytes memory replacementPatternBuy,
        bytes memory replacementPatternSell,
        bytes memory staticExtradataBuy,
        bytes memory staticExtradataSell
    ) public view returns (uint256) {
        Order memory buy = Order(
            addrs[0],
            addrs[1],
            addrs[2],
            uints[0],
            uints[1],
            uints[2],
            uints[3],
            addrs[3],
            FeeMethod(feeMethodsSidesKindsHowToCalls[0]),
            SaleKindInterface.Side(feeMethodsSidesKindsHowToCalls[1]),
            SaleKindInterface.SaleKind(feeMethodsSidesKindsHowToCalls[2]),
            addrs[4],
            AuthenticatedProxy.HowToCall(feeMethodsSidesKindsHowToCalls[3]),
            calldataBuy,
            replacementPatternBuy,
            addrs[5],
            staticExtradataBuy,
            addrs[6],
            uints[4],
            uints[5],
            uints[6],
            uints[7],
            uints[8]
        );
        Order memory sell = Order(
            addrs[7],
            addrs[8],
            addrs[9],
            uints[9],
            uints[10],
            uints[11],
            uints[12],
            addrs[10],
            FeeMethod(feeMethodsSidesKindsHowToCalls[4]),
            SaleKindInterface.Side(feeMethodsSidesKindsHowToCalls[5]),
            SaleKindInterface.SaleKind(feeMethodsSidesKindsHowToCalls[6]),
            addrs[11],
            AuthenticatedProxy.HowToCall(feeMethodsSidesKindsHowToCalls[7]),
            calldataSell,
            replacementPatternSell,
            addrs[12],
            staticExtradataSell,
            addrs[13],
            uints[13],
            uints[14],
            uints[15],
            uints[16],
            uints[17]
        );
        return calculateMatchPrice(buy, sell);
    }

    /**
     * @dev Call atomicMatch - Solidity ABI encoding limitation workaround, hopefully temporary.
     */
    function atomicMatch_(
        address[14] memory addrs,
        uint256[18] memory uints,
        uint8[8] memory feeMethodsSidesKindsHowToCalls,
        bytes memory calldataBuy,
        bytes memory calldataSell,
        bytes memory replacementPatternBuy,
        bytes memory replacementPatternSell,
        bytes memory staticExtradataBuy,
        bytes memory staticExtradataSell,
        bytes[2] memory signatures,
        bytes32 metadata
    ) public payable {
        return
            atomicMatch(
                Order(
                    addrs[0],
                    addrs[1],
                    addrs[2],
                    uints[0],
                    uints[1],
                    uints[2],
                    uints[3],
                    addrs[3],
                    FeeMethod(feeMethodsSidesKindsHowToCalls[0]),
                    SaleKindInterface.Side(feeMethodsSidesKindsHowToCalls[1]),
                    SaleKindInterface.SaleKind(feeMethodsSidesKindsHowToCalls[2]),
                    addrs[4],
                    AuthenticatedProxy.HowToCall(feeMethodsSidesKindsHowToCalls[3]),
                    calldataBuy,
                    replacementPatternBuy,
                    addrs[5],
                    staticExtradataBuy,
                    addrs[6],
                    uints[4],
                    uints[5],
                    uints[6],
                    uints[7],
                    uints[8]
                ),
                signatures[0],
                Order(
                    addrs[7],
                    addrs[8],
                    addrs[9],
                    uints[9],
                    uints[10],
                    uints[11],
                    uints[12],
                    addrs[10],
                    FeeMethod(feeMethodsSidesKindsHowToCalls[4]),
                    SaleKindInterface.Side(feeMethodsSidesKindsHowToCalls[5]),
                    SaleKindInterface.SaleKind(feeMethodsSidesKindsHowToCalls[6]),
                    addrs[11],
                    AuthenticatedProxy.HowToCall(feeMethodsSidesKindsHowToCalls[7]),
                    calldataSell,
                    replacementPatternSell,
                    addrs[12],
                    staticExtradataSell,
                    addrs[13],
                    uints[13],
                    uints[14],
                    uints[15],
                    uints[16],
                    uints[17]
                ),
                signatures[1],
                metadata
            );
    }
}

File 3 of 23 : ExchangeCore.sol
// SPDX-License-Identifier: MIT

/*

  Decentralized digital asset exchange. Supports any digital asset that can be represented on the Ethereum blockchain (i.e. - transferred in an Ethereum transaction or sequence of transactions).

  Let us suppose two agents interacting with a distributed ledger have utility functions preferencing certain states of that ledger over others.
  Aiming to maximize their utility, these agents may construct with their utility functions along with the present ledger state a mapping of state transitions (transactions) to marginal utilities.
  Any composite state transition with positive marginal utility for and enactable by the combined permissions of both agents thus is a mutually desirable trade, and the trustless
  code execution provided by a distributed ledger renders the requisite atomicity trivial.

  Relative to this model, this instantiation makes two concessions to practicality:
  - State transition preferences are not matched directly but instead intermediated by a standard of tokenized value.
  - A small fee can be charged in WYV for order settlement in an amount configurable by the frontend hosting the orderbook.

  Solidity presently possesses neither a first-class functional typesystem nor runtime reflection (ABI encoding in Solidity), so we must be a bit clever in implementation and work at a lower level of abstraction than would be ideal.

  We elect to utilize the following structure for the initial version of the protocol:
  - Buy-side and sell-side orders each provide calldata (bytes) - for a sell-side order, the state transition for sale, for a buy-side order, the state transition to be bought.
    Along with the calldata, orders provide `replacementPattern`: a bytemask indicating which bytes of the calldata can be changed (e.g. NFT destination address).
    When a buy-side and sell-side order are matched, the desired calldatas are unified, masked with the bytemasks, and checked for agreement.
    This alone is enough to implement common simple state transitions, such as "transfer my CryptoKitty to any address" or "buy any of this kind of nonfungible token".
  - Orders (of either side) can optionally specify a static (no state modification) callback function, which receives configurable data along with the actual calldata as a parameter.
    Although it requires some encoding acrobatics, this allows for arbitrary transaction validation functions.
    For example, a buy-sider order could express the intent to buy any CryptoKitty with a particular set of characteristics (checked in the static call),
    or a sell-side order could express the intent to sell any of three ENS names, but not two others.
    Use of the EVM's STATICCALL opcode, added in Ethereum Metropolis, allows the static calldata to be safely specified separately and thus this kind of matching to happen correctly
    - that is to say, wherever the two (transaction => bool) functions intersect.

  Future protocol versions may improve upon this structure in capability or usability according to protocol user feedback demand, with upgrades enacted by the Wyvern DAO.

*/

pragma solidity ^0.8.13;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/interfaces/IERC1271.sol";

import "../registry/ProxyRegistry.sol";
import "../registry/TokenTransferProxy.sol";
import "../registry/AuthenticatedProxy.sol";
import "../common/ArrayUtils.sol";
import "../common/EIP712.sol";
import "../common/ReentrancyGuarded.sol";
import "../common/StaticCall.sol";
import "./SaleKindInterface.sol";

/**
 * @title ExchangeCore
 * @author Project Wyvern Developers
 */
contract ExchangeCore is ReentrancyGuarded, EIP712, Ownable {
    /* The token used to pay exchange fees. */
    ERC20 public exchangeToken;

    /* User registry. */
    ProxyRegistry public registry;

    /* Token transfer proxy. */
    TokenTransferProxy public tokenTransferProxy;

    /* Cancelled / finalized orders, by hash. */
    mapping(address => mapping(bytes32 => bool)) public cancelledOrFinalized;

    /* Orders verified by on-chain approval.
       Alternative to ECDSA signatures so that smart contracts can place orders directly.
       By maker address, then by hash.
       porting from v3.1 */
    mapping(address => mapping(bytes32 => bool)) public approvedOrders;

    /* User order start time. */
    mapping(address => uint256) public startTimes;

    /* For split fee orders, minimum required protocol maker fee, in basis points. Paid to owner (who can change it). */
    uint256 public minimumMakerProtocolFee = 0;

    /* For split fee orders, minimum required protocol taker fee, in basis points. Paid to owner (who can change it). */
    uint256 public minimumTakerProtocolFee = 0;

    /* Recipient of protocol fees. */
    address public protocolFeeRecipient;

    /* Fee method: protocol fee or split fee. */
    enum FeeMethod {
        ProtocolFee,
        SplitFee
    }

    bytes32 public constant ORDER_TYPEHASH =
        keccak256(
            "Order(address exchange,address maker,address taker,uint256 makerRelayerFee,uint256 takerRelayerFee,uint256 makerProtocolFee,uint256 takerProtocolFee,address minter,uint8 feeMethod,uint8 side,uint8 saleKind,address target,uint8 howToCall,bytes data,bytes replacementPattern,address staticTarget,bytes staticExtradata,address paymentToken,uint256 basePrice,uint256 extra,uint256 listingTime,uint256 expirationTime,uint256 salt)"
        );

    //exchange fee to owner
    uint256 public _exchangeFee = 250;

    //exchange fee to owner
    uint256 public _relayExchangeFee = 250;

    /* Recipient of protocol fees. */
    address public _rewardFeeRecipient;

    /* Recipient of protocol fees. */
    address public _relayRewardFeeRecipient;

    /* Inverse basis point. */
    uint256 public constant INVERSE_BASIS_POINT = 10000;

    // Delay to set fee
    uint256 public _delaySetFeeTime = 1 days;

    // Relay to set fee
    uint256 public _relaySetFeeTime = 0;

    // Delay to set fee
    uint256 public _delaySetFeeRecipientTime = 3 days;

    // Relay to set fee
    uint256 public _relaySetFeeRecipientTime = 0;

    /* An order on the exchange. */
    struct Order {
        /* Exchange address, intended as a versioning mechanism. */
        address exchange;
        /* Order maker address. */
        address maker;
        /* Order taker address, if specified. */
        address taker;
        /* Maker relayer fee of the order, unused for taker order. */
        uint256 makerRelayerFee;
        /* Taker relayer fee of the order, or maximum taker fee for a taker order. */
        uint256 takerRelayerFee;
        /* Maker protocol fee of the order, unused for taker order. */
        uint256 makerProtocolFee;
        /* Taker protocol fee of the order, or maximum taker fee for a taker order. */
        uint256 takerProtocolFee;
        /* nft minter. */
        address minter;
        /* Fee method (protocol token or split fee). */
        FeeMethod feeMethod;
        /* Side (buy/sell). */
        SaleKindInterface.Side side;
        /* Kind of sale. */
        SaleKindInterface.SaleKind saleKind;
        /* Target. */
        address target;
        /* HowToCall. */
        AuthenticatedProxy.HowToCall howToCall;
        /* Calldata. */
        bytes data;
        /* Calldata replacement pattern, or an empty byte array for no replacement. */
        bytes replacementPattern;
        /* Static call target, zero-address for no static call. */
        address staticTarget;
        /* Static call extra data. */
        bytes staticExtradata;
        /* Token used to pay for the order, or the zero-address as a sentinel value for Ether. */
        address paymentToken;
        /* Base price of the order (in paymentTokens). */
        uint256 basePrice;
        /* Auction extra parameter - minimum bid increment for English auctions, starting/ending price difference. */
        uint256 extra;
        /* Listing timestamp. */
        uint256 listingTime;
        /* Expiration timestamp - 0 for no expiry. */
        uint256 expirationTime;
        /* Order salt, used to prevent duplicate hashes. */
        uint256 salt;
    }

    event OrderApprovedPartOne(
        bytes32 indexed hash,
        address exchange,
        address indexed maker,
        address taker,
        uint256 makerRelayerFee,
        uint256 takerRelayerFee,
        uint256 makerProtocolFee,
        uint256 takerProtocolFee,
        address indexed minter,
        FeeMethod feeMethod,
        SaleKindInterface.Side side,
        SaleKindInterface.SaleKind saleKind,
        address target
    );
    event OrderApprovedPartTwo(
        bytes32 indexed hash,
        address indexed target,
        AuthenticatedProxy.HowToCall howToCall,
        bytes data,
        bytes replacementPattern,
        address staticTarget,
        bytes staticExtradata,
        address paymentToken,
        uint256 basePrice,
        uint256 extra,
        uint256 listingTime,
        uint256 expirationTime,
        uint256 salt,
        bool orderbookInclusionDesired
    );
    event OrderCancelled(bytes32 indexed hash);
    event OrdersMatched(
        bytes32 buyHash,
        bytes32 sellHash,
        address indexed maker,
        address indexed taker,
        uint256 price,
        bytes32 indexed metadata
    );
    event RelaySetFee(address owner, uint256 relaySetFeeTime, uint256 relayExchangeFee);
    event SetFee(address owner, uint256 exchangeFee);
    event RelaySetRecipientFee(address owner, address relayRewardFeeRecipient, uint256 relaySetFeeRecipientTime);
    event SetFeeRecipient(address owner, address rewardFeeRecipient);
    event SetStartTime(address owner, uint256 startTime);

    constructor(
        string memory name,
        string memory version,
        uint256 chainId,
        bytes32 salt
    ) EIP712(name, version, chainId, salt) {}

    function setExchangeToken(address token) public onlyOwner {
        exchangeToken = ERC20(token);
    }

    function setFee(uint256 exchangeFee_) public onlyOwner {
        require(_relaySetFeeTime != 0);
        require(_relayExchangeFee == exchangeFee_);
        require(_relaySetFeeTime + _delaySetFeeTime <= block.timestamp);
        _relaySetFeeTime = 0;
        _exchangeFee = exchangeFee_;
        emit SetFee(msg.sender, _exchangeFee);
    }

    function relaySetFee(uint256 relayExchangeFee_) public onlyOwner {
        _relaySetFeeTime = block.timestamp;
        _relayExchangeFee = relayExchangeFee_;
        emit RelaySetFee(msg.sender, _relayExchangeFee, _relaySetFeeTime);
    }

    function setFeeRecipient(address rewardFeeRecipient_) public onlyOwner {
        require(_relaySetFeeRecipientTime != 0);
        require(_relayRewardFeeRecipient == rewardFeeRecipient_);
        require(_relaySetFeeRecipientTime + _delaySetFeeRecipientTime <= block.timestamp);
        _relaySetFeeRecipientTime = 0;
        _rewardFeeRecipient = rewardFeeRecipient_;
        emit SetFeeRecipient(msg.sender, _rewardFeeRecipient);
    }

    function setStartTime(uint256 startTime) public {
        startTimes[msg.sender] = startTime;
        emit SetStartTime(msg.sender, startTime);
    }

    function relaySetFeeRecipient(address relayRewardFeeRecipient_) public onlyOwner {
        _relaySetFeeRecipientTime = block.timestamp;
        _relayRewardFeeRecipient = relayRewardFeeRecipient_;
        emit RelaySetRecipientFee(msg.sender, _relayRewardFeeRecipient, _relaySetFeeRecipientTime);
    }

    /**
     * @dev Change the minimum maker fee paid to the protocol (owner only)
     * @param newMinimumMakerProtocolFee New fee to set in basis points
     */
    function changeMinimumMakerProtocolFee(uint256 newMinimumMakerProtocolFee) public onlyOwner {
        minimumMakerProtocolFee = newMinimumMakerProtocolFee;
    }

    /**
     * @dev Change the minimum taker fee paid to the protocol (owner only)
     * @param newMinimumTakerProtocolFee New fee to set in basis points
     */
    function changeMinimumTakerProtocolFee(uint256 newMinimumTakerProtocolFee) public onlyOwner {
        minimumTakerProtocolFee = newMinimumTakerProtocolFee;
    }

    /**
     * @dev Change the protocol fee recipient (owner only)
     * @param newProtocolFeeRecipient New protocol fee recipient address
     */
    function changeProtocolFeeRecipient(address newProtocolFeeRecipient) public onlyOwner {
        protocolFeeRecipient = newProtocolFeeRecipient;
    }

    /**
     * @dev Transfer tokens
     * @param token Token to transfer
     * @param from Address to charge fees
     * @param to Address to receive fees
     * @param amount Amount of protocol tokens to charge
     */
    function transferTokens(
        address token,
        address from,
        address to,
        uint256 amount
    ) internal {
        if (amount > 0) {
            require(tokenTransferProxy.transferFrom(token, from, to, amount));
        }
    }

    /**
     * @dev Charge a fee in protocol tokens
     * @param from Address to charge fees
     * @param to Address to receive fees
     * @param amount Amount of protocol tokens to charge
     */
    function chargeProtocolFee(
        address from,
        address to,
        uint256 amount
    ) internal {
        transferTokens(address(exchangeToken), from, to, amount);
    }

    /**
     * @dev Hash an order, returning the canonical order hash, without the message prefix
     * @param order Order to hash
     * @return hash of order
     */
    function hashOrder(Order memory order) internal pure returns (bytes32 hash) {
        /* Unfortunately abi.encodePacked doesn't work here, stack size constraints. */
        uint256 size = 768;
        bytes memory array = new bytes(size);

        uint256 index;
        assembly {
            index := add(array, 0x20)
        }

        index = ArrayUtils.unsafeWriteBytes32(index, ORDER_TYPEHASH);
        index = ArrayUtils.unsafeWriteAddressWord(index, order.exchange);
        index = ArrayUtils.unsafeWriteAddressWord(index, order.maker);
        index = ArrayUtils.unsafeWriteAddressWord(index, order.taker);
        index = ArrayUtils.unsafeWriteUint(index, order.makerRelayerFee);
        index = ArrayUtils.unsafeWriteUint(index, order.takerRelayerFee);
        index = ArrayUtils.unsafeWriteUint(index, order.makerProtocolFee);
        index = ArrayUtils.unsafeWriteUint(index, order.takerProtocolFee);
        index = ArrayUtils.unsafeWriteAddressWord(index, order.minter);
        index = ArrayUtils.unsafeWriteUint8Word(index, uint8(order.feeMethod));
        index = ArrayUtils.unsafeWriteUint8Word(index, uint8(order.side));
        index = ArrayUtils.unsafeWriteUint8Word(index, uint8(order.saleKind));
        index = ArrayUtils.unsafeWriteAddressWord(index, order.target);
        index = ArrayUtils.unsafeWriteUint8Word(index, uint8(order.howToCall));
        index = ArrayUtils.unsafeWriteBytes32(index, keccak256(order.data));
        index = ArrayUtils.unsafeWriteBytes32(index, keccak256(order.replacementPattern));
        index = ArrayUtils.unsafeWriteAddressWord(index, order.staticTarget);
        index = ArrayUtils.unsafeWriteBytes32(index, keccak256(order.staticExtradata));
        index = ArrayUtils.unsafeWriteAddressWord(index, order.paymentToken);
        index = ArrayUtils.unsafeWriteUint(index, order.basePrice);
        index = ArrayUtils.unsafeWriteUint(index, order.extra);
        index = ArrayUtils.unsafeWriteUint(index, order.listingTime);
        index = ArrayUtils.unsafeWriteUint(index, order.expirationTime);
        index = ArrayUtils.unsafeWriteUint(index, order.salt);

        assembly {
            hash := keccak256(add(array, 0x20), size)
        }
        return hash;
    }

    /**
     * @dev Hash an order, returning the hash that a client must sign, including the standard message prefix
     * @param order Order to hash
     * @return Hash of message prefix and order hash per Ethereum format
     */
    function hashToSign(Order memory order) internal view returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, hashOrder(order)));
    }

    /**
     * @dev Assert an order is valid and return its hash
     * @param order Order to validate
     * @param signature ECDSA signature
     * @return hash Hash of order require validated
     */
    function requireValidOrder(Order memory order, bytes memory signature) internal view returns (bytes32) {
        bytes32 hash = hashToSign(order);
        require(validateOrder(hash, order, signature));
        return hash;
    }

    /**
     * @dev Validate order parameters (does *not* check signature validity)
     * @param order Order to validate
     */
    function validateOrderParameters(Order memory order) internal view returns (bool) {
        /* Order must be targeted at this protocol version (this Exchange contract). */
        if (order.exchange != address(this)) {
            return false;
        }

        /* Order must possess valid sale kind parameter combination. */
        if (order.listingTime < startTimes[order.maker]) {
            return false;
        }

        /* Order must possess valid sale kind parameter combination. */
        if (!SaleKindInterface.validateParameters(order.saleKind, order.expirationTime)) {
            return false;
        }

        /* If using the split fee method, order must have sufficient protocol fees. */
        if (
            order.feeMethod == FeeMethod.SplitFee &&
            (order.makerProtocolFee < minimumMakerProtocolFee || order.takerProtocolFee < minimumTakerProtocolFee)
        ) {
            return false;
        }

        return true;
    }

    /**
     * @dev Validate a provided previously approved / signed order, hash, and signature.
     * @param hash Order hash (already calculated, passed to avoid recalculation)
     * @param order Order to validate
     * @param signature ECDSA signature
     * @return valid Valid for hash and order
     */
    function validateOrder(
        bytes32 hash,
        Order memory order,
        bytes memory signature
    ) internal view returns (bool) {
        /* Not done in an if-conditional to prevent unnecessary ecrecover evaluation, which seems to happen even though it should short-circuit. */

        /* Order must have valid parameters. */
        if (!validateOrderParameters(order)) {
            return false;
        }

        /* Order must have not been canceled or already filled. */
        if (cancelledOrFinalized[order.maker][hash]) {
            return false;
        }

        /* Order authentication. Order must be either:
        /* (a) previously approved */
        if (approvedOrders[order.maker][hash]) {
            return true;
        }

        /* (b): Contract-only authentication: EIP/ERC 1271. */
        if (StaticCall.isContract(order.maker)) {
            return (IERC1271(order.maker).isValidSignature(hash, signature) == EIP_1271_MAGICVALUE);
        }

        /* (c): Account-only authentication: ECDSA-signed by maker. */
        bytes32 r;
        bytes32 s;
        uint8 v;
        assembly {
            r := mload(add(signature, 0x20))
            s := mload(add(signature, 0x40))
            v := mload(add(signature, 0x41))
        }

        if (ecrecover(hash, v, r, s) == order.maker) {
            return true;
        }

        return false;
    }

    /**
     * @dev Approve an order and optionally mark it for orderbook inclusion. Must be called by the maker of the order
     * @param order Order to approve
     * @param orderbookInclusionDesired Whether orderbook providers should include the order in their orderbooks
     */
    function approveOrder(Order memory order, bool orderbookInclusionDesired) internal {
        /* CHECKS */

        /* Assert sender is authorized to approve order. */
        require(msg.sender == order.maker);

        /* Calculate order hash. */
        bytes32 hash = hashToSign(order);

        /* Assert order has not already been approved. */
        require(!approvedOrders[order.maker][hash]);

        /* EFFECTS */

        /* Mark order as approved. */
        approvedOrders[order.maker][hash] = true;

        /* Log approval event. Must be split in two due to Solidity stack size limitations. */
        {
            emit OrderApprovedPartOne(
                hash,
                order.exchange,
                order.maker,
                order.taker,
                order.makerRelayerFee,
                order.takerRelayerFee,
                order.makerProtocolFee,
                order.takerProtocolFee,
                order.minter,
                order.feeMethod,
                order.side,
                order.saleKind,
                order.target
            );
        }
        {
            emit OrderApprovedPartTwo(
                hash,
                order.target,
                order.howToCall,
                order.data,
                order.replacementPattern,
                order.staticTarget,
                order.staticExtradata,
                order.paymentToken,
                order.basePrice,
                order.extra,
                order.listingTime,
                order.expirationTime,
                order.salt,
                orderbookInclusionDesired
            );
        }
    }

    /**
     * @dev Cancel an order, preventing it from being matched. Must be called by the maker of the order
     * @param order Order to cancel
     * @param signature ECDSA signature
     */
    function cancelOrder(Order memory order, bytes memory signature) internal {
        /* CHECKS */

        /* Calculate order hash. */
        bytes32 hash = requireValidOrder(order, signature);

        /* Assert sender is authorized to cancel order. */
        require(msg.sender == order.maker);

        /* EFFECTS */

        /* Mark order as cancelled, preventing it from being matched. */
        cancelledOrFinalized[order.maker][hash] = true;

        /* Log cancel event. */
        emit OrderCancelled(hash);
    }

    /**
     * @dev Calculate the current price of an order (convenience function)
     * @param order Order to calculate the price of
     * @return The current price of the order
     */
    function calculateCurrentPrice(Order memory order) internal view returns (uint256) {
        return
            SaleKindInterface.calculateFinalPrice(
                order.side,
                order.saleKind,
                order.basePrice,
                order.extra,
                order.listingTime,
                order.expirationTime
            );
    }

    /**
     * @dev Calculate the price two orders would match at, if in fact they would match (otherwise fail)
     * @param buy Buy-side order
     * @param sell Sell-side order
     * @return Match price
     */
    function calculateMatchPrice(Order memory buy, Order memory sell) internal view returns (uint256) {
        /* Calculate sell price. */
        uint256 sellPrice = SaleKindInterface.calculateFinalPrice(
            sell.side,
            sell.saleKind,
            sell.basePrice,
            sell.extra,
            sell.listingTime,
            sell.expirationTime
        );

        /* Calculate buy price. */
        uint256 buyPrice = SaleKindInterface.calculateFinalPrice(
            buy.side,
            buy.saleKind,
            buy.basePrice,
            buy.extra,
            buy.listingTime,
            buy.expirationTime
        );

        /* Require price cross. */
        require(buyPrice >= sellPrice);

        /* Maker/taker priority. */
        return sell.minter != address(0) ? sellPrice : buyPrice;
    }

    /**
     * @dev Execute all ERC20 token / Ether transfers associated with an order match (fees and buyer => seller transfer)
     * @param buy Buy-side order
     * @param sell Sell-side order
     */
    function executeFundsTransfer(Order memory buy, Order memory sell) internal returns (uint256) {
        /* Only payable in the special case of unwrapped Ether. */
        if (sell.paymentToken != address(0)) {
            require(msg.value == 0);
        }

        /* Calculate match price. */
        uint256 price = calculateMatchPrice(buy, sell);

        /* If paying using a token (not Ether), transfer tokens. This is done prior to fee payments to that a seller will have tokens before being charged fees. */
        if (price > 0 && sell.paymentToken != address(0)) {
            transferTokens(sell.paymentToken, buy.maker, sell.maker, price);
        }

        /* Amount that will be received by seller (for Ether). */
        uint256 receiveAmount = price;

        /* Amount that must be sent by buyer (for Ether). */
        uint256 requiredAmount = price;

        uint256 feeToExchange = SafeMath.div(SafeMath.mul(_exchangeFee, price), INVERSE_BASIS_POINT);

        /* Determine maker/taker and charge fees accordingly. */
        if (sell.minter != address(0)) {
            /* Sell-side order is maker. */

            /* Assert taker fee is less than or equal to maximum fee specified by buyer. */
            require(sell.takerRelayerFee <= buy.takerRelayerFee);

            if (sell.feeMethod == FeeMethod.SplitFee) {
                /* Assert taker fee is less than or equal to maximum fee specified by buyer. */
                require(sell.takerProtocolFee <= buy.takerProtocolFee);

                /* Maker fees are deducted from the token amount that the maker receives. Taker fees are extra tokens that must be paid by the taker. */
                if (sell.makerRelayerFee == 0 && sell.takerRelayerFee == 0) {
                    if (sell.paymentToken == address(0)) {
                        receiveAmount = SafeMath.sub(receiveAmount, feeToExchange);
                        payable(_rewardFeeRecipient).transfer(feeToExchange);
                    } else {
                        transferTokens(sell.paymentToken, sell.maker, _rewardFeeRecipient, feeToExchange);
                    }
                }
                if (sell.makerRelayerFee > 0) {
                    uint256 makerRelayerFee = SafeMath.div(
                        SafeMath.mul(sell.makerRelayerFee, price),
                        INVERSE_BASIS_POINT
                    );
                    if (sell.paymentToken == address(0)) {
                        receiveAmount = SafeMath.sub(SafeMath.sub(receiveAmount, makerRelayerFee), feeToExchange);
                        payable(sell.minter).transfer(makerRelayerFee);
                        payable(_rewardFeeRecipient).transfer(feeToExchange);
                    } else {
                        transferTokens(sell.paymentToken, sell.maker, sell.minter, makerRelayerFee);
                        transferTokens(sell.paymentToken, sell.maker, address(_rewardFeeRecipient), feeToExchange);
                    }
                }

                if (sell.takerRelayerFee > 0) {
                    uint256 takerRelayerFee = SafeMath.div(
                        SafeMath.mul(sell.takerRelayerFee, price),
                        INVERSE_BASIS_POINT
                    );
                    if (sell.paymentToken == address(0)) {
                        requiredAmount = SafeMath.add(SafeMath.add(requiredAmount, takerRelayerFee), feeToExchange);
                        payable(sell.minter).transfer(takerRelayerFee);
                        payable(_rewardFeeRecipient).transfer(feeToExchange);
                    } else {
                        transferTokens(sell.paymentToken, buy.maker, sell.minter, takerRelayerFee);
                        transferTokens(sell.paymentToken, buy.maker, _rewardFeeRecipient, feeToExchange);
                    }
                }

                if (sell.makerProtocolFee > 0) {
                    uint256 makerProtocolFee = SafeMath.div(
                        SafeMath.mul(sell.makerProtocolFee, price),
                        INVERSE_BASIS_POINT
                    );
                    if (sell.paymentToken == address(0)) {
                        receiveAmount = SafeMath.sub(receiveAmount, makerProtocolFee);
                        payable(protocolFeeRecipient).transfer(makerProtocolFee);
                    } else {
                        transferTokens(sell.paymentToken, sell.maker, protocolFeeRecipient, makerProtocolFee);
                    }
                }

                if (sell.takerProtocolFee > 0) {
                    uint256 takerProtocolFee = SafeMath.div(
                        SafeMath.mul(sell.takerProtocolFee, price),
                        INVERSE_BASIS_POINT
                    );
                    if (sell.paymentToken == address(0)) {
                        requiredAmount = SafeMath.add(requiredAmount, takerProtocolFee);
                        payable(protocolFeeRecipient).transfer(takerProtocolFee);
                    } else {
                        transferTokens(sell.paymentToken, buy.maker, protocolFeeRecipient, takerProtocolFee);
                    }
                }
            } else {
                /* Charge maker fee to seller. */
                chargeProtocolFee(sell.maker, sell.minter, sell.makerRelayerFee);
                chargeProtocolFee(sell.maker, _rewardFeeRecipient, _exchangeFee);
                /* Charge taker fee to buyer. */
                chargeProtocolFee(buy.maker, sell.minter, sell.takerRelayerFee);
                chargeProtocolFee(buy.maker, _rewardFeeRecipient, _exchangeFee);
            }
        } else {
            /* Buy-side order is maker. */

            /* Assert taker fee is less than or equal to maximum fee specified by seller. */
            require(buy.takerRelayerFee <= sell.takerRelayerFee);

            if (sell.feeMethod == FeeMethod.SplitFee) {
                /* The Exchange does not escrow Ether, so direct Ether can only be used to with sell-side maker / buy-side taker orders. */
                require(sell.paymentToken != address(0));

                /* Assert taker fee is less than or equal to maximum fee specified by seller. */
                require(buy.takerProtocolFee <= sell.takerProtocolFee);

                if (buy.makerRelayerFee == 0 && buy.takerRelayerFee == 0) {
                    transferTokens(sell.paymentToken, sell.maker, _rewardFeeRecipient, feeToExchange);
                }

                if (buy.makerRelayerFee > 0) {
                    uint256 makerRelayerFee = SafeMath.div(
                        SafeMath.mul(buy.makerRelayerFee, price),
                        INVERSE_BASIS_POINT
                    );
                    transferTokens(sell.paymentToken, buy.maker, buy.minter, makerRelayerFee);
                    transferTokens(sell.paymentToken, buy.maker, _rewardFeeRecipient, feeToExchange);
                }

                if (buy.takerRelayerFee > 0) {
                    uint256 takerRelayerFee = SafeMath.div(
                        SafeMath.mul(buy.takerRelayerFee, price),
                        INVERSE_BASIS_POINT
                    );
                    transferTokens(sell.paymentToken, sell.maker, buy.minter, takerRelayerFee);
                    transferTokens(sell.paymentToken, sell.maker, _rewardFeeRecipient, feeToExchange);
                }

                if (buy.makerProtocolFee > 0) {
                    uint256 makerProtocolFee = SafeMath.div(
                        SafeMath.mul(buy.makerProtocolFee, price),
                        INVERSE_BASIS_POINT
                    );
                    transferTokens(sell.paymentToken, buy.maker, protocolFeeRecipient, makerProtocolFee);
                }

                if (buy.takerProtocolFee > 0) {
                    uint256 takerProtocolFee = SafeMath.div(
                        SafeMath.mul(buy.takerProtocolFee, price),
                        INVERSE_BASIS_POINT
                    );
                    transferTokens(sell.paymentToken, sell.maker, protocolFeeRecipient, takerProtocolFee);
                }
            } else {
                /* Charge maker fee to buyer. */
                chargeProtocolFee(buy.maker, buy.minter, buy.makerRelayerFee);
                chargeProtocolFee(buy.maker, _rewardFeeRecipient, _exchangeFee);
                /* Charge taker fee to seller. */
                chargeProtocolFee(sell.maker, buy.minter, buy.takerRelayerFee);
                chargeProtocolFee(sell.maker, _rewardFeeRecipient, _exchangeFee);
            }
        }

        if (sell.paymentToken == address(0)) {
            /* Special-case Ether, order must be matched by buyer. */
            require(msg.value >= requiredAmount);
            payable(sell.maker).transfer(receiveAmount);
            /* Allow overshoot for variable-price auctions, refund difference. */
            uint256 diff = SafeMath.sub(msg.value, requiredAmount);
            if (diff > 0) {
                payable(buy.maker).transfer(diff);
            }
        }

        /* This contract should never hold Ether, however, we cannot assert this, since it is impossible to prevent anyone from sending Ether e.g. with selfdestruct. */

        return price;
    }

    /**
     * @dev Return whether or not two orders can be matched with each other by basic parameters (does not check order signatures / calldata or perform static calls)
     * @param buy Buy-side order
     * @param sell Sell-side order
     * @return Whether or not the two orders can be matched
     */
    function ordersCanMatch(Order memory buy, Order memory sell) internal view returns (bool) {
        return (/* Must be opposite-side. */
        (buy.side == SaleKindInterface.Side.Buy && sell.side == SaleKindInterface.Side.Sell) &&
            /* Must use same fee method. */
            (buy.feeMethod == sell.feeMethod) &&
            /* Must use same payment token. */
            (buy.paymentToken == sell.paymentToken) &&
            /* Must match maker/taker addresses. */
            (sell.taker == address(0) || sell.taker == buy.maker) &&
            (buy.taker == address(0) || buy.taker == sell.maker) &&
            /* One must be maker and the other must be taker (no bool XOR in Solidity). */
            ((sell.minter == address(0) && buy.minter != address(0)) ||
                (sell.minter != address(0) && buy.minter == address(0))) &&
            /* Must match target. */
            (buy.target == sell.target) &&
            /* Must match howToCall. */
            (buy.howToCall == sell.howToCall) &&
            /* Buy-side order must be settleable. */
            SaleKindInterface.canSettleOrder(buy.listingTime, buy.expirationTime) &&
            /* Sell-side order must be settleable. */
            SaleKindInterface.canSettleOrder(sell.listingTime, sell.expirationTime));
    }

    /**
     * @dev Atomically match two orders, ensuring validity of the match, and execute all associated state transitions. Protected against reentrancy by a contract-global lock.
     * @param buy Buy-side order
     * @param buySig Buy-side order signature
     * @param sell Sell-side order
     * @param sellSig Sell-side order signature
     */
    function atomicMatch(
        Order memory buy,
        bytes memory buySig,
        Order memory sell,
        bytes memory sellSig,
        bytes32 metadata
    ) internal reentrancyGuard {
        /* CHECKS */

        /* Ensure buy order validity and calculate hash if necessary. */
        bytes32 buyHash;
        if (buy.maker == msg.sender) {
            require(validateOrderParameters(buy));
        } else {
            buyHash = requireValidOrder(buy, buySig);
        }

        /* Ensure sell order validity and calculate hash if necessary. */
        bytes32 sellHash;
        if (sell.maker == msg.sender) {
            require(validateOrderParameters(sell));
        } else {
            sellHash = requireValidOrder(sell, sellSig);
        }

        /* Must be matchable. */
        require(ordersCanMatch(buy, sell));

        /* Target must exist (prevent malicious selfdestructs just prior to order settlement). */
        require(StaticCall.isContract(sell.target));

        /* Must match calldata after replacement, if specified. */
        if (buy.replacementPattern.length > 0) {
            ArrayUtils.guardedArrayReplace(buy.data, sell.data, buy.replacementPattern);
        }
        if (sell.replacementPattern.length > 0) {
            ArrayUtils.guardedArrayReplace(sell.data, buy.data, sell.replacementPattern);
        }
        require(ArrayUtils.arrayEq(buy.data, sell.data));

        /* Retrieve delegateProxy contract. */
        OwnableDelegateProxy delegateProxy = registry.proxies(sell.maker);

        /* Proxy must exist. */
        require(delegateProxy != OwnableDelegateProxy(payable(0)));

        /* Assert implementation. */
        require(delegateProxy.implementation() == registry.delegateProxyImplementation());

        /* Access the passthrough AuthenticatedProxy. */
        AuthenticatedProxy proxy = AuthenticatedProxy(payable(delegateProxy));

        /* EFFECTS */

        /* Mark previously signed or approved orders as finalized. */
        if (msg.sender != buy.maker) {
            cancelledOrFinalized[buy.maker][buyHash] = true;
        }
        if (msg.sender != sell.maker) {
            cancelledOrFinalized[sell.maker][sellHash] = true;
        }

        /* INTERACTIONS */
        /* Execute funds transfer and pay fees. */
        uint256 price = executeFundsTransfer(buy, sell);

        /* Execute specified call through proxy. */
        require(proxy.proxy(sell.target, sell.howToCall, sell.data));

        /* Static calls are intentionally done after the effectful call so they can check resulting state. */

        /* Handle buy-side static call if specified. */
        if (buy.staticTarget != address(0)) {
            require(StaticCall.staticCall(buy.staticTarget, sell.data, buy.staticExtradata));
        }

        /* Handle sell-side static call if specified. */
        if (sell.staticTarget != address(0)) {
            require(StaticCall.staticCall(sell.staticTarget, sell.data, sell.staticExtradata));
        }

        /* Log match event. */
        emit OrdersMatched(
            buyHash,
            sellHash,
            sell.minter != address(0) ? sell.maker : buy.maker,
            sell.minter != address(0) ? buy.maker : sell.maker,
            price,
            metadata
        );
    }
}

File 4 of 23 : ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
        }
        _balances[to] += amount;

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
        }
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}

File 5 of 23 : SafeMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

File 6 of 23 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 7 of 23 : IERC1271.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC1271 standard signature validation method for
 * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
 *
 * _Available since v4.1._
 */
interface IERC1271 {
    /**
     * @dev Should return whether the signature provided is valid for the provided data
     * @param hash      Hash of the data to be signed
     * @param signature Signature byte array associated with _data
     */
    function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}

File 8 of 23 : ProxyRegistry.sol
// SPDX-License-Identifier: MIT

/*

  Proxy registry; keeps a mapping of AuthenticatedProxy contracts and mapping of contracts authorized to access them.  
  
  Abstracted away from the Exchange (a) to reduce Exchange attack surface and (b) so that the Exchange contract can be upgraded without users needing to transfer assets to new proxies.

*/

pragma solidity ^0.8.13;

import "@openzeppelin/contracts/access/Ownable.sol";

import "./OwnableDelegateProxy.sol";

contract ProxyRegistry is Ownable {

    /* DelegateProxy implementation contract. Must be initialized. */
    address public delegateProxyImplementation;

    /* Authenticated proxies by user. */
    mapping(address => OwnableDelegateProxy) public proxies;

    /* Contracts pending access. */
    mapping(address => uint) public pending;

    /* Contracts allowed to call those proxies. */
    mapping(address => bool) public contracts;

    /* Delay period for adding an authenticated contract.
       This mitigates a particular class of potential attack on the Wyvern DAO (which owns this registry) - if at any point the value of assets held by proxy contracts exceeded the value of half the WYV supply (votes in the DAO),
       a malicious but rational attacker could buy half the Wyvern and grant themselves access to all the proxy contracts. A delay period renders this attack nonthreatening - given two weeks, if that happened, users would have
       plenty of time to notice and transfer their assets.
    */
    uint public DELAY_PERIOD = 2 weeks;

    /**
     * Start the process to enable access for specified contract. Subject to delay period.
     *
     * @dev ProxyRegistry owner only
     * @param addr Address to which to grant permissions
     */
    function startGrantAuthentication (address addr)
        public
        onlyOwner
    {
        require(!contracts[addr] && pending[addr] == 0);
        pending[addr] = block.timestamp;
    }

    /**
     * End the process to nable access for specified contract after delay period has passed.
     *
     * @dev ProxyRegistry owner only
     * @param addr Address to which to grant permissions
     */
    function endGrantAuthentication (address addr)
        public
        onlyOwner
    {
        require(!contracts[addr] && pending[addr] != 0 && ((pending[addr] + DELAY_PERIOD) < block.timestamp));
        pending[addr] = 0;
        contracts[addr] = true;
    }

    /**
     * Revoke access for specified contract. Can be done instantly.
     *
     * @dev ProxyRegistry owner only
     * @param addr Address of which to revoke permissions
     */    
    function revokeAuthentication (address addr)
        public
        onlyOwner
    {
        contracts[addr] = false;
    }

    /**
     * Register a proxy contract with this registry
     *
     * @dev Must be called by the user which the proxy is for, creates a new AuthenticatedProxy
     * @return proxy New AuthenticatedProxy contract
     */
    function registerProxy()
        public
        returns (OwnableDelegateProxy proxy)
    {
        require(proxies[msg.sender] == OwnableDelegateProxy(payable(0)), "User already has a proxy");
        proxy = new OwnableDelegateProxy(msg.sender, delegateProxyImplementation, abi.encodeWithSignature("initialize(address,address)", msg.sender, address(this)));
        proxies[msg.sender] = proxy;
        return proxy;
    }

}

File 9 of 23 : TokenTransferProxy.sol
// SPDX-License-Identifier: MIT

/*

  Token transfer proxy. Uses the authentication table of a ProxyRegistry contract to grant ERC20 `transferFrom` access.
  This means that users only need to authorize the proxy contract once for all future protocol versions.

*/

pragma solidity ^0.8.13;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

import "./ProxyRegistry.sol";

contract TokenTransferProxy {

    /* Authentication registry. */
    ProxyRegistry public registry;

    /**
     * Call ERC20 `transferFrom`
     *
     * @dev Authenticated contract only
     * @param token ERC20 token address
     * @param from From address
     * @param to To address
     * @param amount Transfer amount
     */
    function transferFrom(address token, address from, address to, uint amount)
        public
        returns (bool)
    {
        require(registry.contracts(msg.sender));
        return ERC20(token).transferFrom(from, to, amount);
    }

}

File 10 of 23 : AuthenticatedProxy.sol
// SPDX-License-Identifier: MIT

/* 

  Proxy contract to hold access to assets on behalf of a user (e.g. ERC20 approve) and execute calls under particular conditions.

*/

pragma solidity ^0.8.13;

import "./ProxyRegistry.sol";
import "../common/TokenRecipient.sol";
import "./proxy/OwnedUpgradeabilityStorage.sol";

/**
 * @title AuthenticatedProxy
 * @author Project Wyvern Developers
 */
contract AuthenticatedProxy is TokenRecipient, OwnedUpgradeabilityStorage {

    /* Whether initialized. */
    bool initialized = false;

    /* Address which owns this proxy. */
    address public user;

    /* Associated registry with contract authentication information. */
    ProxyRegistry public registry;

    /* Whether access has been revoked. */
    bool public revoked;

    /* Delegate call could be used to atomically transfer multiple assets owned by the proxy contract with one order. */
    enum HowToCall { Call, DelegateCall }

    /* Event fired when the proxy access is revoked or unrevoked. */
    event Revoked(bool revoked);

    /**
     * Initialize an AuthenticatedProxy
     *
     * @param addrUser Address of user on whose behalf this proxy will act
     * @param addrRegistry Address of ProxyRegistry contract which will manage this proxy
     */
    function initialize (address addrUser, ProxyRegistry addrRegistry)
        public
    {
        require(!initialized);
        initialized = true;
        user = addrUser;
        registry = addrRegistry;
    }

    /**
     * Set the revoked flag (allows a user to revoke ProxyRegistry access)
     *
     * @dev Can be called by the user only
     * @param revoke Whether or not to revoke access
     */
    function setRevoke(bool revoke)
        public
    {
        require(msg.sender == user);
        revoked = revoke;
        emit Revoked(revoke);
    }

    /**
     * Execute a message call from the proxy contract
     *
     * @dev Can be called by the user, or by a contract authorized by the registry as long as the user has not revoked access
     * @param dest Address to which the call will be sent
     * @param howToCall Which kind of call to make
     * @param data Calldata to send
     * @return result of the call (success or failure)
     */
    function proxy(address dest, HowToCall howToCall, bytes memory data)
        public
        returns (bool result)
    {
        require(msg.sender == user || (!revoked && registry.contracts(msg.sender)), "Authenticated proxy can only be called by its user, or by a contract authorized by the registry as long as the user has not revoked access");
        bytes memory ret;
        if (howToCall == HowToCall.Call) {
            (result, ret) = dest.call(data);
        } else if (howToCall == HowToCall.DelegateCall) {
            (result, ret) = dest.delegatecall(data);
        }
        return result;
    }

    /**
     * Execute a message call and assert success
     * 
     * @dev Same functionality as `proxy`, just asserts the return value
     * @param dest Address to which the call will be sent
     * @param howToCall What kind of call to make
     * @param data Calldata to send
     */
    function proxyAssert(address dest, HowToCall howToCall, bytes memory data)
        public
    {
        require(proxy(dest, howToCall, data));
    }

}

File 11 of 23 : ArrayUtils.sol
// SPDX-License-Identifier: MIT

/*

  Various functions for manipulating arrays in Solidity.
  This library is completely inlined and does not need to be deployed or linked.

*/

pragma solidity ^0.8.13;

import "@openzeppelin/contracts/utils/math/SafeMath.sol";

/**
 * @title ArrayUtils
 * @author Project Wyvern Developers
 */
library ArrayUtils {
    /**
     * Replace bytes in an array with bytes in another array, guarded by a bitmask
     * Efficiency of this function is a bit unpredictable because of the EVM's word-specific model (arrays under 32 bytes will be slower)
     *
     * @dev Mask must be the size of the byte array. A nonzero byte means the byte array can be changed.
     * @param array The original array
     * @param desired The target array
     * @param mask The mask specifying which bits can be changed
     */
    function guardedArrayReplace(
        bytes memory array,
        bytes memory desired,
        bytes memory mask
    ) internal pure {
        require(array.length == desired.length);
        require(array.length == mask.length);

        uint256 words = array.length / 0x20;
        uint256 index = words * 0x20;
        assert(index / 0x20 == words);
        uint256 i;

        for (i = 0; i < words; i++) {
            /* Conceptually: array[i] = (!mask[i] && array[i]) || (mask[i] && desired[i]), bitwise in word chunks. */
            assembly {
                let commonIndex := mul(0x20, add(1, i))
                let maskValue := mload(add(mask, commonIndex))
                mstore(
                    add(array, commonIndex),
                    or(
                        and(not(maskValue), mload(add(array, commonIndex))),
                        and(maskValue, mload(add(desired, commonIndex)))
                    )
                )
            }
        }

        /* Deal with the last section of the byte array. */
        if (words > 0) {
            /* This overlaps with bytes already set but is still more efficient than iterating through each of the remaining bytes individually. */
            i = words;
            assembly {
                let commonIndex := mul(0x20, add(1, i))
                let maskValue := mload(add(mask, commonIndex))
                mstore(
                    add(array, commonIndex),
                    or(
                        and(not(maskValue), mload(add(array, commonIndex))),
                        and(maskValue, mload(add(desired, commonIndex)))
                    )
                )
            }
        } else {
            /* If the byte array is shorter than a word, we must unfortunately do the whole thing bytewise.
               (bounds checks could still probably be optimized away in assembly, but this is a rare case) */
            for (i = index; i < array.length; i++) {
                array[i] = ((mask[i] ^ 0xff) & array[i]) | (mask[i] & desired[i]);
            }
        }
    }

    /**
     * Test if two arrays are equal
     * Source: https://github.com/GNSPS/solidity-bytes-utils/blob/master/contracts/BytesLib.sol
     *
     * @dev Arrays must be of equal length, otherwise will return false
     * @param a First array
     * @param b Second array
     * @return Whether or not all bytes in the arrays are equal
     */
    function arrayEq(bytes memory a, bytes memory b) internal pure returns (bool) {
        bool success = true;

        assembly {
            let length := mload(a)

            // if lengths don't match the arrays are not equal
            switch eq(length, mload(b))
            case 1 {
                // cb is a circuit breaker in the for loop since there's
                //  no said feature for inline assembly loops
                // cb = 1 - don't breaker
                // cb = 0 - break
                let cb := 1

                let mc := add(a, 0x20)
                let end := add(mc, length)

                for {
                    let cc := add(b, 0x20)
                    // the next line is the loop condition:
                    // while(uint(mc < end) + cb == 2)
                } eq(add(lt(mc, end), cb), 2) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    // if any of these checks fails then arrays are not equal
                    if iszero(eq(mload(mc), mload(cc))) {
                        // unsuccess:
                        success := 0
                        cb := 0
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }

    /**
     * Unsafe write byte array into a memory location
     *
     * @param index Memory location
     * @param source Byte array to write
     * @return End memory index
     */
    function unsafeWriteBytes(uint256 index, bytes memory source) internal pure returns (uint256) {
        if (source.length > 0) {
            assembly {
                let length := mload(source)
                let end := add(source, add(0x20, length))
                let arrIndex := add(source, 0x20)
                let tempIndex := index
                for {

                } eq(lt(arrIndex, end), 1) {
                    arrIndex := add(arrIndex, 0x20)
                    tempIndex := add(tempIndex, 0x20)
                } {
                    mstore(tempIndex, mload(arrIndex))
                }
                index := add(index, length)
            }
        }
        return index;
    }

    /**
     * Unsafe write address into a memory location
     *
     * @param index Memory location
     * @param source Address to write
     * @return End memory index
     */
    function unsafeWriteAddress(uint256 index, address source) internal pure returns (uint256) {
        uint256 conv = uint160(source);
        conv = conv << 0x60;
        assembly {
            mstore(index, conv)
            index := add(index, 0x14)
        }

        return index;
    }

    /**
     * Unsafe write address into a memory location using entire word
     *
     * @param index Memory location
     * @param source uint to write
     * @return End memory index
     */
    function unsafeWriteAddressWord(uint256 index, address source) internal pure returns (uint256) {
        assembly {
            mstore(index, source)
            index := add(index, 0x20)
        }
        return index;
    }

    /**
     * Unsafe write uint into a memory location
     *
     * @param index Memory location
     * @param source uint to write
     * @return End memory index
     */
    function unsafeWriteUint(uint256 index, uint256 source) internal pure returns (uint256) {
        assembly {
            mstore(index, source)
            index := add(index, 0x20)
        }
        return index;
    }

    /**
     * Unsafe write uint8 into a memory location
     *
     * @param index Memory location
     * @param source uint8 to write
     * @return End memory index
     */
    function unsafeWriteUint8(uint256 index, uint8 source) internal pure returns (uint256) {
        assembly {
            mstore8(index, source)
            index := add(index, 0x1)
        }
        return index;
    }

    /**
     * Unsafe write uint8 into a memory location using entire word
     *
     * @param index Memory location
     * @param source uint to write
     * @return End memory index
     */
    function unsafeWriteUint8Word(uint256 index, uint8 source) internal pure returns (uint256) {
        assembly {
            mstore(index, source)
            index := add(index, 0x20)
        }
        return index;
    }

    /**
     * Unsafe write bytes32 into a memory location using entire word
     *
     * @param index Memory location
     * @param source uint to write
     * @return End memory index
     */
    function unsafeWriteBytes32(uint256 index, bytes32 source) internal pure returns (uint256) {
        assembly {
            mstore(index, source)
            index := add(index, 0x20)
        }
        return index;
    }
}

File 12 of 23 : EIP712.sol
// SPDX-License-Identifier: MIT

/*

  << EIP 712 >>

*/

pragma solidity ^0.8.13;

/**
 * @title EIP712
 * @author Anton
 */
contract EIP712 {
    string internal _name;
    string internal _version;
    uint256 internal immutable _chainId;
    address internal immutable _verifyingContract;
    bytes32 internal immutable _salt;
    bytes32 internal immutable DOMAIN_SEPARATOR;
    bytes4 internal constant EIP_1271_MAGICVALUE = 0x1626ba7e;

    bytes internal personalSignPrefix = "\x19Ethereum Signed Message:\n";

    constructor(
        string memory name,
        string memory version,
        uint256 chainId,
        bytes32 salt
    ) {
        _name = name;
        _version = version;
        _chainId = chainId;
        _salt = salt;
        _verifyingContract = address(this);

        DOMAIN_SEPARATOR = keccak256(
            abi.encode(
                keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)"),
                keccak256(bytes(_name)),
                keccak256(bytes(_version)),
                _chainId,
                _verifyingContract,
                _salt
            )
        );
    }

    function domainSeparator() public view returns (bytes32) {
        return DOMAIN_SEPARATOR;
    }
}

File 13 of 23 : ReentrancyGuarded.sol
// SPDX-License-Identifier: MIT

/*

  Simple contract extension to provide a contract-global reentrancy guard on functions.

*/

pragma solidity ^0.8.13;

/**
 * @title ReentrancyGuarded
 * @author Project Wyvern Developers
 */
contract ReentrancyGuarded {

    bool reentrancyLock = false;

    /* Prevent a contract function from being reentrant-called. */
    modifier reentrancyGuard {
        if (reentrancyLock) {
            revert();
        }
        reentrancyLock = true;
        _;
        reentrancyLock = false;
    }

}

File 14 of 23 : StaticCall.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.13;

import "./ArrayUtils.sol";

/**
 * @title Utils
 * @author Anton
 */
library StaticCall {
    function isContract(address what) internal view returns (bool) {
        uint256 size;
        assembly {
            size := extcodesize(what)
        }
        return size > 0;
    }

    /**
     * @dev Execute a STATICCALL (introduced with Ethereum Metropolis, non-state-modifying external call)
     * @param target Contract to call
     * @param data Calldata (appended to extradata)
     * @param extradata Base data for STATICCALL (probably function selector and argument encoding)
     * @return result of the call (success or failure)
     */
    function staticCall(
        address target,
        bytes memory data,
        bytes memory extradata
    ) internal view returns (bool result) {
        bytes memory combined = new bytes(data.length + extradata.length);
        uint256 index;
        assembly {
            index := add(combined, 0x20)
        }
        index = ArrayUtils.unsafeWriteBytes(index, extradata);
        ArrayUtils.unsafeWriteBytes(index, data);

        return staticCall(target, combined);
    }

    /**
     * @dev Execute a STATICCALL (introduced with Ethereum Metropolis, non-state-modifying external call)
     * @param target Contract to call
     * @param data Calldata (appended to extradata)
     * @return result of the call (success or failure)
     */
    function staticCall(
        address target,
        bytes memory data
    ) internal view returns (bool result) {
        assembly {
            result := staticcall(gas(), target, add(data, 0x20), mload(data), mload(0x40), 0)
        }
        return result;
    }
}

File 15 of 23 : SaleKindInterface.sol
// SPDX-License-Identifier: MIT

/*

  Abstract over fixed-price sales and Dutch auctions, with the intent of easily supporting additional methods of sale later.

  Separated into a library for convenience, all the functions are inlined.

*/

pragma solidity ^0.8.13;

import "@openzeppelin/contracts/utils/math/SafeMath.sol";

/**
 * @title SaleKindInterface
 * @author Project Wyvern Developers
 */
library SaleKindInterface {
    /**
     * Side: buy or sell.
     */
    enum Side {
        Buy,
        Sell
    }

    /**
     * Currently supported kinds of sale: fixed price, Dutch auction.
     * English auctions cannot be supported without stronger escrow guarantees.
     * Future interesting options: Vickrey auction, nonlinear Dutch auctions.
     */
    enum SaleKind {
        FixedPrice,
        DutchAuction
    }

    /**
     * @dev Check whether the parameters of a sale are valid
     * @param saleKind Kind of sale
     * @param expirationTime Order expiration time
     * @return Whether the parameters were valid
     */
    function validateParameters(SaleKind saleKind, uint256 expirationTime) internal pure returns (bool) {
        /* Auctions must have a set expiration date. */
        return (saleKind == SaleKind.FixedPrice || expirationTime > 0);
    }

    /**
     * @dev Return whether or not an order can be settled
     * @dev Precondition: parameters have passed validateParameters
     * @param listingTime Order listing time
     * @param expirationTime Order expiration time
     */
    function canSettleOrder(uint256 listingTime, uint256 expirationTime) internal view returns (bool) {
        return (listingTime < block.timestamp) && (expirationTime == 0 || block.timestamp < expirationTime);
    }

    /**
     * @dev Calculate the settlement price of an order
     * @dev Precondition: parameters have passed validateParameters.
     * @param side Order side
     * @param saleKind Method of sale
     * @param basePrice Order base price
     * @param extra Order extra price data
     * @param listingTime Order listing time
     * @param expirationTime Order expiration time
     */
    function calculateFinalPrice(
        Side side,
        SaleKind saleKind,
        uint256 basePrice,
        uint256 extra,
        uint256 listingTime,
        uint256 expirationTime
    ) internal view returns (uint256 finalPrice) {
        if (saleKind == SaleKind.FixedPrice) {
            return basePrice;
        } else if (saleKind == SaleKind.DutchAuction) {
            uint256 diff = SafeMath.div(
                SafeMath.mul(extra, SafeMath.sub(block.timestamp, listingTime)),
                SafeMath.sub(expirationTime, listingTime)
            );
            if (side == Side.Sell) {
                /* Sell-side - start price: basePrice. End price: basePrice - extra. */
                return SafeMath.sub(basePrice, diff);
            } else {
                /* Buy-side - start price: basePrice. End price: basePrice + extra. */
                return SafeMath.add(basePrice, diff);
            }
        }
    }
}

File 16 of 23 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 17 of 23 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 18 of 23 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

File 19 of 23 : OwnableDelegateProxy.sol
// SPDX-License-Identifier: MIT

/*

  WyvernOwnableDelegateProxy

*/

pragma solidity ^0.8.13;

import "./proxy/OwnedUpgradeabilityProxy.sol";

contract OwnableDelegateProxy is OwnedUpgradeabilityProxy {

    constructor(address owner, address initialImplementation, bytes memory data) {
        setUpgradeabilityOwner(owner);
        _upgradeTo(initialImplementation);

        (bool success,) = initialImplementation.delegatecall(data);
        require(success, "OwnableDelegateProxy failed implementation");
    }

}

File 20 of 23 : OwnedUpgradeabilityProxy.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.13;

import './Proxy.sol';
import './OwnedUpgradeabilityStorage.sol';

/**
 * @title OwnedUpgradeabilityProxy
 * @dev This contract combines an upgradeability proxy with basic authorization control functionalities
 */
contract OwnedUpgradeabilityProxy is Proxy, OwnedUpgradeabilityStorage {
  /**
  * @dev Event to show ownership has been transferred
  * @param previousOwner representing the address of the previous owner
  * @param newOwner representing the address of the new owner
  */
  event ProxyOwnershipTransferred(address previousOwner, address newOwner);

  /**
  * @dev This event will be emitted every time the implementation gets upgraded
  * @param implementation_ representing the address of the upgraded implementation
  */
  event Upgraded(address indexed implementation_);

  /**
  * @dev Tells the address of the current implementation
  * @return address of the current implementation
  */
  function implementation() override(Proxy, OwnedUpgradeabilityStorage) public view returns (address) {
    return _implementation;
  }

  /**
  * @dev Tells the proxy type (EIP 897)
  * @return proxyTypeId Proxy type, 2 for forwarding proxy
  */
  function proxyType() override(Proxy, OwnedUpgradeabilityStorage) public pure returns (uint256 proxyTypeId) {
    return 2;
  }

  /**
  * @dev Upgrades the implementation address
  * @param implementation_ representing the address of the new implementation to be set
  */
  function _upgradeTo(address implementation_) internal {
    require(_implementation != implementation_);
    _implementation = implementation_;
    emit Upgraded(_implementation);
  }

  /**
  * @dev Throws if called by any account other than the owner.
  */
  modifier onlyProxyOwner() {
    require(msg.sender == proxyOwner());
    _;
  }

  /**
   * @dev Tells the address of the proxy owner
   * @return the address of the proxy owner
   */
  function proxyOwner() public view returns (address) {
    return upgradeabilityOwner();
  }

  /**
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function transferProxyOwnership(address newOwner) public onlyProxyOwner {
    require(newOwner != address(0));
    emit ProxyOwnershipTransferred(proxyOwner(), newOwner);
    setUpgradeabilityOwner(newOwner);
  }

  /**
   * @dev Allows the upgradeability owner to upgrade the current implementation of the proxy.
   * @param implementation_ representing the address of the new implementation to be set.
   */
  function upgradeTo(address implementation_) public onlyProxyOwner {
    _upgradeTo(implementation_);
  }

  /**
   * @dev Allows the upgradeability owner to upgrade the current implementation of the proxy
   * and delegatecall the new implementation for initialization.
   * @param implementation_ representing the address of the new implementation to be set.
   * @param data represents the msg.data to bet sent in the low level call. This parameter may include the function
   * signature of the implementation to be called with the needed payload
   */
  function upgradeToAndCall(address implementation_, bytes memory data) payable public onlyProxyOwner {
    upgradeTo(implementation_);
    (bool success,) = address(this).delegatecall(data);
    require(success, "Call failed after proxy upgrade");
  }
}

File 21 of 23 : Proxy.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.13;

/**
 * @title Proxy
 * @dev Gives the possibility to delegate any call to a foreign implementation.
 */
abstract contract Proxy {
    /**
     * @dev Tells the address of the implementation where every call will be delegated.
     * @return address of the implementation to which it will be delegated
     */
    function implementation() public view virtual returns (address);

    /**
     * @dev Tells the type of proxy (EIP 897)
     * @return proxyTypeId Type of proxy, 2 for upgradeable proxy
     */
    function proxyType() public pure virtual returns (uint256 proxyTypeId);

    function call() internal {
        address _impl = implementation();
        require(_impl != address(0));

        assembly {
            let ptr := mload(0x40)
            calldatacopy(ptr, 0, calldatasize())
            let result := delegatecall(gas(), _impl, ptr, calldatasize(), 0, 0)
            let size := returndatasize()
            returndatacopy(ptr, 0, size)

            switch result
            case 0 {
                revert(ptr, size)
            }
            default {
                return(ptr, size)
            }
        }
    }

    /**
     * @dev Receive function allowing to perform a delegatecall to the given implementation.
     * This function will return whatever the implementation call returns
     */
    receive() external payable {
        call();
    }

    /**
     * @dev Fallback function allowing to perform a delegatecall to the given implementation.
     * This function will return whatever the implementation call returns
     */
    fallback() external payable {
        call();
    }
}

File 22 of 23 : OwnedUpgradeabilityStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.13;

/**
 * @title OwnedUpgradeabilityStorage
 * @dev This contract keeps track of the upgradeability owner
 */
contract OwnedUpgradeabilityStorage {

  // Current implementation
  address internal _implementation;

  // Owner of the contract
  address private _upgradeabilityOwner;

  /**
   * @dev Tells the address of the owner
   * @return the address of the owner
   */
  function upgradeabilityOwner() public view returns (address) {
    return _upgradeabilityOwner;
  }

  /**
   * @dev Sets the address of the owner
   */
  function setUpgradeabilityOwner(address newUpgradeabilityOwner) internal {
    _upgradeabilityOwner = newUpgradeabilityOwner;
  }

  /**
  * @dev Tells the address of the current implementation
  * @return address of the current implementation
  */
  function implementation() virtual public view returns (address) {
    return _implementation;
  }

  /**
  * @dev Tells the proxy type (EIP 897)
  * @return proxyTypeId Proxy type, 2 for forwarding proxy
  */
  function proxyType() virtual public pure returns (uint256 proxyTypeId) {
    return 2;
  }
}

File 23 of 23 : TokenRecipient.sol
// SPDX-License-Identifier: MIT

/*

  Token recipient. Modified very slightly from the example on http://ethereum.org/dao (just to index log parameters).

*/

pragma solidity ^0.8.13;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

/**
 * @title TokenRecipient
 * @author Project Wyvern Developers
 */
contract TokenRecipient {
    event ReceivedEther(address indexed sender, uint256 amount);
    event ReceivedTokens(address indexed from, uint256 value, address indexed token, bytes extraData);

    /**
     * @dev Receive tokens and generate a log event
     * @param from Address from which to transfer tokens
     * @param value Amount of tokens to transfer
     * @param token Address of token
     * @param extraData Additional data to log
     */
    function receiveApproval(
        address from,
        uint256 value,
        address token,
        bytes memory extraData
    ) public {
        ERC20 t = ERC20(token);
        require(t.transferFrom(from, address(this), value));
        emit ReceivedTokens(from, value, token, extraData);
    }

    /**
     * @dev Receive Ether and generate a log event
     */
    receive() external payable {
        emit ReceivedEther(msg.sender, msg.value);
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"contract ProxyRegistry","name":"registryAddress","type":"address"},{"internalType":"contract TokenTransferProxy","name":"tokenTransferProxyAddress","type":"address"},{"internalType":"contract ERC20","name":"tokenAddress","type":"address"},{"internalType":"address","name":"protocolFeeAddress","type":"address"},{"internalType":"address","name":"rewardFeeRecipient","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"hash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"exchange","type":"address"},{"indexed":true,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"address","name":"taker","type":"address"},{"indexed":false,"internalType":"uint256","name":"makerRelayerFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"takerRelayerFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"makerProtocolFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"takerProtocolFee","type":"uint256"},{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"enum ExchangeCore.FeeMethod","name":"feeMethod","type":"uint8"},{"indexed":false,"internalType":"enum SaleKindInterface.Side","name":"side","type":"uint8"},{"indexed":false,"internalType":"enum SaleKindInterface.SaleKind","name":"saleKind","type":"uint8"},{"indexed":false,"internalType":"address","name":"target","type":"address"}],"name":"OrderApprovedPartOne","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"hash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"enum AuthenticatedProxy.HowToCall","name":"howToCall","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"replacementPattern","type":"bytes"},{"indexed":false,"internalType":"address","name":"staticTarget","type":"address"},{"indexed":false,"internalType":"bytes","name":"staticExtradata","type":"bytes"},{"indexed":false,"internalType":"address","name":"paymentToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"basePrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"extra","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"listingTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"expirationTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"salt","type":"uint256"},{"indexed":false,"internalType":"bool","name":"orderbookInclusionDesired","type":"bool"}],"name":"OrderApprovedPartTwo","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"OrderCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"buyHash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"sellHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"maker","type":"address"},{"indexed":true,"internalType":"address","name":"taker","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"metadata","type":"bytes32"}],"name":"OrdersMatched","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"relaySetFeeTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"relayExchangeFee","type":"uint256"}],"name":"RelaySetFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"address","name":"relayRewardFeeRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"relaySetFeeRecipientTime","type":"uint256"}],"name":"RelaySetRecipientFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"exchangeFee","type":"uint256"}],"name":"SetFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"address","name":"rewardFeeRecipient","type":"address"}],"name":"SetFeeRecipient","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"}],"name":"SetStartTime","type":"event"},{"inputs":[],"name":"INVERSE_BASIS_POINT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ORDER_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_delaySetFeeRecipientTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_delaySetFeeTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_exchangeFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_relayExchangeFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_relayRewardFeeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_relaySetFeeRecipientTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_relaySetFeeTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_rewardFeeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[7]","name":"addrs","type":"address[7]"},{"internalType":"uint256[9]","name":"uints","type":"uint256[9]"},{"internalType":"enum ExchangeCore.FeeMethod","name":"feeMethod","type":"uint8"},{"internalType":"enum SaleKindInterface.Side","name":"side","type":"uint8"},{"internalType":"enum SaleKindInterface.SaleKind","name":"saleKind","type":"uint8"},{"internalType":"enum AuthenticatedProxy.HowToCall","name":"howToCall","type":"uint8"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"replacementPattern","type":"bytes"},{"internalType":"bytes","name":"staticExtradata","type":"bytes"},{"internalType":"bool","name":"orderbookInclusionDesired","type":"bool"}],"name":"approveOrder_","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"approvedOrders","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[14]","name":"addrs","type":"address[14]"},{"internalType":"uint256[18]","name":"uints","type":"uint256[18]"},{"internalType":"uint8[8]","name":"feeMethodsSidesKindsHowToCalls","type":"uint8[8]"},{"internalType":"bytes","name":"calldataBuy","type":"bytes"},{"internalType":"bytes","name":"calldataSell","type":"bytes"},{"internalType":"bytes","name":"replacementPatternBuy","type":"bytes"},{"internalType":"bytes","name":"replacementPatternSell","type":"bytes"},{"internalType":"bytes","name":"staticExtradataBuy","type":"bytes"},{"internalType":"bytes","name":"staticExtradataSell","type":"bytes"},{"internalType":"bytes[2]","name":"signatures","type":"bytes[2]"},{"internalType":"bytes32","name":"metadata","type":"bytes32"}],"name":"atomicMatch_","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[7]","name":"addrs","type":"address[7]"},{"internalType":"uint256[9]","name":"uints","type":"uint256[9]"},{"internalType":"enum ExchangeCore.FeeMethod","name":"feeMethod","type":"uint8"},{"internalType":"enum SaleKindInterface.Side","name":"side","type":"uint8"},{"internalType":"enum SaleKindInterface.SaleKind","name":"saleKind","type":"uint8"},{"internalType":"enum AuthenticatedProxy.HowToCall","name":"howToCall","type":"uint8"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"replacementPattern","type":"bytes"},{"internalType":"bytes","name":"staticExtradata","type":"bytes"}],"name":"calculateCurrentPrice_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum SaleKindInterface.Side","name":"side","type":"uint8"},{"internalType":"enum SaleKindInterface.SaleKind","name":"saleKind","type":"uint8"},{"internalType":"uint256","name":"basePrice","type":"uint256"},{"internalType":"uint256","name":"extra","type":"uint256"},{"internalType":"uint256","name":"listingTime","type":"uint256"},{"internalType":"uint256","name":"expirationTime","type":"uint256"}],"name":"calculateFinalPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[14]","name":"addrs","type":"address[14]"},{"internalType":"uint256[18]","name":"uints","type":"uint256[18]"},{"internalType":"uint8[8]","name":"feeMethodsSidesKindsHowToCalls","type":"uint8[8]"},{"internalType":"bytes","name":"calldataBuy","type":"bytes"},{"internalType":"bytes","name":"calldataSell","type":"bytes"},{"internalType":"bytes","name":"replacementPatternBuy","type":"bytes"},{"internalType":"bytes","name":"replacementPatternSell","type":"bytes"},{"internalType":"bytes","name":"staticExtradataBuy","type":"bytes"},{"internalType":"bytes","name":"staticExtradataSell","type":"bytes"}],"name":"calculateMatchPrice_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[7]","name":"addrs","type":"address[7]"},{"internalType":"uint256[10]","name":"uints","type":"uint256[10]"},{"internalType":"enum ExchangeCore.FeeMethod","name":"feeMethod","type":"uint8"},{"internalType":"enum SaleKindInterface.Side","name":"side","type":"uint8"},{"internalType":"enum SaleKindInterface.SaleKind","name":"saleKind","type":"uint8"},{"internalType":"enum AuthenticatedProxy.HowToCall","name":"howToCall","type":"uint8"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"replacementPattern","type":"bytes"},{"internalType":"bytes","name":"staticExtradata","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"cancelOrderWithNonce_","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[7]","name":"addrs","type":"address[7]"},{"internalType":"uint256[9]","name":"uints","type":"uint256[9]"},{"internalType":"enum ExchangeCore.FeeMethod","name":"feeMethod","type":"uint8"},{"internalType":"enum SaleKindInterface.Side","name":"side","type":"uint8"},{"internalType":"enum SaleKindInterface.SaleKind","name":"saleKind","type":"uint8"},{"internalType":"enum AuthenticatedProxy.HowToCall","name":"howToCall","type":"uint8"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"replacementPattern","type":"bytes"},{"internalType":"bytes","name":"staticExtradata","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"cancelOrder_","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"cancelledOrFinalized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMinimumMakerProtocolFee","type":"uint256"}],"name":"changeMinimumMakerProtocolFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMinimumTakerProtocolFee","type":"uint256"}],"name":"changeMinimumTakerProtocolFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newProtocolFeeRecipient","type":"address"}],"name":"changeProtocolFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"codename","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"domainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeToken","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"array","type":"bytes"},{"internalType":"bytes","name":"desired","type":"bytes"},{"internalType":"bytes","name":"mask","type":"bytes"}],"name":"guardedArrayReplace","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address[7]","name":"addrs","type":"address[7]"},{"internalType":"uint256[9]","name":"uints","type":"uint256[9]"},{"internalType":"enum ExchangeCore.FeeMethod","name":"feeMethod","type":"uint8"},{"internalType":"enum SaleKindInterface.Side","name":"side","type":"uint8"},{"internalType":"enum SaleKindInterface.SaleKind","name":"saleKind","type":"uint8"},{"internalType":"enum AuthenticatedProxy.HowToCall","name":"howToCall","type":"uint8"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"replacementPattern","type":"bytes"},{"internalType":"bytes","name":"staticExtradata","type":"bytes"}],"name":"hashOrder_","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address[7]","name":"addrs","type":"address[7]"},{"internalType":"uint256[9]","name":"uints","type":"uint256[9]"},{"internalType":"enum ExchangeCore.FeeMethod","name":"feeMethod","type":"uint8"},{"internalType":"enum SaleKindInterface.Side","name":"side","type":"uint8"},{"internalType":"enum SaleKindInterface.SaleKind","name":"saleKind","type":"uint8"},{"internalType":"enum AuthenticatedProxy.HowToCall","name":"howToCall","type":"uint8"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"replacementPattern","type":"bytes"},{"internalType":"bytes","name":"staticExtradata","type":"bytes"}],"name":"hashToSign_","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumMakerProtocolFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumTakerProtocolFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"buyCalldata","type":"bytes"},{"internalType":"bytes","name":"buyReplacementPattern","type":"bytes"},{"internalType":"bytes","name":"sellCalldata","type":"bytes"},{"internalType":"bytes","name":"sellReplacementPattern","type":"bytes"}],"name":"orderCalldataCanMatch","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address[14]","name":"addrs","type":"address[14]"},{"internalType":"uint256[18]","name":"uints","type":"uint256[18]"},{"internalType":"uint8[8]","name":"feeMethodsSidesKindsHowToCalls","type":"uint8[8]"},{"internalType":"bytes","name":"calldataBuy","type":"bytes"},{"internalType":"bytes","name":"calldataSell","type":"bytes"},{"internalType":"bytes","name":"replacementPatternBuy","type":"bytes"},{"internalType":"bytes","name":"replacementPatternSell","type":"bytes"},{"internalType":"bytes","name":"staticExtradataBuy","type":"bytes"},{"internalType":"bytes","name":"staticExtradataSell","type":"bytes"}],"name":"ordersCanMatch_","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"contract ProxyRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"relayExchangeFee_","type":"uint256"}],"name":"relaySetFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"relayRewardFeeRecipient_","type":"address"}],"name":"relaySetFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"setExchangeToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"exchangeFee_","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"rewardFeeRecipient_","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"startTime","type":"uint256"}],"name":"setStartTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"startTimes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenTransferProxy","outputs":[{"internalType":"contract TokenTransferProxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[7]","name":"addrs","type":"address[7]"},{"internalType":"uint256[9]","name":"uints","type":"uint256[9]"},{"internalType":"enum ExchangeCore.FeeMethod","name":"feeMethod","type":"uint8"},{"internalType":"enum SaleKindInterface.Side","name":"side","type":"uint8"},{"internalType":"enum SaleKindInterface.SaleKind","name":"saleKind","type":"uint8"},{"internalType":"enum AuthenticatedProxy.HowToCall","name":"howToCall","type":"uint8"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"replacementPattern","type":"bytes"},{"internalType":"bytes","name":"staticExtradata","type":"bytes"}],"name":"validateOrderParameters_","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[7]","name":"addrs","type":"address[7]"},{"internalType":"uint256[9]","name":"uints","type":"uint256[9]"},{"internalType":"enum ExchangeCore.FeeMethod","name":"feeMethod","type":"uint8"},{"internalType":"enum SaleKindInterface.Side","name":"side","type":"uint8"},{"internalType":"enum SaleKindInterface.SaleKind","name":"saleKind","type":"uint8"},{"internalType":"enum AuthenticatedProxy.HowToCall","name":"howToCall","type":"uint8"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"replacementPattern","type":"bytes"},{"internalType":"bytes","name":"staticExtradata","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"validateOrder_","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

6000805460ff19169055610140604052601a6101008190527f19457468657265756d205369676e6564204d6573736167653a0a0000000000006101209081526200004d916003919062000283565b506000600b556000600c5560fa600e5560fa600f556201518060125560006013556203f48060145560006015553480156200008757600080fd5b506040516200626638038062006266833981016040819052620000aa9162000421565b8888888883838383838383838360019080519060200190620000ce92919062000283565b508251620000e490600290602086019062000283565b50608082905260c08190523060a0526040517fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac564729062000126906001906200053d565b604051809103902060026040516200013f91906200053d565b60405190819003812060805160a05160c0516200018c9695946020019586526020860194909452604085019290925260608401526001600160a01b0316608083015260a082015260c00190565b60408051601f19818403018152919052805160209091012060e05250620001bf9250620001b99150503390565b62000231565b5050600680546001600160a01b03199081166001600160a01b039d8e16179091556007805482169b8d169b909b17909a555050600580548916978a16979097179096555050600d80548616938716939093179092556010805490941694169390931790915550620005e0945050505050565b600480546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b828054620002919062000501565b90600052602060002090601f016020900481019282620002b5576000855562000300565b82601f10620002d057805160ff191683800117855562000300565b8280016001018555821562000300579182015b8281111562000300578251825591602001919060010190620002e3565b506200030e92915062000312565b5090565b5b808211156200030e576000815560010162000313565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200035157600080fd5b81516001600160401b03808211156200036e576200036e62000329565b604051601f8301601f19908116603f0116810190828211818310171562000399576200039962000329565b81604052838152602092508683858801011115620003b657600080fd5b600091505b83821015620003da5785820183015181830184015290820190620003bb565b83821115620003ec5760008385830101525b9695505050505050565b6001600160a01b03811681146200040c57600080fd5b50565b80516200041c81620003f6565b919050565b60008060008060008060008060006101208a8c0312156200044157600080fd5b89516001600160401b03808211156200045957600080fd5b620004678d838e016200033f565b9a5060208c01519150808211156200047e57600080fd5b506200048d8c828d016200033f565b98505060408a0151965060608a0151955060808a0151620004ae81620003f6565b60a08b0151909550620004c181620003f6565b9350620004d160c08b016200040f565b9250620004e160e08b016200040f565b9150620004f26101008b016200040f565b90509295985092959850929598565b600181811c908216806200051657607f821691505b6020821081036200053757634e487b7160e01b600052602260045260246000fd5b50919050565b600080835481600182811c9150808316806200055a57607f831692505b602080841082036200057a57634e487b7160e01b86526022600452602486fd5b818015620005915760018114620005a357620005d2565b60ff19861689528489019650620005d2565b60008a81526020902060005b86811015620005ca5781548b820152908501908301620005af565b505084890196505b509498975050505050505050565b60805160a05160c05160e051615c4e620006186000396000818161086d0152613f140152600050506000505060005050615c4e6000f3fe6080604052600436106102885760003560e01c8063796668681161015a578063c3b2d4d9116100c1578063e5cf34981161007a578063e5cf3498146107b6578063e74b981b146107f1578063f2fde38b14610811578063f53fd4ae14610831578063f698da251461085e578063f973a2091461089157600080fd5b8063c3b2d4d914610714578063ca595b9a1461072a578063cae6047f1461074a578063d537e13114610760578063e058ce9714610780578063e363db2f146107a057600080fd5b80638da5cb5b116101135780638da5cb5b1461065657806398b4002314610674578063a03cc0b214610694578063a25eb5d9146106b4578063bfa1dc30146106d4578063c214d638146106f457600080fd5b806379666868146105aa5780637b103999146105ca5780637ccefc52146105ea5780637d766981146106005780637e84cbd41461062057806385bdf9891461063657600080fd5b80633f67ee0d116101fe57806365f15ffd116101b757806365f15ffd1461050257806369fe0e2d14610522578063715018a61461054257806371d02b381461055757806372593b4c14610577578063786023d91461059757600080fd5b80633f67ee0d14610442578063514f03301461046257806351917b0a14610482578063562b2ebc146104a257806363d36c0b146104c257806364df049e146104e257600080fd5b8063239e83df11610250578063239e83df1461034657806328a8ee68146103735780632e819a031461038957806331e631991461039f578063376e7b27146103d75780633e0a322d1461042257600080fd5b806304588e051461028d5780630eefdbad146102b65780631305f35c146102ee57806314350c24146103045780631a6b13e214610326575b600080fd5b34801561029957600080fd5b506102a360135481565b6040519081526020015b60405180910390f35b3480156102c257600080fd5b506007546102d6906001600160a01b031681565b6040516001600160a01b0390911681526020016102ad565b3480156102fa57600080fd5b506102a360125481565b34801561031057600080fd5b5061032461031f366004614cd9565b6108c5565b005b34801561033257600080fd5b50610324610341366004614cd9565b6108d2565b34801561035257600080fd5b50610366610361366004614d94565b6108df565b6040516102ad9190614e68565b34801561037f57600080fd5b506102a3600c5481565b34801561039557600080fd5b506102a360155481565b3480156103ab57600080fd5b506103666040518060400160405280600c81526020016b4c616d62746f6e20576f726d60a01b81525081565b3480156103e357600080fd5b506104126103f2366004614e90565b600860209081526000928352604080842090915290825290205460ff1681565b60405190151581526020016102ad565b34801561042e57600080fd5b5061032461043d366004614cd9565b6108f6565b34801561044e57600080fd5b506102a361045d366004614fa6565b610945565b34801561046e57600080fd5b5061032461047d36600461509a565b610baf565b34801561048e57600080fd5b506011546102d6906001600160a01b031681565b3480156104ae57600080fd5b506104126104bd3660046150b7565b610bd9565b3480156104ce57600080fd5b506102a36104dd366004615163565b610c13565b3480156104ee57600080fd5b50600d546102d6906001600160a01b031681565b34801561050e57600080fd5b5061032461051d3660046151bc565b610c30565b34801561052e57600080fd5b5061032461053d366004614cd9565b610e9d565b34801561054e57600080fd5b50610324610f1e565b34801561056357600080fd5b506102a3610572366004614fa6565b610f32565b34801561058357600080fd5b506104126105923660046153e8565b61118e565b6103246105a5366004615588565b611739565b3480156105b657600080fd5b506103246105c5366004615713565b611d05565b3480156105d657600080fd5b506006546102d6906001600160a01b031681565b3480156105f657600080fd5b506102a3600b5481565b34801561060c57600080fd5b506102a361061b366004614fa6565b611f65565b34801561062c57600080fd5b506102a360145481565b34801561064257600080fd5b5061032461065136600461509a565b6121c1565b34801561066257600080fd5b506004546001600160a01b03166102d6565b34801561068057600080fd5b5061032461068f36600461584e565b61222c565b3480156106a057600080fd5b506103246106af36600461509a565b612479565b3480156106c057600080fd5b506005546102d6906001600160a01b031681565b3480156106e057600080fd5b506010546102d6906001600160a01b031681565b34801561070057600080fd5b5061041261070f3660046151bc565b6124a3565b34801561072057600080fd5b506102a3600e5481565b34801561073657600080fd5b50610412610745366004614fa6565b61270d565b34801561075657600080fd5b506102a361271081565b34801561076c57600080fd5b506102a361077b3660046153e8565b612969565b34801561078c57600080fd5b5061032461079b366004614cd9565b612f04565b3480156107ac57600080fd5b506102a3600f5481565b3480156107c257600080fd5b506104126107d1366004614e90565b600960209081526000928352604080842090915290825290205460ff1681565b3480156107fd57600080fd5b5061032461080c36600461509a565b612f56565b34801561081d57600080fd5b5061032461082c36600461509a565b612ffd565b34801561083d57600080fd5b506102a361084c36600461509a565b600a6020526000908152604090205481565b34801561086a57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006102a3565b34801561089d57600080fd5b506102a37fdf71e6f7b634d9dff3e18cf35f55eb2c50992cdf8f4044e1949ada496d2e9ed281565b6108cd61307b565b600b55565b6108da61307b565b600c55565b60606108ec8484846130d5565b50825b9392505050565b336000818152600a6020908152604091829020849055815192835282018390527f8da5af0cb50a5743c77f99eeeb6f24c1836f9632035e083c916b2875f6165ce391015b60405180910390a150565b6000610ba1604051806102e001604052808c60006007811061096957610969615949565b60200201516001600160a01b031681526020018c60016007811061098f5761098f615949565b60200201516001600160a01b031681526020018c6002600781106109b5576109b5615949565b60200201516001600160a01b031681526020018b6000600981106109db576109db615949565b602002015181526020018b6001600981106109f8576109f8615949565b602002015181526020018b600260098110610a1557610a15615949565b602002015181526020018b600360098110610a3257610a32615949565b602002015181526020018c600360078110610a4f57610a4f615949565b60200201516001600160a01b031681526020018a6001811115610a7457610a7461595f565b8152602001896001811115610a8b57610a8b61595f565b8152602001886001811115610aa257610aa261595f565b815260808d01516001600160a01b03166020820152604001876001811115610acc57610acc61595f565b8152602081018790526040810186905260a0808e01516001600160a01b0316606083015260808201869052018c600660200201516001600160a01b031681526020018b600460098110610b2157610b21615949565b602002015181526020018b600560098110610b3e57610b3e615949565b602002015181526020018b600660098110610b5b57610b5b615949565b602002015181526020018b600760098110610b7857610b78615949565b602002015181526020018b600860098110610b9557610b95615949565b60200201519052613261565b9a9950505050505050505050565b610bb761307b565b600d80546001600160a01b0319166001600160a01b0392909216919091179055565b825160009015610bee57610bee8584866130d5565b815115610c0057610c008386846130d5565b610c0a8584613295565b95945050505050565b6000610c238787878787876132f8565b90505b9695505050505050565b6000604051806102e001604052808c600060078110610c5157610c51615949565b60200201516001600160a01b031681526020018c600160078110610c7757610c77615949565b60200201516001600160a01b031681526020018c600260078110610c9d57610c9d615949565b60200201516001600160a01b031681526020018b600060098110610cc357610cc3615949565b602002015181526020018b600160098110610ce057610ce0615949565b602002015181526020018b600260098110610cfd57610cfd615949565b602002015181526020018b600360098110610d1a57610d1a615949565b602002015181526020018c600360078110610d3757610d37615949565b60200201516001600160a01b031681526020018a6001811115610d5c57610d5c61595f565b8152602001896001811115610d7357610d7361595f565b8152602001886001811115610d8a57610d8a61595f565b815260808d01516001600160a01b03166020820152604001876001811115610db457610db461595f565b8152602081018790526040810186905260a0808e01516001600160a01b0316606083015260808201869052018c600660200201516001600160a01b031681526020018b600460098110610e0957610e09615949565b602002015181526020018b600560098110610e2657610e26615949565b602002015181526020018b600660098110610e4357610e43615949565b602002015181526020018b600760098110610e6057610e60615949565b602002015181526020018b600860098110610e7d57610e7d615949565b602002015190529050610e908183613390565b5050505050505050505050565b610ea561307b565b601354600003610eb457600080fd5b80600f5414610ec257600080fd5b42601254601354610ed3919061598b565b1115610ede57600080fd5b6000601355600e81905560408051338152602081018390527f01fe2943baee27f47add82886c2200f910c749c461c9b63c5fe83901a53bdb49910161093a565b610f2661307b565b610f30600061341d565b565b6000610ba1604051806102e001604052808c600060078110610f5657610f56615949565b60200201516001600160a01b031681526020018c600160078110610f7c57610f7c615949565b60200201516001600160a01b031681526020018c600260078110610fa257610fa2615949565b60200201516001600160a01b031681526020018b600060098110610fc857610fc8615949565b602002015181526020018b600160098110610fe557610fe5615949565b602002015181526020018b60026009811061100257611002615949565b602002015181526020018b60036009811061101f5761101f615949565b602002015181526020018c60036007811061103c5761103c615949565b60200201516001600160a01b031681526020018a60018111156110615761106161595f565b81526020018960018111156110785761107861595f565b815260200188600181111561108f5761108f61595f565b815260808d01516001600160a01b031660208201526040018760018111156110b9576110b961595f565b8152602081018790526040810186905260a0808e01516001600160a01b0316606083015260808201869052018c600660200201516001600160a01b031681526020018b60046009811061110e5761110e615949565b602002015181526020018b60056009811061112b5761112b615949565b602002015181526020018b60066009811061114857611148615949565b602002015181526020018b60076009811061116557611165615949565b602002015181526020018b60086009811061118257611182615949565b6020020151905261346f565b600080604051806102e001604052808c6000600e81106111b0576111b0615949565b60200201516001600160a01b031681526020018c6001600e81106111d6576111d6615949565b60200201516001600160a01b031681526020018c6002600e81106111fc576111fc615949565b60200201516001600160a01b031681526020018b60006012811061122257611222615949565b602002015181526020018b60016012811061123f5761123f615949565b602002015181526020018b60026012811061125c5761125c615949565b602002015181526020018b60036012811061127957611279615949565b602002015181526020018c6003600e811061129657611296615949565b60200201516001600160a01b031681526020018a6000600881106112bc576112bc615949565b602002015160ff1660018111156112d5576112d561595f565b60018111156112e6576112e661595f565b81526020018a6001602002015160ff1660018111156113075761130761595f565b60018111156113185761131861595f565b81526020018a6002602002015160ff1660018111156113395761133961595f565b600181111561134a5761134a61595f565b815260808d01516001600160a01b031660208201526040018a6003602002015160ff16600181111561137e5761137e61595f565b600181111561138f5761138f61595f565b8152602081018a90526040810188905260a0808e01516001600160a01b0316606083015260808201879052018c600660200201516001600160a01b031681526020018b6004601281106113e4576113e4615949565b602002015181526020018b60056012811061140157611401615949565b602002015181526020018b60066012811061141e5761141e615949565b602002015181526020018b60076012811061143b5761143b615949565b602002015181526020018b60086012811061145857611458615949565b602002015181525090506000604051806102e001604052808d6007600e811061148357611483615949565b60200201516001600160a01b031681526020018d6008600e81106114a9576114a9615949565b60200201516001600160a01b031681526020018d6009600e81106114cf576114cf615949565b60200201516001600160a01b031681526020018c6009601281106114f5576114f5615949565b602002015181526020018c600a6012811061151257611512615949565b602002015181526020018c600b6012811061152f5761152f615949565b602002015181526020018c600c6012811061154c5761154c615949565b602002015181526020018d600a600e811061156957611569615949565b60200201516001600160a01b031681526020018b60046008811061158f5761158f615949565b602002015160ff1660018111156115a8576115a861595f565b60018111156115b9576115b961595f565b81526020018b6005602002015160ff1660018111156115da576115da61595f565b60018111156115eb576115eb61595f565b81526020018b6006602002015160ff16600181111561160c5761160c61595f565b600181111561161d5761161d61595f565b81526101608e01516001600160a01b031660208201526040018b6007602002015160ff1660018111156116525761165261595f565b60018111156116635761166361595f565b8152602081018a9052604081018890526101808e01516001600160a01b039081166060830152608082018790526101a08f01511660a082015260c0018c600d602002015181526020018c600e601281106116bf576116bf615949565b602002015181526020018c600f601281106116dc576116dc615949565b602002015181526020018c6010601281106116f9576116f9615949565b602002015181526020018c60116012811061171657611716615949565b6020020151905290506117298282613642565b9c9b505050505050505050505050565b610e90604051806102e001604052808d6000600e811061175b5761175b615949565b60200201516001600160a01b031681526020018d6001600e811061178157611781615949565b60200201516001600160a01b031681526020018d6002600e81106117a7576117a7615949565b60200201516001600160a01b031681526020018c6000601281106117cd576117cd615949565b602002015181526020018c6001601281106117ea576117ea615949565b602002015181526020018c60026012811061180757611807615949565b602002015181526020018c60036012811061182457611824615949565b602002015181526020018d6003600e811061184157611841615949565b60200201516001600160a01b031681526020018b60006008811061186757611867615949565b602002015160ff1660018111156118805761188061595f565b60018111156118915761189161595f565b81526020018b6001602002015160ff1660018111156118b2576118b261595f565b60018111156118c3576118c361595f565b81526020018b6002602002015160ff1660018111156118e4576118e461595f565b60018111156118f5576118f561595f565b815260808e01516001600160a01b031660208201526040018b6003602002015160ff1660018111156119295761192961595f565b600181111561193a5761193a61595f565b8152602081018b90526040810189905260a0808f01516001600160a01b0316606083015260808201889052018d600660200201516001600160a01b031681526020018c60046012811061198f5761198f615949565b602002015181526020018c6005601281106119ac576119ac615949565b602002015181526020018c6006601281106119c9576119c9615949565b602002015181526020018c6007601281106119e6576119e6615949565b602002015181526020018c600860128110611a0357611a03615949565b602002015190528360006020020151604080516102e08101909152808f600760200201516001600160a01b031681526020018f6008600e8110611a4857611a48615949565b60200201516001600160a01b031681526020018f6009600e8110611a6e57611a6e615949565b60200201516001600160a01b031681526020018e600960128110611a9457611a94615949565b602002015181526020018e600a60128110611ab157611ab1615949565b602002015181526020018e600b60128110611ace57611ace615949565b602002015181526020018e600c60128110611aeb57611aeb615949565b602002015181526020018f600a600e8110611b0857611b08615949565b60200201516001600160a01b031681526020018d600460088110611b2e57611b2e615949565b602002015160ff166001811115611b4757611b4761595f565b6001811115611b5857611b5861595f565b81526020018d6005602002015160ff166001811115611b7957611b7961595f565b6001811115611b8a57611b8a61595f565b81526020018d6006602002015160ff166001811115611bab57611bab61595f565b6001811115611bbc57611bbc61595f565b81526020018f600b60200201516001600160a01b031681526020018d600760088110611bea57611bea615949565b602002015160ff166001811115611c0357611c0361595f565b6001811115611c1457611c1461595f565b8152602081018c9052604081018a90526060018f600c60200201516001600160a01b031681526020018781526020018f600d600e8110611c5657611c56615949565b60200201516001600160a01b031681526020018e600d60128110611c7c57611c7c615949565b602002015181526020018e600e60128110611c9957611c99615949565b602002015181526020018e600f60128110611cb657611cb6615949565b602002015181526020018e601060128110611cd357611cd3615949565b602002015181526020018e601160128110611cf057611cf0615949565b60200201519052856001602002015185613840565b6000604051806102e001604052808c600060078110611d2657611d26615949565b60200201516001600160a01b031681526020018c600160078110611d4c57611d4c615949565b60200201516001600160a01b031681526020018c600260078110611d7257611d72615949565b60200201516001600160a01b031681526020018b600060098110611d9857611d98615949565b602002015181526020018b600160098110611db557611db5615949565b602002015181526020018b600260098110611dd257611dd2615949565b602002015181526020018b600360098110611def57611def615949565b602002015181526020018c600360078110611e0c57611e0c615949565b60200201516001600160a01b031681526020018a6001811115611e3157611e3161595f565b8152602001896001811115611e4857611e4861595f565b8152602001886001811115611e5f57611e5f61595f565b815260808d01516001600160a01b03166020820152604001876001811115611e8957611e8961595f565b8152602081018790526040810186905260a0808e01516001600160a01b0316606083015260808201869052018c600660200201516001600160a01b031681526020018b600460098110611ede57611ede615949565b602002015181526020018b600560098110611efb57611efb615949565b602002015181526020018b600660098110611f1857611f18615949565b602002015181526020018b600760098110611f3557611f35615949565b602002015181526020018b600860098110611f5257611f52615949565b602002015190529050610e908183613d30565b6000610ba1604051806102e001604052808c600060078110611f8957611f89615949565b60200201516001600160a01b031681526020018c600160078110611faf57611faf615949565b60200201516001600160a01b031681526020018c600260078110611fd557611fd5615949565b60200201516001600160a01b031681526020018b600060098110611ffb57611ffb615949565b602002015181526020018b60016009811061201857612018615949565b602002015181526020018b60026009811061203557612035615949565b602002015181526020018b60036009811061205257612052615949565b602002015181526020018c60036007811061206f5761206f615949565b60200201516001600160a01b031681526020018a60018111156120945761209461595f565b81526020018960018111156120ab576120ab61595f565b81526020018860018111156120c2576120c261595f565b815260808d01516001600160a01b031660208201526040018760018111156120ec576120ec61595f565b8152602081018790526040810186905260a0808e01516001600160a01b0316606083015260808201869052018c600660200201516001600160a01b031681526020018b60046009811061214157612141615949565b602002015181526020018b60056009811061215e5761215e615949565b602002015181526020018b60066009811061217b5761217b615949565b602002015181526020018b60076009811061219857612198615949565b602002015181526020018b6008600981106121b5576121b5615949565b60200201519052613f10565b6121c961307b565b426015819055601180546001600160a01b0319166001600160a01b0384169081179091556040805133815260208101929092528101919091527f41b9bf56a41f7160677b991bb03fcd599356e239d488c4ecf1dd083fe2df28bd9060600161093a565b6000604051806102e001604052808c60006007811061224d5761224d615949565b60200201516001600160a01b031681526020018c60016007811061227357612273615949565b60200201516001600160a01b031681526020018c60026007811061229957612299615949565b60200201516001600160a01b031681526020018b6000600a81106122bf576122bf615949565b602002015181526020018b6001600a81106122dc576122dc615949565b602002015181526020018b6002600a81106122f9576122f9615949565b602002015181526020018b6003600a811061231657612316615949565b602002015181526020018c60036007811061233357612333615949565b60200201516001600160a01b031681526020018a60018111156123585761235861595f565b815260200189600181111561236f5761236f61595f565b81526020018860018111156123865761238661595f565b815260808d01516001600160a01b031660208201526040018760018111156123b0576123b061595f565b8152602081018790526040810186905260a0808e01516001600160a01b0316606083015260808201869052018c600660200201516001600160a01b031681526020018b6004600a811061240557612405615949565b602002015181526020018b6005600a811061242257612422615949565b602002015181526020018b6006600a811061243f5761243f615949565b602002015181526020018b6007600a811061245c5761245c615949565b602002015181526020018b6008600a8110610e7d57610e7d615949565b61248161307b565b600580546001600160a01b0319166001600160a01b0392909216919091179055565b600080604051806102e001604052808d6000600781106124c5576124c5615949565b60200201516001600160a01b031681526020018d6001600781106124eb576124eb615949565b60200201516001600160a01b031681526020018d60026007811061251157612511615949565b60200201516001600160a01b031681526020018c60006009811061253757612537615949565b602002015181526020018c60016009811061255457612554615949565b602002015181526020018c60026009811061257157612571615949565b602002015181526020018c60036009811061258e5761258e615949565b602002015181526020018d6003600781106125ab576125ab615949565b60200201516001600160a01b031681526020018b60018111156125d0576125d061595f565b81526020018a60018111156125e7576125e761595f565b81526020018960018111156125fe576125fe61595f565b815260808e01516001600160a01b031660208201526040018860018111156126285761262861595f565b8152602081018890526040810187905260a0808f01516001600160a01b0316606083015260808201879052018d600660200201516001600160a01b031681526020018c60046009811061267d5761267d615949565b602002015181526020018c60056009811061269a5761269a615949565b602002015181526020018c6006600981106126b7576126b7615949565b602002015181526020018c6007600981106126d4576126d4615949565b602002015181526020018c6008600981106126f1576126f1615949565b60200201519052905061172961270682613f10565b8285613f77565b6000610ba1604051806102e001604052808c60006007811061273157612731615949565b60200201516001600160a01b031681526020018c60016007811061275757612757615949565b60200201516001600160a01b031681526020018c60026007811061277d5761277d615949565b60200201516001600160a01b031681526020018b6000600981106127a3576127a3615949565b602002015181526020018b6001600981106127c0576127c0615949565b602002015181526020018b6002600981106127dd576127dd615949565b602002015181526020018b6003600981106127fa576127fa615949565b602002015181526020018c60036007811061281757612817615949565b60200201516001600160a01b031681526020018a600181111561283c5761283c61595f565b81526020018960018111156128535761285361595f565b815260200188600181111561286a5761286a61595f565b815260808d01516001600160a01b031660208201526040018760018111156128945761289461595f565b8152602081018790526040810186905260a0808e01516001600160a01b0316606083015260808201869052018c600660200201516001600160a01b031681526020018b6004600981106128e9576128e9615949565b602002015181526020018b60056009811061290657612906615949565b602002015181526020018b60066009811061292357612923615949565b602002015181526020018b60076009811061294057612940615949565b602002015181526020018b60086009811061295d5761295d615949565b6020020151905261412f565b600080604051806102e001604052808c6000600e811061298b5761298b615949565b60200201516001600160a01b031681526020018c6001600e81106129b1576129b1615949565b60200201516001600160a01b031681526020018c6002600e81106129d7576129d7615949565b60200201516001600160a01b031681526020018b6000601281106129fd576129fd615949565b602002015181526020018b600160128110612a1a57612a1a615949565b602002015181526020018b600260128110612a3757612a37615949565b602002015181526020018b600360128110612a5457612a54615949565b602002015181526020018c6003600e8110612a7157612a71615949565b60200201516001600160a01b031681526020018a600060088110612a9757612a97615949565b602002015160ff166001811115612ab057612ab061595f565b6001811115612ac157612ac161595f565b81526020018a6001602002015160ff166001811115612ae257612ae261595f565b6001811115612af357612af361595f565b81526020018a6002602002015160ff166001811115612b1457612b1461595f565b6001811115612b2557612b2561595f565b815260808d01516001600160a01b031660208201526040018a6003602002015160ff166001811115612b5957612b5961595f565b6001811115612b6a57612b6a61595f565b8152602081018a90526040810188905260a0808e01516001600160a01b0316606083015260808201879052018c600660200201516001600160a01b031681526020018b600460128110612bbf57612bbf615949565b602002015181526020018b600560128110612bdc57612bdc615949565b602002015181526020018b600660128110612bf957612bf9615949565b602002015181526020018b600760128110612c1657612c16615949565b602002015181526020018b600860128110612c3357612c33615949565b602002015181525090506000604051806102e001604052808d6007600e8110612c5e57612c5e615949565b60200201516001600160a01b031681526020018d6008600e8110612c8457612c84615949565b60200201516001600160a01b031681526020018d6009600e8110612caa57612caa615949565b60200201516001600160a01b031681526020018c600960128110612cd057612cd0615949565b602002015181526020018c600a60128110612ced57612ced615949565b602002015181526020018c600b60128110612d0a57612d0a615949565b602002015181526020018c600c60128110612d2757612d27615949565b602002015181526020018d600a600e8110612d4457612d44615949565b60200201516001600160a01b031681526020018b600460088110612d6a57612d6a615949565b602002015160ff166001811115612d8357612d8361595f565b6001811115612d9457612d9461595f565b81526020018b6005602002015160ff166001811115612db557612db561595f565b6001811115612dc657612dc661595f565b81526020018b6006602002015160ff166001811115612de757612de761595f565b6001811115612df857612df861595f565b81526101608e01516001600160a01b031660208201526040018b6007602002015160ff166001811115612e2d57612e2d61595f565b6001811115612e3e57612e3e61595f565b8152602081018a9052604081018890526101808e01516001600160a01b039081166060830152608082018790526101a08f01511660a082015260c0018c600d602002015181526020018c600e60128110612e9a57612e9a615949565b602002015181526020018c600f60128110612eb757612eb7615949565b602002015181526020018c601060128110612ed457612ed4615949565b602002015181526020018c601160128110612ef157612ef1615949565b60200201519052905061172982826141ec565b612f0c61307b565b426013819055600f8290556040805133815260208101849052908101919091527fad6b6a1532b4c7d7a4a30501132d072ea2994194ef0faf631e0ae718ecf1f7329060600161093a565b612f5e61307b565b601554600003612f6d57600080fd5b6011546001600160a01b03828116911614612f8757600080fd5b42601454601554612f98919061598b565b1115612fa357600080fd5b6000601555601080546001600160a01b0319166001600160a01b0383169081179091556040805133815260208101929092527fd9d6b85b6d670cd443496fc6d03390f739bbff47f96a8e33fb0cdd52ad26f5c2910161093a565b61300561307b565b6001600160a01b03811661306f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b6130788161341d565b50565b6004546001600160a01b03163314610f305760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401613066565b81518351146130e357600080fd5b80518351146130f157600080fd5b60006020845161310191906159a3565b905060006131108260206159c5565b90508161311e6020836159a3565b1461312b5761312b6159e4565b60005b8281101561316857806001016020028085015181870151811682890151821916178289015250508080613160906159fa565b91505061312e565b82156131955782905080600101602002808501518187015181168289015182191617828901525050613259565b50805b8551811015613259578481815181106131b3576131b3615949565b602001015160f81c60f81b8482815181106131d0576131d0615949565b602001015160f81c60f81b168682815181106131ee576131ee615949565b602001015160f81c60f81b85838151811061320b5761320b615949565b602001015160f81c60f81b60ff60f81b18161786828151811061323057613230615949565b60200101906001600160f81b031916908160001a90535080613251816159fa565b915050613198565b505050505050565b600061328f826101200151836101400151846102400151856102600151866102800151876102a001516132f8565b92915050565b8151815160009160019181148083146132b157600092506132ee565b600160208701838101602088015b60028483851001036132e95780518351146132dd5760009650600093505b602092830192016132bf565b505050505b5090949350505050565b60008086600181111561330d5761330d61595f565b03613319575083610c26565b600186600181111561332d5761332d61595f565b03610c2657600061335961334a86613345428861427a565b614286565b613354858761427a565b614292565b9050600188600181111561336f5761336f61595f565b036133865761337e868261427a565b915050610c26565b61337e868261429e565b600061339c83836142aa565b905082602001516001600160a01b0316336001600160a01b0316146133c057600080fd5b6020808401516001600160a01b03166000908152600882526040808220848352909252818120805460ff19166001179055905182917f5152abf959f6564662358c2e52b702259b78bac5ee7842a0f01937e670efcc7d91a2505050565b600480546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60408051610300808252610320820190925260009190829082602082018180368337019050509050602081016134c8817fdf71e6f7b634d9dff3e18cf35f55eb2c50992cdf8f4044e1949ada496d2e9ed2815260200190565b855181526020808701519082015260408087015190820152606080870151908201526080808701519082015260a0808701519082015260c0808701519082015260e08087015190820152610100808701519101915061353c90829060018111156135345761353461595f565b815260200190565b90506135598186610120015160018111156135345761353461595f565b90506135768186610140015160018111156135345761353461595f565b610160860151815290506020810190506135a18186610180015160018111156135345761353461595f565b90506135bc81866101a0015180519060200120815260200190565b90506135d781866101c0015180519060200120815260200190565b6101e0860151815261020086015180516020918201208183015261022087015160408301526102408701516060830152610260870151608083015261028087015160a08301526102a087015160c08301526102c09096015160e0909101525090920191909120919050565b600080836101200151600181111561365c5761365c61595f565b14801561367f57506001826101200151600181111561367d5761367d61595f565b145b80156136b65750816101000151600181111561369d5761369d61595f565b83610100015160018111156136b4576136b461595f565b145b80156136dd57508161022001516001600160a01b03168361022001516001600160a01b0316145b8015613717575060408201516001600160a01b03161580613717575082602001516001600160a01b031682604001516001600160a01b0316145b8015613751575060408301516001600160a01b03161580613751575081602001516001600160a01b031683604001516001600160a01b0316145b80156137ac575060e08201516001600160a01b031615801561377f575060e08301516001600160a01b031615155b806137ac575060e08201516001600160a01b0316158015906137ac575060e08301516001600160a01b0316155b80156137d357508161016001516001600160a01b03168361016001516001600160a01b0316145b801561380a575081610180015160018111156137f1576137f161595f565b83610180015160018111156138085761380861595f565b145b80156138255750613825836102800151846102a001516142cc565b80156108ef57506108ef826102800151836102a001516142cc565b60005460ff161561385057600080fd5b6000805460ff191660011781556020860151336001600160a01b03919091160361388b5761387d8661412f565b61388657600080fd5b613898565b61389586866142aa565b90505b6000336001600160a01b031685602001516001600160a01b0316036138ce576138c08561412f565b6138c957600080fd5b6138db565b6138d885856142aa565b90505b6138e58786613642565b6138ee57600080fd5b6101608501513b6138fe57600080fd5b6101c0870151511561392457613924876101a00151866101a00151896101c001516130d5565b6101c0850151511561394a5761394a856101a00151886101a00151876101c001516130d5565b61395e876101a00151866101a00151613295565b61396757600080fd5b600654602086015160405163c455279160e01b81526001600160a01b039182166004820152600092919091169063c455279190602401602060405180830381865afa1580156139ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139de9190615a13565b90506001600160a01b0381166139f357600080fd5b600660009054906101000a90046001600160a01b03166001600160a01b03166397204d8e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613a46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a6a9190615a13565b6001600160a01b0316816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613ab1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ad59190615a13565b6001600160a01b031614613ae857600080fd5b602088015181906001600160a01b03163314613b2e576020808a01516001600160a01b0316600090815260088252604080822087835290925220805460ff191660011790555b86602001516001600160a01b0316336001600160a01b031614613b7b576020808801516001600160a01b0316600090815260088252604080822086835290925220805460ff191660011790555b6000613b878a896142e8565b9050816001600160a01b0316631b0f7ba98961016001518a61018001518b6101a001516040518463ffffffff1660e01b8152600401613bc893929190615a4e565b6020604051808303816000875af1158015613be7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c0b9190615a7f565b613c1457600080fd5b6101e08a01516001600160a01b031615613c4b57613c428a6101e00151896101a001518c6102000151614b2a565b613c4b57600080fd5b6101e08801516001600160a01b031615613c8257613c79886101e00151896101a001518a6102000151614b2a565b613c8257600080fd5b60e088015186906001600160a01b0316613ca0578860200151613ca6565b8a602001515b60e08a01516001600160a01b039182169116613cc6578b60200151613ccc565b89602001515b60408051898152602081018990529081018590526001600160a01b0391909116907fc4109843e0b7d514e4c093114b863f8e7d8d9a458c372cd51bfe526b588006c99060600160405180910390a450506000805460ff191690555050505050505050565b81602001516001600160a01b0316336001600160a01b031614613d5257600080fd5b6000613d5d83613f10565b6020808501516001600160a01b03166000908152600982526040808220848352909252205490915060ff1615613d9257600080fd5b60016009600085602001516001600160a01b03166001600160a01b03168152602001908152602001600020600083815260200190815260200160002060006101000a81548160ff0219169083151502179055508260e001516001600160a01b031683602001516001600160a01b0316827f90c7f9f5b58c15f0f635bfb99f55d3d78fdbef3559e7d8abf5c81052a527662286600001518760400151886060015189608001518a60a001518b60c001518c61010001518d61012001518e61014001518f6101600151604051613e6f9a99989796959493929190615a9c565b60405180910390a48261016001516001600160a01b0316817f22eb4a14e1ea7dc5add14b2269965aa8b74b799db587101d239b85f61e4fcc92856101800151866101a00151876101c00151886101e001518961020001518a61022001518b61024001518c61026001518d61028001518e6102a001518f6102c001518f604051613f039c9b9a99989796959493929190615b1a565b60405180910390a3505050565b60007f0000000000000000000000000000000000000000000000000000000000000000613f3c8361346f565b60405161190160f01b602082015260228101929092526042820152606201604051602081830303815290604052805190602001209050919050565b6000613f828361412f565b613f8e575060006108ef565b6020808401516001600160a01b03166000908152600882526040808220878352909252205460ff1615613fc3575060006108ef565b6020808401516001600160a01b03166000908152600982526040808220878352909252205460ff1615613ff8575060016108ef565b60208301513b1561408a576020830151604051630b135d3f60e11b808252916001600160a01b031690631626ba7e906140379088908790600401615bb6565b602060405180830381865afa158015614054573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140789190615bd7565b6001600160e01b0319161490506108ef565b6020828101516040808501516041860151878501518351600081529586018085528a905260ff821693860193909352606085018490526080850182905292939092916001600160a01b03169060019060a0016020604051602081039080840390855afa1580156140fe573d6000803e3d6000fd5b505050602060405103516001600160a01b03160361412257600193505050506108ef565b5060009695505050505050565b80516000906001600160a01b0316301461414b57506000919050565b6020808301516001600160a01b03166000908152600a9091526040902054610280830151101561417d57506000919050565b614191826101400151836102a00151614ba4565b61419d57506000919050565b600182610100015160018111156141b6576141b661595f565b1480156141d75750600b548260a0015110806141d75750600c548260c00151105b156141e457506000919050565b506001919050565b60008061421b836101200151846101400151856102400151866102600151876102800151886102a001516132f8565b9050600061424b8561012001518661014001518761024001518861026001518961028001518a6102a001516132f8565b90508181101561425a57600080fd5b60e08401516001600160a01b03166142725780610c0a565b509392505050565b60006108ef8284615c01565b60006108ef82846159c5565b60006108ef82846159a3565b60006108ef828461598b565b6000806142b684613f10565b90506142c3818585613f77565b6108ef57600080fd5b600042831080156108ef57508115806108ef5750504210919050565b6102208101516000906001600160a01b03161561430a57341561430a57600080fd5b600061431684846141ec565b905060008111801561433557506102208301516001600160a01b031615155b15614353576143538361022001518560200151856020015184614bc8565b600e54819081906000906143739061436b9084614286565b612710614292565b60e08701519091506001600160a01b0316156148265786608001518660800151111561439e57600080fd5b600186610100015160018111156143b7576143b761595f565b036147ba578660c001518660c0015111156143d157600080fd5b60608601511580156143e557506080860151155b1561446b576102208601516001600160a01b031661444857614407838261427a565b6010546040519194506001600160a01b03169082156108fc029083906000818181858888f19350505050158015614442573d6000803e3d6000fd5b5061446b565b610220860151602087015160105461446b9291906001600160a01b031684614bc8565b60608601511561456d57600061448861436b886060015187614286565b6102208801519091506001600160a01b031661452f576144b16144ab858361427a565b8361427a565b60e08801516040519195506001600160a01b03169082156108fc029083906000818181858888f193505050501580156144ee573d6000803e3d6000fd5b506010546040516001600160a01b039091169083156108fc029084906000818181858888f19350505050158015614529573d6000803e3d6000fd5b5061456b565b61454887610220015188602001518960e0015184614bc8565b610220870151602088015160105461456b9291906001600160a01b031685614bc8565b505b60808601511561466f57600061458a61436b886080015187614286565b6102208801519091506001600160a01b0316614631576145b36145ad848361429e565b8361429e565b60e08801516040519194506001600160a01b03169082156108fc029083906000818181858888f193505050501580156145f0573d6000803e3d6000fd5b506010546040516001600160a01b039091169083156108fc029084906000818181858888f1935050505015801561462b573d6000803e3d6000fd5b5061466d565b61464a87610220015189602001518960e0015184614bc8565b610220870151602089015160105461466d9291906001600160a01b031685614bc8565b505b60a08601511561471257600061468c61436b8860a0015187614286565b6102208801519091506001600160a01b03166146ed576146ac848261427a565b600d546040519195506001600160a01b03169082156108fc029083906000818181858888f193505050501580156146e7573d6000803e3d6000fd5b50614710565b6102208701516020880151600d546147109291906001600160a01b031684614bc8565b505b60c0860151156147b557600061472f61436b8860c0015187614286565b6102208801519091506001600160a01b03166147905761474f838261429e565b600d546040519194506001600160a01b03169082156108fc029083906000818181858888f1935050505015801561478a573d6000803e3d6000fd5b506147b3565b6102208701516020890151600d546147b39291906001600160a01b031684614bc8565b505b614a6c565b6147d186602001518760e001518860600151614c64565b6020860151601054600e546147f092916001600160a01b031690614c64565b61480787602001518760e001518860800151614c64565b6020870151601054600e546147b592916001600160a01b031690614c64565b85608001518760800151111561483b57600080fd5b600186610100015160018111156148545761485461595f565b03614a00576102208601516001600160a01b031661487157600080fd5b8560c001518760c00151111561488657600080fd5b606087015115801561489a57506080870151155b156148c25761022086015160208701516010546148c29291906001600160a01b031684614bc8565b60608701511561491f5760006148df61436b896060015187614286565b90506148fa87610220015189602001518a60e0015184614bc8565b610220870151602089015160105461491d9291906001600160a01b031685614bc8565b505b60808701511561497c57600061493c61436b896080015187614286565b905061495787610220015188602001518a60e0015184614bc8565b610220870151602088015160105461497a9291906001600160a01b031685614bc8565b505b60a0870151156149bf57600061499961436b8960a0015187614286565b61022088015160208a0151600d549293506149bd926001600160a01b031684614bc8565b505b60c0870151156147b55760006149dc61436b8960c0015187614286565b6102208801516020890151600d549293506147b3926001600160a01b031684614bc8565b614a1787602001518860e001518960600151614c64565b6020870151601054600e54614a3692916001600160a01b031690614c64565b614a4d86602001518860e001518960800151614c64565b6020860151601054600e54614a6c92916001600160a01b031690614c64565b6102208601516001600160a01b0316614b1f5781341015614a8c57600080fd5b85602001516001600160a01b03166108fc849081150290604051600060405180830381858888f19350505050158015614ac9573d6000803e3d6000fd5b506000614ad6348461427a565b90508015614b1d5787602001516001600160a01b03166108fc829081150290604051600060405180830381858888f19350505050158015614b1b573d6000803e3d6000fd5b505b505b509195945050505050565b60008082518451614b3b919061598b565b6001600160401b03811115614b5257614b52614cf2565b6040519080825280601f01601f191660200182016040528015614b7c576020820181803683370190505b50905060208101614b8d8185614c81565b9050614b998186614c81565b50610c268683614cc3565b600080836001811115614bb957614bb961595f565b14806108ef5750501515919050565b8015614c5e57600754604051630aed65f560e11b81526001600160a01b0386811660048301528581166024830152848116604483015260648201849052909116906315dacbea906084016020604051808303816000875af1158015614c31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c559190615a7f565b614c5e57600080fd5b50505050565b600554614c7c906001600160a01b0316848484614bc8565b505050565b805160009015614cbc57815180602001830160208401855b600183831003614cb3578151815260209182019101614c99565b50505092909201915b5090919050565b600080604051835160208501865afa9392505050565b600060208284031215614ceb57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112614d1957600080fd5b81356001600160401b0380821115614d3357614d33614cf2565b604051601f8301601f19908116603f01168101908282118183101715614d5b57614d5b614cf2565b81604052838152866020858801011115614d7457600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600060608486031215614da957600080fd5b83356001600160401b0380821115614dc057600080fd5b614dcc87838801614d08565b94506020860135915080821115614de257600080fd5b614dee87838801614d08565b93506040860135915080821115614e0457600080fd5b50614e1186828701614d08565b9150509250925092565b6000815180845260005b81811015614e4157602081850181015186830182015201614e25565b81811115614e53576000602083870101525b50601f01601f19169290920160200192915050565b6020815260006108ef6020830184614e1b565b6001600160a01b038116811461307857600080fd5b60008060408385031215614ea357600080fd5b8235614eae81614e7b565b946020939093013593505050565b600082601f830112614ecd57600080fd5b60405160e081018181106001600160401b0382111715614eef57614eef614cf2565b6040528060e0840185811115614f0457600080fd5b845b81811015614b1f578035614f1981614e7b565b835260209283019201614f06565b600082601f830112614f3857600080fd5b6040516101208082018281106001600160401b0382111715614f5c57614f5c614cf2565b60405283018185821115614f6f57600080fd5b845b82811015614b1f578035825260209182019101614f71565b6002811061307857600080fd5b8035614fa181614f89565b919050565b60008060008060008060008060006102e08a8c031215614fc557600080fd5b614fcf8b8b614ebc565b9850614fde8b60e08c01614f27565b9750614fed6102008b01614f96565b9650614ffc6102208b01614f96565b955061500b6102408b01614f96565b945061501a6102608b01614f96565b93506102808a01356001600160401b038082111561503757600080fd5b6150438d838e01614d08565b94506102a08c013591508082111561505a57600080fd5b6150668d838e01614d08565b93506102c08c013591508082111561507d57600080fd5b5061508a8c828d01614d08565b9150509295985092959850929598565b6000602082840312156150ac57600080fd5b81356108ef81614e7b565b600080600080608085870312156150cd57600080fd5b84356001600160401b03808211156150e457600080fd5b6150f088838901614d08565b9550602087013591508082111561510657600080fd5b61511288838901614d08565b9450604087013591508082111561512857600080fd5b61513488838901614d08565b9350606087013591508082111561514a57600080fd5b5061515787828801614d08565b91505092959194509250565b60008060008060008060c0878903121561517c57600080fd5b863561518781614f89565b9550602087013561519781614f89565b95989597505050506040840135936060810135936080820135935060a0909101359150565b6000806000806000806000806000806103008b8d0312156151dc57600080fd5b6151e68c8c614ebc565b99506151f58c60e08d01614f27565b98506152046102008c01614f96565b97506152136102208c01614f96565b96506152226102408c01614f96565b95506152316102608c01614f96565b94506102808b01356001600160401b038082111561524e57600080fd5b61525a8e838f01614d08565b95506102a08d013591508082111561527157600080fd5b61527d8e838f01614d08565b94506102c08d013591508082111561529457600080fd5b6152a08e838f01614d08565b93506102e08d01359150808211156152b757600080fd5b506152c48d828e01614d08565b9150509295989b9194979a5092959850565b600082601f8301126152e757600080fd5b6040516101c08082018281106001600160401b038211171561530b5761530b614cf2565b6040528301818582111561531e57600080fd5b845b82811015614b1f57803561533381614e7b565b825260209182019101615320565b600082601f83011261535257600080fd5b6040516102408082018281106001600160401b0382111715614f5c57614f5c614cf2565b600082601f83011261538757600080fd5b6040516101008082018281106001600160401b03821117156153ab576153ab614cf2565b604052830181858211156153be57600080fd5b845b82811015614b1f57803560ff811681146153da5760008081fd5b8252602091820191016153c0565b60008060008060008060008060006105c08a8c03121561540757600080fd5b6154118b8b6152d6565b98506154218b6101c08c01615341565b97506154318b6104008c01615376565b96506105008a01356001600160401b038082111561544e57600080fd5b61545a8d838e01614d08565b97506105208c013591508082111561547157600080fd5b61547d8d838e01614d08565b96506105408c013591508082111561549457600080fd5b6154a08d838e01614d08565b95506105608c01359150808211156154b757600080fd5b6154c38d838e01614d08565b94506105808c01359150808211156154da57600080fd5b6154e68d838e01614d08565b93506105a08c013591508082111561507d57600080fd5b600082601f83011261550e57600080fd5b604051604081016001600160401b03828210818311171561553157615531614cf2565b6040918252829185018681111561554757600080fd5b855b8181101561557c578035838111156155615760008081fd5b61556d89828a01614d08565b85525060209384019301615549565b50929695505050505050565b60008060008060008060008060008060006106008c8e0312156155aa57600080fd5b6155b48d8d6152d6565b9a506155c48d6101c08e01615341565b99506155d48d6104008e01615376565b98506001600160401b03806105008e013511156155f057600080fd5b6156018e6105008f01358f01614d08565b9850806105208e0135111561561557600080fd5b6156268e6105208f01358f01614d08565b9750806105408e0135111561563a57600080fd5b61564b8e6105408f01358f01614d08565b9650806105608e0135111561565f57600080fd5b6156708e6105608f01358f01614d08565b9550806105808e0135111561568457600080fd5b6156958e6105808f01358f01614d08565b9450806105a08e013511156156a957600080fd5b6156ba8e6105a08f01358f01614d08565b9350806105c08e013511156156ce57600080fd5b506156e08d6105c08e01358e016154fd565b91506105e08c013590509295989b509295989b9093969950565b801515811461307857600080fd5b8035614fa1816156fa565b6000806000806000806000806000806103008b8d03121561573357600080fd5b61573d8c8c614ebc565b995061574c8c60e08d01614f27565b985061575b6102008c01614f96565b975061576a6102208c01614f96565b96506157796102408c01614f96565b95506157886102608c01614f96565b94506102808b01356001600160401b03808211156157a557600080fd5b6157b18e838f01614d08565b95506102a08d01359150808211156157c857600080fd5b6157d48e838f01614d08565b94506102c08d01359150808211156157eb57600080fd5b506157f88d828e01614d08565b9250506158086102e08c01615708565b90509295989b9194979a5092959850565b600082601f83011261582a57600080fd5b6040516101408082018281106001600160401b0382111715614f5c57614f5c614cf2565b6000806000806000806000806000806103208b8d03121561586e57600080fd5b6158788c8c614ebc565b99506158878c60e08d01615819565b98506158966102208c01614f96565b97506158a56102408c01614f96565b96506158b46102608c01614f96565b95506158c36102808c01614f96565b94506102a08b01356001600160401b03808211156158e057600080fd5b6158ec8e838f01614d08565b95506102c08d013591508082111561590357600080fd5b61590f8e838f01614d08565b94506102e08d013591508082111561592657600080fd5b6159328e838f01614d08565b93506103008d01359150808211156152b757600080fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000821982111561599e5761599e615975565b500190565b6000826159c057634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156159df576159df615975565b500290565b634e487b7160e01b600052600160045260246000fd5b600060018201615a0c57615a0c615975565b5060010190565b600060208284031215615a2557600080fd5b81516108ef81614e7b565b6002811061307857634e487b7160e01b600052602160045260246000fd5b6001600160a01b0384168152615a6383615a30565b826020820152606060408201526000610c0a6060830184614e1b565b600060208284031215615a9157600080fd5b81516108ef816156fa565b6001600160a01b038b811682528a81166020830152604082018a9052606082018990526080820188905260a08201879052610140820190615adc87615a30565b8660c0840152615aeb86615a30565b8560e0840152615afa85615a30565b84610100840152808416610120840152509b9a5050505050505050505050565b6000610180615b288f615a30565b8e8352806020840152615b3d8184018f614e1b565b90508281036040840152615b51818e614e1b565b6001600160a01b038d811660608601528482036080860152909150615b76828d614e1b565b9a1660a0840152505060c081019690965260e086019490945261010085019290925261012084015261014083015215156101609091015295945050505050565b828152604060208201526000615bcf6040830184614e1b565b949350505050565b600060208284031215615be957600080fd5b81516001600160e01b0319811681146108ef57600080fd5b600082821015615c1357615c13615975565b50039056fea264697066735822122019439388370cda7d02557f957c87e110d25bca1e69243da5692fea45c5f5a18e64736f6c634300080d0033000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000089f408722d87d4531f9cc01f0b4984449e9fda816c56f3d645eb9f6b6041ea84280000000000000000000000009d2f447f99260efabd0db7280e7800d97180079200000000000000000000000042f347642b9201dd7d2a7da2ee2bd0b5a3025135000000000000000000000000349d51ced2d09d0729dad114f67521ee686baeba000000000000000000000000e18fa57fd4a6c4c4b23e87b58f33d7f2a8bde19b0000000000000000000000008f949859b838f719ac8fe305239ca92391875fab000000000000000000000000000000000000000000000000000000000000001750726f6a65637420506c614e46542045786368616e67650000000000000000000000000000000000000000000000000000000000000000000000000000000003312e310000000000000000000000000000000000000000000000000000000000

Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.