ETH Price: $2,522.12 (-4.84%)

Transaction Decoder

Block:
21934006 at Feb-27-2025 12:11:47 AM +UTC
Transaction Fee:
0.000198948880484718 ETH $0.50
Gas Used:
273,714 Gas / 0.726849487 Gwei

Emitted Events:

222 Proxy.0x9866f8ddfe70bb512b2f2b28b49d4017c43f7ba775f1a20c61c13eea8cdac111( 0x9866f8ddfe70bb512b2f2b28b49d4017c43f7ba775f1a20c61c13eea8cdac111, a2b75dfa7e651ad1a326e05f65dcf439821238decf417a86cce1fc08f546eb9d )
223 Proxy.0x54fe7a67f8957a96919a0d1b81eeb25ea8c06f96ad528671da17a4a840040664( 0x54fe7a67f8957a96919a0d1b81eeb25ea8c06f96ad528671da17a4a840040664, 0000000000000000000000000000000000000000000000000000000000002154, 0000000000000000000000000000000000000000000000000000000000002170, 01eb131025686e844d1f547ee272a4eaa5370c882a3d0fd9918359301785028e, 0075364111a7a336756626d19fc8ec8df6328a5e63681c68ffaa312f6bf98c5c, 02cb9d0310fe3e17001d93109c481548167a535b10505468ff0f93edd32fbb77 )
224 Proxy.0x03c10a82c955f7bcd0c934147fb39cafca947a4294425b1751d884c8ac954287( 0x03c10a82c955f7bcd0c934147fb39cafca947a4294425b1751d884c8ac954287, 0000000000000000000000002dd8c037c1ed4e9b417bc39f388de8a370d7ad81, 02f1ac180be47ec22c2315cc442d53d92f3be8e1d0249263e6598cf4ecddab78, 000000000000000000000000000000000000000000000000e04e3821aefa3c00, 000000000000000000000000000000000000000000000000000000006056a7c7 )
225 Proxy.0x03c10a82c955f7bcd0c934147fb39cafca947a4294425b1751d884c8ac954287( 0x03c10a82c955f7bcd0c934147fb39cafca947a4294425b1751d884c8ac954287, 0000000000000000000000002dd8c037c1ed4e9b417bc39f388de8a370d7ad81, 00081aa49c199a78e0a085fc5552cc9fa460b111a730d2e4cd37ac8dd58ba117, 0000000000000000000000000000000000000000000034ba512a057589a00000, 000000000000000000000000000000000000000000000000000016a57ba7a800 )
226 Proxy.0x03c10a82c955f7bcd0c934147fb39cafca947a4294425b1751d884c8ac954287( 0x03c10a82c955f7bcd0c934147fb39cafca947a4294425b1751d884c8ac954287, 0000000000000000000000002dd8c037c1ed4e9b417bc39f388de8a370d7ad81, 00b333e3142fe16b78628f19bb15afddaef437e72d6d7f5c6c20c6801a27fba6, 0000000000000000000000000000000000000000000000000057a2817cacb000, 000000000000000000000000000000000000000000000000000000000025a38c )
227 Proxy.0x03c10a82c955f7bcd0c934147fb39cafca947a4294425b1751d884c8ac954287( 0x03c10a82c955f7bcd0c934147fb39cafca947a4294425b1751d884c8ac954287, 00000000000000000000000028d9e67aa72214f90d728901df0ddcd15b668151, 03f72d60d5cd06866bdcc3f288e01350503d0661fdd6ee9aaf7f6391f863eeab, 00000000000000000000000000000000000000000000000000656d9779e02c00, 00000000000000000000000000000000000000000000000000000000002b9023 )

Account State Difference:

  Address   Before After State Difference Code
3.220253321773022754 Eth3.220280693173022754 Eth0.0000273714
0x5d22045D...Fad24609b
(Rhino.fi: Bridge)
0x8A6c80Aa...9D78f6ae5
3.341137495633492338 Eth
Nonce: 32734
3.34093854675300762 Eth
Nonce: 32735
0.000198948880484718

Execution Trace

Proxy.538f9406( )
  • StarkExchange.538f9406( )
    • StarkExState.updateState( publicInput=[1, 3582806132929304568525101776950243164426395274135034711043908882055311041758, 867653477285437904827897202819971078275709364878465383121417891125712454286, 207095555137602068174310225607660532858489993604082708018689543482077973596, 207095555137602068174310225607660532858489993604082708018689543482077973596, 1327822111325147789693706415809692658661783487724229218768274353663161342170, 1264379308162416896240332567510551373955443750323960940219144249286436305783, 487817, 31, 31, 251, 4, 5, 0, 0, 261738290182157643678576771394542615984357223809, 1331623588440924049918005314280397803333944431605828002356867555895877151608, 9223372035238484025, 261738290182157643678576771394542615984357223809, 14318659793747172997107906456918529274357618201697323149265026796065890583, 9223347136854775808, 261738290182157643678576771394542615984357223809, 316623735692853304525146192642758839706355829840274185964789512850136103846, 9223372036852309108, 233218970103405834171697715675047157406867292497, 1793662960006406435728969979651030070874294685078013441662346959249956138667, 9223372036851920861, 614486031536312997026762163129950357908491396124249221933721437794472713035, 385112356568586717046209875422450280314180810925507987654031974442021710515, 424639904306688795013883101344625566727481712776244502528778021543754341844, 895286044074423971286861784864846555952615064455695972247186637954803442859, 409163880734405076902315378436582316068476017800756919073851413027883995907, 80490897095073259527478935306175458038822506617034638276450078406368143165531, 2], applicationData=[8560, 8559, 1117762832213081296956947358801442244224111778854, 81319873481894485633332667541799461089250491147505893308666232228177578566788, 1117762832213081296956947358801442244224111778854, 23656256633433585920285192568679297519127552725381778395695004863649133309920, 1117762832213081296956947358801442244224111778854, 98072960455373217512192172476839509880806098551643082152165234757029349012732, 1117762832213081296956947358801442244224111778854, 83292431363530024825534466162615431102866876865410472815635120347468847075130, 1117762832213081296956947358801442244224111778854, 31365240377135321216915374609733857411163688444721281992242780751104544383205] )
      • GpsFactRegistryAdapter.isValid( fact=A2B75DFA7E651AD1A326E05F65DCF439821238DECF417A86CCE1FC08F546EB9D ) => ( True )
        • Proxy.6a938567( )
          • CallProxy.isValid( fact=BF5AF7330D24243BF5B8859589AF1782DF11DBD17C2F4DAE5CD059A7A021B5EC ) => ( True )
            • GpsStatementVerifier.isValid( fact=BF5AF7330D24243BF5B8859589AF1782DF11DBD17C2F4DAE5CD059A7A021B5EC ) => ( True )
            • Committee.isValid( fact=FACEC9FAE85B9383FCFDE6BBD3481FA02D7478B67B5FA9D76EAD336A60DADDE9 ) => ( True )
            • TransferRegistry.isValid( fact=B3C96AD4EBF1E22AD5A444A18BB17C2A04DD856B18660C8F6E7FD29E67102484 ) => ( True )
            • TransferRegistry.isValid( fact=344CF77E11D926563DA2E137EAF72F4630F0607D406A3DA0823A4EB852432FE0 ) => ( True )
            • TransferRegistry.isValid( fact=D8D354195F37D897330EA0ADF071D3DBDE6A0F9C826EE2075D5878095B53B4FC ) => ( True )
            • TransferRegistry.isValid( fact=B825D8733172932ADB1F1392547C00219466E852355DA8ABC23B61793EAB4F3A ) => ( True )
            • TransferRegistry.isValid( fact=455818D13F210A350E7246F4CFE67A1DE44FC2A7645061D41E26D1C73DE4A0E5 ) => ( True )
              File 1 of 9: Proxy
              {"Common.sol":{"content":"/*\n  Copyright 2019,2020 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\npragma solidity ^0.5.2;\n\n/*\n  Common Utility libraries.\n  1. Addresses (extending address).\n*/\nlibrary Addresses {\n    function isContract(address account) internal view returns (bool) {\n        uint256 size;\n        // solium-disable-next-line security/no-inline-assembly\n        assembly {\n            size := extcodesize(account)\n        }\n        return size \u003e 0;\n    }\n}\n"},"Governance.sol":{"content":"/*\n  Copyright 2019,2020 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\npragma solidity ^0.5.2;\n\nimport \"GovernanceStorage.sol\";\nimport \"MGovernance.sol\";\n\n/*\n  Implements Generic Governance, applicable for both proxy and main contract, and possibly others.\n  Notes:\n  1. This class is virtual (getGovernanceTag is not implemented).\n  2. The use of the same function names by both the Proxy and a delegated implementation\n     is not possible since calling the implementation functions is done via the default function\n     of the Proxy. For this reason, for example, the implementation of MainContract (MainGovernance)\n     exposes mainIsGovernor, which calls the internal isGovernor method.\n*/\ncontract Governance is GovernanceStorage, MGovernance {\n    event LogNominatedGovernor(address nominatedGovernor);\n    event LogNewGovernorAccepted(address acceptedGovernor);\n    event LogRemovedGovernor(address removedGovernor);\n    event LogNominationCancelled();\n\n    address internal constant ZERO_ADDRESS = address(0x0);\n\n    /*\n      Returns a string which uniquely identifies the type of the governance mechanism.\n    */\n    function getGovernanceTag()\n        internal\n        view\n        returns (string memory);\n\n    /*\n      Returns the GovernanceInfoStruct associated with the governance tag.\n    */\n    function contractGovernanceInfo()\n        internal\n        view\n        returns (GovernanceInfoStruct storage) {\n        string memory tag = getGovernanceTag();\n        GovernanceInfoStruct storage gub = governanceInfo[tag];\n        require(gub.initialized == true, \"NOT_INITIALIZED\");\n        return gub;\n    }\n\n    function initGovernance()\n        internal\n    {\n        string memory tag = getGovernanceTag();\n        GovernanceInfoStruct storage gub = governanceInfo[tag];\n        require(gub.initialized == false, \"ALREADY_INITIALIZED\");\n        gub.initialized = true;  // to ensure addGovernor() won\u0027t fail.\n        // Add the initial governer.\n        addGovernor(msg.sender);\n    }\n\n    modifier onlyGovernance()\n    {\n        require(isGovernor(msg.sender), \"ONLY_GOVERNANCE\");\n        _;\n    }\n\n    function isGovernor(address testGovernor)\n        internal view\n        returns (bool addressIsGovernor){\n        GovernanceInfoStruct storage gub = contractGovernanceInfo();\n        addressIsGovernor = gub.effectiveGovernors[testGovernor];\n    }\n\n    /*\n      Cancels the nomination of a governor condidate.\n    */\n    function cancelNomination() internal onlyGovernance() {\n        GovernanceInfoStruct storage gub = contractGovernanceInfo();\n        gub.candidateGovernor = ZERO_ADDRESS;\n        emit LogNominationCancelled();\n    }\n\n    function nominateNewGovernor(address newGovernor) internal onlyGovernance() {\n        GovernanceInfoStruct storage gub = contractGovernanceInfo();\n        require(isGovernor(newGovernor) == false, \"ALREADY_GOVERNOR\");\n        gub.candidateGovernor = newGovernor;\n        emit LogNominatedGovernor(newGovernor);\n    }\n\n    /*\n      The addGovernor is called in two cases:\n      1. by acceptGovernance when a new governor accepts its role.\n      2. by initGovernance to add the initial governor.\n      The difference is that the init path skips the nominate step\n      that would fail because of the onlyGovernance modifier.\n    */\n    function addGovernor(address newGovernor) private {\n        require(isGovernor(newGovernor) == false, \"ALREADY_GOVERNOR\");\n        GovernanceInfoStruct storage gub = contractGovernanceInfo();\n        gub.effectiveGovernors[newGovernor] = true;\n    }\n\n    function acceptGovernance()\n        internal\n    {\n        // The new governor was proposed as a candidate by the current governor.\n        GovernanceInfoStruct storage gub = contractGovernanceInfo();\n        require(msg.sender == gub.candidateGovernor, \"ONLY_CANDIDATE_GOVERNOR\");\n\n        // Update state.\n        addGovernor(gub.candidateGovernor);\n        gub.candidateGovernor = ZERO_ADDRESS;\n\n        // Send a notification about the change of governor.\n        emit LogNewGovernorAccepted(msg.sender);\n    }\n\n    /*\n      Remove a governor from office.\n    */\n    function removeGovernor(address governorForRemoval) internal onlyGovernance() {\n        require(msg.sender != governorForRemoval, \"GOVERNOR_SELF_REMOVE\");\n        GovernanceInfoStruct storage gub = contractGovernanceInfo();\n        require (isGovernor(governorForRemoval), \"NOT_GOVERNOR\");\n        gub.effectiveGovernors[governorForRemoval] = false;\n        emit LogRemovedGovernor(governorForRemoval);\n    }\n}\n"},"GovernanceStorage.sol":{"content":"/*\n  Copyright 2019,2020 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\npragma solidity ^0.5.2;\n\n/*\n  Holds the governance slots for ALL entities, including proxy and the main contract.\n*/\ncontract GovernanceStorage {\n\n    struct GovernanceInfoStruct {\n        mapping (address =\u003e bool) effectiveGovernors;\n        address candidateGovernor;\n        bool initialized;\n    }\n\n    // A map from a Governor tag to its own GovernanceInfoStruct.\n    mapping (string =\u003e GovernanceInfoStruct) internal governanceInfo;\n}\n"},"MGovernance.sol":{"content":"/*\n  Copyright 2019,2020 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\npragma solidity ^0.5.2;\n\ncontract MGovernance {\n    /*\n      Allows calling the function only by a Governor.\n    */\n    modifier onlyGovernance()\n    {\n        // Pure modifier declarations are not supported. Instead we provide\n        // a dummy definition.\n        revert(\"UNIMPLEMENTED\");\n        _;\n    }\n}\n"},"Proxy.sol":{"content":"/*\n  Copyright 2019,2020 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\npragma solidity ^0.5.2;\n\nimport \"ProxyGovernance.sol\";\nimport \"ProxyStorage.sol\";\nimport \"Common.sol\";\n\n/**\n  The Proxy contract implements delegation of calls to other contracts (`implementations`), with\n  proper forwarding of return values and revert reasons. This pattern allows retaining the contract\n  storage while replacing implementation code.\n\n  The following operations are supported by the proxy contract:\n\n  - :sol:func:`addImplementation`: Defines a new implementation, the data with which it should be initialized and whether this will be the last version of implementation.\n  - :sol:func:`upgradeTo`: Once an implementation is added, the governor may upgrade to that implementation only after a safety time period has passed (time lock), the current implementation is not the last version and the implementation is not frozen (see :sol:mod:`FullWithdrawals`).\n  - :sol:func:`removeImplementation`: Any announced implementation may be removed. Removing an implementation is especially important once it has been used for an upgrade in order to avoid an additional unwanted revert to an older version.\n\n  The only entity allowed to perform the above operations is the proxy governor\n  (see :sol:mod:`ProxyGovernance`).\n\n  Every implementation is required to have an `initialize` function that replaces the constructor\n  of a normal contract. Furthermore, the only parameter of this function is an array of bytes\n  (`data`) which may be decoded arbitrarily by the `initialize` function. It is up to the\n  implementation to ensure that this function cannot be run more than once if so desired.\n\n  When an implementation is added (:sol:func:`addImplementation`) the initialization `data` is also\n  announced, allowing users of the contract to analyze the full effect of an upgrade to the new\n  implementation. During an :sol:func:`upgradeTo`, the `data` is provided again and only if it is\n  identical to the announced `data` is the upgrade performed by pointing the proxy to the new\n  implementation and calling its `initialize` function with this `data`.\n\n  It is the responsibility of the implementation not to overwrite any storage belonging to the\n  proxy (`ProxyStorage`). In addition, upon upgrade, the new implementation is assumed to be\n  backward compatible with previous implementations with respect to the storage used until that\n  point.\n*/\ncontract Proxy is ProxyStorage, ProxyGovernance {\n\n    // Emitted when the active implementation is replaced.\n    event Upgraded(address indexed implementation);\n\n    // Emitted when an implementation is submitted as an upgrade candidate and a time lock\n    // is activated.\n    event ImplementationAdded(address indexed implementation, bytes initializer, bool finalize);\n\n    // Emitted when an implementation is removed from the list of upgrade candidates.\n    event ImplementationRemoved(address indexed implementation);\n\n    // Emitted when the implementation is finalized.\n    event FinalizedImplementation(address indexed implementation);\n\n    // Storage slot with the address of the current implementation.\n    // The address of the slot is keccak256(\"StarkWare2019.implemntation-slot\").\n    // We need to keep this variable stored outside of the commonly used space,\n    // so that it\u0027s not overrun by the logical implementaiton (the proxied contract).\n    bytes32 internal constant IMPLEMENTATION_SLOT =\n    0x177667240aeeea7e35eabe3a35e18306f336219e1386f7710a6bf8783f761b24;\n\n    // This storage slot stores the finalization flag.\n    // Once the value stored in this slot is set to non-zero\n    // the proxy blocks implementation upgrades.\n    // The current implementation is then referred to as Finalized.\n    // Web3.solidityKeccak([\u0027string\u0027], [\"StarkWare2019.finalization-flag-slot\"]).\n    bytes32 internal constant FINALIZED_STATE_SLOT =\n    0x7d433c6f837e8f93009937c466c82efbb5ba621fae36886d0cac433c5d0aa7d2;\n    uint256 public constant UPGRADE_ACTIVATION_DELAY = 28 days;\n\n    using Addresses for address;\n\n    constructor ( )\n        public\n    {\n        initGovernance();\n    }\n\n    /*\n      Returns true if the implementation is frozen.\n      If the implementation was not assigned yet, returns false.\n    */\n    function implementationIsFrozen() private returns (bool) {\n        address _implementation = implementation();\n\n        // We can\u0027t call low level implementation before it\u0027s assigned. (i.e. ZERO).\n        if (_implementation == ZERO_ADDRESS) {\n            return false;\n        }\n        // solium-disable-next-line security/no-low-level-calls\n        (bool success, bytes memory returndata) = _implementation.delegatecall(\n            abi.encodeWithSignature(\"isFrozen()\"));\n        require(success, string(returndata));\n        return abi.decode(returndata, (bool));\n    }\n\n    /*\n      This method blocks delegation to initialize().\n      Only upgradeTo should be able to delegate call to initialize().\n    */\n    function initialize(bytes calldata /*data*/)\n        external pure\n    {\n        revert(\"CANNOT_CALL_INITIALIZE\");\n    }\n\n    modifier notFinalized()\n    {\n        require(isNotFinalized(), \"IMPLEMENTATION_FINALIZED\");\n        _;\n    }\n\n    /*\n      Forbids calling the function if the implementation is frozen.\n      This modifier relies on the lower level (logical contract) implementation of isFrozen().\n    */\n    modifier notFrozen()\n    {\n        require(implementationIsFrozen() == false, \"STATE_IS_FROZEN\");\n        _;\n    }\n\n    /*\n      Contract\u0027s default function. Delegates execution to the implementation contract.\n      It returns back to the external caller whatever the implementation delegated code returns.\n    */\n    function () external payable {\n        address _implementation = implementation();\n        require (_implementation != ZERO_ADDRESS, \"MISSING_IMPLEMENTATION\");\n\n        // solium-disable-next-line security/no-inline-assembly\n        assembly {\n            // Copy msg.data. We take full control of memory in this inline assembly\n            // block because it will not return to Solidity code. We overwrite the\n            // Solidity scratch pad at memory position 0.\n            calldatacopy(0, 0, calldatasize)\n\n            // Call the implementation.\n            // out and outsize are 0 for now, as we don\u0027t know the out size yet.\n            let result := delegatecall(gas, _implementation, 0, calldatasize, 0, 0)\n\n            // Copy the returned data.\n            returndatacopy(0, 0, returndatasize)\n\n            switch result\n            // delegatecall returns 0 on error.\n            case 0 { revert(0, returndatasize) }\n            default { return(0, returndatasize) }\n        }\n    }\n\n    /*\n      Returns the address of the current implementation.\n    */\n    function implementation() public view returns (address _implementation) {\n        bytes32 slot = IMPLEMENTATION_SLOT;\n        // solium-disable-next-line security/no-inline-assembly\n        assembly {\n            _implementation := sload(slot)\n        }\n    }\n\n    /*\n      Sets the implementation address of the proxy.\n    */\n    function setImplementation(address newImplementation) private {\n        bytes32 slot = IMPLEMENTATION_SLOT;\n        // solium-disable-next-line security/no-inline-assembly\n        assembly {\n            sstore(slot, newImplementation)\n        }\n    }\n\n    /*\n      Returns true if the contract is not in the finalized state.\n    */\n    function isNotFinalized() public view returns (bool notFinal) {\n        bytes32 slot = FINALIZED_STATE_SLOT;\n        uint256 slotValue;\n        // solium-disable-next-line security/no-inline-assembly\n        assembly {\n            slotValue := sload(slot)\n        }\n        notFinal = (slotValue == 0);\n    }\n\n    /*\n      Marks the current implementation as finalized.\n    */\n    function setFinalizedFlag() private {\n        bytes32 slot = FINALIZED_STATE_SLOT;\n        // solium-disable-next-line security/no-inline-assembly\n        assembly {\n            sstore(slot, 0x1)\n        }\n    }\n\n    /*\n      Introduce an implementation and its initialization vector,\n      and start the time-lock before it can be upgraded to.\n      addImplementation is not blocked when frozen or finalized.\n      (upgradeTo API is blocked when finalized or frozen).\n    */\n    function addImplementation(address newImplementation, bytes calldata data, bool finalize)\n        external onlyGovernance {\n        require(newImplementation.isContract(), \"ADDRESS_NOT_CONTRACT\");\n\n        bytes32 init_hash = keccak256(abi.encode(data, finalize));\n        initializationHash[newImplementation] = init_hash;\n\n        // solium-disable-next-line security/no-block-members\n        uint256 activation_time = now + UPGRADE_ACTIVATION_DELAY;\n\n        // First implementation should not have time-lock.\n        if (implementation() == ZERO_ADDRESS) {\n            // solium-disable-next-line security/no-block-members\n            activation_time = now;\n        }\n\n        enabledTime[newImplementation] = activation_time;\n        emit ImplementationAdded(newImplementation, data, finalize);\n    }\n\n    /*\n      Removes a candidate implementation.\n      Note that it is possible to remove the current implementation. Doing so doesn\u0027t affect the\n      current implementation, but rather revokes it as a future candidate.\n    */\n    function removeImplementation(address newImplementation)\n        external onlyGovernance {\n\n        // If we have initializer, we set the hash of it.\n        uint256 activation_time = enabledTime[newImplementation];\n\n        require(activation_time \u003e 0, \"ADDRESS_NOT_UPGRADE_CANDIDATE\");\n\n        enabledTime[newImplementation] = 0;\n\n        initializationHash[newImplementation] = 0;\n        emit ImplementationRemoved(newImplementation);\n    }\n\n    /*\n      Upgrades the proxy to a new implementation, with its initialization.\n      to upgrade successfully, implementation must have been added time-lock agreeably\n      before, and the init vector must be identical ot the one submitted before.\n\n      Upon assignment of new implementation address,\n      its initialize will be called with the inititalizing vector (even if empty).\n      Therefore, the implementatin MUST must have such a method.\n    */\n    function upgradeTo(address newImplementation, bytes calldata data, bool finalize)\n        external payable onlyGovernance notFinalized notFrozen {\n        uint256 activation_time = enabledTime[newImplementation];\n\n        require(activation_time \u003e 0, \"ADDRESS_NOT_UPGRADE_CANDIDATE\");\n        // solium-disable-next-line security/no-block-members\n        require(activation_time \u003c= now, \"UPGRADE_NOT_ENABLED_YET\");\n\n        bytes32 init_vector_hash = initializationHash[newImplementation];\n        require(init_vector_hash == keccak256(abi.encode(data, finalize)), \"CHANGED_INITIALIZER\");\n        setImplementation(newImplementation);\n\n        // solium-disable-next-line security/no-low-level-calls\n        (bool success, bytes memory returndata) = newImplementation.delegatecall(\n            abi.encodeWithSelector(this.initialize.selector, data));\n        require(success, string(returndata));\n\n        // Verify that the new implementation is not frozen post initialization.\n        (success, returndata) = newImplementation.delegatecall(\n            abi.encodeWithSignature(\"isFrozen()\"));\n        require(success, \"CALL_TO_ISFROZEN_REVERTED\");\n        require(abi.decode(returndata, (bool)) == false, \"NEW_IMPLEMENTATION_FROZEN\");\n\n        if (finalize == true) {\n            setFinalizedFlag();\n            emit FinalizedImplementation(newImplementation);\n        }\n\n        emit Upgraded(newImplementation);\n    }\n}\n"},"ProxyGovernance.sol":{"content":"/*\n  Copyright 2019,2020 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\npragma solidity ^0.5.2;\n\nimport \"Governance.sol\";\n\n/**\n  The Proxy contract is governed by one or more Governors of which the initial one is the\n  deployer of the contract.\n\n  A governor has the sole authority to perform the following operations:\n\n  1. Nominate additional governors (:sol:func:`proxyNominateNewGovernor`)\n  2. Remove other governors (:sol:func:`proxyRemoveGovernor`)\n  3. Add new `implementations` (proxied contracts)\n  4. Remove (new or old) `implementations`\n  5. Update `implementations` after a timelock allows it\n\n  Adding governors is performed in a two step procedure:\n\n  1. First, an existing governor nominates a new governor (:sol:func:`proxyNominateNewGovernor`)\n  2. Then, the new governor must accept governance to become a governor (:sol:func:`proxyAcceptGovernance`)\n\n  This two step procedure ensures that a governor public key cannot be nominated unless there is an\n  entity that has the corresponding private key. This is intended to prevent errors in the addition\n  process.\n\n  The governor private key should typically be held in a secure cold wallet or managed via a\n  multi-sig contract.\n*/\n/*\n  Implements Governance for the proxy contract.\n  It is a thin wrapper to the Governance contract,\n  which is needed so that it can have non-colliding function names,\n  and a specific tag (key) to allow unique state storage.\n*/\ncontract ProxyGovernance is Governance {\n\n    // The tag is the string key that is used in the Governance storage mapping.\n    string public constant PROXY_GOVERNANCE_TAG = \"StarkEx.Proxy.2019.GovernorsInformation\";\n\n    function getGovernanceTag()\n        internal\n        view\n        returns (string memory tag) {\n        tag = PROXY_GOVERNANCE_TAG;\n    }\n\n    function proxyIsGovernor(address testGovernor) external view returns (bool) {\n        return isGovernor(testGovernor);\n    }\n\n    function proxyNominateNewGovernor(address newGovernor) external {\n        nominateNewGovernor(newGovernor);\n    }\n\n    function proxyRemoveGovernor(address governorForRemoval) external {\n        removeGovernor(governorForRemoval);\n    }\n\n    function proxyAcceptGovernance()\n        external\n    {\n        acceptGovernance();\n    }\n\n    function proxyCancelNomination() external {\n        cancelNomination();\n    }\n}\n"},"ProxyStorage.sol":{"content":"/*\n  Copyright 2019,2020 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\npragma solidity ^0.5.2;\n\nimport \"GovernanceStorage.sol\";\n\n/*\n  Holds the Proxy-specific state variables.\n  This contract is inherited by the GovernanceStorage (and indirectly by MainStorage)\n  to prevent collision hazard.\n*/\ncontract ProxyStorage is GovernanceStorage {\n\n    // Stores the hash of the initialization vector of the added implementation.\n    // Upon upgradeTo the implementation, the initialization vector is verified\n    // to be identical to the one submitted when adding the implementaion.\n    mapping (address =\u003e bytes32) internal initializationHash;\n\n    // The time after which we can switch to the implementation.\n    mapping (address =\u003e uint256) internal enabledTime;\n\n    // A central storage of the flags whether implementation has been initialized.\n    // Note - it can be used flexibly enough to accomodate multiple level of initialization\n    // (i.e. using different key salting schemes for different initialization levels).\n    mapping (bytes32 =\u003e bool) internal initialized;\n}\n"}}

              File 2 of 9: StarkExchange
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              /*
                This contract provides means to block direct call of an external function.
                A derived contract (e.g. MainDispatcherBase) should decorate sensitive functions with the
                notCalledDirectly modifier, thereby preventing it from being called directly, and allowing only calling
                using delegate_call.
              */
              abstract contract BlockDirectCall {
                  address immutable this_;
                  constructor() internal {
                      this_ = address(this);
                  }
                  modifier notCalledDirectly() {
                      require(this_ != address(this), "DIRECT_CALL_DISALLOWED");
                      _;
                  }
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              /*
                Common Utility librarries.
                I. Addresses (extending address).
              */
              library Addresses {
                  function isContract(address account) internal view returns (bool) {
                      uint256 size;
                      assembly {
                          size := extcodesize(account)
                      }
                      return size > 0;
                  }
                  function performEthTransfer(address recipient, uint256 amount) internal {
                      (bool success, ) = recipient.call{value: amount}(""); // NOLINT: low-level-calls.
                      require(success, "ETH_TRANSFER_FAILED");
                  }
                  /*
                    Safe wrapper around ERC20/ERC721 calls.
                    This is required because many deployed ERC20 contracts don't return a value.
                    See https://github.com/ethereum/solidity/issues/4116.
                  */
                  function safeTokenContractCall(address tokenAddress, bytes memory callData) internal {
                      require(isContract(tokenAddress), "BAD_TOKEN_ADDRESS");
                      // NOLINTNEXTLINE: low-level-calls.
                      (bool success, bytes memory returndata) = tokenAddress.call(callData);
                      require(success, string(returndata));
                      if (returndata.length > 0) {
                          require(abi.decode(returndata, (bool)), "TOKEN_OPERATION_FAILED");
                      }
                  }
                  /*
                    Validates that the passed contract address is of a real contract,
                    and that its id hash (as infered fromn identify()) matched the expected one.
                  */
                  function validateContractId(address contractAddress, bytes32 expectedIdHash) internal {
                      require(isContract(contractAddress), "ADDRESS_NOT_CONTRACT");
                      (bool success, bytes memory returndata) = contractAddress.call( // NOLINT: low-level-calls.
                          abi.encodeWithSignature("identify()")
                      );
                      require(success, "FAILED_TO_IDENTIFY_CONTRACT");
                      string memory realContractId = abi.decode(returndata, (string));
                      require(
                          keccak256(abi.encodePacked(realContractId)) == expectedIdHash,
                          "UNEXPECTED_CONTRACT_IDENTIFIER"
                      );
                  }
              }
              /*
                II. StarkExTypes - Common data types.
              */
              library StarkExTypes {
                  // Structure representing a list of verifiers (validity/availability).
                  // A statement is valid only if all the verifiers in the list agree on it.
                  // Adding a verifier to the list is immediate - this is used for fast resolution of
                  // any soundness issues.
                  // Removing from the list is time-locked, to ensure that any user of the system
                  // not content with the announced removal has ample time to leave the system before it is
                  // removed.
                  struct ApprovalChainData {
                      address[] list;
                      // Represents the time after which the verifier with the given address can be removed.
                      // Removal of the verifier with address A is allowed only in the case the value
                      // of unlockedForRemovalTime[A] != 0 and unlockedForRemovalTime[A] < (current time).
                      mapping(address => uint256) unlockedForRemovalTime;
                  }
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "../interfaces/MGovernance.sol";
              /*
                Holds the governance slots for ALL entities, including proxy and the main contract.
              */
              contract GovernanceStorage {
                  // A map from a Governor tag to its own GovernanceInfoStruct.
                  mapping(string => GovernanceInfoStruct) internal governanceInfo; //NOLINT uninitialized-state.
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              /*
                Interface for a generic dispatcher to use, which the concrete dispatcher must implement.
                It contains the functions that are specific to the concrete dispatcher instance.
                The interface is implemented as contract, because interface implies all methods external.
              */
              abstract contract IDispatcherBase {
                  function getSubContract(bytes4 selector) public view virtual returns (address);
                  function setSubContractAddress(uint256 index, address subContract) internal virtual;
                  function getNumSubcontracts() internal pure virtual returns (uint256);
                  function validateSubContractIndex(uint256 index, address subContract) internal pure virtual;
                  /*
                    Ensures initializer can be called. Reverts otherwise.
                  */
                  function initializationSentinel() internal view virtual;
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              interface Identity {
                  /*
                    Allows a caller, typically another contract,
                    to ensure that the provided address is of the expected type and version.
                  */
                  function identify() external pure returns (string memory);
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              struct GovernanceInfoStruct {
                  mapping(address => bool) effectiveGovernors;
                  address candidateGovernor;
                  bool initialized;
              }
              abstract contract MGovernance {
                  function _isGovernor(address testGovernor) internal view virtual returns (bool);
                  /*
                    Allows calling the function only by a Governor.
                  */
                  modifier onlyGovernance() {
                      require(_isGovernor(msg.sender), "ONLY_GOVERNANCE");
                      _;
                  }
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "../components/MainStorage.sol";
              import "./MainDispatcherBase.sol";
              abstract contract MainDispatcher is MainStorage, MainDispatcherBase {
                  uint256 constant SUBCONTRACT_BITS = 4;
                  function magicSalt() internal pure virtual returns (uint256);
                  function handlerMapSection(uint256 section) internal pure virtual returns (uint256);
                  function expectedIdByIndex(uint256 index) internal pure virtual returns (string memory id);
                  function validateSubContractIndex(uint256 index, address subContract) internal pure override {
                      string memory id = SubContractor(subContract).identify();
                      bytes32 hashed_expected_id = keccak256(abi.encodePacked(expectedIdByIndex(index)));
                      require(
                          hashed_expected_id == keccak256(abi.encodePacked(id)),
                          "MISPLACED_INDEX_OR_BAD_CONTRACT_ID"
                      );
                      // Gets the list of critical selectors from the sub-contract and checks that the selector
                      // is mapped to that sub-contract.
                      bytes4[] memory selectorsToValidate = SubContractor(subContract).validatedSelectors();
                      for (uint256 i = 0; i < selectorsToValidate.length; i++) {
                          require(
                              getSubContractIndex(selectorsToValidate[i]) == index,
                              "INCONSISTENT_DISPATCHER_MAP"
                          );
                      }
                  }
                  function handlingContractId(bytes4 selector) external pure virtual returns (string memory id) {
                      uint256 index = getSubContractIndex(selector);
                      return expectedIdByIndex(index);
                  }
                  /*
                    Returns the index in subContracts where the address of the sub-contract implementing
                    the function with the queried selector is held.
                    Note: The nature of the sub-contracts handler map is such that all the required selectors
                    are mapped. However, other selectors, such that are not implemented in any subcontract,
                    may also return a sub-contract address.
                    This behavior is by-design, and not a problem.
                  */
                  function getSubContractIndex(bytes4 selector) internal pure returns (uint256) {
                      uint256 location = 0xFF & uint256(keccak256(abi.encodePacked(selector, magicSalt())));
                      uint256 offset = (SUBCONTRACT_BITS * location) % 256;
                      // We have 64 locations in each register, hence the >> 6 (i.e. location // 64).
                      return (handlerMapSection(location >> 6) >> offset) & 0xF;
                  }
                  /*
                    Returns the address of the sub-contract that would be delegated to handle a call
                    with the queried selector. (see note above).
                  */
                  function getSubContract(bytes4 selector) public view override returns (address) {
                      return subContracts[getSubContractIndex(selector)];
                  }
                  function setSubContractAddress(uint256 index, address subContractAddress) internal override {
                      subContracts[index] = subContractAddress;
                  }
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "./SubContractor.sol";
              import "./IDispatcherBase.sol";
              import "../interfaces/BlockDirectCall.sol";
              import "../libraries/Common.sol";
              abstract contract MainDispatcherBase is IDispatcherBase, BlockDirectCall {
                  using Addresses for address;
                  /*
                    This entry point serves only transactions with empty calldata. (i.e. pure value transfer tx).
                    We don't expect to receive such, thus block them.
                  */
                  receive() external payable {
                      revert("CONTRACT_NOT_EXPECTED_TO_RECEIVE");
                  }
                  fallback() external payable {
                      address subContractAddress = getSubContract(msg.sig);
                      require(subContractAddress != address(0x0), "NO_CONTRACT_FOR_FUNCTION");
                      assembly {
                          // Copy msg.data. We take full control of memory in this inline assembly
                          // block because it will not return to Solidity code. We overwrite the
                          // Solidity scratch pad at memory position 0.
                          calldatacopy(0, 0, calldatasize())
                          // Call the implementation.
                          // out and outsize are 0 for now, as we don"t know the out size yet.
                          let result := delegatecall(gas(), subContractAddress, 0, calldatasize(), 0, 0)
                          // Copy the returned data.
                          returndatacopy(0, 0, returndatasize())
                          switch result
                          // delegatecall returns 0 on error.
                          case 0 {
                              revert(0, returndatasize())
                          }
                          default {
                              return(0, returndatasize())
                          }
                      }
                  }
                  /*
                    1. Extract subcontracts.
                    2. Verify correct sub-contract initializer size.
                    3. Extract sub-contract initializer data.
                    4. Call sub-contract initializer.
                    The init data bytes passed to initialize are structed as following:
                    I. N slots (uin256 size) addresses of the deployed sub-contracts.
                    II. An address of an external initialization contract (optional, or ZERO_ADDRESS).
                    III. (Up to) N bytes sections of the sub-contracts initializers.
                    If already initialized (i.e. upgrade) we expect the init data to be consistent with this.
                    and if a different size of init data is expected when upgrading, the initializerSize should
                    reflect this.
                    If an external initializer contract is not used, ZERO_ADDRESS is passed in its slot.
                    If the external initializer contract is used, all the remaining init data is passed to it,
                    and internal initialization will not occur.
                    External Initialization Contract
                    --------------------------------
                    External Initialization Contract (EIC) is a hook for custom initialization.
                    Typically in an upgrade flow, the expected initialization contains only the addresses of
                    the sub-contracts. Normal initialization of the sub-contracts is such that is not needed
                    in an upgrade, and actually may be very dangerous, as changing of state on a working system
                    may corrupt it.
                    In the event that some state initialization is required, the EIC is a hook that allows this.
                    It may be deployed and called specifically for this purpose.
                    The address of the EIC must be provided (if at all) when a new implementation is added to
                    a Proxy contract (as part of the initialization vector).
                    Hence, it is considered part of the code open to reviewers prior to a time-locked upgrade.
                    When a custom initialization is performed using an EIC,
                    the main dispatcher initialize extracts and stores the sub-contracts addresses, and then
                    yields to the EIC, skipping the rest of its initialization code.
                    Flow of MainDispatcher initialize
                    ---------------------------------
                    1. Extraction and assignment of subcontracts addresses
                       Main dispatcher expects a valid and consistent set of addresses in the passed data.
                       It validates that, extracts the addresses from the data, and validates that the addresses
                       are of the expected type and order. Then those addresses are stored.
                    2. Extraction of EIC address
                       The address of the EIC is extracted from the data.
                       External Initializer Contract is optional. ZERO_ADDRESS indicates it is not used.
                    3a. EIC is used
                        Dispatcher calls the EIC initialize function with the remaining data.
                        Note - In this option 3b is not performed.
                    3b. EIC is not used
                        If there is additional initialization data then:
                        I. Sentitenl function is called to permit subcontracts initialization.
                        II. Dispatcher loops through the subcontracts and for each one it extracts the
                            initializing data and passes it to the subcontract's initialize function.
                  */
                  function initialize(bytes calldata data) external virtual notCalledDirectly {
                      // Number of sub-contracts.
                      uint256 nSubContracts = getNumSubcontracts();
                      // We support currently 4 bits per contract, i.e. 16, reserving 00 leads to 15.
                      require(nSubContracts <= 15, "TOO_MANY_SUB_CONTRACTS");
                      // Sum of subcontract initializers. Aggregated for verification near the end.
                      uint256 totalInitSizes = 0;
                      // Offset (within data) of sub-contract initializer vector.
                      // Just past the sub-contract+eic addresses.
                      uint256 initDataContractsOffset = 32 * (nSubContracts + 1);
                      // Init data MUST include addresses for all sub-contracts + EIC.
                      require(data.length >= initDataContractsOffset, "SUB_CONTRACTS_NOT_PROVIDED");
                      // Size of passed data, excluding sub-contract addresses.
                      uint256 additionalDataSize = data.length - initDataContractsOffset;
                      // Extract & update contract addresses.
                      for (uint256 nContract = 1; nContract <= nSubContracts; nContract++) {
                          // Extract sub-contract address.
                          address contractAddress = abi.decode(
                              data[32 * (nContract - 1):32 * nContract],
                              (address)
                          );
                          validateSubContractIndex(nContract, contractAddress);
                          // Contracts are indexed from 1 and 0 is not in use here.
                          setSubContractAddress(nContract, contractAddress);
                      }
                      // Check if we have an external initializer contract.
                      address externalInitializerAddr = abi.decode(
                          data[initDataContractsOffset - 32:initDataContractsOffset],
                          (address)
                      );
                      // 3(a). Yield to EIC initialization.
                      if (externalInitializerAddr != address(0x0)) {
                          callExternalInitializer(externalInitializerAddr, data[initDataContractsOffset:]);
                          return;
                      }
                      // 3(b). Subcontracts initialization.
                      // I. If no init data passed besides sub-contracts, return.
                      if (additionalDataSize == 0) {
                          return;
                      }
                      // Just to be on the safe side.
                      assert(externalInitializerAddr == address(0x0));
                      // II. Gate further initialization.
                      initializationSentinel();
                      // III. Loops through the subcontracts, extracts their data and calls their initializer.
                      for (uint256 nContract = 1; nContract <= nSubContracts; nContract++) {
                          // Extract sub-contract address.
                          address contractAddress = abi.decode(
                              data[32 * (nContract - 1):32 * nContract],
                              (address)
                          );
                          // The initializerSize is called via delegatecall, so that it can relate to the state,
                          // and not only to the new contract code. (e.g. return 0 if state-intialized else 192).
                          // NOLINTNEXTLINE: controlled-delegatecall low-level-calls calls-loop.
                          (bool success, bytes memory returndata) = contractAddress.delegatecall(
                              abi.encodeWithSelector(SubContractor(contractAddress).initializerSize.selector)
                          );
                          require(success, string(returndata));
                          uint256 initSize = abi.decode(returndata, (uint256));
                          require(initSize <= additionalDataSize, "INVALID_INITIALIZER_SIZE");
                          require(totalInitSizes + initSize <= additionalDataSize, "INVALID_INITIALIZER_SIZE");
                          if (initSize == 0) {
                              continue;
                          }
                          // Call sub-contract initializer.
                          // NOLINTNEXTLINE: controlled-delegatecall calls-loop.
                          (success, returndata) = contractAddress.delegatecall(
                              abi.encodeWithSelector(
                                  this.initialize.selector,
                                  data[initDataContractsOffset:initDataContractsOffset + initSize]
                              )
                          );
                          require(success, string(returndata));
                          totalInitSizes += initSize;
                          initDataContractsOffset += initSize;
                      }
                      require(additionalDataSize == totalInitSizes, "MISMATCHING_INIT_DATA_SIZE");
                  }
                  function callExternalInitializer(address externalInitializerAddr, bytes calldata extInitData)
                      private
                  {
                      require(externalInitializerAddr.isContract(), "NOT_A_CONTRACT");
                      // NOLINTNEXTLINE: low-level-calls, controlled-delegatecall.
                      (bool success, bytes memory returndata) = externalInitializerAddr.delegatecall(
                          abi.encodeWithSelector(this.initialize.selector, extInitData)
                      );
                      require(success, string(returndata));
                      require(returndata.length == 0, string(returndata));
                  }
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "../upgrade/ProxyStorage.sol";
              import "../libraries/Common.sol";
              /*
                Holds ALL the main contract state (storage) variables.
              */
              contract MainStorage is ProxyStorage {
                  uint256 internal constant LAYOUT_LENGTH = 2**64;
                  address escapeVerifierAddress; // NOLINT: constable-states.
                  // Global dex-frozen flag.
                  bool stateFrozen; // NOLINT: constable-states.
                  // Time when unFreeze can be successfully called (UNFREEZE_DELAY after freeze).
                  uint256 unFreezeTime; // NOLINT: constable-states.
                  // Pending deposits.
                  // A map STARK key => asset id => vault id => quantized amount.
                  mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))) pendingDeposits;
                  // Cancellation requests.
                  // A map STARK key => asset id => vault id => request timestamp.
                  mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))) cancellationRequests;
                  // Pending withdrawals.
                  // A map STARK key => asset id => quantized amount.
                  mapping(uint256 => mapping(uint256 => uint256)) pendingWithdrawals;
                  // vault_id => escape used boolean.
                  mapping(uint256 => bool) escapesUsed;
                  // Number of escapes that were performed when frozen.
                  uint256 escapesUsedCount; // NOLINT: constable-states.
                  // NOTE: fullWithdrawalRequests is deprecated, and replaced by forcedActionRequests.
                  // NOLINTNEXTLINE naming-convention.
                  mapping(uint256 => mapping(uint256 => uint256)) fullWithdrawalRequests_DEPRECATED;
                  // State sequence number.
                  uint256 sequenceNumber; // NOLINT: constable-states uninitialized-state.
                  // Validium Vaults Tree Root & Height.
                  uint256 validiumVaultRoot; // NOLINT: constable-states uninitialized-state.
                  uint256 validiumTreeHeight; // NOLINT: constable-states uninitialized-state.
                  // Order Tree Root & Height.
                  uint256 orderRoot; // NOLINT: constable-states uninitialized-state.
                  uint256 orderTreeHeight; // NOLINT: constable-states uninitialized-state.
                  // True if and only if the address is allowed to add tokens.
                  mapping(address => bool) tokenAdmins;
                  // This mapping is no longer in use, remains for backwards compatibility.
                  mapping(address => bool) userAdmins_DEPRECATED; // NOLINT: naming-convention.
                  // True if and only if the address is an operator (allowed to update state).
                  mapping(address => bool) operators; // NOLINT: uninitialized-state.
                  // Mapping of contract ID to asset data.
                  mapping(uint256 => bytes) assetTypeToAssetInfo; // NOLINT: uninitialized-state.
                  // Mapping of registered contract IDs.
                  mapping(uint256 => bool) registeredAssetType; // NOLINT: uninitialized-state.
                  // Mapping from contract ID to quantum.
                  mapping(uint256 => uint256) assetTypeToQuantum; // NOLINT: uninitialized-state.
                  // This mapping is no longer in use, remains for backwards compatibility.
                  mapping(address => uint256) starkKeys_DEPRECATED; // NOLINT: naming-convention.
                  // Mapping from STARK public key to the Ethereum public key of its owner.
                  mapping(uint256 => address) ethKeys; // NOLINT: uninitialized-state.
                  // Timelocked state transition and availability verification chain.
                  StarkExTypes.ApprovalChainData verifiersChain;
                  StarkExTypes.ApprovalChainData availabilityVerifiersChain;
                  // Batch id of last accepted proof.
                  uint256 lastBatchId; // NOLINT: constable-states uninitialized-state.
                  // Mapping between sub-contract index to sub-contract address.
                  mapping(uint256 => address) subContracts; // NOLINT: uninitialized-state.
                  mapping(uint256 => bool) permissiveAssetType_DEPRECATED; // NOLINT: naming-convention.
                  // ---- END OF MAIN STORAGE AS DEPLOYED IN STARKEX2.0 ----
                  // Onchain-data version configured for the system.
                  uint256 onchainDataVersion_DEPRECATED; // NOLINT: naming-convention constable-states.
                  // Counter of forced action request in block. The key is the block number.
                  mapping(uint256 => uint256) forcedRequestsInBlock;
                  // ForcedAction requests: actionHash => requestTime.
                  mapping(bytes32 => uint256) forcedActionRequests;
                  // Mapping for timelocked actions.
                  // A actionKey => activation time.
                  mapping(bytes32 => uint256) actionsTimeLock;
                  // Append only list of requested forced action hashes.
                  bytes32[] actionHashList;
                  // ---- END OF MAIN STORAGE AS DEPLOYED IN STARKEX3.0 ----
                  // ---- END OF MAIN STORAGE AS DEPLOYED IN STARKEX4.0 ----
                  // Rollup Vaults Tree Root & Height.
                  uint256 rollupVaultRoot; // NOLINT: constable-states uninitialized-state.
                  uint256 rollupTreeHeight; // NOLINT: constable-states uninitialized-state.
                  uint256 globalConfigCode; // NOLINT: constable-states uninitialized-state.
                  // Mapping of owner keys that are blocked from withdrawals.
                  mapping(uint256 => uint256) internal blockListed;
                  // Reserved storage space for Extensibility.
                  // Every added MUST be added above the end gap, and the __endGap size must be reduced
                  // accordingly.
                  // NOLINTNEXTLINE: naming-convention.
                  uint256[LAYOUT_LENGTH - 41] private __endGap; // __endGap complements layout to LAYOUT_LENGTH.
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "../components/GovernanceStorage.sol";
              /*
                Holds the Proxy-specific state variables.
                This contract is inherited by the GovernanceStorage (and indirectly by MainStorage)
                to prevent collision hazard.
              */
              contract ProxyStorage is GovernanceStorage {
                  // NOLINTNEXTLINE: naming-convention uninitialized-state.
                  mapping(address => bytes32) internal initializationHash_DEPRECATED;
                  // The time after which we can switch to the implementation.
                  // Hash(implementation, data, finalize) => time.
                  mapping(bytes32 => uint256) internal enabledTime;
                  // A central storage of the flags whether implementation has been initialized.
                  // Note - it can be used flexibly enough to accommodate multiple levels of initialization
                  // (i.e. using different key salting schemes for different initialization levels).
                  mapping(bytes32 => bool) internal initialized;
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "../interfaces/MainDispatcher.sol";
              contract StarkExchange is MainDispatcher {
                  string public constant VERSION = "4.5.3-blc";
                  // Salt for a 8 bit unique spread of all relevant selectors. Pre-caclulated.
                  // ---------- The following code was auto-generated. PLEASE DO NOT EDIT. ----------
                  uint256 constant MAGIC_SALT = 4259003;
                  uint256 constant IDX_MAP_0 = 0x1030220010120000001021030000002223022000021220125001010000021300;
                  uint256 constant IDX_MAP_1 = 0x2023105020000205000002451020200305120020000000000002230015000201;
                  uint256 constant IDX_MAP_2 = 0x1000000030000003000002000000020000500100500230025010222000010;
                  uint256 constant IDX_MAP_3 = 0x420002010300345030000000005010021020004000000050002052300060001;
                  // ---------- End of auto-generated code. ----------
                  function getNumSubcontracts() internal pure override returns (uint256) {
                      return 6;
                  }
                  function magicSalt() internal pure override returns (uint256) {
                      return MAGIC_SALT;
                  }
                  function handlerMapSection(uint256 section) internal pure override returns (uint256) {
                      if (section == 0) {
                          return IDX_MAP_0;
                      } else if (section == 1) {
                          return IDX_MAP_1;
                      } else if (section == 2) {
                          return IDX_MAP_2;
                      } else if (section == 3) {
                          return IDX_MAP_3;
                      }
                      revert("BAD_IDX_MAP_SECTION");
                  }
                  function expectedIdByIndex(uint256 index) internal pure override returns (string memory id) {
                      if (index == 1) {
                          id = "StarkWare_AllVerifiers_2022_2";
                      } else if (index == 2) {
                          id = "StarkWare_TokensAndRamping_2024_4";
                      } else if (index == 3) {
                          id = "StarkWare_StarkExState_2022_5";
                      } else if (index == 4) {
                          id = "StarkWare_ForcedActions_2022_3";
                      } else if (index == 5) {
                          id = "StarkWare_OnchainVaults_2022_2";
                      } else if (index == 6) {
                          id = "StarkWare_ProxyUtils_2022_2";
                      } else {
                          revert("UNEXPECTED_INDEX");
                      }
                  }
                  function initializationSentinel() internal view override {
                      string memory REVERT_MSG = "INITIALIZATION_BLOCKED";
                      // This initializer sets roots etc. It must not be applied twice.
                      // I.e. it can run only when the state is still empty.
                      require(validiumVaultRoot == 0, REVERT_MSG);
                      require(validiumTreeHeight == 0, REVERT_MSG);
                      require(rollupVaultRoot == 0, REVERT_MSG);
                      require(rollupTreeHeight == 0, REVERT_MSG);
                      require(orderRoot == 0, REVERT_MSG);
                      require(orderTreeHeight == 0, REVERT_MSG);
                  }
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "./Identity.sol";
              interface SubContractor is Identity {
                  function initialize(bytes calldata data) external;
                  function initializerSize() external view returns (uint256);
                  /*
                    Returns an array with selectors for validation.
                    These selectors are the critical ones for maintaining self custody and anti censorship.
                    During the upgrade process, as part of the sub-contract validation, the MainDispatcher
                    validates that the selectos are mapped to the correct sub-contract.
                  */
                  function validatedSelectors() external pure returns (bytes4[] memory);
              }
              

              File 3 of 9: StarkExState
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "MGovernance.sol";
              abstract contract MOperator {
                  event LogOperatorAdded(address operator);
                  event LogOperatorRemoved(address operator);
                  function isOperator(address testedOperator) public view virtual returns (bool);
                  modifier onlyOperator() {
                      require(isOperator(msg.sender), "ONLY_OPERATOR");
                      _;
                  }
                  function registerOperator(address newOperator) external virtual;
                  function unregisterOperator(address removedOperator) external virtual;
                  function getOperators() internal view virtual returns (mapping(address => bool) storage);
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              /*
                The Fact Registry design pattern is a way to separate cryptographic verification from the
                business logic of the contract flow.
                A fact registry holds a hash table of verified "facts" which are represented by a hash of claims
                that the registry hash check and found valid. This table may be queried by accessing the
                isValid() function of the registry with a given hash.
                In addition, each fact registry exposes a registry specific function for submitting new claims
                together with their proofs. The information submitted varies from one registry to the other
                depending of the type of fact requiring verification.
                For further reading on the Fact Registry design pattern see this
                `StarkWare blog post <https://medium.com/starkware/the-fact-registry-a64aafb598b6>`_.
              */
              interface IFactRegistry {
                  /*
                    Returns true if the given fact was previously registered in the contract.
                  */
                  function isValid(bytes32 fact) external view returns (bool);
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "ProxyStorage.sol";
              import "Common.sol";
              /*
                Holds ALL the main contract state (storage) variables.
              */
              contract MainStorage is ProxyStorage {
                  uint256 internal constant LAYOUT_LENGTH = 2**64;
                  address escapeVerifierAddress; // NOLINT: constable-states.
                  // Global dex-frozen flag.
                  bool stateFrozen; // NOLINT: constable-states.
                  // Time when unFreeze can be successfully called (UNFREEZE_DELAY after freeze).
                  uint256 unFreezeTime; // NOLINT: constable-states.
                  // Pending deposits.
                  // A map STARK key => asset id => vault id => quantized amount.
                  mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))) pendingDeposits;
                  // Cancellation requests.
                  // A map STARK key => asset id => vault id => request timestamp.
                  mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))) cancellationRequests;
                  // Pending withdrawals.
                  // A map STARK key => asset id => quantized amount.
                  mapping(uint256 => mapping(uint256 => uint256)) pendingWithdrawals;
                  // vault_id => escape used boolean.
                  mapping(uint256 => bool) escapesUsed;
                  // Number of escapes that were performed when frozen.
                  uint256 escapesUsedCount; // NOLINT: constable-states.
                  // NOTE: fullWithdrawalRequests is deprecated, and replaced by forcedActionRequests.
                  // NOLINTNEXTLINE naming-convention.
                  mapping(uint256 => mapping(uint256 => uint256)) fullWithdrawalRequests_DEPRECATED;
                  // State sequence number.
                  uint256 sequenceNumber; // NOLINT: constable-states uninitialized-state.
                  // Validium Vaults Tree Root & Height.
                  uint256 validiumVaultRoot; // NOLINT: constable-states uninitialized-state.
                  uint256 validiumTreeHeight; // NOLINT: constable-states uninitialized-state.
                  // Order Tree Root & Height.
                  uint256 orderRoot; // NOLINT: constable-states uninitialized-state.
                  uint256 orderTreeHeight; // NOLINT: constable-states uninitialized-state.
                  // True if and only if the address is allowed to add tokens.
                  mapping(address => bool) tokenAdmins;
                  // This mapping is no longer in use, remains for backwards compatibility.
                  mapping(address => bool) userAdmins_DEPRECATED; // NOLINT: naming-convention.
                  // True if and only if the address is an operator (allowed to update state).
                  mapping(address => bool) operators; // NOLINT: uninitialized-state.
                  // Mapping of contract ID to asset data.
                  mapping(uint256 => bytes) assetTypeToAssetInfo; // NOLINT: uninitialized-state.
                  // Mapping of registered contract IDs.
                  mapping(uint256 => bool) registeredAssetType; // NOLINT: uninitialized-state.
                  // Mapping from contract ID to quantum.
                  mapping(uint256 => uint256) assetTypeToQuantum; // NOLINT: uninitialized-state.
                  // This mapping is no longer in use, remains for backwards compatibility.
                  mapping(address => uint256) starkKeys_DEPRECATED; // NOLINT: naming-convention.
                  // Mapping from STARK public key to the Ethereum public key of its owner.
                  mapping(uint256 => address) ethKeys; // NOLINT: uninitialized-state.
                  // Timelocked state transition and availability verification chain.
                  StarkExTypes.ApprovalChainData verifiersChain;
                  StarkExTypes.ApprovalChainData availabilityVerifiersChain;
                  // Batch id of last accepted proof.
                  uint256 lastBatchId; // NOLINT: constable-states uninitialized-state.
                  // Mapping between sub-contract index to sub-contract address.
                  mapping(uint256 => address) subContracts; // NOLINT: uninitialized-state.
                  mapping(uint256 => bool) permissiveAssetType_DEPRECATED; // NOLINT: naming-convention.
                  // ---- END OF MAIN STORAGE AS DEPLOYED IN STARKEX2.0 ----
                  // Onchain-data version configured for the system.
                  uint256 onchainDataVersion_DEPRECATED; // NOLINT: naming-convention constable-states.
                  // Counter of forced action request in block. The key is the block number.
                  mapping(uint256 => uint256) forcedRequestsInBlock;
                  // ForcedAction requests: actionHash => requestTime.
                  mapping(bytes32 => uint256) forcedActionRequests;
                  // Mapping for timelocked actions.
                  // A actionKey => activation time.
                  mapping(bytes32 => uint256) actionsTimeLock;
                  // Append only list of requested forced action hashes.
                  bytes32[] actionHashList;
                  // ---- END OF MAIN STORAGE AS DEPLOYED IN STARKEX3.0 ----
                  // ---- END OF MAIN STORAGE AS DEPLOYED IN STARKEX4.0 ----
                  // Rollup Vaults Tree Root & Height.
                  uint256 rollupVaultRoot; // NOLINT: constable-states uninitialized-state.
                  uint256 rollupTreeHeight; // NOLINT: constable-states uninitialized-state.
                  uint256 globalConfigCode; // NOLINT: constable-states uninitialized-state.
                  // Reserved storage space for Extensibility.
                  // Every added MUST be added above the end gap, and the __endGap size must be reduced
                  // accordingly.
                  // NOLINTNEXTLINE: naming-convention.
                  uint256[LAYOUT_LENGTH - 40] private __endGap; // __endGap complements layout to LAYOUT_LENGTH.
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "MGovernance.sol";
              /*
                Holds the governance slots for ALL entities, including proxy and the main contract.
              */
              contract GovernanceStorage {
                  // A map from a Governor tag to its own GovernanceInfoStruct.
                  mapping(string => GovernanceInfoStruct) internal governanceInfo; //NOLINT uninitialized-state.
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "MainStorage.sol";
              import "LibConstants.sol";
              import "MAcceptModifications.sol";
              import "MFreezable.sol";
              import "IFactRegistry.sol";
              import "MStateRoot.sol";
              /**
                Escaping the exchange is the last resort for users that wish to withdraw their funds without
                relying on off-chain exchange services. The Escape functionality may only be invoked once the
                contract has become frozen. This will be as the result of an unserviced full withdraw request
                (see :sol:mod:`FullWithdrawals`). At that point, any escaper entity may perform an escape
                operation as follows:
                1. Escapers must obtain a Merkle path of a vault leaf to be evicted with respect to the frozen vault tree root. There are two vault trees: a validium vaults tree and a rollup vaults tree. Rollup vaults data can always be reconstructed from on-chain data. Typically, once the exchange is frozen, validium vaults data will be made public or would be obtainable from an exchange API, depending on the data availability approach used by the exchange.
                2. Escapers call the :sol:mod:`EscapeVerifier` contract with the Merkle proof for the vault to be evicted. The leaf index for the escape verifier can be computed from the vaultId by clearing the ROLLUP_VAULTS_BIT bit. If the proof is valid, this results in the registration of such proof.
                3. Escapers call :sol:func:`escape` function with the parameters that constituted the escapeProof submitted to the :sol:mod:`EscapeVerifier` (i.e. the Public Key of the vault owner, full vault ID, asset ID and vault balance). If a proof was accepted for those parameters by the :sol:mod:`EscapeVerifier`, and no prior escape call was made for the vault, the contract adds the vault balance to an on-chain pending withdrawals account under the Public Key of the vault owner and the appropriate asset ID.
                4. The owner of the vault may then withdraw this amount from the pending withdrawals account by calling the normal withdraw function (see :sol:mod:`Withdrawals`) to transfer the funds to the users Eth or ERC20 account (depending on the token type).
                Note that while anyone can perform the initial steps of the escape operation (including the
                exchange operator, for example), only the owner of the vault may perform the final step of
                transferring the funds.
              */
              abstract contract Escapes is
                  MainStorage,
                  LibConstants,
                  MAcceptModifications,
                  MFreezable,
                  MStateRoot
              {
                  function initialize(address escapeVerifier) internal {
                      escapeVerifierAddress = escapeVerifier;
                  }
                  /*
                    Escape when the contract is frozen.
                  */
                  function escape(
                      uint256 ownerKey,
                      uint256 vaultId,
                      uint256 assetId,
                      uint256 quantizedAmount
                  ) external onlyFrozen {
                      require(isVaultInRange(vaultId), "OUT_OF_RANGE_VAULT_ID");
                      require(!escapesUsed[vaultId], "ESCAPE_ALREADY_USED");
                      // Escape can be used only once.
                      escapesUsed[vaultId] = true;
                      escapesUsedCount += 1;
                      // Select a vault tree to escape from, based on the vault id.
                      (uint256 root, uint256 treeHeight) = isValidiumVault(vaultId)
                          ? (getValidiumVaultRoot(), getValidiumTreeHeight())
                          : (getRollupVaultRoot(), getRollupTreeHeight());
                      // The index of vaultId leaf in its tree doesn't include the rollup bit flag.
                      uint256 vaultLeafIndex = getVaultLeafIndex(vaultId);
                      bytes32 claimHash = keccak256(
                          abi.encode(ownerKey, assetId, quantizedAmount, root, treeHeight, vaultLeafIndex)
                      );
                      IFactRegistry escapeVerifier = IFactRegistry(escapeVerifierAddress);
                      require(escapeVerifier.isValid(claimHash), "ESCAPE_LACKS_PROOF");
                      allowWithdrawal(ownerKey, assetId, quantizedAmount);
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              /*
                Interface containing actions a verifier can invoke on the state.
                The contract containing the state should implement these and verify correctness.
              */
              abstract contract MAcceptModifications {
                  function acceptDeposit(
                      uint256 ownerKey,
                      uint256 vaultId,
                      uint256 assetId,
                      uint256 quantizedAmount
                  ) internal virtual;
                  function allowWithdrawal(
                      uint256 ownerKey,
                      uint256 assetId,
                      uint256 quantizedAmount
                  ) internal virtual;
                  function acceptWithdrawal(
                      uint256 ownerKey,
                      uint256 assetId,
                      uint256 quantizedAmount
                  ) internal virtual;
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              /*
                Common Utility librarries.
                I. Addresses (extending address).
              */
              library Addresses {
                  function isContract(address account) internal view returns (bool) {
                      uint256 size;
                      assembly {
                          size := extcodesize(account)
                      }
                      return size > 0;
                  }
                  function performEthTransfer(address recipient, uint256 amount) internal {
                      (bool success, ) = recipient.call{value: amount}(""); // NOLINT: low-level-calls.
                      require(success, "ETH_TRANSFER_FAILED");
                  }
                  /*
                    Safe wrapper around ERC20/ERC721 calls.
                    This is required because many deployed ERC20 contracts don't return a value.
                    See https://github.com/ethereum/solidity/issues/4116.
                  */
                  function safeTokenContractCall(address tokenAddress, bytes memory callData) internal {
                      require(isContract(tokenAddress), "BAD_TOKEN_ADDRESS");
                      // NOLINTNEXTLINE: low-level-calls.
                      (bool success, bytes memory returndata) = tokenAddress.call(callData);
                      require(success, string(returndata));
                      if (returndata.length > 0) {
                          require(abi.decode(returndata, (bool)), "TOKEN_OPERATION_FAILED");
                      }
                  }
                  /*
                    Validates that the passed contract address is of a real contract,
                    and that its id hash (as infered fromn identify()) matched the expected one.
                  */
                  function validateContractId(address contractAddress, bytes32 expectedIdHash) internal {
                      require(isContract(contractAddress), "ADDRESS_NOT_CONTRACT");
                      (bool success, bytes memory returndata) = contractAddress.call( // NOLINT: low-level-calls.
                          abi.encodeWithSignature("identify()")
                      );
                      require(success, "FAILED_TO_IDENTIFY_CONTRACT");
                      string memory realContractId = abi.decode(returndata, (string));
                      require(
                          keccak256(abi.encodePacked(realContractId)) == expectedIdHash,
                          "UNEXPECTED_CONTRACT_IDENTIFIER"
                      );
                  }
              }
              /*
                II. StarkExTypes - Common data types.
              */
              library StarkExTypes {
                  // Structure representing a list of verifiers (validity/availability).
                  // A statement is valid only if all the verifiers in the list agree on it.
                  // Adding a verifier to the list is immediate - this is used for fast resolution of
                  // any soundness issues.
                  // Removing from the list is time-locked, to ensure that any user of the system
                  // not content with the announced removal has ample time to leave the system before it is
                  // removed.
                  struct ApprovalChainData {
                      address[] list;
                      // Represents the time after which the verifier with the given address can be removed.
                      // Removal of the verifier with address A is allowed only in the case the value
                      // of unlockedForRemovalTime[A] != 0 and unlockedForRemovalTime[A] < (current time).
                      mapping(address => uint256) unlockedForRemovalTime;
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              struct GovernanceInfoStruct {
                  mapping(address => bool) effectiveGovernors;
                  address candidateGovernor;
                  bool initialized;
              }
              abstract contract MGovernance {
                  function _isGovernor(address testGovernor) internal view virtual returns (bool);
                  /*
                    Allows calling the function only by a Governor.
                  */
                  modifier onlyGovernance() {
                      require(_isGovernor(msg.sender), "ONLY_GOVERNANCE");
                      _;
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "MainStorage.sol";
              import "IFactRegistry.sol";
              import "Common.sol";
              contract VerifyFactChain is MainStorage {
                  function verifyFact(
                      StarkExTypes.ApprovalChainData storage chain,
                      bytes32 fact,
                      string memory noVerifiersErrorMessage,
                      string memory invalidFactErrorMessage
                  ) internal view {
                      address[] storage list = chain.list;
                      uint256 n_entries = list.length;
                      require(n_entries > 0, noVerifiersErrorMessage);
                      for (uint256 i = 0; i < n_entries; i++) {
                          // NOLINTNEXTLINE: calls-loop.
                          require(IFactRegistry(list[i]).isValid(fact), invalidFactErrorMessage);
                      }
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "LibConstants.sol";
              import "MFreezable.sol";
              import "MGovernance.sol";
              import "MainStorage.sol";
              /*
                Implements MFreezable.
              */
              abstract contract Freezable is MainStorage, LibConstants, MGovernance, MFreezable {
                  event LogFrozen();
                  event LogUnFrozen();
                  function isFrozen() public view override returns (bool) {
                      return stateFrozen;
                  }
                  function validateFreezeRequest(uint256 requestTime) internal override {
                      require(requestTime != 0, "FORCED_ACTION_UNREQUESTED");
                      // Verify timer on escape request.
                      uint256 freezeTime = requestTime + FREEZE_GRACE_PERIOD;
                      // Prevent wraparound.
                      assert(freezeTime >= FREEZE_GRACE_PERIOD);
                      require(block.timestamp >= freezeTime, "FORCED_ACTION_PENDING"); // NOLINT: timestamp.
                      // Forced action requests placed before freeze, are no longer valid after the un-freeze.
                      require(freezeTime > unFreezeTime, "REFREEZE_ATTEMPT");
                  }
                  function freeze() internal override notFrozen {
                      unFreezeTime = block.timestamp + UNFREEZE_DELAY;
                      // Update state.
                      stateFrozen = true;
                      // Log event.
                      emit LogFrozen();
                  }
                  function unFreeze() external onlyFrozen onlyGovernance {
                      require(block.timestamp >= unFreezeTime, "UNFREEZE_NOT_ALLOWED_YET");
                      // Update state.
                      stateFrozen = false;
                      // Increment roots to invalidate them, w/o losing information.
                      validiumVaultRoot += 1;
                      rollupVaultRoot += 1;
                      orderRoot += 1;
                      // Log event.
                      emit LogUnFrozen();
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "GovernanceStorage.sol";
              /*
                Holds the Proxy-specific state variables.
                This contract is inherited by the GovernanceStorage (and indirectly by MainStorage)
                to prevent collision hazard.
              */
              contract ProxyStorage is GovernanceStorage {
                  // NOLINTNEXTLINE: naming-convention uninitialized-state.
                  mapping(address => bytes32) internal initializationHash_DEPRECATED;
                  // The time after which we can switch to the implementation.
                  // Hash(implementation, data, finalize) => time.
                  mapping(bytes32 => uint256) internal enabledTime;
                  // A central storage of the flags whether implementation has been initialized.
                  // Note - it can be used flexibly enough to accommodate multiple levels of initialization
                  // (i.e. using different key salting schemes for different initialization levels).
                  mapping(bytes32 => bool) internal initialized;
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "MOperator.sol";
              import "MGovernance.sol";
              /**
                The Operator of the contract is the entity entitled to submit state update requests
                by calling :sol:func:`updateState`.
                An Operator may be instantly appointed or removed by the contract Governor
                (see :sol:mod:`Governance`). Typically, the Operator is the hot wallet of the service
                submitting proofs for state updates.
              */
              abstract contract Operator is MGovernance, MOperator {
                  function registerOperator(address newOperator) external override onlyGovernance {
                      getOperators()[newOperator] = true;
                      emit LogOperatorAdded(newOperator);
                  }
                  function unregisterOperator(address removedOperator) external override onlyGovernance {
                      getOperators()[removedOperator] = false;
                      emit LogOperatorRemoved(removedOperator);
                  }
                  function isOperator(address testedOperator) public view override returns (bool) {
                      return getOperators()[testedOperator];
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "StarkExStorage.sol";
              import "MStarkExForcedActionState.sol";
              import "PublicInputOffsets.sol";
              import "StarkExConstants.sol";
              import "MessageRegistry.sol";
              import "OnchainDataFactTreeEncoder.sol";
              import "VerifyFactChain.sol";
              import "MAcceptModifications.sol";
              import "MFreezable.sol";
              import "MOperator.sol";
              import "Common.sol";
              /**
                The StarkEx contract tracks the state of the off-chain exchange service by storing Merkle roots
                of the vault state (off-chain account state) and the order state (including fully executed and
                partially fulfilled orders).
                The :sol:mod:`Operator` is the only entity entitled to submit state updates for a batch of
                exchange transactions by calling :sol:func:`updateState` and this is only allowed if the contract
                is not in the `frozen` state (see :sol:mod:`FullWithdrawals`). The call includes the `publicInput`
                of a STARK proof, and additional data (`applicationData`) that includes information not attested
                to by the proof.
                The `publicInput` includes the current (initial) and next (final) Merkle roots as mentioned above,
                the heights of the Merkle trees, a list of vault operations and a list of conditional transfers.
                A vault operation can be a ramping operation (deposit/withdrawal) or an indication to clear
                a full withdrawal request. Each vault operation is encoded in 3 words as follows:
                | 1. Word 0: Stark Key of the vault owner (or the requestor Stark Key for false full
                |    withdrawal).
                | 2. Word 1: Asset ID of the vault representing either the currency (for fungible tokens) or
                |    a unique token ID and its on-chain contract association (for non-fungible tokens).
                | 3. Word 2:
                |    a. ID of the vault (off-chain account)
                |    b. Vault balance change in biased representation (excess-2**63).
                |       A negative balance change implies a withdrawal while a positive amount implies a deposit.
                |       A zero balance change may be used for operations implying neither
                |       (e.g. a false full withdrawal request).
                |    c. A bit indicating whether the operation requires clearing a full withdrawal request.
                The above information is used by the exchange contract in order to update the pending accounts
                used for deposits (see :sol:mod:`Deposits`) and withdrawals (see :sol:mod:`Withdrawals`).
                The next section in the publicInput is a list of encoded conditions corresponding to the
                conditional transfers in the batch. A condition is encoded as a hash of the conditional transfer
                `applicationData`, described below, masked to 250 bits.
                The `applicationData` holds the following information:
                | 1. The ID of the current batch for which the operator is submitting the update.
                | 2. The expected ID of the last batch accepted on chain. This allows the operator submitting
                |    state updates to ensure the same batch order is accepted on-chain as was intended by the
                |    operator in the event that more than one valid update may have been generated based on
                |    different previous batches - an unlikely but possible event.
                | 3. For each conditional transfer in the batch two words are provided:
                |    a. Word 0: The address of a fact registry contract
                |    b. Word 1: A fact to be verified on the above contract attesting that the
                |       condition has been met on-chain.
                The following section in the publicInput is a list of orders to be verified onchain, corresponding
                to the onchain orders in the batch. An onchain order is of a variable length (at least 3 words)
                and is structured as follows:
                | 1. The Eth address of the user who submitted the order.
                | 2. The size (number of words) of the order blob that follows. Denoted 'n' below.
                | 3. First word of the order blob.
                | ...
                | n + 2. Last word of the order blob.
                The STARK proof attesting to the validity of the state update is submitted separately by the
                exchange service to (one or more) STARK integrity verifier contract(s).
                Likewise, the signatures of committee members attesting to
                the availability of the vault and order data is submitted separately by the exchange service to
                (one or more) availability verifier contract(s) (see :sol:mod:`Committee`).
                The state update is only accepted by the exchange contract if the integrity verifier and
                availability verifier contracts have indeed received such proof of soundness and data
                availability.
              */
              abstract contract UpdateState is
                  StarkExStorage,
                  StarkExConstants,
                  MStarkExForcedActionState,
                  VerifyFactChain,
                  MAcceptModifications,
                  MFreezable,
                  MOperator,
                  PublicInputOffsets
              {
                  event LogRootUpdate(
                      uint256 sequenceNumber,
                      uint256 batchId,
                      uint256 validiumVaultRoot,
                      uint256 rollupVaultRoot,
                      uint256 orderRoot
                  );
                  event LogStateTransitionFact(bytes32 stateTransitionFact);
                  event LogVaultBalanceChangeApplied(
                      address ethKey,
                      uint256 assetId,
                      uint256 vaultId,
                      int256 quantizedAmountChange
                  );
                  function updateState(uint256[] calldata publicInput, uint256[] calldata applicationData)
                      external
                      virtual
                      notFrozen
                      onlyOperator
                  {
                      require(
                          publicInput.length >= PUB_IN_TRANSACTIONS_DATA_OFFSET,
                          "publicInput does not contain all required fields."
                      );
                      require(
                          publicInput[PUB_IN_GLOBAL_CONFIG_CODE_OFFSET] == globalConfigCode,
                          "Global config code mismatch."
                      );
                      require(
                          publicInput[PUB_IN_FINAL_VALIDIUM_VAULT_ROOT_OFFSET] < K_MODULUS,
                          "New validium vault root >= PRIME."
                      );
                      require(
                          publicInput[PUB_IN_FINAL_ROLLUP_VAULT_ROOT_OFFSET] < K_MODULUS,
                          "New rollup vault root >= PRIME."
                      );
                      require(
                          publicInput[PUB_IN_FINAL_ORDER_ROOT_OFFSET] < K_MODULUS,
                          "New order root >= PRIME."
                      );
                      require(
                          lastBatchId == 0 || applicationData[APP_DATA_PREVIOUS_BATCH_ID_OFFSET] == lastBatchId,
                          "WRONG_PREVIOUS_BATCH_ID"
                      );
                      // Ensure global timestamp has not expired.
                      require(
                          publicInput[PUB_IN_GLOBAL_EXPIRATION_TIMESTAMP_OFFSET] <
                              2**STARKEX_EXPIRATION_TIMESTAMP_BITS,
                          "Global expiration timestamp is out of range."
                      );
                      require( // NOLINT: block-timestamp.
                          publicInput[PUB_IN_GLOBAL_EXPIRATION_TIMESTAMP_OFFSET] > block.timestamp / 3600,
                          "Timestamp of the current block passed the threshold for the transaction batch."
                      );
                      bytes32 stateTransitionFact = getStateTransitionFact(publicInput);
                      emit LogStateTransitionFact(stateTransitionFact);
                      verifyFact(
                          verifiersChain,
                          stateTransitionFact,
                          "NO_STATE_TRANSITION_VERIFIERS",
                          "NO_STATE_TRANSITION_PROOF"
                      );
                      bytes32 availabilityFact = keccak256(
                          abi.encodePacked(
                              publicInput[PUB_IN_FINAL_VALIDIUM_VAULT_ROOT_OFFSET],
                              publicInput[PUB_IN_VALIDIUM_VAULT_TREE_HEIGHT_OFFSET],
                              publicInput[PUB_IN_FINAL_ORDER_ROOT_OFFSET],
                              publicInput[PUB_IN_ORDER_TREE_HEIGHT_OFFSET],
                              sequenceNumber + 1
                          )
                      );
                      verifyFact(
                          availabilityVerifiersChain,
                          availabilityFact,
                          "NO_AVAILABILITY_VERIFIERS",
                          "NO_AVAILABILITY_PROOF"
                      );
                      performUpdateState(publicInput, applicationData);
                  }
                  function getStateTransitionFact(uint256[] calldata publicInput)
                      internal
                      pure
                      returns (bytes32)
                  {
                      // Use a simple fact tree.
                      require(
                          publicInput.length >=
                              PUB_IN_TRANSACTIONS_DATA_OFFSET +
                                  OnchainDataFactTreeEncoder.ONCHAIN_DATA_FACT_ADDITIONAL_WORDS,
                          "programOutput does not contain all required fields."
                      );
                      return
                          OnchainDataFactTreeEncoder.encodeFactWithOnchainData(
                              publicInput[:publicInput.length -
                                  OnchainDataFactTreeEncoder.ONCHAIN_DATA_FACT_ADDITIONAL_WORDS],
                              OnchainDataFactTreeEncoder.DataAvailabilityFact({
                                  onchainDataHash: publicInput[publicInput.length - 2],
                                  onchainDataSize: publicInput[publicInput.length - 1]
                              })
                          );
                  }
                  function performUpdateState(uint256[] calldata publicInput, uint256[] calldata applicationData)
                      internal
                  {
                      rootUpdate(
                          publicInput[PUB_IN_INITIAL_VALIDIUM_VAULT_ROOT_OFFSET],
                          publicInput[PUB_IN_FINAL_VALIDIUM_VAULT_ROOT_OFFSET],
                          publicInput[PUB_IN_INITIAL_ROLLUP_VAULT_ROOT_OFFSET],
                          publicInput[PUB_IN_FINAL_ROLLUP_VAULT_ROOT_OFFSET],
                          publicInput[PUB_IN_INITIAL_ORDER_ROOT_OFFSET],
                          publicInput[PUB_IN_FINAL_ORDER_ROOT_OFFSET],
                          publicInput[PUB_IN_VALIDIUM_VAULT_TREE_HEIGHT_OFFSET],
                          publicInput[PUB_IN_ROLLUP_VAULT_TREE_HEIGHT_OFFSET],
                          publicInput[PUB_IN_ORDER_TREE_HEIGHT_OFFSET],
                          applicationData[APP_DATA_BATCH_ID_OFFSET]
                      );
                      performOnchainOperations(publicInput, applicationData);
                  }
                  function rootUpdate(
                      uint256 oldValidiumVaultRoot,
                      uint256 newValidiumVaultRoot,
                      uint256 oldRollupVaultRoot,
                      uint256 newRollupVaultRoot,
                      uint256 oldOrderRoot,
                      uint256 newOrderRoot,
                      uint256 validiumTreeHeightSent,
                      uint256 rollupTreeHeightSent,
                      uint256 orderTreeHeightSent,
                      uint256 batchId
                  ) internal virtual {
                      // Assert that the old state is correct.
                      require(oldValidiumVaultRoot == validiumVaultRoot, "VALIDIUM_VAULT_ROOT_INCORRECT");
                      require(oldRollupVaultRoot == rollupVaultRoot, "ROLLUP_VAULT_ROOT_INCORRECT");
                      require(oldOrderRoot == orderRoot, "ORDER_ROOT_INCORRECT");
                      // Assert that heights are correct.
                      require(validiumTreeHeight == validiumTreeHeightSent, "VALIDIUM_TREE_HEIGHT_INCORRECT");
                      require(rollupTreeHeight == rollupTreeHeightSent, "ROLLUP_TREE_HEIGHT_INCORRECT");
                      require(orderTreeHeight == orderTreeHeightSent, "ORDER_TREE_HEIGHT_INCORRECT");
                      // Update state.
                      validiumVaultRoot = newValidiumVaultRoot;
                      rollupVaultRoot = newRollupVaultRoot;
                      orderRoot = newOrderRoot;
                      sequenceNumber = sequenceNumber + 1;
                      lastBatchId = batchId;
                      // Log update.
                      emit LogRootUpdate(sequenceNumber, batchId, validiumVaultRoot, rollupVaultRoot, orderRoot);
                  }
                  function performOnchainOperations(
                      uint256[] calldata publicInput,
                      uint256[] calldata applicationData
                  ) private {
                      uint256 nModifications = publicInput[PUB_IN_N_MODIFICATIONS_OFFSET];
                      uint256 nCondTransfers = publicInput[PUB_IN_N_CONDITIONAL_TRANSFERS_OFFSET];
                      uint256 nOnchainVaultUpdates = publicInput[PUB_IN_N_ONCHAIN_VAULT_UPDATES_OFFSET];
                      uint256 nOnchainOrders = publicInput[PUB_IN_N_ONCHAIN_ORDERS_OFFSET];
                      // Sanity value that also protects from theoretical overflow in multiplication.
                      require(nModifications < 2**64, "Invalid number of modifications.");
                      require(nCondTransfers < 2**64, "Invalid number of conditional transfers.");
                      require(nOnchainVaultUpdates < 2**64, "Invalid number of onchain vault updates.");
                      require(nOnchainOrders < 2**64, "Invalid number of onchain orders.");
                      require(
                          publicInput.length >=
                              PUB_IN_TRANSACTIONS_DATA_OFFSET +
                                  PUB_IN_N_WORDS_PER_MODIFICATION *
                                  nModifications +
                                  PUB_IN_N_WORDS_PER_CONDITIONAL_TRANSFER *
                                  nCondTransfers +
                                  PUB_IN_N_WORDS_PER_ONCHAIN_VAULT_UPDATE *
                                  nOnchainVaultUpdates +
                                  PUB_IN_N_MIN_WORDS_PER_ONCHAIN_ORDER *
                                  nOnchainOrders +
                                  OnchainDataFactTreeEncoder.ONCHAIN_DATA_FACT_ADDITIONAL_WORDS,
                          "publicInput size is inconsistent with expected transactions."
                      );
                      require(
                          applicationData.length ==
                              APP_DATA_TRANSACTIONS_DATA_OFFSET +
                                  APP_DATA_N_WORDS_PER_CONDITIONAL_TRANSFER *
                                  nCondTransfers,
                          "applicationData size is inconsistent with expected transactions."
                      );
                      uint256 offsetPubInput = PUB_IN_TRANSACTIONS_DATA_OFFSET;
                      uint256 offsetAppData = APP_DATA_TRANSACTIONS_DATA_OFFSET;
                      // When reaching this line, offsetPubInput is initialized to the beginning of modifications
                      // data in publicInput. Following this line's execution, offsetPubInput is incremented by
                      // the number of words consumed by sendModifications.
                      offsetPubInput += sendModifications(publicInput[offsetPubInput:], nModifications);
                      // When reaching this line, offsetPubInput and offsetAppData are pointing to the beginning
                      // of conditional transfers data in publicInput and applicationData.
                      // Following the execution of this block, offsetPubInput and offsetAppData are incremented
                      // by the number of words consumed by verifyConditionalTransfers.
                      {
                          uint256 consumedPubInputWords;
                          uint256 consumedAppDataWords;
                          (consumedPubInputWords, consumedAppDataWords) = verifyConditionalTransfers(
                              publicInput[offsetPubInput:],
                              applicationData[offsetAppData:],
                              nCondTransfers
                          );
                          offsetPubInput += consumedPubInputWords;
                          offsetAppData += consumedAppDataWords;
                      }
                      // offsetPubInput is incremented by the number of words consumed by updateOnchainVaults.
                      // NOLINTNEXTLINE: reentrancy-benign.
                      offsetPubInput += updateOnchainVaults(publicInput[offsetPubInput:], nOnchainVaultUpdates);
                      // offsetPubInput is incremented by the number of words consumed by verifyOnchainOrders.
                      offsetPubInput += verifyOnchainOrders(publicInput[offsetPubInput:], nOnchainOrders);
                      // The Onchain Data info appears at the end of publicInput.
                      offsetPubInput += OnchainDataFactTreeEncoder.ONCHAIN_DATA_FACT_ADDITIONAL_WORDS;
                      require(offsetPubInput == publicInput.length, "Incorrect Size");
                  }
                  /*
                    Deposits and withdrawals. Moves funds off and on chain.
                      slidingPublicInput - a pointer to the beginning of modifications data in publicInput.
                      nModifications - the number of modifications.
                    Returns the number of publicInput words consumed by this function.
                  */
                  function sendModifications(uint256[] calldata slidingPublicInput, uint256 nModifications)
                      private
                      returns (uint256 consumedPubInputItems)
                  {
                      uint256 offsetPubInput = 0;
                      for (uint256 i = 0; i < nModifications; i++) {
                          uint256 ownerKey = slidingPublicInput[offsetPubInput];
                          uint256 assetId = slidingPublicInput[offsetPubInput + 1];
                          require(ownerKey < K_MODULUS, "Stark key >= PRIME");
                          require(assetId < K_MODULUS, "Asset id >= PRIME");
                          uint256 actionParams = slidingPublicInput[offsetPubInput + 2];
                          require((actionParams >> 129) == 0, "Unsupported modification action field.");
                          // Extract and unbias the balanceDiff.
                          int256 balanceDiff = int256((actionParams & ((1 << 64) - 1)) - (1 << 63));
                          uint256 vaultId = (actionParams >> 64) & ((1 << 64) - 1);
                          if (balanceDiff > 0) {
                              // This is a deposit.
                              acceptDeposit(ownerKey, vaultId, assetId, uint256(balanceDiff));
                          } else if (balanceDiff < 0) {
                              // This is a withdrawal.
                              acceptWithdrawal(ownerKey, assetId, uint256(-balanceDiff));
                          }
                          if ((actionParams & (1 << 128)) != 0) {
                              clearFullWithdrawalRequest(ownerKey, vaultId);
                          }
                          offsetPubInput += PUB_IN_N_WORDS_PER_MODIFICATION;
                      }
                      return offsetPubInput;
                  }
                  /*
                    Verifies that each conditional transfer's condition was met.
                      slidingPublicInput - a pointer to the beginning of condTransfers data in publicInput.
                      slidingAppData - a pointer to the beginning of condTransfers data in applicationData.
                      nCondTransfers - the number of conditional transfers.
                    Returns the number of publicInput and applicationData words consumed by this function.
                  */
                  function verifyConditionalTransfers(
                      uint256[] calldata slidingPublicInput,
                      uint256[] calldata slidingAppData,
                      uint256 nCondTransfers
                  ) private view returns (uint256 consumedPubInputItems, uint256 consumedAppDataItems) {
                      uint256 offsetPubInput = 0;
                      uint256 offsetAppData = 0;
                      for (uint256 i = 0; i < nCondTransfers; i++) {
                          address factRegistryAddress = address(slidingAppData[offsetAppData]);
                          bytes32 condTransferFact = bytes32(slidingAppData[offsetAppData + 1]);
                          uint256 condition = slidingPublicInput[offsetPubInput];
                          // The condition is the 250 LS bits of keccak256 of the fact registry & fact.
                          require(
                              condition ==
                                  uint256(keccak256(abi.encodePacked(factRegistryAddress, condTransferFact))) &
                                      MASK_250,
                              "Condition mismatch."
                          );
                          // NOLINTNEXTLINE: low-level-calls-loop.
                          (bool success, bytes memory returndata) = factRegistryAddress.staticcall(
                              abi.encodeWithSignature("isValid(bytes32)", condTransferFact)
                          );
                          require(success && returndata.length == 32, "BAD_FACT_REGISTRY_CONTRACT");
                          require(
                              abi.decode(returndata, (bool)),
                              "Condition for the conditional transfer was not met."
                          );
                          offsetPubInput += PUB_IN_N_WORDS_PER_CONDITIONAL_TRANSFER;
                          offsetAppData += APP_DATA_N_WORDS_PER_CONDITIONAL_TRANSFER;
                      }
                      return (offsetPubInput, offsetAppData);
                  }
                  /*
                    Moves funds into and out of onchain vaults.
                      slidingPublicInput - a pointer to the beginning of onchain vaults update data in publicInput.
                      nOnchainVaultUpdates - the number of onchain vaults updates.
                    Returns the number of publicInput words consumed by this function.
                  */
                  function updateOnchainVaults(
                      uint256[] calldata slidingPublicInput,
                      uint256 nOnchainVaultUpdates
                  ) private returns (uint256 consumedPubInputItems) {
                      uint256 offsetPubInput = 0;
                      for (uint256 i = 0; i < nOnchainVaultUpdates; i++) {
                          address ethAddress = address(slidingPublicInput[offsetPubInput]);
                          uint256 assetId = slidingPublicInput[offsetPubInput + 1];
                          require(assetId < K_MODULUS, "assetId >= PRIME");
                          uint256 additionalParams = slidingPublicInput[offsetPubInput + 2];
                          require((additionalParams >> 160) == 0, "Unsupported vault update field.");
                          // Extract and unbias the balanceDiff.
                          int256 balanceDiff = int256((additionalParams & ((1 << 64) - 1)) - (1 << 63));
                          int256 minBalance = int256((additionalParams >> 64) & ((1 << 64) - 1));
                          uint256 vaultId = (additionalParams >> 128) & ((1 << 31) - 1);
                          int256 balanceBefore = int256(vaultsBalances[ethAddress][assetId][vaultId]);
                          int256 newBalance = balanceBefore + balanceDiff;
                          if (balanceDiff > 0) {
                              require(newBalance > balanceBefore, "VAULT_OVERFLOW");
                          } else {
                              require(balanceBefore >= balanceDiff, "INSUFFICIENT_VAULT_BALANCE");
                          }
                          if (strictVaultBalancePolicy) {
                              require(minBalance >= 0, "ILLEGAL_BALANCE_REQUIREMENT");
                              require(balanceBefore >= minBalance, "UNMET_BALANCE_REQUIREMENT");
                          }
                          require(newBalance >= 0, "NEGATIVE_BALANCE");
                          vaultsBalances[ethAddress][assetId][vaultId] = uint256(newBalance);
                          // NOLINTNEXTLINE: reentrancy-events.
                          emit LogVaultBalanceChangeApplied(ethAddress, assetId, vaultId, balanceDiff);
                          offsetPubInput += PUB_IN_N_WORDS_PER_ONCHAIN_VAULT_UPDATE;
                      }
                      return offsetPubInput;
                  }
                  /*
                    Verifies that each order was registered by its sender.
                      slidingPublicInput - a pointer to the beginning of onchain orders data in publicInput.
                      nOnchainOrders - the number of onchain orders.
                    Returns the number of publicInput words consumed by this function.
                  */
                  function verifyOnchainOrders(uint256[] calldata slidingPublicInput, uint256 nOnchainOrders)
                      private
                      view
                      returns (uint256 consumedPubInputItems)
                  {
                      MessageRegistry orderRegistry = MessageRegistry(orderRegistryAddress);
                      uint256 offsetPubInput = 0;
                      for (uint256 i = 0; i < nOnchainOrders; i++) {
                          // Make sure we remain within slidingPublicInput's bounds.
                          require(offsetPubInput + 2 <= slidingPublicInput.length, "Input out of bounds.");
                          // First word is the order sender.
                          address orderSender = address(slidingPublicInput[offsetPubInput]);
                          // Second word is the order blob size (number of blob words) that follow.
                          uint256 blobSize = uint256(slidingPublicInput[offsetPubInput + 1]);
                          require(offsetPubInput + blobSize + 2 >= offsetPubInput, "Blob size overflow.");
                          offsetPubInput += 2;
                          require(offsetPubInput + blobSize <= slidingPublicInput.length, "Input out of bounds.");
                          // Calculate the hash of the order blob.
                          bytes32 orderHash = keccak256(
                              abi.encodePacked(slidingPublicInput[offsetPubInput:offsetPubInput + blobSize])
                          );
                          // Verify this order has been registered.
                          require(
                              orderRegistry.isMessageRegistered(orderSender, address(this), orderHash),
                              "Order not registered."
                          );
                          offsetPubInput += blobSize;
                      }
                      return offsetPubInput;
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              library OnchainDataFactTreeEncoder {
                  struct DataAvailabilityFact {
                      uint256 onchainDataHash;
                      uint256 onchainDataSize;
                  }
                  // The number of additional words appended to the public input when using the
                  // OnchainDataFactTreeEncoder format.
                  uint256 internal constant ONCHAIN_DATA_FACT_ADDITIONAL_WORDS = 2;
                  /*
                    Encodes a GPS fact Merkle tree where the root has two children.
                    The left child contains the data we care about and the right child contains
                    on-chain data for the fact.
                  */
                  function encodeFactWithOnchainData(
                      uint256[] calldata programOutput,
                      DataAvailabilityFact memory factData
                  ) internal pure returns (bytes32) {
                      // The state transition fact is computed as a Merkle tree, as defined in
                      // GpsOutputParser.
                      //
                      // In our case the fact tree looks as follows:
                      //   The root has two children.
                      //   The left child is a leaf that includes the main part - the information regarding
                      //   the state transition required by this contract.
                      //   The right child contains the onchain-data which shouldn't be accessed by this
                      //   contract, so we are only given its hash and length
                      //   (it may be a leaf or an inner node, this has no effect on this contract).
                      // Compute the hash without the two additional fields.
                      uint256 mainPublicInputLen = programOutput.length;
                      bytes32 mainPublicInputHash = keccak256(abi.encodePacked(programOutput));
                      // Compute the hash of the fact Merkle tree.
                      bytes32 hashResult = keccak256(
                          abi.encodePacked(
                              mainPublicInputHash,
                              mainPublicInputLen,
                              factData.onchainDataHash,
                              mainPublicInputLen + factData.onchainDataSize
                          )
                      );
                      // Add one to the hash to indicate it represents an inner node, rather than a leaf.
                      return bytes32(uint256(hashResult) + 1);
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "Identity.sol";
              interface SubContractor is Identity {
                  function initialize(bytes calldata data) external;
                  function initializerSize() external view returns (uint256);
                  /*
                    Returns an array with selectors for validation.
                    These selectors are the critical ones for maintaining self custody and anti censorship.
                    During the upgrade process, as part of the sub-contract validation, the MainDispatcher
                    validates that the selectos are mapped to the correct sub-contract.
                  */
                  function validatedSelectors() external pure returns (bytes4[] memory);
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "IQueryableFactRegistry.sol";
              contract FactRegistry is IQueryableFactRegistry {
                  // Mapping: fact hash -> true.
                  mapping(bytes32 => bool) private verifiedFact;
                  // Indicates whether the Fact Registry has at least one fact registered.
                  bool anyFactRegistered;
                  /*
                    Checks if a fact has been verified.
                  */
                  function isValid(bytes32 fact) external view override returns (bool) {
                      return _factCheck(fact);
                  }
                  /*
                    This is an internal method to check if the fact is already registered.
                    In current implementation of FactRegistry it's identical to isValid().
                    But the check is against the local fact registry,
                    So for a derived referral fact registry, it's not the same.
                  */
                  function _factCheck(bytes32 fact) internal view returns (bool) {
                      return verifiedFact[fact];
                  }
                  function registerFact(bytes32 factHash) internal {
                      // This function stores the fact hash in the mapping.
                      verifiedFact[factHash] = true;
                      // Mark first time off.
                      if (!anyFactRegistered) {
                          anyFactRegistered = true;
                      }
                  }
                  /*
                    Indicates whether at least one fact was registered.
                  */
                  function hasRegisteredFact() external view override returns (bool) {
                      return anyFactRegistered;
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              abstract contract MFreezable {
                  /*
                    Returns true if the exchange is frozen.
                  */
                  function isFrozen() public view virtual returns (bool); // NOLINT: external-function.
                  /*
                    Forbids calling the function if the exchange is frozen.
                  */
                  modifier notFrozen() {
                      require(!isFrozen(), "STATE_IS_FROZEN");
                      _;
                  }
                  function validateFreezeRequest(uint256 requestTime) internal virtual;
                  /*
                    Allows calling the function only if the exchange is frozen.
                  */
                  modifier onlyFrozen() {
                      require(isFrozen(), "STATE_NOT_FROZEN");
                      _;
                  }
                  /*
                    Freezes the exchange.
                  */
                  function freeze() internal virtual;
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "Escapes.sol";
              import "StarkExForcedActionState.sol";
              import "UpdateState.sol";
              import "Freezable.sol";
              import "MainGovernance.sol";
              import "StarkExOperator.sol";
              import "AcceptModifications.sol";
              import "StateRoot.sol";
              import "TokenQuantization.sol";
              import "SubContractor.sol";
              contract StarkExState is
                  MainGovernance,
                  SubContractor,
                  StarkExOperator,
                  Freezable,
                  AcceptModifications,
                  TokenQuantization,
                  StarkExForcedActionState,
                  StateRoot,
                  Escapes,
                  UpdateState
              {
                  // InitializationArgStruct contains 2 * address + 8 * uint256 + 1 * bool = 352 bytes.
                  uint256 constant INITIALIZER_SIZE = 11 * 32;
                  struct InitializationArgStruct {
                      uint256 globalConfigCode;
                      address escapeVerifierAddress;
                      uint256 sequenceNumber;
                      uint256 validiumVaultRoot;
                      uint256 rollupVaultRoot;
                      uint256 orderRoot;
                      uint256 validiumTreeHeight;
                      uint256 rollupTreeHeight;
                      uint256 orderTreeHeight;
                      bool strictVaultBalancePolicy;
                      address orderRegistryAddress;
                  }
                  /*
                    Initialization flow:
                    1. Extract initialization parameters from data.
                    2. Call internalInitializer with those parameters.
                  */
                  function initialize(bytes calldata data) external virtual override {
                      // This initializer sets roots etc. It must not be applied twice.
                      // I.e. it can run only when the state is still empty.
                      string memory ALREADY_INITIALIZED_MSG = "STATE_ALREADY_INITIALIZED";
                      require(validiumVaultRoot == 0, ALREADY_INITIALIZED_MSG);
                      require(validiumTreeHeight == 0, ALREADY_INITIALIZED_MSG);
                      require(rollupVaultRoot == 0, ALREADY_INITIALIZED_MSG);
                      require(rollupTreeHeight == 0, ALREADY_INITIALIZED_MSG);
                      require(orderRoot == 0, ALREADY_INITIALIZED_MSG);
                      require(orderTreeHeight == 0, ALREADY_INITIALIZED_MSG);
                      require(data.length == INITIALIZER_SIZE, "INCORRECT_INIT_DATA_SIZE_352");
                      // Copies initializer values into initValues.
                      // TODO(zuphit,01/06/2021): Add a struct parsing test.
                      InitializationArgStruct memory initValues;
                      bytes memory _data = data;
                      assembly {
                          initValues := add(32, _data)
                      }
                      require(initValues.globalConfigCode < K_MODULUS, "GLOBAL_CONFIG_CODE >= PRIME");
                      require(initValues.validiumTreeHeight < ROLLUP_VAULTS_BIT, "INVALID_VALIDIUM_HEIGHT");
                      require(initValues.rollupTreeHeight < ROLLUP_VAULTS_BIT, "INVALID_ROLLUP_HEIGHT");
                      initGovernance();
                      StarkExOperator.initialize();
                      StateRoot.initialize(
                          initValues.sequenceNumber,
                          initValues.validiumVaultRoot,
                          initValues.rollupVaultRoot,
                          initValues.orderRoot,
                          initValues.validiumTreeHeight,
                          initValues.rollupTreeHeight,
                          initValues.orderTreeHeight
                      );
                      Escapes.initialize(initValues.escapeVerifierAddress);
                      globalConfigCode = initValues.globalConfigCode;
                      strictVaultBalancePolicy = initValues.strictVaultBalancePolicy;
                      orderRegistryAddress = initValues.orderRegistryAddress;
                  }
                  /*
                    The call to initializerSize is done from MainDispatcherBase using delegatecall,
                    thus the existing state is already accessible.
                  */
                  function initializerSize() external view virtual override returns (uint256) {
                      return INITIALIZER_SIZE;
                  }
                  function validatedSelectors() external pure override returns (bytes4[] memory selectors) {
                      uint256 len_ = 1;
                      uint256 index_ = 0;
                      selectors = new bytes4[](len_);
                      selectors[index_++] = Escapes.escape.selector;
                      require(index_ == len_, "INCORRECT_SELECTORS_ARRAY_LENGTH");
                  }
                  function identify() external pure override returns (string memory) {
                      return "StarkWare_StarkExState_2022_5";
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "LibConstants.sol";
              contract StarkExConstants is LibConstants {
                  uint256 constant STARKEX_EXPIRATION_TIMESTAMP_BITS = 22;
                  uint256 public constant STARKEX_MAX_DEFAULT_VAULT_LOCK = 7 days;
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              abstract contract MTokenQuantization {
                  function fromQuantized(uint256 presumedAssetType, uint256 quantizedAmount)
                      internal
                      view
                      virtual
                      returns (uint256 amount);
                  // NOLINTNEXTLINE: external-function.
                  function getQuantum(uint256 presumedAssetType) public view virtual returns (uint256 quantum);
                  function toQuantized(uint256 presumedAssetType, uint256 amount)
                      internal
                      view
                      virtual
                      returns (uint256 quantizedAmount);
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "Operator.sol";
              import "MainStorage.sol";
              /**
                Operator implementation for StarkEx (StarkExchange & StarkPerpetual).
              */
              abstract contract StarkExOperator is MainStorage, Operator {
                  function initialize() internal {
                      getOperators()[msg.sender] = true;
                      emit LogOperatorAdded(msg.sender);
                  }
                  function getOperators() internal view override returns (mapping(address => bool) storage) {
                      return operators;
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "MStateRoot.sol";
              import "MainStorage.sol";
              import "LibConstants.sol";
              contract StateRoot is MainStorage, LibConstants, MStateRoot {
                  function initialize(
                      uint256 initialSequenceNumber,
                      uint256 initialValidiumVaultRoot,
                      uint256 initialRollupVaultRoot,
                      uint256 initialOrderRoot,
                      uint256 initialValidiumTreeHeight,
                      uint256 initialRollupTreeHeight,
                      uint256 initialOrderTreeHeight
                  ) internal {
                      sequenceNumber = initialSequenceNumber;
                      validiumVaultRoot = initialValidiumVaultRoot;
                      rollupVaultRoot = initialRollupVaultRoot;
                      orderRoot = initialOrderRoot;
                      validiumTreeHeight = initialValidiumTreeHeight;
                      rollupTreeHeight = initialRollupTreeHeight;
                      orderTreeHeight = initialOrderTreeHeight;
                  }
                  function getValidiumVaultRoot() public view override returns (uint256) {
                      return validiumVaultRoot;
                  }
                  function getValidiumTreeHeight() public view override returns (uint256) {
                      return validiumTreeHeight;
                  }
                  function getRollupVaultRoot() public view override returns (uint256) {
                      return rollupVaultRoot;
                  }
                  function getRollupTreeHeight() public view override returns (uint256) {
                      return rollupTreeHeight;
                  }
                  function getOrderRoot() external view returns (uint256) {
                      return orderRoot;
                  }
                  function getOrderTreeHeight() external view returns (uint256) {
                      return orderTreeHeight;
                  }
                  function getSequenceNumber() external view returns (uint256) {
                      return sequenceNumber;
                  }
                  function getLastBatchId() external view returns (uint256) {
                      return lastBatchId;
                  }
                  function getGlobalConfigCode() external view returns (uint256) {
                      return globalConfigCode;
                  }
                  function isVaultInRange(uint256 vaultId) internal view override returns (bool) {
                      return (isValidiumVault(vaultId) || isRollupVault(vaultId));
                  }
                  function isValidiumVault(uint256 vaultId) internal view override returns (bool) {
                      // Return true iff vaultId is in the validium vaults tree.
                      return vaultId < 2**getValidiumTreeHeight();
                  }
                  function isRollupVault(uint256 vaultId) internal view override returns (bool) {
                      // Return true iff vaultId is in the rollup vaults tree.
                      uint256 rollupLowerBound = 2**ROLLUP_VAULTS_BIT;
                      uint256 rollupUpperBound = rollupLowerBound + 2**getRollupTreeHeight();
                      return (rollupLowerBound <= vaultId && vaultId < rollupUpperBound);
                  }
                  function getVaultLeafIndex(uint256 vaultId) internal pure override returns (uint256) {
                      // Return the index of vaultId leaf in its tree, which doesn't include the rollup bit flag.
                      return (vaultId & (2**ROLLUP_VAULTS_BIT - 1));
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "MGovernance.sol";
              /*
                Implements Generic Governance, applicable for both proxy and main contract, and possibly others.
                Notes:
                 The use of the same function names by both the Proxy and a delegated implementation
                 is not possible since calling the implementation functions is done via the default function
                 of the Proxy. For this reason, for example, the implementation of MainContract (MainGovernance)
                 exposes mainIsGovernor, which calls the internal _isGovernor method.
              */
              abstract contract Governance is MGovernance {
                  event LogNominatedGovernor(address nominatedGovernor);
                  event LogNewGovernorAccepted(address acceptedGovernor);
                  event LogRemovedGovernor(address removedGovernor);
                  event LogNominationCancelled();
                  function getGovernanceInfo() internal view virtual returns (GovernanceInfoStruct storage);
                  /*
                    Current code intentionally prevents governance re-initialization.
                    This may be a problem in an upgrade situation, in a case that the upgrade-to implementation
                    performs an initialization (for real) and within that calls initGovernance().
                    Possible workarounds:
                    1. Clearing the governance info altogether by changing the MAIN_GOVERNANCE_INFO_TAG.
                       This will remove existing main governance information.
                    2. Modify the require part in this function, so that it will exit quietly
                       when trying to re-initialize (uncomment the lines below).
                  */
                  function initGovernance() internal {
                      GovernanceInfoStruct storage gub = getGovernanceInfo();
                      require(!gub.initialized, "ALREADY_INITIALIZED");
                      gub.initialized = true; // to ensure addGovernor() won't fail.
                      // Add the initial governer.
                      addGovernor(msg.sender);
                  }
                  function _isGovernor(address testGovernor) internal view override returns (bool) {
                      GovernanceInfoStruct storage gub = getGovernanceInfo();
                      return gub.effectiveGovernors[testGovernor];
                  }
                  /*
                    Cancels the nomination of a governor candidate.
                  */
                  function _cancelNomination() internal onlyGovernance {
                      GovernanceInfoStruct storage gub = getGovernanceInfo();
                      gub.candidateGovernor = address(0x0);
                      emit LogNominationCancelled();
                  }
                  function _nominateNewGovernor(address newGovernor) internal onlyGovernance {
                      GovernanceInfoStruct storage gub = getGovernanceInfo();
                      require(!_isGovernor(newGovernor), "ALREADY_GOVERNOR");
                      gub.candidateGovernor = newGovernor;
                      emit LogNominatedGovernor(newGovernor);
                  }
                  /*
                    The addGovernor is called in two cases:
                    1. by _acceptGovernance when a new governor accepts its role.
                    2. by initGovernance to add the initial governor.
                    The difference is that the init path skips the nominate step
                    that would fail because of the onlyGovernance modifier.
                  */
                  function addGovernor(address newGovernor) private {
                      require(!_isGovernor(newGovernor), "ALREADY_GOVERNOR");
                      GovernanceInfoStruct storage gub = getGovernanceInfo();
                      gub.effectiveGovernors[newGovernor] = true;
                  }
                  function _acceptGovernance() internal {
                      // The new governor was proposed as a candidate by the current governor.
                      GovernanceInfoStruct storage gub = getGovernanceInfo();
                      require(msg.sender == gub.candidateGovernor, "ONLY_CANDIDATE_GOVERNOR");
                      // Update state.
                      addGovernor(gub.candidateGovernor);
                      gub.candidateGovernor = address(0x0);
                      // Send a notification about the change of governor.
                      emit LogNewGovernorAccepted(msg.sender);
                  }
                  /*
                    Remove a governor from office.
                  */
                  function _removeGovernor(address governorForRemoval) internal onlyGovernance {
                      require(msg.sender != governorForRemoval, "GOVERNOR_SELF_REMOVE");
                      GovernanceInfoStruct storage gub = getGovernanceInfo();
                      require(_isGovernor(governorForRemoval), "NOT_GOVERNOR");
                      gub.effectiveGovernors[governorForRemoval] = false;
                      emit LogRemovedGovernor(governorForRemoval);
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "MainStorage.sol";
              import "LibConstants.sol";
              /*
                Calculation action hash for the various forced actions in a generic manner.
              */
              contract ActionHash is MainStorage, LibConstants {
                  function getActionHash(string memory actionName, bytes memory packedActionParameters)
                      internal
                      pure
                      returns (bytes32 actionHash)
                  {
                      actionHash = keccak256(abi.encodePacked(actionName, packedActionParameters));
                  }
                  function setActionHash(bytes32 actionHash, bool premiumCost) internal {
                      // The rate of forced trade requests is restricted.
                      // First restriction is by capping the number of requests in a block.
                      // User can override this cap by requesting with a permium flag set,
                      // in this case, the gas cost is high (~1M) but no "technical" limit is set.
                      // However, the high gas cost creates an obvious limitation due to the block gas limit.
                      if (premiumCost) {
                          for (uint256 i = 0; i < 21129; i++) {}
                      } else {
                          require(
                              forcedRequestsInBlock[block.number] < MAX_FORCED_ACTIONS_REQS_PER_BLOCK,
                              "MAX_REQUESTS_PER_BLOCK_REACHED"
                          );
                          forcedRequestsInBlock[block.number] += 1;
                      }
                      forcedActionRequests[actionHash] = block.timestamp;
                      actionHashList.push(actionHash);
                  }
                  function getActionCount() external view returns (uint256) {
                      return actionHashList.length;
                  }
                  function getActionHashByIndex(uint256 actionIndex) external view returns (bytes32) {
                      require(actionIndex < actionHashList.length, "ACTION_INDEX_TOO_HIGH");
                      return actionHashList[actionIndex];
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "IFactRegistry.sol";
              /*
                Extends the IFactRegistry interface with a query method that indicates
                whether the fact registry has successfully registered any fact or is still empty of such facts.
              */
              interface IQueryableFactRegistry is IFactRegistry {
                  /*
                    Returns true if at least one fact has been registered.
                  */
                  function hasRegisteredFact() external view returns (bool);
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "LibConstants.sol";
              import "MAcceptModifications.sol";
              import "MTokenQuantization.sol";
              import "MainStorage.sol";
              /*
                Interface containing actions a verifier can invoke on the state.
                The contract containing the state should implement these and verify correctness.
              */
              abstract contract AcceptModifications is
                  MainStorage,
                  LibConstants,
                  MAcceptModifications,
                  MTokenQuantization
              {
                  event LogWithdrawalAllowed(
                      uint256 ownerKey,
                      uint256 assetType,
                      uint256 nonQuantizedAmount,
                      uint256 quantizedAmount
                  );
                  event LogNftWithdrawalAllowed(uint256 ownerKey, uint256 assetId);
                  event LogAssetWithdrawalAllowed(uint256 ownerKey, uint256 assetId, uint256 quantizedAmount);
                  event LogMintableWithdrawalAllowed(uint256 ownerKey, uint256 assetId, uint256 quantizedAmount);
                  /*
                    Transfers funds from the on-chain deposit area to the off-chain area.
                    Implemented in the Deposits contracts.
                  */
                  function acceptDeposit(
                      uint256 ownerKey,
                      uint256 vaultId,
                      uint256 assetId,
                      uint256 quantizedAmount
                  ) internal virtual override {
                      // Fetch deposit.
                      require(
                          pendingDeposits[ownerKey][assetId][vaultId] >= quantizedAmount,
                          "DEPOSIT_INSUFFICIENT"
                      );
                      // Subtract accepted quantized amount.
                      pendingDeposits[ownerKey][assetId][vaultId] -= quantizedAmount;
                  }
                  /*
                    Transfers funds from the off-chain area to the on-chain withdrawal area.
                  */
                  function allowWithdrawal(
                      uint256 ownerKey,
                      uint256 assetId,
                      uint256 quantizedAmount
                  ) internal override {
                      // Fetch withdrawal.
                      uint256 withdrawal = pendingWithdrawals[ownerKey][assetId];
                      // Add accepted quantized amount.
                      withdrawal += quantizedAmount;
                      require(withdrawal >= quantizedAmount, "WITHDRAWAL_OVERFLOW");
                      // Store withdrawal.
                      pendingWithdrawals[ownerKey][assetId] = withdrawal;
                      // Log event.
                      uint256 presumedAssetType = assetId;
                      if (registeredAssetType[presumedAssetType]) {
                          emit LogWithdrawalAllowed(
                              ownerKey,
                              presumedAssetType,
                              fromQuantized(presumedAssetType, quantizedAmount),
                              quantizedAmount
                          );
                      } else if (assetId == ((assetId & MASK_240) | MINTABLE_ASSET_ID_FLAG)) {
                          emit LogMintableWithdrawalAllowed(ownerKey, assetId, quantizedAmount);
                      } else {
                          // Default case is Non-Mintable ERC721 or ERC1155 asset id.
                          // In ERC721 and ERC1155 cases, assetId is not the assetType.
                          require(assetId == assetId & MASK_250, "INVALID_ASSET_ID");
                          // If withdrawal amount is 1, the asset could be either NFT or SFT. In that case, both
                          // NFT and general events will be emitted so that the listened for event is captured.
                          // When withdrawal is greater than 1, it must be SFT and only one event will be emitted.
                          if (withdrawal <= 1) {
                              emit LogNftWithdrawalAllowed(ownerKey, assetId);
                          }
                          emit LogAssetWithdrawalAllowed(ownerKey, assetId, quantizedAmount);
                      }
                  }
                  // Verifier authorizes withdrawal.
                  function acceptWithdrawal(
                      uint256 ownerKey,
                      uint256 assetId,
                      uint256 quantizedAmount
                  ) internal virtual override {
                      allowWithdrawal(ownerKey, assetId, quantizedAmount);
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              contract LibConstants {
                  // Durations for time locked mechanisms (in seconds).
                  // Note that it is known that miners can manipulate block timestamps
                  // up to a deviation of a few seconds.
                  // This mechanism should not be used for fine grained timing.
                  // The time required to cancel a deposit, in the case the operator does not move the funds
                  // to the off-chain storage.
                  uint256 public constant DEPOSIT_CANCEL_DELAY = 2 days;
                  // The time required to freeze the exchange, in the case the operator does not execute a
                  // requested full withdrawal.
                  uint256 public constant FREEZE_GRACE_PERIOD = 7 days;
                  // The time after which the exchange may be unfrozen after it froze. This should be enough time
                  // for users to perform escape hatches to get back their funds.
                  uint256 public constant UNFREEZE_DELAY = 365 days;
                  // Maximal number of verifiers which may co-exist.
                  uint256 public constant MAX_VERIFIER_COUNT = uint256(64);
                  // The time required to remove a verifier in case of a verifier upgrade.
                  uint256 public constant VERIFIER_REMOVAL_DELAY = FREEZE_GRACE_PERIOD + (21 days);
                  address constant ZERO_ADDRESS = address(0x0);
                  uint256 constant K_MODULUS = 0x800000000000011000000000000000000000000000000000000000000000001;
                  uint256 constant K_BETA = 0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89;
                  uint256 internal constant MASK_250 =
                      0x03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
                  uint256 internal constant MASK_240 =
                      0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
                  uint256 public constant MAX_FORCED_ACTIONS_REQS_PER_BLOCK = 10;
                  uint256 constant QUANTUM_UPPER_BOUND = 2**128;
                  uint256 internal constant MINTABLE_ASSET_ID_FLAG = 1 << 250;
                  // The 64th bit (indexed 63, counting from 0) is a flag indicating a rollup vault id.
                  uint256 constant ROLLUP_VAULTS_BIT = 63;
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              contract PublicInputOffsets {
                  // The following constants are offsets of data expected in the public input.
                  uint256 internal constant PUB_IN_GLOBAL_CONFIG_CODE_OFFSET = 0;
                  uint256 internal constant PUB_IN_INITIAL_VALIDIUM_VAULT_ROOT_OFFSET = 1;
                  uint256 internal constant PUB_IN_FINAL_VALIDIUM_VAULT_ROOT_OFFSET = 2;
                  uint256 internal constant PUB_IN_INITIAL_ROLLUP_VAULT_ROOT_OFFSET = 3;
                  uint256 internal constant PUB_IN_FINAL_ROLLUP_VAULT_ROOT_OFFSET = 4;
                  uint256 internal constant PUB_IN_INITIAL_ORDER_ROOT_OFFSET = 5;
                  uint256 internal constant PUB_IN_FINAL_ORDER_ROOT_OFFSET = 6;
                  uint256 internal constant PUB_IN_GLOBAL_EXPIRATION_TIMESTAMP_OFFSET = 7;
                  uint256 internal constant PUB_IN_VALIDIUM_VAULT_TREE_HEIGHT_OFFSET = 8;
                  uint256 internal constant PUB_IN_ROLLUP_VAULT_TREE_HEIGHT_OFFSET = 9;
                  uint256 internal constant PUB_IN_ORDER_TREE_HEIGHT_OFFSET = 10;
                  uint256 internal constant PUB_IN_N_MODIFICATIONS_OFFSET = 11;
                  uint256 internal constant PUB_IN_N_CONDITIONAL_TRANSFERS_OFFSET = 12;
                  uint256 internal constant PUB_IN_N_ONCHAIN_VAULT_UPDATES_OFFSET = 13;
                  uint256 internal constant PUB_IN_N_ONCHAIN_ORDERS_OFFSET = 14;
                  uint256 internal constant PUB_IN_TRANSACTIONS_DATA_OFFSET = 15;
                  uint256 internal constant PUB_IN_N_WORDS_PER_MODIFICATION = 3;
                  uint256 internal constant PUB_IN_N_WORDS_PER_CONDITIONAL_TRANSFER = 1;
                  uint256 internal constant PUB_IN_N_WORDS_PER_ONCHAIN_VAULT_UPDATE = 3;
                  uint256 internal constant PUB_IN_N_MIN_WORDS_PER_ONCHAIN_ORDER = 3;
                  // The following constants are offsets of data expected in the application data.
                  uint256 internal constant APP_DATA_BATCH_ID_OFFSET = 0;
                  uint256 internal constant APP_DATA_PREVIOUS_BATCH_ID_OFFSET = 1;
                  uint256 internal constant APP_DATA_TRANSACTIONS_DATA_OFFSET = 2;
                  uint256 internal constant APP_DATA_N_WORDS_PER_CONDITIONAL_TRANSFER = 2;
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "Governance.sol";
              import "GovernanceStorage.sol";
              /**
                The StarkEx contract is governed by one or more Governors of which the initial one is the
                deployer of the contract.
                A governor has the sole authority to perform the following operations:
                1. Nominate additional governors (:sol:func:`mainNominateNewGovernor`)
                2. Remove other governors (:sol:func:`mainRemoveGovernor`)
                3. Add new :sol:mod:`Verifiers` and :sol:mod:`AvailabilityVerifiers`
                4. Remove :sol:mod:`Verifiers` and :sol:mod:`AvailabilityVerifiers` after a timelock allows it
                5. Nominate Operators (see :sol:mod:`Operator`) and Token Administrators (see :sol:mod:`TokenRegister`)
                Adding governors is performed in a two step procedure:
                1. First, an existing governor nominates a new governor (:sol:func:`mainNominateNewGovernor`)
                2. Then, the new governor must accept governance to become a governor (:sol:func:`mainAcceptGovernance`)
                This two step procedure ensures that a governor public key cannot be nominated unless there is an
                entity that has the corresponding private key. This is intended to prevent errors in the addition
                process.
                The governor private key should typically be held in a secure cold wallet.
              */
              /*
                Implements Governance for the StarkDex main contract.
                The wrapper methods (e.g. mainIsGovernor wrapping _isGovernor) are needed to give
                the method unique names.
                Both Proxy and StarkExchange inherit from Governance. Thus, the logical contract method names
                must have unique names in order for the proxy to successfully delegate to them.
              */
              contract MainGovernance is GovernanceStorage, Governance {
                  // The tag is the sting key that is used in the Governance storage mapping.
                  string public constant MAIN_GOVERNANCE_INFO_TAG = "StarkEx.Main.2019.GovernorsInformation";
                  /*
                    Returns the GovernanceInfoStruct associated with the governance tag.
                  */
                  function getGovernanceInfo() internal view override returns (GovernanceInfoStruct storage) {
                      return governanceInfo[MAIN_GOVERNANCE_INFO_TAG];
                  }
                  function mainIsGovernor(address testGovernor) external view returns (bool) {
                      return _isGovernor(testGovernor);
                  }
                  function mainNominateNewGovernor(address newGovernor) external {
                      _nominateNewGovernor(newGovernor);
                  }
                  function mainRemoveGovernor(address governorForRemoval) external {
                      _removeGovernor(governorForRemoval);
                  }
                  function mainAcceptGovernance() external {
                      _acceptGovernance();
                  }
                  function mainCancelNomination() external {
                      _cancelNomination();
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "StarkExStorage.sol";
              import "MStarkExForcedActionState.sol";
              import "ActionHash.sol";
              /*
                StarkExchange specific action hashses.
              */
              contract StarkExForcedActionState is StarkExStorage, ActionHash, MStarkExForcedActionState {
                  function fullWithdrawActionHash(uint256 ownerKey, uint256 vaultId)
                      internal
                      pure
                      override
                      returns (bytes32)
                  {
                      return getActionHash("FULL_WITHDRAWAL", abi.encode(ownerKey, vaultId));
                  }
                  /*
                    Implemented in the FullWithdrawal contracts.
                  */
                  function clearFullWithdrawalRequest(uint256 ownerKey, uint256 vaultId)
                      internal
                      virtual
                      override
                  {
                      // Reset escape request.
                      delete forcedActionRequests[fullWithdrawActionHash(ownerKey, vaultId)];
                  }
                  function getFullWithdrawalRequest(uint256 ownerKey, uint256 vaultId)
                      public
                      view
                      override
                      returns (uint256)
                  {
                      // Return request value. Expect zero if the request doesn't exist or has been serviced, and
                      // a non-zero value otherwise.
                      return forcedActionRequests[fullWithdrawActionHash(ownerKey, vaultId)];
                  }
                  function setFullWithdrawalRequest(uint256 ownerKey, uint256 vaultId) internal override {
                      // FullWithdrawal is always at premium cost, hence the `true`.
                      setActionHash(fullWithdrawActionHash(ownerKey, vaultId), true);
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              interface Identity {
                  /*
                    Allows a caller, typically another contract,
                    to ensure that the provided address is of the expected type and version.
                  */
                  function identify() external pure returns (string memory);
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "MainStorage.sol";
              import "MTokenQuantization.sol";
              contract TokenQuantization is MainStorage, MTokenQuantization {
                  function fromQuantized(uint256 presumedAssetType, uint256 quantizedAmount)
                      internal
                      view
                      override
                      returns (uint256 amount)
                  {
                      uint256 quantum = getQuantum(presumedAssetType);
                      amount = quantizedAmount * quantum;
                      require(amount / quantum == quantizedAmount, "DEQUANTIZATION_OVERFLOW");
                  }
                  function getQuantum(uint256 presumedAssetType) public view override returns (uint256 quantum) {
                      if (!registeredAssetType[presumedAssetType]) {
                          // Default quantization, for NFTs etc.
                          quantum = 1;
                      } else {
                          // Retrieve registration.
                          quantum = assetTypeToQuantum[presumedAssetType];
                      }
                  }
                  function toQuantized(uint256 presumedAssetType, uint256 amount)
                      internal
                      view
                      override
                      returns (uint256 quantizedAmount)
                  {
                      uint256 quantum = getQuantum(presumedAssetType);
                      require(amount % quantum == 0, "INVALID_AMOUNT");
                      quantizedAmount = amount / quantum;
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              abstract contract MStateRoot {
                  function getValidiumVaultRoot() public view virtual returns (uint256);
                  function getValidiumTreeHeight() public view virtual returns (uint256);
                  function getRollupVaultRoot() public view virtual returns (uint256);
                  function getRollupTreeHeight() public view virtual returns (uint256);
                  /*
                    Returns true iff vaultId is in the valid vault ids range,
                    i.e. could appear in either the validium or rollup vaults trees.
                  */
                  function isVaultInRange(uint256 vaultId) internal view virtual returns (bool);
                  /*
                    Returns true if vaultId is a valid validium vault id.
                    Note: when this function returns false it might mean that vaultId is invalid and does not
                    guarantee that vaultId is a valid rollup vault id.
                  */
                  function isValidiumVault(uint256 vaultId) internal view virtual returns (bool);
                  /*
                    Returns true if vaultId is a valid rollup vault id.
                    Note: when this function returns false it might mean that vaultId is invalid and does not
                    guarantee that vaultId is a valid validium vault id.
                  */
                  function isRollupVault(uint256 vaultId) internal view virtual returns (bool);
                  /*
                    Given a valid vaultId, returns its leaf index in the validium/rollup tree.
                    Note: this function does not assert the validity of vaultId, make sure to explicitly assert it
                    when required.
                  */
                  function getVaultLeafIndex(uint256 vaultId) internal pure virtual returns (uint256);
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "Identity.sol";
              import "FactRegistry.sol";
              contract MessageRegistry is FactRegistry, Identity {
                  event LogMsgRegistered(address from, address to, bytes32 msgHash);
                  function identify() external pure virtual override returns (string memory) {
                      return "StarkWare_MessageRegistry_2021_1";
                  }
                  // NOLINTNEXTLINE: external-function.
                  function registerMessage(address to, bytes32 messageHash) public {
                      bytes32 messageFact = keccak256(abi.encodePacked(msg.sender, to, messageHash));
                      registerFact(messageFact);
                      emit LogMsgRegistered(msg.sender, to, messageHash);
                  }
                  function isMessageRegistered(
                      address from,
                      address to,
                      bytes32 messageHash
                  ) external view returns (bool) {
                      bytes32 messageFact = keccak256(abi.encodePacked(from, to, messageHash));
                      return _factCheck(messageFact);
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              abstract contract MStarkExForcedActionState {
                  function fullWithdrawActionHash(uint256 ownerKey, uint256 vaultId)
                      internal
                      pure
                      virtual
                      returns (bytes32);
                  function clearFullWithdrawalRequest(uint256 ownerKey, uint256 vaultId) internal virtual;
                  // NOLINTNEXTLINE: external-function.
                  function getFullWithdrawalRequest(uint256 ownerKey, uint256 vaultId)
                      public
                      view
                      virtual
                      returns (uint256);
                  function setFullWithdrawalRequest(uint256 ownerKey, uint256 vaultId) internal virtual;
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "MainStorage.sol";
              /*
                Extends MainStorage, holds StarkEx App specific state (storage) variables.
                ALL State variables that are common to all applications, reside in MainStorage,
                whereas ALL the StarkEx app specific ones reside here.
              */
              contract StarkExStorage is MainStorage {
                  // Onchain vaults balances.
                  // A map eth_address => asset_id => vault_id => quantized amount.
                  mapping(address => mapping(uint256 => mapping(uint256 => uint256))) vaultsBalances;
                  // Onchain vaults withdrawal lock time.
                  // A map eth_address => asset_id => vault_id => lock expiration timestamp.
                  mapping(address => mapping(uint256 => mapping(uint256 => uint256))) vaultsWithdrawalLocks;
                  // Enforces the minimal balance requirement (as output by Cairo) on onchain vault updates.
                  // When disabled, flash loans are enabled.
                  bool strictVaultBalancePolicy; // NOLINT: constable-states, uninitialized-state.
                  // The default time, in seconds, that an onchain vault is locked for withdrawal after a deposit.
                  uint256 public defaultVaultWithdrawalLock; // NOLINT: constable-states.
                  // Address of the message registry contract that is used to sign and verify L1 orders.
                  address public orderRegistryAddress; // NOLINT: constable-states.
                  // Reserved storage space for Extensibility.
                  // Every added MUST be added above the end gap, and the __endGap size must be reduced
                  // accordingly.
                  // NOLINTNEXTLINE: naming-convention shadowing-abstract.
                  uint256[LAYOUT_LENGTH - 5] private __endGap; // __endGap complements layout to LAYOUT_LENGTH.
              }
              

              File 4 of 9: GpsFactRegistryAdapter
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "Identity.sol";
              import "IQueryableFactRegistry.sol";
              /*
                The GpsFactRegistryAdapter contract is used as an adapter between a Dapp contract and a GPS fact
                registry. An isValid(fact) query is answered by querying the GPS contract about
                new_fact := keccak256(programHash, fact).
                The goal of this contract is to simplify the verifier upgradability logic in the Dapp contract
                by making the upgrade flow the same regardless of whether the update is to the program hash or
                the gpsContractAddress.
              */
              contract GpsFactRegistryAdapter is IQueryableFactRegistry, Identity {
                  IQueryableFactRegistry public gpsContract;
                  uint256 public programHash;
                  constructor(IQueryableFactRegistry gpsStatementContract, uint256 programHash_) public {
                      gpsContract = gpsStatementContract;
                      programHash = programHash_;
                  }
                  function identify() external pure virtual override returns (string memory) {
                      return "StarkWare_GpsFactRegistryAdapter_2020_1";
                  }
                  /*
                    Checks if a fact has been verified.
                  */
                  function isValid(bytes32 fact) external view override returns (bool) {
                      return gpsContract.isValid(keccak256(abi.encode(programHash, fact)));
                  }
                  /*
                    Indicates whether at least one fact was registered.
                  */
                  function hasRegisteredFact() external view override returns (bool) {
                      return gpsContract.hasRegisteredFact();
                  }
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              /*
                The Fact Registry design pattern is a way to separate cryptographic verification from the
                business logic of the contract flow.
                A fact registry holds a hash table of verified "facts" which are represented by a hash of claims
                that the registry hash check and found valid. This table may be queried by accessing the
                isValid() function of the registry with a given hash.
                In addition, each fact registry exposes a registry specific function for submitting new claims
                together with their proofs. The information submitted varies from one registry to the other
                depending of the type of fact requiring verification.
                For further reading on the Fact Registry design pattern see this
                `StarkWare blog post <https://medium.com/starkware/the-fact-registry-a64aafb598b6>`_.
              */
              interface IFactRegistry {
                  /*
                    Returns true if the given fact was previously registered in the contract.
                  */
                  function isValid(bytes32 fact) external view returns (bool);
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "IFactRegistry.sol";
              /*
                Extends the IFactRegistry interface with a query method that indicates
                whether the fact registry has successfully registered any fact or is still empty of such facts.
              */
              interface IQueryableFactRegistry is IFactRegistry {
                  /*
                    Returns true if at least one fact has been registered.
                  */
                  function hasRegisteredFact() external view returns (bool);
              }
              /*
                Copyright 2019-2022 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              interface Identity {
                  /*
                    Allows a caller to ensure that the provided address is of the expected type and version.
                  */
                  function identify() external pure returns (string memory);
              }
              

              File 5 of 9: Proxy
              {"Common.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.12;\n\n/*\n  Common Utility librarries.\n  I. Addresses (extending address).\n*/\nlibrary Addresses {\n    function isContract(address account) internal view returns (bool) {\n        uint256 size;\n        assembly {\n            size := extcodesize(account)\n        }\n        return size \u003e 0;\n    }\n\n    function performEthTransfer(address recipient, uint256 amount) internal {\n        (bool success, ) = recipient.call{value: amount}(\"\"); // NOLINT: low-level-calls.\n        require(success, \"ETH_TRANSFER_FAILED\");\n    }\n\n    /*\n      Safe wrapper around ERC20/ERC721 calls.\n      This is required because many deployed ERC20 contracts don\u0027t return a value.\n      See https://github.com/ethereum/solidity/issues/4116.\n    */\n    function safeTokenContractCall(address tokenAddress, bytes memory callData) internal {\n        require(isContract(tokenAddress), \"BAD_TOKEN_ADDRESS\");\n        // NOLINTNEXTLINE: low-level-calls.\n        (bool success, bytes memory returndata) = tokenAddress.call(callData);\n        require(success, string(returndata));\n\n        if (returndata.length \u003e 0) {\n            require(abi.decode(returndata, (bool)), \"TOKEN_OPERATION_FAILED\");\n        }\n    }\n\n    /*\n      Validates that the passed contract address is of a real contract,\n      and that its id hash (as infered fromn identify()) matched the expected one.\n    */\n    function validateContractId(address contractAddress, bytes32 expectedIdHash) internal {\n        require(isContract(contractAddress), \"ADDRESS_NOT_CONTRACT\");\n        (bool success, bytes memory returndata) = contractAddress.call( // NOLINT: low-level-calls.\n            abi.encodeWithSignature(\"identify()\")\n        );\n        require(success, \"FAILED_TO_IDENTIFY_CONTRACT\");\n        string memory realContractId = abi.decode(returndata, (string));\n        require(\n            keccak256(abi.encodePacked(realContractId)) == expectedIdHash,\n            \"UNEXPECTED_CONTRACT_IDENTIFIER\"\n        );\n    }\n\n    /*\n      Similar to safeTokenContractCall, but always ignores the return value.\n\n      Assumes some other method is used to detect the failures\n      (e.g. balance is checked before and after the call).\n    */\n    function uncheckedTokenContractCall(address tokenAddress, bytes memory callData) internal {\n        // NOLINTNEXTLINE: low-level-calls.\n        (bool success, bytes memory returndata) = tokenAddress.call(callData);\n        require(success, string(returndata));\n    }\n}\n\n/*\n  II. StarkExTypes - Common data types.\n*/\nlibrary StarkExTypes {\n    // Structure representing a list of verifiers (validity/availability).\n    // A statement is valid only if all the verifiers in the list agree on it.\n    // Adding a verifier to the list is immediate - this is used for fast resolution of\n    // any soundness issues.\n    // Removing from the list is time-locked, to ensure that any user of the system\n    // not content with the announced removal has ample time to leave the system before it is\n    // removed.\n    struct ApprovalChainData {\n        address[] list;\n        // Represents the time after which the verifier with the given address can be removed.\n        // Removal of the verifier with address A is allowed only in the case the value\n        // of unlockedForRemovalTime[A] != 0 and unlockedForRemovalTime[A] \u003c (current time).\n        mapping(address =\u003e uint256) unlockedForRemovalTime;\n    }\n}\n"},"Governance.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.12;\n\nimport \"MGovernance.sol\";\n\n/*\n  Implements Generic Governance, applicable for both proxy and main contract, and possibly others.\n  Notes:\n   The use of the same function names by both the Proxy and a delegated implementation\n   is not possible since calling the implementation functions is done via the default function\n   of the Proxy. For this reason, for example, the implementation of MainContract (MainGovernance)\n   exposes mainIsGovernor, which calls the internal isGovernor method.\n*/\nabstract contract Governance is MGovernance {\n    event LogNominatedGovernor(address nominatedGovernor);\n    event LogNewGovernorAccepted(address acceptedGovernor);\n    event LogRemovedGovernor(address removedGovernor);\n    event LogNominationCancelled();\n\n    function getGovernanceInfo() internal view virtual returns (GovernanceInfoStruct storage);\n\n    /*\n      Current code intentionally prevents governance re-initialization.\n      This may be a problem in an upgrade situation, in a case that the upgrade-to implementation\n      performs an initialization (for real) and within that calls initGovernance().\n\n      Possible workarounds:\n      1. Clearing the governance info altogether by changing the MAIN_GOVERNANCE_INFO_TAG.\n         This will remove existing main governance information.\n      2. Modify the require part in this function, so that it will exit quietly\n         when trying to re-initialize (uncomment the lines below).\n    */\n    function initGovernance() internal {\n        GovernanceInfoStruct storage gub = getGovernanceInfo();\n        require(!gub.initialized, \"ALREADY_INITIALIZED\");\n        gub.initialized = true; // to ensure addGovernor() won\u0027t fail.\n        // Add the initial governer.\n        addGovernor(msg.sender);\n    }\n\n    function isGovernor(address testGovernor) internal view override returns (bool) {\n        GovernanceInfoStruct storage gub = getGovernanceInfo();\n        return gub.effectiveGovernors[testGovernor];\n    }\n\n    /*\n      Cancels the nomination of a governor candidate.\n    */\n    function cancelNomination() internal onlyGovernance {\n        GovernanceInfoStruct storage gub = getGovernanceInfo();\n        gub.candidateGovernor = address(0x0);\n        emit LogNominationCancelled();\n    }\n\n    function nominateNewGovernor(address newGovernor) internal onlyGovernance {\n        GovernanceInfoStruct storage gub = getGovernanceInfo();\n        require(!isGovernor(newGovernor), \"ALREADY_GOVERNOR\");\n        gub.candidateGovernor = newGovernor;\n        emit LogNominatedGovernor(newGovernor);\n    }\n\n    /*\n      The addGovernor is called in two cases:\n      1. by acceptGovernance when a new governor accepts its role.\n      2. by initGovernance to add the initial governor.\n      The difference is that the init path skips the nominate step\n      that would fail because of the onlyGovernance modifier.\n    */\n    function addGovernor(address newGovernor) private {\n        require(!isGovernor(newGovernor), \"ALREADY_GOVERNOR\");\n        GovernanceInfoStruct storage gub = getGovernanceInfo();\n        gub.effectiveGovernors[newGovernor] = true;\n    }\n\n    function acceptGovernance() internal {\n        // The new governor was proposed as a candidate by the current governor.\n        GovernanceInfoStruct storage gub = getGovernanceInfo();\n        require(msg.sender == gub.candidateGovernor, \"ONLY_CANDIDATE_GOVERNOR\");\n\n        // Update state.\n        addGovernor(gub.candidateGovernor);\n        gub.candidateGovernor = address(0x0);\n\n        // Send a notification about the change of governor.\n        emit LogNewGovernorAccepted(msg.sender);\n    }\n\n    /*\n      Remove a governor from office.\n    */\n    function removeGovernor(address governorForRemoval) internal onlyGovernance {\n        require(msg.sender != governorForRemoval, \"GOVERNOR_SELF_REMOVE\");\n        GovernanceInfoStruct storage gub = getGovernanceInfo();\n        require(isGovernor(governorForRemoval), \"NOT_GOVERNOR\");\n        gub.effectiveGovernors[governorForRemoval] = false;\n        emit LogRemovedGovernor(governorForRemoval);\n    }\n}\n"},"GovernanceStorage.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.12;\nimport \"MGovernance.sol\";\n\n/*\n  Holds the governance slots for ALL entities, including proxy and the main contract.\n*/\ncontract GovernanceStorage {\n    // A map from a Governor tag to its own GovernanceInfoStruct.\n    mapping(string =\u003e GovernanceInfoStruct) internal governanceInfo; //NOLINT uninitialized-state.\n}\n"},"MGovernance.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.12;\n\nstruct GovernanceInfoStruct {\n    mapping(address =\u003e bool) effectiveGovernors;\n    address candidateGovernor;\n    bool initialized;\n}\n\nabstract contract MGovernance {\n    function isGovernor(address testGovernor) internal view virtual returns (bool);\n\n    /*\n      Allows calling the function only by a Governor.\n    */\n    modifier onlyGovernance() {\n        require(isGovernor(msg.sender), \"ONLY_GOVERNANCE\");\n        _;\n    }\n}\n"},"Proxy.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.12;\n\nimport \"ProxyGovernance.sol\";\nimport \"ProxyStorage.sol\";\nimport \"StorageSlots.sol\";\nimport \"Common.sol\";\n\n/**\n  The Proxy contract implements delegation of calls to other contracts (`implementations`), with\n  proper forwarding of return values and revert reasons. This pattern allows retaining the contract\n  storage while replacing implementation code.\n\n  The following operations are supported by the proxy contract:\n\n  - :sol:func:`addImplementation`: Defines a new implementation, the data with which it should be initialized and whether this will be the last version of implementation.\n  - :sol:func:`upgradeTo`: Once an implementation is added, the governor may upgrade to that implementation only after a safety time period has passed (time lock), the current implementation is not the last version and the implementation is not frozen (see :sol:mod:`FullWithdrawals`).\n  - :sol:func:`removeImplementation`: Any announced implementation may be removed. Removing an implementation is especially important once it has been used for an upgrade in order to avoid an additional unwanted revert to an older version.\n\n  The only entity allowed to perform the above operations is the proxy governor\n  (see :sol:mod:`ProxyGovernance`).\n\n  Every implementation is required to have an `initialize` function that replaces the constructor\n  of a normal contract. Furthermore, the only parameter of this function is an array of bytes\n  (`data`) which may be decoded arbitrarily by the `initialize` function. It is up to the\n  implementation to ensure that this function cannot be run more than once if so desired.\n\n  When an implementation is added (:sol:func:`addImplementation`) the initialization `data` is also\n  announced, allowing users of the contract to analyze the full effect of an upgrade to the new\n  implementation. During an :sol:func:`upgradeTo`, the `data` is provided again and only if it is\n  identical to the announced `data` is the upgrade performed by pointing the proxy to the new\n  implementation and calling its `initialize` function with this `data`.\n\n  It is the responsibility of the implementation not to overwrite any storage belonging to the\n  proxy (`ProxyStorage`). In addition, upon upgrade, the new implementation is assumed to be\n  backward compatible with previous implementations with respect to the storage used until that\n  point.\n*/\ncontract Proxy is ProxyStorage, ProxyGovernance, StorageSlots {\n    // Emitted when the active implementation is replaced.\n    event ImplementationUpgraded(address indexed implementation, bytes initializer);\n\n    // Emitted when an implementation is submitted as an upgrade candidate and a time lock\n    // is activated.\n    event ImplementationAdded(address indexed implementation, bytes initializer, bool finalize);\n\n    // Emitted when an implementation is removed from the list of upgrade candidates.\n    event ImplementationRemoved(address indexed implementation, bytes initializer, bool finalize);\n\n    // Emitted when the implementation is finalized.\n    event FinalizedImplementation(address indexed implementation);\n\n    using Addresses for address;\n\n    string public constant PROXY_VERSION = \"3.0.0\";\n\n    constructor(uint256 upgradeActivationDelay) public {\n        initGovernance();\n        setUpgradeActivationDelay(upgradeActivationDelay);\n    }\n\n    function setUpgradeActivationDelay(uint256 delayInSeconds) private {\n        bytes32 slot = UPGRADE_DELAY_SLOT;\n        assembly {\n            sstore(slot, delayInSeconds)\n        }\n    }\n\n    function getUpgradeActivationDelay() public view returns (uint256 delay) {\n        bytes32 slot = UPGRADE_DELAY_SLOT;\n        assembly {\n            delay := sload(slot)\n        }\n        return delay;\n    }\n\n    /*\n      Returns the address of the current implementation.\n    */\n    // NOLINTNEXTLINE external-function.\n    function implementation() public view returns (address _implementation) {\n        bytes32 slot = IMPLEMENTATION_SLOT;\n        assembly {\n            _implementation := sload(slot)\n        }\n    }\n\n    /*\n      Returns true if the implementation is frozen.\n      If the implementation was not assigned yet, returns false.\n    */\n    function implementationIsFrozen() private returns (bool) {\n        address _implementation = implementation();\n\n        // We can\u0027t call low level implementation before it\u0027s assigned. (i.e. ZERO).\n        if (_implementation == address(0x0)) {\n            return false;\n        }\n\n        // NOLINTNEXTLINE: low-level-calls.\n        (bool success, bytes memory returndata) = _implementation.delegatecall(\n            abi.encodeWithSignature(\"isFrozen()\")\n        );\n        require(success, string(returndata));\n        return abi.decode(returndata, (bool));\n    }\n\n    /*\n      This method blocks delegation to initialize().\n      Only upgradeTo should be able to delegate call to initialize().\n    */\n    function initialize(\n        bytes calldata /*data*/\n    ) external pure {\n        revert(\"CANNOT_CALL_INITIALIZE\");\n    }\n\n    modifier notFinalized() {\n        require(isNotFinalized(), \"IMPLEMENTATION_FINALIZED\");\n        _;\n    }\n\n    /*\n      Forbids calling the function if the implementation is frozen.\n      This modifier relies on the lower level (logical contract) implementation of isFrozen().\n    */\n    modifier notFrozen() {\n        require(!implementationIsFrozen(), \"STATE_IS_FROZEN\");\n        _;\n    }\n\n    /*\n      This entry point serves only transactions with empty calldata. (i.e. pure value transfer tx).\n      We don\u0027t expect to receive such, thus block them.\n    */\n    receive() external payable {\n        revert(\"CONTRACT_NOT_EXPECTED_TO_RECEIVE\");\n    }\n\n    /*\n      Contract\u0027s default function. Delegates execution to the implementation contract.\n      It returns back to the external caller whatever the implementation delegated code returns.\n    */\n    fallback() external payable {\n        address _implementation = implementation();\n        require(_implementation != address(0x0), \"MISSING_IMPLEMENTATION\");\n\n        assembly {\n            // Copy msg.data. We take full control of memory in this inline assembly\n            // block because it will not return to Solidity code. We overwrite the\n            // Solidity scratch pad at memory position 0.\n            calldatacopy(0, 0, calldatasize())\n\n            // Call the implementation.\n            // out and outsize are 0 for now, as we don\u0027t know the out size yet.\n            let result := delegatecall(gas(), _implementation, 0, calldatasize(), 0, 0)\n\n            // Copy the returned data.\n            returndatacopy(0, 0, returndatasize())\n\n            switch result\n            // delegatecall returns 0 on error.\n            case 0 {\n                revert(0, returndatasize())\n            }\n            default {\n                return(0, returndatasize())\n            }\n        }\n    }\n\n    /*\n      Sets the implementation address of the proxy.\n    */\n    function setImplementation(address newImplementation) private {\n        bytes32 slot = IMPLEMENTATION_SLOT;\n        assembly {\n            sstore(slot, newImplementation)\n        }\n    }\n\n    /*\n      Returns true if the contract is not in the finalized state.\n    */\n    function isNotFinalized() public view returns (bool notFinal) {\n        bytes32 slot = FINALIZED_STATE_SLOT;\n        uint256 slotValue;\n        assembly {\n            slotValue := sload(slot)\n        }\n        notFinal = (slotValue == 0);\n    }\n\n    /*\n      Marks the current implementation as finalized.\n    */\n    function setFinalizedFlag() private {\n        bytes32 slot = FINALIZED_STATE_SLOT;\n        assembly {\n            sstore(slot, 0x1)\n        }\n    }\n\n    /*\n      Introduce an implementation and its initialization vector,\n      and start the time-lock before it can be upgraded to.\n      addImplementation is not blocked when frozen or finalized.\n      (upgradeTo API is blocked when finalized or frozen).\n    */\n    function addImplementation(\n        address newImplementation,\n        bytes calldata data,\n        bool finalize\n    ) external onlyGovernance {\n        require(newImplementation.isContract(), \"ADDRESS_NOT_CONTRACT\");\n\n        bytes32 implVectorHash = keccak256(abi.encode(newImplementation, data, finalize));\n\n        uint256 activationTime = block.timestamp + getUpgradeActivationDelay();\n\n        // First implementation should not have time-lock.\n        if (implementation() == address(0x0)) {\n            activationTime = block.timestamp;\n        }\n\n        enabledTime[implVectorHash] = activationTime;\n        emit ImplementationAdded(newImplementation, data, finalize);\n    }\n\n    /*\n      Removes a candidate implementation.\n      Note that it is possible to remove the current implementation. Doing so doesn\u0027t affect the\n      current implementation, but rather revokes it as a future candidate.\n    */\n    function removeImplementation(\n        address removedImplementation,\n        bytes calldata data,\n        bool finalize\n    ) external onlyGovernance {\n        bytes32 implVectorHash = keccak256(abi.encode(removedImplementation, data, finalize));\n\n        // If we have initializer, we set the hash of it.\n        uint256 activationTime = enabledTime[implVectorHash];\n        require(activationTime \u003e 0, \"UNKNOWN_UPGRADE_INFORMATION\");\n        delete enabledTime[implVectorHash];\n        emit ImplementationRemoved(removedImplementation, data, finalize);\n    }\n\n    /*\n      Upgrades the proxy to a new implementation, with its initialization.\n      to upgrade successfully, implementation must have been added time-lock agreeably\n      before, and the init vector must be identical ot the one submitted before.\n\n      Upon assignment of new implementation address,\n      its initialize will be called with the initializing vector (even if empty).\n      Therefore, the implementation MUST must have such a method.\n\n      Note - Initialization data is committed to in advance, therefore it must remain valid\n      until the actual contract upgrade takes place.\n\n      Care should be taken regarding initialization data and flow when planning the contract upgrade.\n\n      When planning contract upgrade, special care is also needed with regard to governance\n      (See comments in Governance.sol).\n    */\n    // NOLINTNEXTLINE: reentrancy-events timestamp.\n    function upgradeTo(\n        address newImplementation,\n        bytes calldata data,\n        bool finalize\n    ) external payable onlyGovernance notFinalized notFrozen {\n        bytes32 implVectorHash = keccak256(abi.encode(newImplementation, data, finalize));\n        uint256 activationTime = enabledTime[implVectorHash];\n        require(activationTime \u003e 0, \"UNKNOWN_UPGRADE_INFORMATION\");\n        require(newImplementation.isContract(), \"ADDRESS_NOT_CONTRACT\");\n        // NOLINTNEXTLINE: timestamp.\n        require(activationTime \u003c= block.timestamp, \"UPGRADE_NOT_ENABLED_YET\");\n\n        setImplementation(newImplementation);\n\n        // NOLINTNEXTLINE: low-level-calls controlled-delegatecall.\n        (bool success, bytes memory returndata) = newImplementation.delegatecall(\n            abi.encodeWithSelector(this.initialize.selector, data)\n        );\n        require(success, string(returndata));\n\n        // Verify that the new implementation is not frozen post initialization.\n        // NOLINTNEXTLINE: low-level-calls controlled-delegatecall.\n        (success, returndata) = newImplementation.delegatecall(\n            abi.encodeWithSignature(\"isFrozen()\")\n        );\n        require(success, \"CALL_TO_ISFROZEN_REVERTED\");\n        require(!abi.decode(returndata, (bool)), \"NEW_IMPLEMENTATION_FROZEN\");\n\n        if (finalize) {\n            setFinalizedFlag();\n            emit FinalizedImplementation(newImplementation);\n        }\n\n        emit ImplementationUpgraded(newImplementation, data);\n    }\n}\n"},"ProxyGovernance.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.12;\n\nimport \"Governance.sol\";\nimport \"GovernanceStorage.sol\";\n\n/**\n  The Proxy contract is governed by one or more Governors of which the initial one is the\n  deployer of the contract.\n\n  A governor has the sole authority to perform the following operations:\n\n  1. Nominate additional governors (:sol:func:`proxyNominateNewGovernor`)\n  2. Remove other governors (:sol:func:`proxyRemoveGovernor`)\n  3. Add new `implementations` (proxied contracts)\n  4. Remove (new or old) `implementations`\n  5. Update `implementations` after a timelock allows it\n\n  Adding governors is performed in a two step procedure:\n\n  1. First, an existing governor nominates a new governor (:sol:func:`proxyNominateNewGovernor`)\n  2. Then, the new governor must accept governance to become a governor (:sol:func:`proxyAcceptGovernance`)\n\n  This two step procedure ensures that a governor public key cannot be nominated unless there is an\n  entity that has the corresponding private key. This is intended to prevent errors in the addition\n  process.\n\n  The governor private key should typically be held in a secure cold wallet or managed via a\n  multi-sig contract.\n*/\n/*\n  Implements Governance for the proxy contract.\n  It is a thin wrapper to the Governance contract,\n  which is needed so that it can have non-colliding function names,\n  and a specific tag (key) to allow unique state storage.\n*/\ncontract ProxyGovernance is GovernanceStorage, Governance {\n    // The tag is the string key that is used in the Governance storage mapping.\n    string public constant PROXY_GOVERNANCE_TAG = \"StarkEx.Proxy.2019.GovernorsInformation\";\n\n    /*\n      Returns the GovernanceInfoStruct associated with the governance tag.\n    */\n    function getGovernanceInfo() internal view override returns (GovernanceInfoStruct storage) {\n        return governanceInfo[PROXY_GOVERNANCE_TAG];\n    }\n\n    function proxyIsGovernor(address testGovernor) external view returns (bool) {\n        return isGovernor(testGovernor);\n    }\n\n    function proxyNominateNewGovernor(address newGovernor) external {\n        nominateNewGovernor(newGovernor);\n    }\n\n    function proxyRemoveGovernor(address governorForRemoval) external {\n        removeGovernor(governorForRemoval);\n    }\n\n    function proxyAcceptGovernance() external {\n        acceptGovernance();\n    }\n\n    function proxyCancelNomination() external {\n        cancelNomination();\n    }\n}\n"},"ProxyStorage.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.12;\n\nimport \"GovernanceStorage.sol\";\n\n/*\n  Holds the Proxy-specific state variables.\n  This contract is inherited by the GovernanceStorage (and indirectly by MainStorage)\n  to prevent collision hazard.\n*/\ncontract ProxyStorage is GovernanceStorage {\n    // NOLINTNEXTLINE: naming-convention uninitialized-state.\n    mapping(address =\u003e bytes32) internal initializationHash_DEPRECATED;\n\n    // The time after which we can switch to the implementation.\n    // Hash(implementation, data, finalize) =\u003e time.\n    mapping(bytes32 =\u003e uint256) internal enabledTime;\n\n    // A central storage of the flags whether implementation has been initialized.\n    // Note - it can be used flexibly enough to accommodate multiple levels of initialization\n    // (i.e. using different key salting schemes for different initialization levels).\n    mapping(bytes32 =\u003e bool) internal initialized;\n}\n"},"StorageSlots.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.12;\n\n/**\n  StorageSlots holds the arbitrary storage slots used throughout the Proxy pattern.\n  Storage address slots are a mechanism to define an arbitrary location, that will not be\n  overlapped by the logical contracts.\n*/\ncontract StorageSlots {\n    // Storage slot with the address of the current implementation.\n    // The address of the slot is keccak256(\"StarkWare2019.implemntation-slot\").\n    // We need to keep this variable stored outside of the commonly used space,\n    // so that it\u0027s not overrun by the logical implementation (the proxied contract).\n    bytes32 internal constant IMPLEMENTATION_SLOT =\n        0x177667240aeeea7e35eabe3a35e18306f336219e1386f7710a6bf8783f761b24;\n\n    // Storage slot with the address of the call-proxy current implementation.\n    // The address of the slot is keccak256(\"\u0027StarkWare2020.CallProxy.Implemntation.Slot\u0027\").\n    // We need to keep this variable stored outside of the commonly used space.\n    // so that it\u0027s not overrun by the logical implementation (the proxied contract).\n    bytes32 internal constant CALL_PROXY_IMPL_SLOT =\n        0x7184681641399eb4ad2fdb92114857ee6ff239f94ad635a1779978947b8843be;\n\n    // This storage slot stores the finalization flag.\n    // Once the value stored in this slot is set to non-zero\n    // the proxy blocks implementation upgrades.\n    // The current implementation is then referred to as Finalized.\n    // Web3.solidityKeccak([\u0027string\u0027], [\"StarkWare2019.finalization-flag-slot\"]).\n    bytes32 internal constant FINALIZED_STATE_SLOT =\n        0x7d433c6f837e8f93009937c466c82efbb5ba621fae36886d0cac433c5d0aa7d2;\n\n    // Storage slot to hold the upgrade delay (time-lock).\n    // The intention of this slot is to allow modification using an EIC.\n    // Web3.solidityKeccak([\u0027string\u0027], [\u0027StarkWare.Upgradibility.Delay.Slot\u0027]).\n    bytes32 public constant UPGRADE_DELAY_SLOT =\n        0xc21dbb3089fcb2c4f4c6a67854ab4db2b0f233ea4b21b21f912d52d18fc5db1f;\n}\n"}}

              File 6 of 9: CallProxy
              {"BlockDirectCall.sol":{"content":"/*\n  Copyright 2019-2022 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.12;\n\n/*\n  This contract provides means to block direct call of an external function.\n  A derived contract (e.g. MainDispatcherBase) should decorate sensitive functions with the\n  notCalledDirectly modifier, thereby preventing it from being called directly, and allowing only calling\n  using delegate_call.\n\n  This Guard contract uses pseudo-random slot, So each deployed contract would have its own guard.\n*/\nabstract contract BlockDirectCall {\n    bytes32 immutable UNIQUE_SAFEGUARD_SLOT; // NOLINT naming-convention.\n\n    constructor() internal {\n        // The slot is pseudo-random to allow hierarchy of contracts with guarded functions.\n        bytes32 slot = keccak256(abi.encode(this, block.timestamp, gasleft()));\n        UNIQUE_SAFEGUARD_SLOT = slot;\n        assembly {\n            sstore(slot, 42)\n        }\n    }\n\n    modifier notCalledDirectly() {\n        {\n            // Prevent too many local variables in stack.\n            uint256 safeGuardValue;\n            bytes32 slot = UNIQUE_SAFEGUARD_SLOT;\n            assembly {\n                safeGuardValue := sload(slot)\n            }\n            require(safeGuardValue == 0, \"DIRECT_CALL_DISALLOWED\");\n        }\n        _;\n    }\n}\n"},"CallProxy.sol":{"content":"/*\n  Copyright 2019-2022 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.12;\n\nimport \"IFactRegistry.sol\";\nimport \"StorageSlots.sol\";\nimport \"BlockDirectCall.sol\";\nimport \"Common.sol\";\n\n/**\n  CallProxy is a \u0027call\u0027 based proxy.\n  It is a facade to a real implementation,\n  only that unlike the Proxy pattern, it uses call and not delegatecall,\n  so that the state is recorded on the called contract.\n\n  This contract is expected to be placed behind the regular proxy,\n  thus:\n  1. Implementation address is stored in a hashed slot (other than proxy\u0027s one...).\n  2. No state variable is allowed in low address ranges.\n  3. Setting of implementation is done in initialize.\n  4. isFrozen and initialize are implemented, to be compliant with Proxy.\n\n  This implementation is intentionally minimal,\n  and has no management or governance.\n  The assumption is that if a different implementation is needed, it will be performed\n  in an upgradeTo a new deployed CallProxy, pointing to a new implementation.\n*/\n// NOLINTNEXTLINE locked-ether.\ncontract CallProxy is BlockDirectCall, StorageSlots {\n    using Addresses for address;\n\n    string public constant CALL_PROXY_VERSION = \"3.1.0\";\n\n    // Proxy client - initialize \u0026 isFrozen.\n    // NOLINTNEXTLINE: external-function.\n    function isFrozen() public pure returns (bool) {\n        return false;\n    }\n\n    /*\n      This function is called by the Proxy upon activating an implementation.\n      The data passed in to this function contains the implementation address,\n      and if applicable, an address of an EIC (ExternalInitializerContract) and its data.\n\n      The expected data format is as following:\n\n      Case I (no EIC):\n        data.length == 64.\n        [0 :32] implementation address\n        [32:64] Zero address.\n\n      Case II (EIC):\n        data length \u003e= 64\n        [0 :32] implementation address\n        [32:64] EIC address\n        [64:  ] EIC init data.\n    */\n    function initialize(bytes calldata data) external notCalledDirectly {\n        require(data.length \u003e= 64, \"INCORRECT_DATA_SIZE\");\n        (address impl, address eic) = abi.decode(data, (address, address));\n        require(impl.isContract(), \"ADDRESS_NOT_CONTRACT\");\n        setCallProxyImplementation(impl);\n        if (eic != address(0x0)) {\n            callExternalInitializer(eic, data[64:]);\n        } else {\n            require(data.length == 64, \"INVALID_INIT_DATA\");\n        }\n    }\n\n    function callExternalInitializer(address externalInitializerAddr, bytes calldata eicData)\n        private\n    {\n        require(externalInitializerAddr.isContract(), \"EIC_NOT_A_CONTRACT\");\n\n        // NOLINTNEXTLINE: low-level-calls, controlled-delegatecall.\n        (bool success, bytes memory returndata) = externalInitializerAddr.delegatecall(\n            abi.encodeWithSelector(this.initialize.selector, eicData)\n        );\n        require(success, string(returndata));\n        require(returndata.length == 0, string(returndata));\n    }\n\n    /*\n      Returns the call proxy implementation address.\n    */\n    function callProxyImplementation() public view returns (address _implementation) {\n        bytes32 slot = CALL_PROXY_IMPL_SLOT;\n        assembly {\n            _implementation := sload(slot)\n        }\n    }\n\n    /*\n      Sets the call proxy implementation address.\n    */\n    function setCallProxyImplementation(address newImplementation) private {\n        bytes32 slot = CALL_PROXY_IMPL_SLOT;\n        assembly {\n            sstore(slot, newImplementation)\n        }\n    }\n\n    /*\n      An explicit isValid entry point, used to make isValid a part of the ABI and visible\n      on Etherscan (and alike).\n    */\n    function isValid(bytes32 fact) external view returns (bool) {\n        return IFactRegistry(callProxyImplementation()).isValid(fact);\n    }\n\n    /*\n      This entry point serves only transactions with empty calldata. (i.e. pure value transfer tx).\n      We don\u0027t expect to receive such, thus block them.\n    */\n    receive() external payable {\n        revert(\"CONTRACT_NOT_EXPECTED_TO_RECEIVE\");\n    }\n\n    /*\n      Contract\u0027s default function. Pass execution to the implementation contract (using call).\n      It returns back to the external caller whatever the implementation called code returns.\n    */\n    fallback() external payable {\n        // NOLINT locked-ether.\n        address _implementation = callProxyImplementation();\n        require(_implementation != address(0x0), \"MISSING_IMPLEMENTATION\");\n        uint256 value = msg.value;\n        assembly {\n            // Copy msg.data. We take full control of memory in this inline assembly\n            // block because it will not return to Solidity code. We overwrite the\n            // Solidity scratch pad at memory position 0.\n            calldatacopy(0, 0, calldatasize())\n\n            // Call the implementation.\n            // out and outsize are 0 for now, as we don\u0027t know the out size yet.\n            let result := call(gas(), _implementation, value, 0, calldatasize(), 0, 0)\n\n            // Copy the returned data.\n            returndatacopy(0, 0, returndatasize())\n\n            switch result\n            // delegatecall returns 0 on error.\n            case 0 {\n                revert(0, returndatasize())\n            }\n            default {\n                return(0, returndatasize())\n            }\n        }\n    }\n}\n"},"Common.sol":{"content":"/*\n  Copyright 2019-2022 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.12;\n\n/*\n  Common Utility librarries.\n  I. Addresses (extending address).\n*/\nlibrary Addresses {\n    function isContract(address account) internal view returns (bool) {\n        uint256 size;\n        assembly {\n            size := extcodesize(account)\n        }\n        return size \u003e 0;\n    }\n\n    function performEthTransfer(address recipient, uint256 amount) internal {\n        (bool success, ) = recipient.call{value: amount}(\"\"); // NOLINT: low-level-calls.\n        require(success, \"ETH_TRANSFER_FAILED\");\n    }\n\n    /*\n      Safe wrapper around ERC20/ERC721 calls.\n      This is required because many deployed ERC20 contracts don\u0027t return a value.\n      See https://github.com/ethereum/solidity/issues/4116.\n    */\n    function safeTokenContractCall(address tokenAddress, bytes memory callData) internal {\n        require(isContract(tokenAddress), \"BAD_TOKEN_ADDRESS\");\n        // NOLINTNEXTLINE: low-level-calls.\n        (bool success, bytes memory returndata) = tokenAddress.call(callData);\n        require(success, string(returndata));\n\n        if (returndata.length \u003e 0) {\n            require(abi.decode(returndata, (bool)), \"TOKEN_OPERATION_FAILED\");\n        }\n    }\n\n    /*\n      Validates that the passed contract address is of a real contract,\n      and that its id hash (as infered fromn identify()) matched the expected one.\n    */\n    function validateContractId(address contractAddress, bytes32 expectedIdHash) internal {\n        require(isContract(contractAddress), \"ADDRESS_NOT_CONTRACT\");\n        (bool success, bytes memory returndata) = contractAddress.call( // NOLINT: low-level-calls.\n            abi.encodeWithSignature(\"identify()\")\n        );\n        require(success, \"FAILED_TO_IDENTIFY_CONTRACT\");\n        string memory realContractId = abi.decode(returndata, (string));\n        require(\n            keccak256(abi.encodePacked(realContractId)) == expectedIdHash,\n            \"UNEXPECTED_CONTRACT_IDENTIFIER\"\n        );\n    }\n\n    /*\n      Similar to safeTokenContractCall, but always ignores the return value.\n\n      Assumes some other method is used to detect the failures\n      (e.g. balance is checked before and after the call).\n    */\n    function uncheckedTokenContractCall(address tokenAddress, bytes memory callData) internal {\n        // NOLINTNEXTLINE: low-level-calls.\n        (bool success, bytes memory returndata) = tokenAddress.call(callData);\n        require(success, string(returndata));\n    }\n}\n\n/*\n  II. StarkExTypes - Common data types.\n*/\nlibrary StarkExTypes {\n    // Structure representing a list of verifiers (validity/availability).\n    // A statement is valid only if all the verifiers in the list agree on it.\n    // Adding a verifier to the list is immediate - this is used for fast resolution of\n    // any soundness issues.\n    // Removing from the list is time-locked, to ensure that any user of the system\n    // not content with the announced removal has ample time to leave the system before it is\n    // removed.\n    struct ApprovalChainData {\n        address[] list;\n        // Represents the time after which the verifier with the given address can be removed.\n        // Removal of the verifier with address A is allowed only in the case the value\n        // of unlockedForRemovalTime[A] != 0 and unlockedForRemovalTime[A] \u003c (current time).\n        mapping(address =\u003e uint256) unlockedForRemovalTime;\n    }\n}\n"},"IFactRegistry.sol":{"content":"/*\n  Copyright 2019-2022 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.12;\n\n/*\n  The Fact Registry design pattern is a way to separate cryptographic verification from the\n  business logic of the contract flow.\n\n  A fact registry holds a hash table of verified \"facts\" which are represented by a hash of claims\n  that the registry hash check and found valid. This table may be queried by accessing the\n  isValid() function of the registry with a given hash.\n\n  In addition, each fact registry exposes a registry specific function for submitting new claims\n  together with their proofs. The information submitted varies from one registry to the other\n  depending of the type of fact requiring verification.\n\n  For further reading on the Fact Registry design pattern see this\n  `StarkWare blog post \u003chttps://medium.com/starkware/the-fact-registry-a64aafb598b6\u003e`_.\n*/\ninterface IFactRegistry {\n    /*\n      Returns true if the given fact was previously registered in the contract.\n    */\n    function isValid(bytes32 fact) external view returns (bool);\n}\n"},"StorageSlots.sol":{"content":"/*\n  Copyright 2019-2022 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.12;\n\n/**\n  StorageSlots holds the arbitrary storage slots used throughout the Proxy pattern.\n  Storage address slots are a mechanism to define an arbitrary location, that will not be\n  overlapped by the logical contracts.\n*/\ncontract StorageSlots {\n    // Storage slot with the address of the current implementation.\n    // The address of the slot is keccak256(\"StarkWare2019.implemntation-slot\").\n    // We need to keep this variable stored outside of the commonly used space,\n    // so that it\u0027s not overrun by the logical implementation (the proxied contract).\n    bytes32 internal constant IMPLEMENTATION_SLOT =\n        0x177667240aeeea7e35eabe3a35e18306f336219e1386f7710a6bf8783f761b24;\n\n    // Storage slot with the address of the call-proxy current implementation.\n    // The address of the slot is keccak256(\"\u0027StarkWare2020.CallProxy.Implemntation.Slot\u0027\").\n    // We need to keep this variable stored outside of the commonly used space.\n    // so that it\u0027s not overrun by the logical implementation (the proxied contract).\n    bytes32 internal constant CALL_PROXY_IMPL_SLOT =\n        0x7184681641399eb4ad2fdb92114857ee6ff239f94ad635a1779978947b8843be;\n\n    // This storage slot stores the finalization flag.\n    // Once the value stored in this slot is set to non-zero\n    // the proxy blocks implementation upgrades.\n    // The current implementation is then referred to as Finalized.\n    // Web3.solidityKeccak([\u0027string\u0027], [\"StarkWare2019.finalization-flag-slot\"]).\n    bytes32 internal constant FINALIZED_STATE_SLOT =\n        0x7d433c6f837e8f93009937c466c82efbb5ba621fae36886d0cac433c5d0aa7d2;\n\n    // Storage slot to hold the upgrade delay (time-lock).\n    // The intention of this slot is to allow modification using an EIC.\n    // Web3.solidityKeccak([\u0027string\u0027], [\u0027StarkWare.Upgradibility.Delay.Slot\u0027]).\n    bytes32 public constant UPGRADE_DELAY_SLOT =\n        0xc21dbb3089fcb2c4f4c6a67854ab4db2b0f233ea4b21b21f912d52d18fc5db1f;\n}\n"}}

              File 7 of 9: GpsStatementVerifier
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity >=0.6.12;
              /*
                Common Utility Libraries.
                I. Addresses (extending address).
              */
              library Addresses {
                  /*
                    Note: isContract function has some known limitation.
                    See https://github.com/OpenZeppelin/
                    openzeppelin-contracts/blob/master/contracts/utils/Address.sol.
                  */
                  function isContract(address account) internal view returns (bool) {
                      uint256 size;
                      assembly {
                          size := extcodesize(account)
                      }
                      return size > 0;
                  }
                  function performEthTransfer(address recipient, uint256 amount) internal {
                      if (amount == 0) return;
                      (bool success, ) = recipient.call{value: amount}(""); // NOLINT: low-level-calls.
                      require(success, "ETH_TRANSFER_FAILED");
                  }
                  /*
                    Safe wrapper around ERC20/ERC721 calls.
                    This is required because many deployed ERC20 contracts don't return a value.
                    See https://github.com/ethereum/solidity/issues/4116.
                  */
                  function safeTokenContractCall(address tokenAddress, bytes memory callData) internal {
                      require(isContract(tokenAddress), "BAD_TOKEN_ADDRESS");
                      // NOLINTNEXTLINE: low-level-calls.
                      (bool success, bytes memory returndata) = tokenAddress.call(callData);
                      require(success, string(returndata));
                      if (returndata.length > 0) {
                          require(abi.decode(returndata, (bool)), "TOKEN_OPERATION_FAILED");
                      }
                  }
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // ---------- The following code was auto-generated. PLEASE DO NOT EDIT. ----------
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              contract CairoBootloaderProgramSize {
                  uint256 internal constant PROGRAM_SIZE = 794;
              }
              contract CairoBootloaderProgram is CairoBootloaderProgramSize {
                  function getCompiledProgram()
                      external pure
                      returns (uint256[PROGRAM_SIZE] memory)
                  {
                      return [
                          290341444919459839,
                          11,
                          1226245742482522112,
                          778,
                          74168662805676031,
                          0,
                          2345108766317314046,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020480,
                          5198420613823102976,
                          3618502788666131213697322783095070105623107215331596699973092056135872020479,
                          2345108766317314046,
                          146226256843603965,
                          4,
                          5191102238658887680,
                          2345108766317314046,
                          290341444919459839,
                          3,
                          4632937381316558848,
                          4612671182992932865,
                          4612671182992998402,
                          146226256843603968,
                          4,
                          74168662805676031,
                          4,
                          4612671182993063937,
                          4612671182993129474,
                          5198983563776196608,
                          1,
                          5198983563776262144,
                          1,
                          5200109459388203008,
                          5200109459388268544,
                          5198983563776458752,
                          3618502788666131213697322783095070105623107215331596699973092056135872020480,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020458,
                          2345108766317314046,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020449,
                          5207990763031068672,
                          10,
                          5198420613823168512,
                          12,
                          5191102230068953088,
                          5191102234363920384,
                          5191102242953854976,
                          5201798292068466688,
                          5191102238658887680,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020444,
                          4623648689905041407,
                          291467327646433279,
                          2345108766317314046,
                          5199827962936983548,
                          5208553695804948479,
                          4612389708016287743,
                          5198983563776262144,
                          1,
                          2345108766317314046,
                          146226256843603965,
                          4,
                          5191102230068953088,
                          2345108766317314046,
                          5191102230068953088,
                          5188850460319711232,
                          5188850460319776768,
                          5188850460319842304,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020467,
                          5198983563776262144,
                          1,
                          5198983563776327680,
                          1,
                          5198983563776393216,
                          1,
                          5198983563776458752,
                          3618502788666131213697322783095070105623107215331596699973092056135872020480,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020463,
                          2345108766317314046,
                          5189976364521848832,
                          0,
                          5189976364521848832,
                          0,
                          5189976364521848832,
                          0,
                          5191102247248822272,
                          5191102238658887680,
                          290341444919459839,
                          1,
                          145944781866893311,
                          4,
                          74168662805676031,
                          58,
                          5188287510366486528,
                          5201798304953368576,
                          4611826758062997503,
                          5188287514661322752,
                          5201798304953303040,
                          4611826762357833727,
                          4611826766652801016,
                          5188287523251191808,
                          5188287518956093440,
                          5201798304953696256,
                          4611826783832473599,
                          5188287527545962496,
                          5188287523250864128,
                          5201798304953696256,
                          4611826788127244287,
                          5188287531840733184,
                          4611826792422146047,
                          5188287549020536832,
                          5188287527545569280,
                          5201798304953696256,
                          4611826809601818623,
                          5188287553315307520,
                          5188287531840339968,
                          5201798304953696256,
                          4611826813896589311,
                          5188287557610078208,
                          4611826818191491071,
                          5188287574789881856,
                          5188287536135045120,
                          5201798304953696256,
                          4611826835371163647,
                          5188287579084652544,
                          5188287540429815808,
                          5201798304953696256,
                          4611826839665934335,
                          5188287583379423232,
                          4611826843960836095,
                          5188287600559226880,
                          5188287544724520960,
                          5201798304953696256,
                          4611826861140508671,
                          5188287604853997568,
                          5188287549019291648,
                          5201798304953696256,
                          4611826865435279359,
                          5188287609148768256,
                          4611826869730181119,
                          5188287626328571904,
                          5188287630623473664,
                          5188287634918375424,
                          5198420613820743680,
                          10,
                          5198420613820743680,
                          30,
                          74168662805676031,
                          3618502788666131213697322783095070105623107215331596699973092056135872020421,
                          290341444919459839,
                          1,
                          145944781866893311,
                          4,
                          74168662805676031,
                          18,
                          5188287510366420992,
                          5201798304953303040,
                          4611826758062931967,
                          5188287514661257216,
                          5201798304953237504,
                          4611826762357768191,
                          4611826766652735479,
                          5188287523251126272,
                          5188287527546028032,
                          5188287531840929792,
                          5198420613822513152,
                          2,
                          5198420613822513152,
                          6,
                          74168662805676031,
                          3618502788666131213697322783095070105623107215331596699973092056135872020399,
                          5200109442208464896,
                          5201798287773958143,
                          145944781866893311,
                          11,
                          5198420613822644224,
                          1,
                          4611826758062866431,
                          4611826762357833719,
                          4611826766652801016,
                          5198420613822840832,
                          6,
                          5188287523251126272,
                          2345108766317314046,
                          4613515612218425343,
                          1,
                          5188287510366289920,
                          5201798304953171968,
                          4611826758062800895,
                          5198420613822578688,
                          1,
                          4611826762357702655,
                          4611826766652669942,
                          5198420613822709760,
                          6,
                          5188287523250995200,
                          2345108766317314046,
                          5188850460319907840,
                          5202361254907052032,
                          5191102242953854976,
                          5188287510366552064,
                          5188287506071519232,
                          5188287510366486527,
                          4611826762357964797,
                          5198420613822906368,
                          3618502788666131213697322783095070105623107215331596699973092056135872020480,
                          5198420613822906368,
                          3,
                          5188287518956224512,
                          4623085744246521853,
                          145944781866893308,
                          3618502788666131213697322783095070105623107215331596699973092056135872020472,
                          2345108766317314046,
                          5198983563776458752,
                          3618502788666131213697322783095070105623107215331596699973092056135872020480,
                          145944781866893311,
                          12,
                          5191102238658887680,
                          5188850460319842304,
                          5198983563776393216,
                          1,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020339,
                          5191102234363920384,
                          5193354047062507520,
                          5193354047062507520,
                          2345108766317314046,
                          5191102234363920384,
                          5191102242953854976,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020449,
                          5193354051357474816,
                          5191102238658887680,
                          5193354047062507520,
                          2345108766317314046,
                          290341444919459839,
                          30,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020248,
                          4617174774030761984,
                          4612671182992932866,
                          5189976364521848832,
                          0,
                          4612389712311713791,
                          5188850464614612992,
                          5188850490384416768,
                          5191102264428691456,
                          5191102247248822272,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020446,
                          4612389712311779327,
                          4622804286450008067,
                          4,
                          4612671195878359044,
                          5200109476568596480,
                          5188850468910104576,
                          4625619027626983429,
                          4622804286450073606,
                          2,
                          4617174761145860103,
                          4612671191582867464,
                          4612671195877834761,
                          4612671200172802058,
                          4612671204467769355,
                          4612671208762736652,
                          4617174765440827405,
                          4612671217352671246,
                          4612671221647638543,
                          4612671225942605840,
                          5191102238658887680,
                          5198983563776655360,
                          6,
                          5189976364521848832,
                          11,
                          5191102273018626048,
                          5191102277313593344,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020241,
                          1191342862550269952,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020207,
                          4623648724266090495,
                          5191102238658887680,
                          5198983563776655360,
                          18,
                          5191102273018626048,
                          5191102333148168192,
                          5189976364521848832,
                          11,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020202,
                          4623648719970271231,
                          5191102234363920384,
                          5198983563776655360,
                          6,
                          5198983563776655360,
                          18,
                          5191102242953854976,
                          5189976364521848832,
                          11,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020239,
                          4623930190653653010,
                          4612671182993522717,
                          5198983563776655360,
                          18,
                          5193354051357474816,
                          2345108766317314046,
                          290341444919459839,
                          35,
                          4622804286449090561,
                          1,
                          4614922931267403778,
                          4614922982807011331,
                          4614922939857338372,
                          4614922944152305669,
                          4614922948447272966,
                          4614922952742240263,
                          4614922957037207560,
                          4614922961332174857,
                          4614922965627142154,
                          4614922969922109451,
                          4613797087195136012,
                          122550255383924,
                          4613797087195136013,
                          8098989891770344814,
                          4613797087195136014,
                          138277649577220228665140075,
                          4613797087195136015,
                          435459224417,
                          4613797087195136016,
                          27700496658166629,
                          4613797087195136017,
                          435458895728,
                          4613797087195136018,
                          118083203326315,
                          4613797087195136019,
                          8101821134059892590,
                          4613797087195136020,
                          9062164042692704905798619969846,
                          4613797087195136021,
                          27413455001448292,
                          4613797087195136022,
                          30809880779386724,
                          4613797087195136023,
                          1,
                          4613797087195136024,
                          3,
                          4613797087195136025,
                          1,
                          4613797087195136026,
                          2,
                          4613797087195136027,
                          5,
                          4613797087195136028,
                          7,
                          4613797087195136029,
                          16,
                          4613797087195136030,
                          6,
                          4613797087195136031,
                          1,
                          4613797087195136032,
                          7,
                          4613797087195136033,
                          7,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020119,
                          5198420613823102976,
                          1,
                          5191102212889083904,
                          5198420613822971904,
                          12,
                          5198420613822906368,
                          23,
                          5188850460319252480,
                          1226245742482522112,
                          38,
                          4614641507830300671,
                          4617174774030762018,
                          5188850468912267264,
                          5201798300658860031,
                          5189976364521848832,
                          64,
                          1226245742482522112,
                          14,
                          5188850460322332672,
                          5188850464617299968,
                          5188850468912267264,
                          5188850473207234560,
                          5188850477502201856,
                          5188850481797169152,
                          5188850486092136448,
                          5188850490387103744,
                          5188850494682071040,
                          5188850498977038336,
                          5188850503272005632,
                          2345108766317314046,
                          146226256843603965,
                          5,
                          4613797087195135996,
                          0,
                          2345108766317314046,
                          290341444919459839,
                          1,
                          5201798304953761792,
                          5202079779930537980,
                          4634344751905079295,
                          5193354047062507520,
                          5198983563776458752,
                          3618502788666131213697322783095070105623107215331596699973092056135872020480,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020468,
                          2345108766317314046,
                          146226256843603965,
                          5,
                          5191102230068953088,
                          5191102234363920384,
                          2345108766317314046,
                          290341444919459839,
                          1,
                          5191102230068953088,
                          5191102234363920384,
                          5191102238658887680,
                          5191102242953854976,
                          5193354038472572928,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020290,
                          5191102238658887680,
                          5191102242953854976,
                          5198983563776458752,
                          3618502788666131213697322783095070105623107215331596699973092056135872020480,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020463,
                          2345108766317314046,
                          4612671182993129469,
                          5198983563776393216,
                          1,
                          2345108766317314046,
                          5191102238658887680,
                          5199827967231950845,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020475,
                          2345108766317314046,
                          5191102238658887680,
                          5191102242953854976,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020470,
                          5191102242953854976,
                          5191102247248822272,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020470,
                          2345108766317314046,
                          290341444919459839,
                          1,
                          5191102230068953088,
                          5191102260133724160,
                          5198983563776393216,
                          3618502788666131213697322783095070105623107215331596699973092056135872020480,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020466,
                          5209116658642944000,
                          5202361254906855424,
                          4612108233039904765,
                          5193354047062507520,
                          5193354051357474816,
                          2345108766317314046,
                          4612671182993063932,
                          4612671187288031229,
                          5198983563776327680,
                          3,
                          5188850468909711360,
                          2345108766317314046,
                          290341444919459839,
                          2,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020010,
                          4613797087195136000,
                          0,
                          4613797087195136001,
                          0,
                          5193354051357474816,
                          2345108766317314046,
                          290341444919459839,
                          2,
                          5191102234363920384,
                          5191102242953854976,
                          5191102247248822272,
                          5188850460319776768,
                          1226245742482522112,
                          16,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872019994,
                          4617174769735794688,
                          5188850464614744064,
                          4623367219223429121,
                          5193354038472572928,
                          5193354042767540224,
                          2345108766317314046,
                          5191102242953854976,
                          5188850460319907840,
                          5188850464614875136,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020446,
                          2345108766317314046,
                          146226256843603964,
                          5,
                          5191102234363920384,
                          5191102247248822272,
                          2345108766317314046,
                          290341444919459839,
                          1,
                          5198983563776393216,
                          3618502788666131213697322783095070105623107215331596699973092056135872020480,
                          4626181977580208128,
                          5191102238658887680,
                          5191102234363920384,
                          5191102247248822272,
                          5202079771340603392,
                          4611826758063063038,
                          5188287510366420992,
                          4611826762357964799,
                          5198420613822906368,
                          1,
                          5198420613822906368,
                          3,
                          5188287518956224512,
                          145944781866893307,
                          3618502788666131213697322783095070105623107215331596699973092056135872020472,
                          2345108766317314046,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020424,
                          5191102238658887680,
                          5193354051357474816,
                          5191102242953854976,
                          5191102247248822272,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020428,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020442,
                          2345108766317314046,
                          146226256843603965,
                          3,
                          2345108766317314046,
                          5191102238658887680,
                          5191102242953854976,
                          5188287510366617600,
                          4611826758063063039,
                          5198420613823037441,
                          1,
                          5198420613823037441,
                          1,
                          722405534170316798,
                          3618502788666131213697322783095070105623107215331596699973092056135872020475,
                          4623648689905041407,
                          2345108766317314046,
                          290341444919459839,
                          14,
                          5191102260133724160,
                          5191102208594116608,
                          5191102212889083904,
                          5191102217184051200,
                          5191102221479018496,
                          5191102225773985792,
                          5191102230068953088,
                          5191102234363920384,
                          5191102238658887680,
                          5191102242953854976,
                          5191102247248822272,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020220,
                          4617174743965990913,
                          4617174748260958210,
                          4617174752555925507,
                          4617174756850892804,
                          4617174761145860101,
                          4617174765440827398,
                          4617174769735794695,
                          4617174774030761992,
                          4617174778325729289,
                          4617174735376056330,
                          4614922926972436492,
                          5191102204299149312,
                          5193354012702769152,
                          5191102307378364416,
                          1226245742482522112,
                          75,
                          4617174774030761997,
                          5198420613823102976,
                          1,
                          5193354051357474816,
                          5191102285903527936,
                          5191102264428691456,
                          5189976364521848832,
                          0,
                          5198983563776655360,
                          1,
                          5191102307378364416,
                          5188850460320104448,
                          5191102311673331712,
                          1226245742482522112,
                          16,
                          4617174778325729290,
                          4612389708017532926,
                          5193354034177605632,
                          5193354034177605632,
                          5193354038472572928,
                          5191102268723658752,
                          5191102273018626048,
                          5191102277313593344,
                          5191102281608560640,
                          5193354012702769152,
                          5191102290198495232,
                          5191102294493462528,
                          5191102298788429824,
                          2345108766317314046,
                          146226256843603964,
                          9,
                          5191102212889083904,
                          5191102217184051200,
                          5191102221479018496,
                          5191102225773985792,
                          5191102230068953088,
                          5191102234363920384,
                          2345108766317314046,
                          290341444919459839,
                          0,
                          290341444919459839,
                          1,
                          145944781866893311,
                          14,
                          5191102212889083904,
                          5191102217184051200,
                          5191102221479018496,
                          5191102225773985792,
                          5191102230068953088,
                          5191102234363920384,
                          5191102238658887680,
                          5191102247248822272,
                          1226245742482522112,
                          39,
                          74168662805676031,
                          12,
                          5191102212889083904,
                          5191102217184051200,
                          5191102221479018496,
                          5191102225773985792,
                          5191102230068953088,
                          5191102234363920384,
                          5191102238658887680,
                          5191102247248822272,
                          1226245742482522112,
                          74,
                          5191102238658887680,
                          5198983563776393216,
                          3618502788666131213697322783095070105623107215331596699973092056135872020480,
                          5191102247248822272,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020440,
                          2345108766317314046,
                          5188850460319907840,
                          4612389708016353279,
                          5188850473204809728,
                          4612389712311320575,
                          5191102242953854976,
                          5188850468909842432,
                          5188850464614875136,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020344,
                          4612389716606287871,
                          5198983563776327680,
                          3,
                          5193354047062507520,
                          2345108766317314046,
                          5198983563776458752,
                          2,
                          5191102247248822272,
                          2345108766317314046,
                          290341444919459839,
                          4,
                          5191102225773985792,
                          5191102264428691456,
                          5191102260133724160,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872019877,
                          5191102238658887680,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020469,
                          5189976364521848832,
                          4,
                          4611826758063128575,
                          5191102230068953088,
                          5188850468909776896,
                          5189976364521848832,
                          1,
                          5188850464614809600,
                          5188287514661257216,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020237,
                          5188850460319842304,
                          4611826758060965887,
                          4611826762355933145,
                          4622241336494227458,
                          2,
                          4614922982807011331,
                          5191102217184051200,
                          5191102221479018496,
                          5193353879558782976,
                          5193354034177605632,
                          5191102234363920384,
                          5198983563776655360,
                          1,
                          5191102242953854976,
                          5188850460320104448,
                          5191102247248822272,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020382,
                          4623648711380271103,
                          5193354034177605632,
                          5193354034177605632,
                          5193354034177605632,
                          5193354034177605632,
                          5193354034177605632,
                          5191102268723658752,
                          2345108766317314046,
                          290341444919459839,
                          4,
                          5191102238658887680,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020427,
                          4617174774030761984,
                          5188287514661584896,
                          5188850473204744192,
                          5201798304953827326,
                          145944781866893311,
                          16,
                          4613797087195136003,
                          4,
                          5188287510366420992,
                          4623648719970074623,
                          4612671182993391618,
                          5198983563776655360,
                          1,
                          5191102247248822272,
                          5189976364521848832,
                          3,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020276,
                          74168662805676031,
                          6,
                          4612108233039708161,
                          4612108237334675458,
                          4613797087195136003,
                          0,
                          4612671182992736257,
                          4612671187287703554,
                          5198983563776000000,
                          2,
                          5200109472273432576,
                          5198983563776720896,
                          3618502788666131213697322783095070105623107215331596699973092056135872020479,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020261,
                          5198983563776000000,
                          2,
                          5198983563776720896,
                          3618502788666131213697322783095070105623107215331596699973092056135872020479,
                          5200109472273432576,
                          5198983563776720896,
                          3618502788666131213697322783095070105623107215331596699973092056135872020479,
                          5201798296363630592,
                          5191102221479018496,
                          5191102225773985792,
                          5191102230068953088,
                          5198983563776262144,
                          1,
                          5201798283478532096,
                          2345108766317314046,
                          5191102204299149312,
                          5191102208594116608,
                          5191102212889083904,
                          5191102217184051200,
                          5191102221479018496,
                          5191102225773985792,
                          5191102230068953088,
                          5191102234363920384,
                          5191102238658887680,
                          5191102242953854976,
                          5191102247248822272,
                          1226245742482522112,
                          3618502788666131213697322783095070105623107215331596699973092056135872020248,
                          2345108766317314046
                      ];
                  }
              }
              // ---------- End of auto-generated code. ----------
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              abstract contract CairoVerifierContract {
                  function verifyProofExternal(
                      uint256[] calldata proofParams,
                      uint256[] calldata proof,
                      uint256[] calldata publicInput
                  ) external virtual;
                  /*
                    Returns information that is related to the layout.
                    publicMemoryOffset is the offset of the public memory pages' information in the public input.
                    selectedBuiltins is a bit-map of builtins that are present in the layout.
                  */
                  function getLayoutInfo()
                      external
                      pure
                      virtual
                      returns (uint256 publicMemoryOffset, uint256 selectedBuiltins);
                  uint256 internal constant OUTPUT_BUILTIN_BIT = 0;
                  uint256 internal constant PEDERSEN_BUILTIN_BIT = 1;
                  uint256 internal constant RANGE_CHECK_BUILTIN_BIT = 2;
                  uint256 internal constant ECDSA_BUILTIN_BIT = 3;
                  uint256 internal constant BITWISE_BUILTIN_BIT = 4;
                  uint256 internal constant EC_OP_BUILTIN_BIT = 5;
                  uint256 internal constant KECCAK_BUILTIN_BIT = 6;
                  uint256 internal constant POSEIDON_BUILTIN_BIT = 7;
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // ---------- The following code was auto-generated. PLEASE DO NOT EDIT. ----------
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "./PageInfo.sol";
              contract CpuPublicInputOffsetsBase is PageInfo {
                  // The following constants are offsets of data expected in the public input.
                  uint256 internal constant OFFSET_N_VERIFIER_FRIENDLY_LAYERS = 0;
                  uint256 internal constant OFFSET_LOG_N_STEPS = 1;
                  uint256 internal constant OFFSET_RC_MIN = 2;
                  uint256 internal constant OFFSET_RC_MAX = 3;
                  uint256 internal constant OFFSET_LAYOUT_CODE = 4;
                  uint256 internal constant OFFSET_PROGRAM_BEGIN_ADDR = 5;
                  uint256 internal constant OFFSET_PROGRAM_STOP_PTR = 6;
                  uint256 internal constant OFFSET_EXECUTION_BEGIN_ADDR = 7;
                  uint256 internal constant OFFSET_EXECUTION_STOP_PTR = 8;
                  uint256 internal constant OFFSET_OUTPUT_BEGIN_ADDR = 9;
                  uint256 internal constant OFFSET_OUTPUT_STOP_PTR = 10;
                  uint256 internal constant OFFSET_PEDERSEN_BEGIN_ADDR = 11;
                  uint256 internal constant OFFSET_PEDERSEN_STOP_PTR = 12;
                  uint256 internal constant OFFSET_RANGE_CHECK_BEGIN_ADDR = 13;
                  uint256 internal constant OFFSET_RANGE_CHECK_STOP_PTR = 14;
                  // The program segment starts from 1, so that memory address 0 is kept for the null pointer.
                  uint256 internal constant INITIAL_PC = 1;
                  // The first Cairo instructions are:
                  //   ap += n_args; call main; jmp rel 0.
                  // As the first two instructions occupy 2 cells each, the "jmp rel 0" instruction is at
                  // offset 4 relative to INITIAL_PC.
                  uint256 internal constant FINAL_PC = INITIAL_PC + 4;
              }
              // ---------- End of auto-generated code. ----------
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "../interfaces/IQueryableFactRegistry.sol";
              contract FactRegistry is IQueryableFactRegistry {
                  // Mapping: fact hash -> true.
                  mapping(bytes32 => bool) private verifiedFact;
                  // Indicates whether the Fact Registry has at least one fact registered.
                  bool anyFactRegistered = false;
                  /*
                    Checks if a fact was registered.
                  */
                  function isValid(bytes32 fact) external view virtual override returns (bool) {
                      return internalIsValid(fact);
                  }
                  /*
                    The internal implementation that checks if the fact was registered.
                  */
                  function internalIsValid(bytes32 fact) internal view virtual returns (bool) {
                      return verifiedFact[fact];
                  }
                  function registerFact(bytes32 factHash) internal {
                      // This function stores the fact hash in the mapping.
                      verifiedFact[factHash] = true;
                      // Mark first time off.
                      if (!anyFactRegistered) {
                          anyFactRegistered = true;
                      }
                  }
                  /*
                    Indicates whether at least one fact was registered.
                  */
                  function hasRegisteredFact() external view override returns (bool) {
                      return anyFactRegistered;
                  }
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "../../components/ReferableFactRegistry.sol";
              import "../cpu/CpuPublicInputOffsetsBase.sol";
              /*
                A utility contract to parse the GPS output.
                See registerGpsFacts for more details.
              */
              contract GpsOutputParser is CpuPublicInputOffsetsBase, ReferableFactRegistry {
                  uint256 internal constant METADATA_TASKS_OFFSET = 1;
                  uint256 internal constant METADATA_OFFSET_TASK_OUTPUT_SIZE = 0;
                  uint256 internal constant METADATA_OFFSET_TASK_PROGRAM_HASH = 1;
                  uint256 internal constant METADATA_OFFSET_TASK_N_TREE_PAIRS = 2;
                  uint256 internal constant METADATA_TASK_HEADER_SIZE = 3;
                  uint256 internal constant METADATA_OFFSET_TREE_PAIR_N_PAGES = 0;
                  uint256 internal constant METADATA_OFFSET_TREE_PAIR_N_NODES = 1;
                  uint256 internal constant NODE_STACK_OFFSET_HASH = 0;
                  uint256 internal constant NODE_STACK_OFFSET_END = 1;
                  // The size of each node in the node stack.
                  uint256 internal constant NODE_STACK_ITEM_SIZE = 2;
                  uint256 internal constant FIRST_CONTINUOUS_PAGE_INDEX = 1;
                  /*
                    Logs the program output fact together with the relevant continuous memory pages' hashes.
                    The event is emitted for each registered fact.
                  */
                  event LogMemoryPagesHashes(bytes32 programOutputFact, bytes32[] pagesHashes);
                  constructor(address refFactRegistry, uint256 referralDuration)
                      public
                      ReferableFactRegistry(refFactRegistry, referralDuration)
                  {}
                  /*
                    Parses the GPS program output (using taskMetadata, which should be verified by the caller),
                    and registers the facts of the tasks which were executed.
                    The first entry in taskMetadata is the number of tasks.
                    For each task, the structure is as follows:
                      1. Size (including the size and hash fields).
                      2. Program hash.
                      3. The number of pairs in the Merkle tree structure (see below).
                      4. The Merkle tree structure (see below).
                    The fact of each task is stored as a (non-binary) Merkle tree.
                    Leaf nodes are labeled with the hash of their data.
                    Each non-leaf node is labeled as 1 + the hash of (node0, end0, node1, end1, ...)
                    where node* is a label of a child children and end* is the total number of data words up to
                    and including that node and its children (including the previous sibling nodes).
                    We add 1 to the result of the hash to prevent an attacker from using a preimage of a leaf node
                    as a preimage of a non-leaf hash and vice versa.
                    The structure of the tree is passed as a list of pairs (n_pages, n_nodes), and the tree is
                    constructed using a stack of nodes (initialized to an empty stack) by repeating for each pair:
                    1. Add n_pages to the stack of nodes.
                    2. Pop the top n_nodes, construct a parent node for them, and push it back to the stack.
                    After applying the steps above, the stack much contain exactly one node, which will
                    constitute the root of the Merkle tree.
                    For example, [(2, 2)] will create a Merkle tree with a root and two direct children, while
                    [(3, 2), (0, 2)] will create a Merkle tree with a root whose left child is a leaf and
                    right child has two leaf children.
                    Assumptions: taskMetadata and cairoAuxInput are verified externally.
                  */
                  function registerGpsFacts(
                      uint256[] calldata taskMetadata,
                      uint256[] memory publicMemoryPages,
                      uint256 outputStartAddress
                  ) internal {
                      uint256 totalNumPages = publicMemoryPages[0];
                      // Allocate some of the loop variables here to avoid the stack-too-deep error.
                      uint256 task;
                      uint256 nTreePairs;
                      uint256 nTasks = taskMetadata[0];
                      // Contains fact hash with the relevant memory pages' hashes.
                      // Size is bounded from above with the total number of pages. Three extra places are
                      // dedicated for the fact hash and the array address and length.
                      uint256[] memory pageHashesLogData = new uint256[](totalNumPages + 3);
                      // Relative address to the beginning of the memory pages' hashes in the array.
                      pageHashesLogData[1] = 0x40;
                      uint256 taskMetadataOffset = METADATA_TASKS_OFFSET;
                      // Skip the first 6 output cells, which contain the bootloader config (3 cells), the number
                      // of tasks and the size and program hash of the first task. curAddr points to the output of
                      // the first task.
                      uint256 curAddr = outputStartAddress + 6;
                      // Skip the main page.
                      uint256 curPage = FIRST_CONTINUOUS_PAGE_INDEX;
                      // Bound the size of the stack by the total number of pages.
                      // TODO(lior, 15/04/2022): Get a better bound on the size of the stack.
                      uint256[] memory nodeStack = new uint256[](NODE_STACK_ITEM_SIZE * totalNumPages);
                      // Copy to memory to workaround the "stack too deep" error.
                      uint256[] memory taskMetadataCopy = taskMetadata;
                      uint256[PAGE_INFO_SIZE] memory pageInfoPtr;
                      assembly {
                          // Skip the array length and the first page.
                          pageInfoPtr := add(add(publicMemoryPages, 0x20), PAGE_INFO_SIZE_IN_BYTES)
                      }
                      // Register the fact for each task.
                      for (task = 0; task < nTasks; task++) {
                          uint256 curOffset = 0;
                          uint256 firstPageOfTask = curPage;
                          nTreePairs = taskMetadataCopy[taskMetadataOffset + METADATA_OFFSET_TASK_N_TREE_PAIRS];
                          // Build the Merkle tree using a stack (see the function documentation) to compute
                          // the fact.
                          uint256 nodeStackLen = 0;
                          for (uint256 treePair = 0; treePair < nTreePairs; treePair++) {
                              // Add nPages to the stack of nodes.
                              uint256 nPages = taskMetadataCopy[
                                  taskMetadataOffset +
                                      METADATA_TASK_HEADER_SIZE +
                                      2 *
                                      treePair +
                                      METADATA_OFFSET_TREE_PAIR_N_PAGES
                              ];
                              // Ensure 'nPages' is bounded from above as a sanity check
                              // (the bound is somewhat arbitrary).
                              require(nPages < 2**20, "Invalid value of n_pages in tree structure.");
                              for (uint256 i = 0; i < nPages; i++) {
                                  (uint256 pageSize, uint256 pageHash) = pushPageToStack(
                                      pageInfoPtr,
                                      curAddr,
                                      curOffset,
                                      nodeStack,
                                      nodeStackLen
                                  );
                                  pageHashesLogData[curPage - firstPageOfTask + 3] = pageHash;
                                  curPage += 1;
                                  nodeStackLen += 1;
                                  curAddr += pageSize;
                                  curOffset += pageSize;
                                  assembly {
                                      pageInfoPtr := add(pageInfoPtr, PAGE_INFO_SIZE_IN_BYTES)
                                  }
                              }
                              // Pop the top n_nodes, construct a parent node for them, and push it back to the
                              // stack.
                              uint256 nNodes = taskMetadataCopy[
                                  taskMetadataOffset +
                                      METADATA_TASK_HEADER_SIZE +
                                      2 *
                                      treePair +
                                      METADATA_OFFSET_TREE_PAIR_N_NODES
                              ];
                              if (nNodes != 0) {
                                  nodeStackLen = constructNode(nodeStack, nodeStackLen, nNodes);
                              }
                          }
                          require(nodeStackLen == 1, "Node stack must contain exactly one item.");
                          uint256 programHash = taskMetadataCopy[
                              taskMetadataOffset + METADATA_OFFSET_TASK_PROGRAM_HASH
                          ];
                          // Verify that the sizes of the pages correspond to the task output, to make
                          // sure that the computed hash is indeed the hash of the entire output of the task.
                          {
                              uint256 outputSize = taskMetadataCopy[
                                  taskMetadataOffset + METADATA_OFFSET_TASK_OUTPUT_SIZE
                              ];
                              require(
                                  nodeStack[NODE_STACK_OFFSET_END] + 2 == outputSize,
                                  "The sum of the page sizes does not match output size."
                              );
                          }
                          uint256 programOutputFact = nodeStack[NODE_STACK_OFFSET_HASH];
                          bytes32 fact = keccak256(abi.encode(programHash, programOutputFact));
                          // Update taskMetadataOffset.
                          taskMetadataOffset += METADATA_TASK_HEADER_SIZE + 2 * nTreePairs;
                          {
                              // Log the output Merkle root with the hashes of the relevant memory pages.
                              // Instead of emit, we use log1 https://docs.soliditylang.org/en/v0.4.24/assembly.html,
                              // https://docs.soliditylang.org/en/v0.6.2/abi-spec.html#use-of-dynamic-types.
                              bytes32 logHash = keccak256("LogMemoryPagesHashes(bytes32,bytes32[])");
                              assembly {
                                  let buf := add(pageHashesLogData, 0x20)
                                  // Number of memory pages that are relevant for this fact.
                                  let length := sub(curPage, firstPageOfTask)
                                  mstore(buf, programOutputFact)
                                  mstore(add(buf, 0x40), length)
                                  log1(buf, mul(add(length, 3), 0x20), logHash)
                              }
                          }
                          registerFact(fact);
                          // Move curAddr to the output of the next task (skipping the size and hash fields).
                          curAddr += 2;
                      }
                      require(totalNumPages == curPage, "Not all memory pages were processed.");
                  }
                  /*
                    Push one page (curPage) to the top of the node stack.
                    curAddr is the memory address, curOffset is the offset from the beginning of the task output.
                    Verifies that the page has the right start address and returns the page size and the page
                    hash.
                  */
                  function pushPageToStack(
                      uint256[PAGE_INFO_SIZE] memory pageInfoPtr,
                      uint256 curAddr,
                      uint256 curOffset,
                      uint256[] memory nodeStack,
                      uint256 nodeStackLen
                  ) private pure returns (uint256 pageSize, uint256 pageHash) {
                      // Read the first address, page size and hash.
                      uint256 pageAddr = pageInfoPtr[PAGE_INFO_ADDRESS_OFFSET];
                      pageSize = pageInfoPtr[PAGE_INFO_SIZE_OFFSET];
                      pageHash = pageInfoPtr[PAGE_INFO_HASH_OFFSET];
                      // Ensure 'pageSize' is bounded as a sanity check (the bound is somewhat arbitrary).
                      require(pageSize < 2**30, "Invalid page size.");
                      require(pageAddr == curAddr, "Invalid page address.");
                      nodeStack[NODE_STACK_ITEM_SIZE * nodeStackLen + NODE_STACK_OFFSET_END] =
                          curOffset +
                          pageSize;
                      nodeStack[NODE_STACK_ITEM_SIZE * nodeStackLen + NODE_STACK_OFFSET_HASH] = pageHash;
                  }
                  /*
                    Pops the top nNodes nodes from the stack and pushes one parent node instead.
                    Returns the new value of nodeStackLen.
                  */
                  function constructNode(
                      uint256[] memory nodeStack,
                      uint256 nodeStackLen,
                      uint256 nNodes
                  ) private pure returns (uint256) {
                      require(nNodes <= nodeStackLen, "Invalid value of n_nodes in tree structure.");
                      // The end of the node is the end of the last child.
                      uint256 newNodeEnd = nodeStack[
                          NODE_STACK_ITEM_SIZE * (nodeStackLen - 1) + NODE_STACK_OFFSET_END
                      ];
                      uint256 newStackLen = nodeStackLen - nNodes;
                      // Compute node hash.
                      uint256 nodeStart = 0x20 + newStackLen * NODE_STACK_ITEM_SIZE * 0x20;
                      uint256 newNodeHash;
                      assembly {
                          newNodeHash := keccak256(
                              add(nodeStack, nodeStart),
                              mul(
                                  nNodes,
                                  // NODE_STACK_ITEM_SIZE * 0x20 =
                                  0x40
                              )
                          )
                      }
                      nodeStack[NODE_STACK_ITEM_SIZE * newStackLen + NODE_STACK_OFFSET_END] = newNodeEnd;
                      // Add one to the new node hash to distinguish it from the hash of a leaf (a page).
                      nodeStack[NODE_STACK_ITEM_SIZE * newStackLen + NODE_STACK_OFFSET_HASH] = newNodeHash + 1;
                      return newStackLen + 1;
                  }
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "../cpu/CairoBootloaderProgram.sol";
              import "../cpu/CairoVerifierContract.sol";
              import "../cpu/MemoryPageFactRegistry.sol";
              import "../../interfaces/Identity.sol";
              import "../PrimeFieldElement0.sol";
              import "./GpsOutputParser.sol";
              contract GpsStatementVerifier is
                  GpsOutputParser,
                  Identity,
                  CairoBootloaderProgramSize,
                  PrimeFieldElement0
              {
                  CairoBootloaderProgram bootloaderProgramContractAddress;
                  MemoryPageFactRegistry memoryPageFactRegistry;
                  CairoVerifierContract[] cairoVerifierContractAddresses;
                  uint256 internal constant N_BUILTINS = 11;
                  uint256 internal constant N_MAIN_ARGS = N_BUILTINS;
                  uint256 internal constant N_MAIN_RETURN_VALUES = N_BUILTINS;
                  // Cairo verifier program hash.
                  uint256 immutable hashedSupportedCairoVerifiers_;
                  // Simple bootloader program hash.
                  uint256 immutable simpleBootloaderProgramHash_;
                  // Applicative bootloader program hash.
                  uint256 immutable applicativeBootloaderProgramHash_;
                  /*
                    Constructs an instance of GpsStatementVerifier.
                    bootloaderProgramContract is the address of the bootloader program contract
                    and cairoVerifierContracts is a list of cairoVerifiers indexed by their id.
                  */
                  constructor(
                      address bootloaderProgramContract,
                      address memoryPageFactRegistry_,
                      address[] memory cairoVerifierContracts,
                      uint256 simpleBootloaderProgramHash,
                      uint256 applicativeBootloaderProgramHash,
                      uint256 hashedSupportedCairoVerifiers,
                      address referenceVerifier,
                      uint256 referralDurationSeconds
                  ) public GpsOutputParser(referenceVerifier, referralDurationSeconds) {
                      bootloaderProgramContractAddress = CairoBootloaderProgram(bootloaderProgramContract);
                      memoryPageFactRegistry = MemoryPageFactRegistry(memoryPageFactRegistry_);
                      cairoVerifierContractAddresses = new CairoVerifierContract[](cairoVerifierContracts.length);
                      for (uint256 i = 0; i < cairoVerifierContracts.length; ++i) {
                          cairoVerifierContractAddresses[i] = CairoVerifierContract(cairoVerifierContracts[i]);
                      }
                      hashedSupportedCairoVerifiers_ = hashedSupportedCairoVerifiers;
                      simpleBootloaderProgramHash_ = simpleBootloaderProgramHash;
                      applicativeBootloaderProgramHash_ = applicativeBootloaderProgramHash;
                  }
                  function identify() external pure override returns (string memory) {
                      return "StarkWare_GpsStatementVerifier_2024_10";
                  }
                  /*
                    Returns the bootloader config.
                  */
                  function getBootloaderConfig()
                      external
                      view
                      returns (
                          uint256,
                          uint256,
                          uint256
                      )
                  {
                      return (
                          simpleBootloaderProgramHash_,
                          applicativeBootloaderProgramHash_,
                          hashedSupportedCairoVerifiers_
                      );
                  }
                  /*
                    Verifies a proof and registers the corresponding facts.
                    For the structure of cairoAuxInput, see cpu/CpuPublicInputOffsets.sol.
                    taskMetadata is structured as follows:
                    1. Number of tasks.
                    2. For each task:
                       1. Task output size (including program hash and size).
                       2. Program hash.
                  */
                  function verifyProofAndRegister(
                      uint256[] calldata proofParams,
                      uint256[] calldata proof,
                      uint256[] calldata taskMetadata,
                      uint256[] calldata cairoAuxInput,
                      uint256 cairoVerifierId
                  ) external {
                      require(
                          cairoVerifierId < cairoVerifierContractAddresses.length,
                          "cairoVerifierId is out of range."
                      );
                      CairoVerifierContract cairoVerifier = cairoVerifierContractAddresses[cairoVerifierId];
                      // The values z and alpha are used only for the fact registration of the main page.
                      // They are not part of the public input of CpuVerifier as they are computed there.
                      // Take the relevant slice from 'cairoAuxInput'.
                      uint256[] calldata cairoPublicInput = (
                          cairoAuxInput[:cairoAuxInput.length -
                              // z and alpha.
                              2]
                      );
                      uint256[] memory publicMemoryPages;
                      {
                          (uint256 publicMemoryOffset, uint256 selectedBuiltins) = cairoVerifier.getLayoutInfo();
                          require(cairoAuxInput.length > publicMemoryOffset, "Invalid cairoAuxInput length.");
                          publicMemoryPages = (uint256[])(cairoPublicInput[publicMemoryOffset:]);
                          uint256 nPages = publicMemoryPages[0];
                          require(nPages < 10000, "Invalid nPages.");
                          // Validate publicMemoryPages.length.
                          // Each page has a page info and a cumulative product.
                          // There is no 'page address' in the page info for page 0, but this 'free' slot is
                          // used to store the number of pages.
                          require(
                              publicMemoryPages.length == nPages * (PAGE_INFO_SIZE + 1),
                              "Invalid publicMemoryPages length."
                          );
                          // Process public memory.
                          (
                              uint256 publicMemoryLength,
                              uint256 memoryHash,
                              uint256 prod
                          ) = registerPublicMemoryMainPage(taskMetadata, cairoAuxInput, selectedBuiltins);
                          // Make sure the first page is valid.
                          // If the size or the hash are invalid, it may indicate that there is a mismatch
                          // between the prover and the verifier on the bootloader program or bootloader config.
                          require(
                              publicMemoryPages[PAGE_INFO_SIZE_OFFSET] == publicMemoryLength,
                              "Invalid size for memory page 0."
                          );
                          require(
                              publicMemoryPages[PAGE_INFO_HASH_OFFSET] == memoryHash,
                              "Invalid hash for memory page 0."
                          );
                          require(
                              publicMemoryPages[nPages * PAGE_INFO_SIZE] == prod,
                              "Invalid cumulative product for memory page 0."
                          );
                      }
                      // NOLINTNEXTLINE: reentrancy-benign.
                      cairoVerifier.verifyProofExternal(proofParams, proof, (uint256[])(cairoPublicInput));
                      registerGpsFacts(taskMetadata, publicMemoryPages, cairoAuxInput[OFFSET_OUTPUT_BEGIN_ADDR]);
                  }
                  /*
                    Registers the fact for memory page 0, which includes:
                    1. The bootloader program,
                    2. Arguments and return values of main()
                    3. Some of the data required for computing the task facts. which is represented in
                       taskMetadata.
                    Returns information on the registered fact.
                    Arguments:
                      selectedBuiltins: A bit-map of builtins that are present in the layout.
                          See CairoVerifierContract.sol for more information.
                      taskMetadata: Per task metadata.
                      cairoAuxInput: Auxiliary input for the cairo verifier.
                    Assumptions: cairoAuxInput is connected to the public input, which is verified by
                    cairoVerifierContractAddresses.
                    Guarantees: taskMetadata is consistent with the public memory, with some sanity checks.
                  */
                  function registerPublicMemoryMainPage(
                      uint256[] calldata taskMetadata,
                      uint256[] calldata cairoAuxInput,
                      uint256 selectedBuiltins
                  )
                      private
                      returns (
                          uint256 publicMemoryLength,
                          uint256 memoryHash,
                          uint256 prod
                      )
                  {
                      uint256 nTasks = taskMetadata[0];
                      // Ensure 'nTasks' is bounded as a sanity check (the bound is somewhat arbitrary).
                      require(nTasks < 2**30, "Invalid number of tasks.");
                      // Public memory length.
                      publicMemoryLength = (PROGRAM_SIZE +
                          // return fp and pc =
                          2 +
                          N_MAIN_ARGS +
                          N_MAIN_RETURN_VALUES +
                          // Bootloader config size =
                          3 +
                          // Number of tasks cell =
                          1 +
                          2 *
                          nTasks);
                      uint256[] memory publicMemory = new uint256[](MEMORY_PAIR_SIZE * publicMemoryLength);
                      uint256 offset = 0;
                      // Write public memory, which is a list of pairs (address, value).
                      {
                          // Program segment.
                          uint256[PROGRAM_SIZE] memory bootloaderProgram = bootloaderProgramContractAddress
                              .getCompiledProgram();
                          for (uint256 i = 0; i < bootloaderProgram.length; i++) {
                              // Force that memory[i + INITIAL_PC] = bootloaderProgram[i].
                              publicMemory[offset] = i + INITIAL_PC;
                              publicMemory[offset + 1] = bootloaderProgram[i];
                              offset += 2;
                          }
                      }
                      {
                          // Execution segment - Make sure [initial_fp - 2] = initial_fp and .
                          // This is required for the "safe call" feature (that is, all "call" instructions will
                          // return, even if the called function is malicious).
                          // It guarantees that it's not possible to create a cycle in the call stack.
                          uint256 initialFp = cairoAuxInput[OFFSET_EXECUTION_BEGIN_ADDR];
                          require(initialFp >= 2, "Invalid execution begin address.");
                          publicMemory[offset + 0] = initialFp - 2;
                          publicMemory[offset + 1] = initialFp;
                          // Make sure [initial_fp - 1] = 0.
                          publicMemory[offset + 2] = initialFp - 1;
                          publicMemory[offset + 3] = 0;
                          offset += 4;
                          // Execution segment: Enforce main's arguments and return values.
                          // Note that the page hash depends on the order of the (address, value) pair in the
                          // publicMemory and consequently the arguments must be written before the return values.
                          uint256 returnValuesAddress = cairoAuxInput[OFFSET_EXECUTION_STOP_PTR] - N_BUILTINS;
                          uint256 builtinSegmentInfoOffset = OFFSET_OUTPUT_BEGIN_ADDR;
                          for (uint256 i = 0; i < N_BUILTINS; i++) {
                              // Write argument address.
                              publicMemory[offset] = initialFp + i;
                              uint256 returnValueOffset = offset + 2 * N_BUILTINS;
                              // Write return value address.
                              publicMemory[returnValueOffset] = returnValuesAddress + i;
                              // Write values.
                              if ((selectedBuiltins & 1) != 0) {
                                  // Set the argument to the builtin start pointer.
                                  publicMemory[offset + 1] = cairoAuxInput[builtinSegmentInfoOffset];
                                  // Set the return value to the builtin stop pointer.
                                  publicMemory[returnValueOffset + 1] = cairoAuxInput[
                                      builtinSegmentInfoOffset + 1
                                  ];
                                  builtinSegmentInfoOffset += 2;
                              } else {
                                  // Builtin is not present in layout, set the argument value and return value to 0.
                                  publicMemory[offset + 1] = 0;
                                  publicMemory[returnValueOffset + 1] = 0;
                              }
                              offset += 2;
                              selectedBuiltins >>= 1;
                          }
                          require(selectedBuiltins == 0, "SELECTED_BUILTINS_VECTOR_IS_TOO_LONG");
                          // Skip the return values which were already written.
                          offset += 2 * N_BUILTINS;
                      }
                      // Program output.
                      {
                          {
                              uint256 outputAddress = cairoAuxInput[OFFSET_OUTPUT_BEGIN_ADDR];
                              // Force that memory[outputAddress: outputAddress + 3] contain the bootloader config
                              // (which is 3 words size).
                              publicMemory[offset + 0] = outputAddress;
                              publicMemory[offset + 1] = simpleBootloaderProgramHash_;
                              publicMemory[offset + 2] = outputAddress + 1;
                              publicMemory[offset + 3] = applicativeBootloaderProgramHash_;
                              publicMemory[offset + 4] = outputAddress + 2;
                              publicMemory[offset + 5] = hashedSupportedCairoVerifiers_;
                              // Force that memory[outputAddress + 3] = nTasks.
                              publicMemory[offset + 6] = outputAddress + 3;
                              publicMemory[offset + 7] = nTasks;
                              offset += 8;
                              outputAddress += 4;
                              uint256[] calldata taskMetadataSlice = taskMetadata[METADATA_TASKS_OFFSET:];
                              for (uint256 task = 0; task < nTasks; task++) {
                                  uint256 outputSize = taskMetadataSlice[METADATA_OFFSET_TASK_OUTPUT_SIZE];
                                  // Ensure 'outputSize' is at least 2 and bounded from above as a sanity check
                                  // (the bound is somewhat arbitrary).
                                  require(2 <= outputSize && outputSize < 2**30, "Invalid task output size.");
                                  uint256 programHash = taskMetadataSlice[METADATA_OFFSET_TASK_PROGRAM_HASH];
                                  uint256 nTreePairs = taskMetadataSlice[METADATA_OFFSET_TASK_N_TREE_PAIRS];
                                  // Ensure 'nTreePairs' is at least 1 and bounded from above as a sanity check
                                  // (the bound is somewhat arbitrary).
                                  require(
                                      1 <= nTreePairs && nTreePairs < 2**20,
                                      "Invalid number of pairs in the Merkle tree structure."
                                  );
                                  // Force that memory[outputAddress] = outputSize.
                                  publicMemory[offset + 0] = outputAddress;
                                  publicMemory[offset + 1] = outputSize;
                                  // Force that memory[outputAddress + 1] = programHash.
                                  publicMemory[offset + 2] = outputAddress + 1;
                                  publicMemory[offset + 3] = programHash;
                                  offset += 4;
                                  outputAddress += outputSize;
                                  taskMetadataSlice = taskMetadataSlice[METADATA_TASK_HEADER_SIZE +
                                      2 *
                                      nTreePairs:];
                              }
                              require(taskMetadataSlice.length == 0, "Invalid length of taskMetadata.");
                              require(
                                  cairoAuxInput[OFFSET_OUTPUT_STOP_PTR] == outputAddress,
                                  "Inconsistent program output length."
                              );
                          }
                      }
                      require(publicMemory.length == offset, "Not all Cairo public inputs were written.");
                      uint256 z = cairoAuxInput[cairoAuxInput.length - 2];
                      uint256 alpha = cairoAuxInput[cairoAuxInput.length - 1];
                      bytes32 factHash;
                      (factHash, memoryHash, prod) = memoryPageFactRegistry.registerRegularMemoryPage(
                          publicMemory,
                          z,
                          alpha,
                          K_MODULUS
                      );
                  }
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity >=0.6.12;
              /*
                The Fact Registry design pattern is a way to separate cryptographic verification from the
                business logic of the contract flow.
                A fact registry holds a hash table of verified "facts" which are represented by a hash of claims
                that the registry hash check and found valid. This table may be queried by accessing the
                isValid() function of the registry with a given hash.
                In addition, each fact registry exposes a registry specific function for submitting new claims
                together with their proofs. The information submitted varies from one registry to the other
                depending of the type of fact requiring verification.
                For further reading on the Fact Registry design pattern see this
                `StarkWare blog post <https://medium.com/starkware/the-fact-registry-a64aafb598b6>`_.
              */
              interface IFactRegistry {
                  /*
                    Returns true if the given fact was previously registered in the contract.
                  */
                  function isValid(bytes32 fact) external view returns (bool);
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              struct MemoryPageEntry {
                  uint256 startAddr;
                  uint256[] values;
                  uint256 z;
                  uint256 alpha;
                  uint256 prime;
              }
              interface IMemoryPageRegistry {
                  function registerContinuousMemoryPage(
                      uint256 startAddr,
                      uint256[] memory values,
                      uint256 z,
                      uint256 alpha,
                      uint256 prime
                  )
                      external
                      returns (
                          bytes32,
                          uint256,
                          uint256
                      );
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "./IFactRegistry.sol";
              /*
                Extends the IFactRegistry interface with a query method that indicates
                whether the fact registry has successfully registered any fact or is still empty of such facts.
              */
              interface IQueryableFactRegistry is IFactRegistry {
                  /*
                    Returns true if at least one fact has been registered.
                  */
                  function hasRegisteredFact() external view returns (bool);
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity >=0.6.12;
              interface Identity {
                  /*
                    Allows a caller to ensure that the provided address is of the expected type and version.
                  */
                  function identify() external pure returns (string memory);
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              pragma experimental ABIEncoderV2;
              import "./IMemoryPageRegistry.sol";
              import "../../components/FactRegistry.sol";
              contract MemoryPageFactRegistryConstants {
                  // A page based on a list of pairs (address, value).
                  // In this case, memoryHash = hash(address, value, address, value, address, value, ...).
                  uint256 internal constant REGULAR_PAGE = 0;
                  // A page based on adjacent memory cells, starting from a given address.
                  // In this case, memoryHash = hash(value, value, value, ...).
                  uint256 internal constant CONTINUOUS_PAGE = 1;
              }
              /*
                A fact registry for the claim:
                  I know n pairs (addr, value) for which the hash of the pairs is memoryHash, and the cumulative
                  product: \\prod_i( z - (addr_i + alpha * value_i) ) is prod.
                The exact format of the hash depends on the type of the page
                (see MemoryPageFactRegistryConstants).
                The fact consists of (pageType, prime, n, z, alpha, prod, memoryHash, address).
                Note that address is only available for CONTINUOUS_PAGE, and otherwise it is 0.
              */
              contract MemoryPageFactRegistry is
                  FactRegistry,
                  MemoryPageFactRegistryConstants,
                  IMemoryPageRegistry
              {
                  event LogMemoryPageFactRegular(bytes32 factHash, uint256 memoryHash, uint256 prod);
                  event LogMemoryPageFactContinuous(bytes32 factHash, uint256 memoryHash, uint256 prod);
                  /*
                    Registers a fact based of the given memory (address, value) pairs (REGULAR_PAGE).
                  */
                  function registerRegularMemoryPage(
                      uint256[] calldata memoryPairs,
                      uint256 z,
                      uint256 alpha,
                      uint256 prime
                  )
                      external
                      returns (
                          bytes32 factHash,
                          uint256 memoryHash,
                          uint256 prod
                      )
                  {
                      // Ensure 'memoryPairs.length' is bounded as a sanity check (the bound is somewhat arbitrary).
                      require(memoryPairs.length < 2**20, "Too many memory values.");
                      require(memoryPairs.length % 2 == 0, "Size of memoryPairs must be even.");
                      require(z < prime, "Invalid value of z.");
                      require(alpha < prime, "Invalid value of alpha.");
                      (factHash, memoryHash, prod) = computeFactHash(memoryPairs, z, alpha, prime);
                      emit LogMemoryPageFactRegular(factHash, memoryHash, prod);
                      registerFact(factHash);
                  }
                  function computeFactHash(
                      uint256[] memory memoryPairs,
                      uint256 z,
                      uint256 alpha,
                      uint256 prime
                  )
                      private
                      pure
                      returns (
                          bytes32 factHash,
                          uint256 memoryHash,
                          uint256 prod
                      )
                  {
                      uint256 memorySize = memoryPairs.length / 2; // NOLINT: divide-before-multiply.
                      prod = 1;
                      assembly {
                          let memoryPtr := add(memoryPairs, 0x20)
                          // Each value of memoryPairs is a pair: (address, value).
                          let lastPtr := add(memoryPtr, mul(memorySize, 0x40))
                          for {
                              let ptr := memoryPtr
                          } lt(ptr, lastPtr) {
                              ptr := add(ptr, 0x40)
                          } {
                              // Compute address + alpha * value.
                              let address_value_lin_comb := addmod(
                                  // address=
                                  mload(ptr),
                                  mulmod(
                                      // value=
                                      mload(add(ptr, 0x20)),
                                      alpha,
                                      prime
                                  ),
                                  prime
                              )
                              prod := mulmod(prod, add(z, sub(prime, address_value_lin_comb)), prime)
                          }
                          memoryHash := keccak256(
                              memoryPtr,
                              mul(
                                  // 0x20 * 2.
                                  0x40,
                                  memorySize
                              )
                          )
                      }
                      factHash = keccak256(
                          abi.encodePacked(
                              REGULAR_PAGE,
                              prime,
                              memorySize,
                              z,
                              alpha,
                              prod,
                              memoryHash,
                              uint256(0)
                          )
                      );
                  }
                  /*
                    Receives a list of MemoryPageEntry. Each element in the list holds arguments for a seperate
                    call to registerContinuousMemoryPage.
                  */
                  function registerContinuousPageBatch(MemoryPageEntry[] calldata memoryPageEntries) external {
                      for (uint256 i = 0; i < memoryPageEntries.length; i++) {
                          registerContinuousMemoryPage(
                              memoryPageEntries[i].startAddr,
                              memoryPageEntries[i].values,
                              memoryPageEntries[i].z,
                              memoryPageEntries[i].alpha,
                              memoryPageEntries[i].prime
                          );
                      }
                  }
                  /*
                    Registers a fact based on the given values, assuming continuous addresses.
                    values should be [value at startAddr, value at (startAddr + 1), ...].
                  */
                  function registerContinuousMemoryPage(
                      // NOLINT: external-function.
                      uint256 startAddr,
                      uint256[] memory values,
                      uint256 z,
                      uint256 alpha,
                      uint256 prime
                  )
                      public
                      override
                      returns (
                          bytes32 factHash,
                          uint256 memoryHash,
                          uint256 prod
                      )
                  {
                      require(values.length < 2**20, "Too many memory values.");
                      require(prime < 2**254, "prime is too big for the optimizations in this function.");
                      require(z < prime, "Invalid value of z.");
                      require(alpha < prime, "Invalid value of alpha.");
                      // Ensure 'startAddr' less then prime and bounded as a sanity check (the bound is somewhat arbitrary).
                      require((startAddr < prime) && (startAddr < 2**64), "Invalid value of startAddr.");
                      uint256 nValues = values.length;
                      assembly {
                          // Initialize prod to 1.
                          prod := 1
                          // Initialize valuesPtr to point to the first value in the array.
                          let valuesPtr := add(values, 0x20)
                          let minus_z := mod(sub(prime, z), prime)
                          // Start by processing full batches of 8 cells, addr represents the last address in each
                          // batch.
                          let addr := add(startAddr, 7)
                          let lastAddr := add(startAddr, nValues)
                          for {
                          } lt(addr, lastAddr) {
                              addr := add(addr, 8)
                          } {
                              // Compute the product of (lin_comb - z) instead of (z - lin_comb), since we're
                              // doing an even number of iterations, the result is the same.
                              prod := mulmod(
                                  prod,
                                  mulmod(
                                      add(add(sub(addr, 7), mulmod(mload(valuesPtr), alpha, prime)), minus_z),
                                      add(
                                          add(sub(addr, 6), mulmod(mload(add(valuesPtr, 0x20)), alpha, prime)),
                                          minus_z
                                      ),
                                      prime
                                  ),
                                  prime
                              )
                              prod := mulmod(
                                  prod,
                                  mulmod(
                                      add(
                                          add(sub(addr, 5), mulmod(mload(add(valuesPtr, 0x40)), alpha, prime)),
                                          minus_z
                                      ),
                                      add(
                                          add(sub(addr, 4), mulmod(mload(add(valuesPtr, 0x60)), alpha, prime)),
                                          minus_z
                                      ),
                                      prime
                                  ),
                                  prime
                              )
                              prod := mulmod(
                                  prod,
                                  mulmod(
                                      add(
                                          add(sub(addr, 3), mulmod(mload(add(valuesPtr, 0x80)), alpha, prime)),
                                          minus_z
                                      ),
                                      add(
                                          add(sub(addr, 2), mulmod(mload(add(valuesPtr, 0xa0)), alpha, prime)),
                                          minus_z
                                      ),
                                      prime
                                  ),
                                  prime
                              )
                              prod := mulmod(
                                  prod,
                                  mulmod(
                                      add(
                                          add(sub(addr, 1), mulmod(mload(add(valuesPtr, 0xc0)), alpha, prime)),
                                          minus_z
                                      ),
                                      add(add(addr, mulmod(mload(add(valuesPtr, 0xe0)), alpha, prime)), minus_z),
                                      prime
                                  ),
                                  prime
                              )
                              valuesPtr := add(valuesPtr, 0x100)
                          }
                          // Handle leftover.
                          // Translate addr to the beginning of the last incomplete batch.
                          addr := sub(addr, 7)
                          for {
                          } lt(addr, lastAddr) {
                              addr := add(addr, 1)
                          } {
                              let address_value_lin_comb := addmod(
                                  addr,
                                  mulmod(mload(valuesPtr), alpha, prime),
                                  prime
                              )
                              prod := mulmod(prod, add(z, sub(prime, address_value_lin_comb)), prime)
                              valuesPtr := add(valuesPtr, 0x20)
                          }
                          memoryHash := keccak256(add(values, 0x20), mul(0x20, nValues))
                      }
                      factHash = keccak256(
                          abi.encodePacked(CONTINUOUS_PAGE, prime, nValues, z, alpha, prod, memoryHash, startAddr)
                      );
                      emit LogMemoryPageFactContinuous(factHash, memoryHash, prod);
                      registerFact(factHash);
                  }
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              contract PageInfo {
                  uint256 public constant PAGE_INFO_SIZE = 3;
                  // PAGE_INFO_SIZE_IN_BYTES cannot reference PAGE_INFO_SIZE as only direct constants are
                  // supported in assembly.
                  uint256 public constant PAGE_INFO_SIZE_IN_BYTES = 3 * 32;
                  uint256 public constant PAGE_INFO_ADDRESS_OFFSET = 0;
                  uint256 public constant PAGE_INFO_SIZE_OFFSET = 1;
                  uint256 public constant PAGE_INFO_HASH_OFFSET = 2;
                  // A regular page entry is a (address, value) pair stored as 2 uint256 words.
                  uint256 internal constant MEMORY_PAIR_SIZE = 2;
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              contract PrimeFieldElement0 {
                  uint256 internal constant K_MODULUS =
                      0x800000000000011000000000000000000000000000000000000000000000001;
                  uint256 internal constant K_MONTGOMERY_R =
                      0x7fffffffffffdf0ffffffffffffffffffffffffffffffffffffffffffffffe1;
                  uint256 internal constant K_MONTGOMERY_R_INV =
                      0x40000000000001100000000000012100000000000000000000000000000000;
                  uint256 internal constant GENERATOR_VAL = 3;
                  uint256 internal constant ONE_VAL = 1;
                  function fromMontgomery(uint256 val) internal pure returns (uint256 res) {
                      // uint256 res = fmul(val, kMontgomeryRInv);
                      assembly {
                          res := mulmod(val, K_MONTGOMERY_R_INV, K_MODULUS)
                      }
                      return res;
                  }
                  function fromMontgomeryBytes(bytes32 bs) internal pure returns (uint256) {
                      // Assuming bs is a 256bit bytes object, in Montgomery form, it is read into a field
                      // element.
                      uint256 res = uint256(bs);
                      return fromMontgomery(res);
                  }
                  function toMontgomeryInt(uint256 val) internal pure returns (uint256 res) {
                      //uint256 res = fmul(val, kMontgomeryR);
                      assembly {
                          res := mulmod(val, K_MONTGOMERY_R, K_MODULUS)
                      }
                      return res;
                  }
                  function fmul(uint256 a, uint256 b) internal pure returns (uint256 res) {
                      //uint256 res = mulmod(a, b, kModulus);
                      assembly {
                          res := mulmod(a, b, K_MODULUS)
                      }
                      return res;
                  }
                  function fadd(uint256 a, uint256 b) internal pure returns (uint256 res) {
                      // uint256 res = addmod(a, b, kModulus);
                      assembly {
                          res := addmod(a, b, K_MODULUS)
                      }
                      return res;
                  }
                  function fsub(uint256 a, uint256 b) internal pure returns (uint256 res) {
                      // uint256 res = addmod(a, kModulus - b, kModulus);
                      assembly {
                          res := addmod(a, sub(K_MODULUS, b), K_MODULUS)
                      }
                      return res;
                  }
                  function fpow(uint256 val, uint256 exp) internal view returns (uint256) {
                      return expmod(val, exp, K_MODULUS);
                  }
                  function expmod(
                      uint256 base,
                      uint256 exponent,
                      uint256 modulus
                  ) private view returns (uint256 res) {
                      assembly {
                          let p := mload(0x40)
                          mstore(p, 0x20) // Length of Base.
                          mstore(add(p, 0x20), 0x20) // Length of Exponent.
                          mstore(add(p, 0x40), 0x20) // Length of Modulus.
                          mstore(add(p, 0x60), base) // Base.
                          mstore(add(p, 0x80), exponent) // Exponent.
                          mstore(add(p, 0xa0), modulus) // Modulus.
                          // Call modexp precompile.
                          if iszero(staticcall(gas(), 0x05, p, 0xc0, p, 0x20)) {
                              revert(0, 0)
                          }
                          res := mload(p)
                      }
                  }
                  function inverse(uint256 val) internal view returns (uint256) {
                      return expmod(val, K_MODULUS - 2, K_MODULUS);
                  }
              }
              /*
                Copyright 2019-2024 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              // SPDX-License-Identifier: Apache-2.0.
              pragma solidity ^0.6.12;
              import "./FactRegistry.sol";
              import "../libraries/Addresses.sol";
              /*
                ReferableFactRegistry extends FactRegistry,
                so that it can be deployed with a reference FactRegistry.
                The reference FactRegistry is used as a secondary fact registry.
                When the contract is queried for fact validity using isValid(),
                if the queried fact is not in the local fact registry, the call is passed to the reference.
                The reference FactRegistry is active only for a pre-defined duration (in seconds).
                After that duration expires, the reference FactRegistry can not be queried anymore.
              */
              contract ReferableFactRegistry is FactRegistry {
                  IFactRegistry public referenceFactRegistry;
                  uint256 public referralExpirationTime;
                  using Addresses for address;
                  constructor(address refFactRegistry, uint256 referralDurationSeconds) public {
                      // Allow 0 address, i.e. no referral.
                      if (refFactRegistry != address(0)) {
                          referenceFactRegistry = IFactRegistry(refFactRegistry);
                          // NOLINTNEXTLINE: no-block-members.
                          referralExpirationTime = block.timestamp + referralDurationSeconds;
                          require(referralExpirationTime >= block.timestamp, "DURATION_WRAP_AROUND");
                          require(refFactRegistry.isContract(), "REFERENCE_NOT_CONTRACT");
                          require(refFactRegistry != address(this), "SELF_ASSIGNMENT");
                          // NOLINTNEXTLINE: reentrancy-benign no-low-level-calls.
                          (bool success, ) = refFactRegistry.staticcall(
                              abi.encodeWithSelector(
                                  IFactRegistry(refFactRegistry).isValid.selector,
                                  bytes32(0x0)
                              )
                          );
                          require(success, "REFERENCE_NOT_FACT_REGISTRY");
                      }
                  }
                  /*
                    Checks if a fact was registered.
                  */
                  function isValid(bytes32 fact) external view virtual override returns (bool) {
                      if (internalIsValid(fact)) {
                          return true;
                      }
                      return isValidOnReference(fact);
                  }
                  /*
                    Checks if the fact is stored in the local fact registry.
                  */
                  function localIsValid(bytes32 fact) external view returns (bool) {
                      return internalIsValid(fact);
                  }
                  function isReferralActive() internal view returns (bool) {
                      // solium-disable-next-line security/no-block-members
                      return block.timestamp < referralExpirationTime;
                  }
                  /*
                    Checks if a fact has been verified by the reference IFactRegistry.
                  */
                  function isValidOnReference(bytes32 fact) internal view returns (bool) {
                      if (!isReferralActive()) {
                          return false;
                      }
                      return referenceFactRegistry.isValid(fact);
                  }
              }
              

              File 8 of 9: Committee
              {"Committee.sol":{"content":"/*\n  Copyright 2019,2020 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// Solidity 0.5.4 has this bug: https://github.com/ethereum/solidity/issues/5997\n// It\u0027s already fixed: https://github.com/ethereum/solidity/pull/6000 and will be released in 0.5.5.\npragma solidity ^0.5.2;\n\nimport \"FactRegistry.sol\";\nimport \"Identity.sol\";\n\ncontract Committee is FactRegistry, Identity {\n\n    uint256 constant SIGNATURE_LENGTH = 32 * 2 + 1; // r(32) + s(32) +  v(1).\n    uint256 public signaturesRequired;\n    mapping (address =\u003e bool) public isMember;\n\n    /// @dev Contract constructor sets initial members and required number of signatures.\n    /// @param committeeMembers List of committee members.\n    /// @param numSignaturesRequired Number of required signatures.\n    constructor (address[] memory committeeMembers, uint256 numSignaturesRequired)\n        public\n    {\n        require(numSignaturesRequired \u003c= committeeMembers.length, \"TOO_MANY_REQUIRED_SIGNATURES\");\n        for (uint256 idx = 0; idx \u003c committeeMembers.length; idx++) {\n            require(!isMember[committeeMembers[idx]], \"NON_UNIQUE_COMMITTEE_MEMBERS\");\n            isMember[committeeMembers[idx]] = true;\n        }\n        signaturesRequired = numSignaturesRequired;\n    }\n\n    function identify()\n        external pure\n        returns(string memory)\n    {\n        return \"StarkWare_Committee_2019_1\";\n    }\n\n    /// @dev Verifies the availability proof. Reverts if invalid.\n    /// An availability proof should have a form of a concatenation of ec-signatures by signatories.\n    /// Signatures should be sorted by signatory address ascendingly.\n    /// Signatures should be 65 bytes long. r(32) + s(32) + v(1).\n    /// There should be at least the number of required signatures as defined in this contract\n    /// and all signatures provided should be from signatories.\n    ///\n    /// See :sol:mod:`AvailabilityVerifiers` for more information on when this is used.\n    ///\n    /// @param claimHash The hash of the claim the committee is signing on.\n    /// The format is keccak256(abi.encodePacked(\n    ///    newVaultRoot, vaultTreeHeight, newOrderRoot, orderTreeHeight sequenceNumber))\n    /// @param availabilityProofs Concatenated ec signatures by committee members.\n    function verifyAvailabilityProof(\n        bytes32 claimHash,\n        bytes calldata availabilityProofs\n    )\n        external\n    {\n        require(\n            availabilityProofs.length \u003e= signaturesRequired * SIGNATURE_LENGTH,\n            \"INVALID_AVAILABILITY_PROOF_LENGTH\");\n\n        uint256 offset = 0;\n        address prevRecoveredAddress = address(0);\n        for (uint256 proofIdx = 0; proofIdx \u003c signaturesRequired; proofIdx++) {\n            bytes32 r = bytesToBytes32(availabilityProofs, offset);\n            bytes32 s = bytesToBytes32(availabilityProofs, offset + 32);\n            uint8 v = uint8(availabilityProofs[offset + 64]);\n            offset += SIGNATURE_LENGTH;\n            address recovered = ecrecover(\n                claimHash,\n                v,\n                r,\n                s\n            );\n            // Signatures should be sorted off-chain before submitting to enable cheap uniqueness\n            // check on-chain.\n            require(isMember[recovered], \"AVAILABILITY_PROVER_NOT_IN_COMMITTEE\");\n            require(recovered \u003e prevRecoveredAddress, \"NON_SORTED_SIGNATURES\");\n            prevRecoveredAddress = recovered;\n        }\n        registerFact(claimHash);\n    }\n\n    function bytesToBytes32(bytes memory array, uint256 offset)\n        private pure\n        returns (bytes32 result) {\n        // Arrays are prefixed by a 256 bit length parameter.\n        uint256 actualOffset = offset + 32;\n\n        // Read the bytes32 from array memory.\n        // solium-disable-next-line security/no-inline-assembly\n        assembly {\n            result := mload(add(array, actualOffset))\n        }\n    }\n}\n"},"FactRegistry.sol":{"content":"/*\n  Copyright 2019,2020 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\npragma solidity ^0.5.2;\n\nimport \"IQueryableFactRegistry.sol\";\n\ncontract FactRegistry is IQueryableFactRegistry {\n    // Mapping: fact hash -\u003e true.\n    mapping (bytes32 =\u003e bool) private verifiedFact;\n\n    // Indicates whether the Fact Registry has at least one fact registered.\n    bool anyFactRegistered;\n\n    /*\n      Checks if a fact has been verified.\n    */\n    function isValid(bytes32 fact)\n        external view\n        returns(bool)\n    {\n        return _factCheck(fact);\n    }\n\n\n    /*\n      This is an internal method to check if the fact is already registered.\n      In current implementation of FactRegistry it\u0027s identical to isValid().\n      But the check is against the local fact registry,\n      So for a derived referral fact registry, it\u0027s not the same.\n    */\n    function _factCheck(bytes32 fact)\n        internal view\n        returns(bool)\n    {\n        return verifiedFact[fact];\n    }\n\n    function registerFact(\n        bytes32 factHash\n        )\n        internal\n    {\n        // This function stores the fact hash in the mapping.\n        verifiedFact[factHash] = true;\n\n        // Mark first time off.\n        if (!anyFactRegistered) {\n            anyFactRegistered = true;\n        }\n    }\n\n    /*\n      Indicates whether at least one fact was registered.\n    */\n    function hasRegisteredFact()\n        external view\n        returns(bool)\n    {\n        return anyFactRegistered;\n    }\n\n}\n"},"Identity.sol":{"content":"/*\n  Copyright 2019,2020 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\npragma solidity ^0.5.2;\n\ncontract Identity {\n\n    /*\n      Allows a caller, typically another contract,\n      to ensure that the provided address is of the expected type and version.\n    */\n    function identify()\n        external pure\n        returns(string memory);\n}\n"},"IFactRegistry.sol":{"content":"/*\n  Copyright 2019,2020 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\npragma solidity ^0.5.2;\n\n/*\n  The Fact Registry design pattern is a way to separate cryptographic verification from the\n  business logic of the contract flow.\n\n  A fact registry holds a hash table of verified \"facts\" which are represented by a hash of claims\n  that the registry hash check and found valid. This table may be queried by accessing the\n  isValid() function of the registry with a given hash.\n\n  In addition, each fact registry exposes a registry specific function for submitting new claims\n  together with their proofs. The information submitted varies from one registry to the other\n  depending of the type of fact requiring verification.\n\n  For further reading on the Fact Registry design pattern see this\n  `StarkWare blog post \u003chttps://medium.com/starkware/the-fact-registry-a64aafb598b6\u003e`_.\n*/\ncontract IFactRegistry {\n    /*\n      Returns true if the given fact was previously registered in the contract.\n    */\n    function isValid(bytes32 fact)\n        external view\n        returns(bool);\n}\n"},"IQueryableFactRegistry.sol":{"content":"/*\n  Copyright 2019,2020 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\npragma solidity ^0.5.2;\n\nimport \"IFactRegistry.sol\";\n\n/*\n  Extends the IFactRegistry interface with a query method that indicates\n  whether the fact registry has successfully registered any fact or is still empty of such facts.\n*/\ncontract IQueryableFactRegistry is IFactRegistry {\n\n    /*\n      Returns true if at least one fact has been registered.\n    */\n    function hasRegisteredFact()\n        external view\n        returns(bool);\n\n}\n"}}

              File 9 of 9: TransferRegistry
              /*
                Copyright 2019,2020 StarkWare Industries Ltd.
                Licensed under the Apache License, Version 2.0 (the "License").
                You may not use this file except in compliance with the License.
                You may obtain a copy of the License at
                https://www.starkware.co/open-source-license/
                Unless required by applicable law or agreed to in writing,
                software distributed under the License is distributed on an "AS IS" BASIS,
                WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                See the License for the specific language governing permissions
                and limitations under the License.
              */
              
              pragma solidity ^0.6.2;
              
              
              interface IFactRegistry {
                  /*
                    Returns true if the given fact was previously registered in the contract.
                  */
                  function isValid(bytes32 fact)
                      external view
                      returns(bool);
              }
              
              /*
                Extends the IFactRegistry interface with a query method that indicates
                whether the fact registry has successfully registered any fact or is still empty of such facts.
              */
              interface IQueryableFactRegistry is IFactRegistry {
              
                  /*
                    Returns true if at least one fact has been registered.
                  */
                  function hasRegisteredFact()
                      external view
                      returns(bool);
              
              }
              
              
              contract FactRegistry is IQueryableFactRegistry {
                  // Mapping: fact hash -> true.
                  mapping (bytes32 => bool) private verifiedFact;
              
                  // Indicates whether the Fact Registry has at least one fact registered.
                  bool anyFactRegistered;
              
                  /*
                    Checks if a fact has been verified.
                  */
                  function isValid(bytes32 fact)
                      external view override
                      returns(bool)
                  {
                      return _factCheck(fact);
                  }
              
              
                  /*
                    This is an internal method to check if the fact is already registered.
                    In current implementation of FactRegistry it's identical to isValid().
                    But the check is against the local fact registrey,
                    So for a derived referral fact registry, it's not the same.
                  */
                  function _factCheck(bytes32 fact)
                      internal view
                      returns(bool)
                  {
                      return verifiedFact[fact];
                  }
              
                  function registerFact(
                      bytes32 factHash
                      )
                      internal
                  {
                      // This function stores the fact hash in the mapping.
                      verifiedFact[factHash] = true;
              
                      // Mark first time off.
                      if (!anyFactRegistered) {
                          anyFactRegistered = true;
                      }
                  }
              
                  /*
                    Indicates whether at least one fact was registered.
                  */
                  function hasRegisteredFact()
                      external view override
                      returns(bool)
                  {
                      return anyFactRegistered;
                  }
              
              }
              
              interface Identity {
              
                  /*
                    Allows a caller, typically another contract,
                    to ensure that the provided address is of the expected type and version.
                  */
                  function identify()
                      external view
                      returns(string memory);
              }
              
              /**
               * @dev Interface of the ERC20 standard as defined in the EIP.
               */
              interface IERC20 {
                  /**
                   * @dev Returns the amount of tokens in existence.
                   */
                  function totalSupply() external view returns (uint256);
              
                  /**
                   * @dev Returns the amount of tokens owned by `account`.
                   */
                  function balanceOf(address account) external view returns (uint256);
              
                  /**
                   * @dev Moves `amount` tokens from the caller's account to `recipient`.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * Emits a {Transfer} event.
                   */
                  function transfer(address recipient, uint256 amount) external returns (bool);
              
                  /**
                   * @dev Returns the remaining number of tokens that `spender` will be
                   * allowed to spend on behalf of `owner` through {transferFrom}. This is
                   * zero by default.
                   *
                   * This value changes when {approve} or {transferFrom} are called.
                   */
                  function allowance(address owner, address spender) external view returns (uint256);
              
                  /**
                   * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * IMPORTANT: Beware that changing an allowance with this method brings the risk
                   * that someone may use both the old and the new allowance by unfortunate
                   * transaction ordering. One possible solution to mitigate this race
                   * condition is to first reduce the spender's allowance to 0 and set the
                   * desired value afterwards:
                   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                   *
                   * Emits an {Approval} event.
                   */
                  function approve(address spender, uint256 amount) external returns (bool);
              
                  /**
                   * @dev Moves `amount` tokens from `sender` to `recipient` using the
                   * allowance mechanism. `amount` is then deducted from the caller's
                   * allowance.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * Emits a {Transfer} event.
                   */
                  function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
              
                  /**
                   * @dev Emitted when `value` tokens are moved from one account (`from`) to
                   * another (`to`).
                   *
                   * Note that `value` may be zero.
                   */
                  event Transfer(address indexed from, address indexed to, uint256 value);
              
                  /**
                   * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                   * a call to {approve}. `value` is the new allowance.
                   */
                  event Approval(address indexed owner, address indexed spender, uint256 value);
              }
              
              /**
               * @dev Wrappers over Solidity's arithmetic operations with added overflow
               * checks.
               *
               * Arithmetic operations in Solidity wrap on overflow. This can easily result
               * in bugs, because programmers usually assume that an overflow raises an
               * error, which is the standard behavior in high level programming languages.
               * `SafeMath` restores this intuition by reverting the transaction when an
               * operation overflows.
               *
               * Using this library instead of the unchecked operations eliminates an entire
               * class of bugs, so it's recommended to use it always.
               */
              library SafeMath {
                  /**
                   * @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) {
                      uint256 c = a + b;
                      require(c >= a, "SafeMath: addition overflow");
              
                      return c;
                  }
              
                  /**
                   * @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 sub(a, b, "SafeMath: subtraction overflow");
                  }
              
                  /**
                   * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                   * overflow (when the result is negative).
                   *
                   * Counterpart to Solidity's `-` operator.
                   *
                   * Requirements:
                   *
                   * - Subtraction cannot overflow.
                   */
                  function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      require(b <= a, errorMessage);
                      uint256 c = a - b;
              
                      return c;
                  }
              
                  /**
                   * @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) {
                      // 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 0;
                      }
              
                      uint256 c = a * b;
                      require(c / a == b, "SafeMath: multiplication overflow");
              
                      return c;
                  }
              
                  /**
                   * @dev Returns the integer division of two unsigned integers. Reverts 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) internal pure returns (uint256) {
                      return div(a, b, "SafeMath: division by zero");
                  }
              
                  /**
                   * @dev Returns the integer division of two unsigned integers. Reverts 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) {
                      require(b > 0, errorMessage);
                      uint256 c = a / b;
                      // assert(a == b * c + a % b); // There is no case in which this doesn't hold
              
                      return c;
                  }
              
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                   * Reverts 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 mod(a, b, "SafeMath: modulo by zero");
                  }
              
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                   * Reverts with custom message 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, string memory errorMessage) internal pure returns (uint256) {
                      require(b != 0, errorMessage);
                      return a % b;
                  }
              }
              
              
              /**
               * @dev Collection of functions related to the address type
               */
              library Address {
                  /**
                   * @dev Returns true if `account` is a contract.
                   *
                   * [IMPORTANT]
                   * ====
                   * It is unsafe to assume that an address for which this function returns
                   * false is an externally-owned account (EOA) and not a contract.
                   *
                   * Among others, `isContract` will return false for the following
                   * types of addresses:
                   *
                   *  - an externally-owned account
                   *  - a contract in construction
                   *  - an address where a contract will be created
                   *  - an address where a contract lived, but was destroyed
                   * ====
                   */
                  function isContract(address account) internal view returns (bool) {
                      // This method relies in extcodesize, which returns 0 for contracts in
                      // construction, since the code is only stored at the end of the
                      // constructor execution.
              
                      uint256 size;
                      // solhint-disable-next-line no-inline-assembly
                      assembly { size := extcodesize(account) }
                      return size > 0;
                  }
              
                  /**
                   * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                   * `recipient`, forwarding all available gas and reverting on errors.
                   *
                   * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                   * of certain opcodes, possibly making contracts go over the 2300 gas limit
                   * imposed by `transfer`, making them unable to receive funds via
                   * `transfer`. {sendValue} removes this limitation.
                   *
                   * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                   *
                   * IMPORTANT: because control is transferred to `recipient`, care must be
                   * taken to not create reentrancy vulnerabilities. Consider using
                   * {ReentrancyGuard} or the
                   * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                   */
                  function sendValue(address payable recipient, uint256 amount) internal {
                      require(address(this).balance >= amount, "Address: insufficient balance");
              
                      // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                      (bool success, ) = recipient.call{ value: amount }("");
                      require(success, "Address: unable to send value, recipient may have reverted");
                  }
              
                  /**
                   * @dev Performs a Solidity function call using a low level `call`. A
                   * plain`call` is an unsafe replacement for a function call: use this
                   * function instead.
                   *
                   * If `target` reverts with a revert reason, it is bubbled up by this
                   * function (like regular Solidity function calls).
                   *
                   * Returns the raw returned data. To convert to the expected return value,
                   * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                   *
                   * Requirements:
                   *
                   * - `target` must be a contract.
                   * - calling `target` with `data` must not revert.
                   *
                   * _Available since v3.1._
                   */
                  function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionCall(target, data, "Address: low-level call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                   * `errorMessage` as a fallback revert reason when `target` reverts.
                   *
                   * _Available since v3.1._
                   */
                  function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                      return _functionCallWithValue(target, data, 0, errorMessage);
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but also transferring `value` wei to `target`.
                   *
                   * Requirements:
                   *
                   * - the calling contract must have an ETH balance of at least `value`.
                   * - the called Solidity function must be `payable`.
                   *
                   * _Available since v3.1._
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                      return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                   * with `errorMessage` as a fallback revert reason when `target` reverts.
                   *
                   * _Available since v3.1._
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                      require(address(this).balance >= value, "Address: insufficient balance for call");
                      return _functionCallWithValue(target, data, value, errorMessage);
                  }
              
                  function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
                      require(isContract(target), "Address: call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
                      if (success) {
                          return returndata;
                      } else {
                          // Look for revert reason and bubble it up if present
                          if (returndata.length > 0) {
                              // The easiest way to bubble the revert reason is using memory via assembly
              
                              // solhint-disable-next-line no-inline-assembly
                              assembly {
                                  let returndata_size := mload(returndata)
                                  revert(add(32, returndata), returndata_size)
                              }
                          } else {
                              revert(errorMessage);
                          }
                      }
                  }
              }
              
              /**
               * @title SafeERC20
               * @dev Wrappers around ERC20 operations that throw on failure (when the token
               * contract returns false). Tokens that return no value (and instead revert or
               * throw on failure) are also supported, non-reverting calls are assumed to be
               * successful.
               * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
               * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
               */
              library SafeERC20 {
                  using SafeMath for uint256;
                  using Address for address;
              
                  function safeTransfer(IERC20 token, address to, uint256 value) internal {
                      _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
                  }
              
                  function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
                      _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
                  }
              
                  /**
                   * @dev Deprecated. This function has issues similar to the ones found in
                   * {IERC20-approve}, and its usage is discouraged.
                   *
                   * Whenever possible, use {safeIncreaseAllowance} and
                   * {safeDecreaseAllowance} instead.
                   */
                  function safeApprove(IERC20 token, address spender, uint256 value) internal {
                      // safeApprove should only be called when setting an initial allowance,
                      // or when resetting it to zero. To increase and decrease it, use
                      // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
                      // solhint-disable-next-line max-line-length
                      require((value == 0) || (token.allowance(address(this), spender) == 0),
                          "SafeERC20: approve from non-zero to non-zero allowance"
                      );
                      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
                  }
              
                  function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                      uint256 newAllowance = token.allowance(address(this), spender).add(value);
                      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                  }
              
                  function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                      uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
                      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                  }
              
                  /**
                   * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
                   * on the return value: the return value is optional (but if data is returned, it must not be false).
                   * @param token The token targeted by the call.
                   * @param data The call data (encoded using abi.encode or one of its variants).
                   */
                  function _callOptionalReturn(IERC20 token, bytes memory data) private {
                      // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                      // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
                      // the target address contains contract code and also asserts for success in the low-level call.
              
                      bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
                      if (returndata.length > 0) { // Return data is optional
                          // solhint-disable-next-line max-line-length
                          require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
                      }
                  }
              }
              
              contract TransferRegistry is FactRegistry, Identity {
                  using SafeERC20 for IERC20;
              
                  event LogRegisteredTransfer(
                      address recipient,
                      address token,
                      uint256 amount,
                      uint256 salt
                  );
              
                  function identify()
                      external view override
                      returns(string memory)
                  {
                      return "StarkWare_TransferRegistry_2020_1";
                  }
              
                  /*
                    Passes on the transaction ETH value onto the recipient address,
                    and register the associated fact.
                    Reverts if the fact has already been registered.
                  */
                  function transfer(address payable recipient, uint256 salt) // NOLINT: erc20-interface.
                      payable
                      external {
                      bytes32 transferFact = keccak256(
                          abi.encodePacked(recipient, msg.value, address(0x0), salt));
                      require(!_factCheck(transferFact), "TRANSFER_ALREADY_REGISTERED");
                      registerFact(transferFact);
                      emit LogRegisteredTransfer(recipient, address(0x0), msg.value, salt);
                      recipient.transfer(msg.value);
                  }
              
                  /*
                    Transfer the specified amount of erc20 tokens from msg.sender balance to the recipient's
                    balance.
                    Pre-conditions to successful transfer are that the msg.sender has sufficient balance,
                    and the the approval (for the transfer) was granted to this contract.
                    A fact with the transfer details is registered upon success.
                    Reverts if the fact has already been registered.
                  */
                  function transferERC20(address recipient, address erc20, uint256 amount, uint256 salt)
                      external {
                      bytes32 transferFact = keccak256(
                          abi.encodePacked(recipient, amount, erc20, salt));
                      require(!_factCheck(transferFact), "TRANSFER_ALREADY_REGISTERED");
                      registerFact(transferFact);
                      emit LogRegisteredTransfer(recipient, erc20, amount, salt);
                      IERC20(erc20).safeTransferFrom(msg.sender, recipient, amount);
                  }
              
              }