ETH Price: $3,535.84 (+1.62%)

Transaction Decoder

Block:
16928162 at Mar-28-2023 08:19:59 PM +UTC
Transaction Fee:
0.010162289467531326 ETH $35.93
Gas Used:
278,346 Gas / 36.509558131 Gwei

Emitted Events:

168 MiniMeToken.Transfer( _from=[Sender] 0x65a8f07bd9a8598e1b5b6c0a88f4779dbc077675, _to=[Receiver] L1ChugSplashProxy, _amount=858786314735489337618 )
169 CanonicalTransactionChain.TransactionEnqueued( _l1TxOrigin=0x36BDE71C...4f7AB70B2, _target=0x42000000...000000007, _gasLimit=200000, _data=0xCBD4ECE9000000000000000000000000420000000000000000000000000000000000001000000000000000000000000099C9FC46F92E8A1C0DEC1B1747D010903E884BE1000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000503BA00000000000000000000000000000000000000000000000000000000000000E4662A633A000000000000000000000000D0CD466B34A24FCB2F87676278AF2005CA8A78C40000000000000000000000006F0FECBC276DE8FC69257065FE47C5A03D98639400000000000000000000000065A8F07BD9A8598E1B5B6C0A88F4779DBC07767500000000000000000000000065A8F07BD9A8598E1B5B6C0A88F4779DBC07767500000000000000000000000000000000000000000000002E8E0DE334FFA7491200000000000000000000000000000000000000000000000000000000000000C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, _queueIndex=328634, _timestamp=1680034799 )
170 Lib_ResolvedDelegateProxy.0xcb0f7ffd78f9aee47a248fae8db181db6eee833039123e026dcbff529522e52a( 0xcb0f7ffd78f9aee47a248fae8db181db6eee833039123e026dcbff529522e52a, 0x0000000000000000000000004200000000000000000000000000000000000010, 00000000000000000000000099c9fc46f92e8a1c0dec1b1747d010903e884be1, 0000000000000000000000000000000000000000000000000000000000000080, 00000000000000000000000000000000000000000000000000000000000503ba, 0000000000000000000000000000000000000000000000000000000000030d40, 00000000000000000000000000000000000000000000000000000000000000e4, 662a633a000000000000000000000000d0cd466b34a24fcb2f87676278af2005, ca8a78c40000000000000000000000006f0fecbc276de8fc69257065fe47c5a0, 3d98639400000000000000000000000065a8f07bd9a8598e1b5b6c0a88f4779d, bc07767500000000000000000000000065a8f07bd9a8598e1b5b6c0a88f4779d, bc07767500000000000000000000000000000000000000000000002e8e0de334, ffa7491200000000000000000000000000000000000000000000000000000000, 000000c000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
171 L1ChugSplashProxy.0x718594027abd4eaed59f95162563e0cc6d0e8d5b86b1c7be8b1b0ac3343d0396( 0x718594027abd4eaed59f95162563e0cc6d0e8d5b86b1c7be8b1b0ac3343d0396, 0x000000000000000000000000d0cd466b34a24fcb2f87676278af2005ca8a78c4, 0x0000000000000000000000006f0fecbc276de8fc69257065fe47c5a03d986394, 0x00000000000000000000000065a8f07bd9a8598e1b5b6c0a88f4779dbc077675, 00000000000000000000000065a8f07bd9a8598e1b5b6c0a88f4779dbc077675, 00000000000000000000000000000000000000000000002e8e0de334ffa74912, 0000000000000000000000000000000000000000000000000000000000000060, 0000000000000000000000000000000000000000000000000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x5E4e6592...0D24E9dD2
(Optimism: Canonical Transaction Chain)
0x65A8F07B...DBC077675
1.577626642249958786 Eth
Nonce: 74268
1.56746435278242746 Eth
Nonce: 74269
0.010162289467531326
(beaverbuild)
234.645409081491737162 Eth234.64546122611825471 Eth0.000052144626517548
0x99C9fc46...03E884bE1
(Optimism: Gateway)
0xD0Cd466b...5Ca8A78c4

Execution Trace

L1ChugSplashProxy.58a997f6( )
  • Proxy.STATICCALL( )
  • L1StandardBridge.depositERC20( _l1Token=0xD0Cd466b34A24fcB2f87676278AF2005Ca8A78c4, _l2Token=0x6F0fecBC276de8fC69257065fE47C5a03d986394, _amount=858786314735489337618, _l2Gas=200000, _data=0x )
    • MiniMeToken.transferFrom( _from=0x65A8F07Bd9A8598E1b5B6C0a88F4779DBC077675, _to=0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1, _amount=858786314735489337618 ) => ( success=True )
      • AppProxyUpgradeable.4a393149( )
        • KernelProxy.be00bbd8( )
          • Kernel.getApp( _namespace=F1F3EB40F5BC1AD1344716CED8B8A0431D840B5783AEA1FD01786BC26F35AC0F, _appId=6B20A3010614EEEBF2138CCEC99F028A61C811B3B1A3343B6FF635985C75C91F ) => ( 0xde3A93028F2283cc28756B3674BD657eaFB992f4 )
          • TokenManager.onTransfer( _from=0x65A8F07Bd9A8598E1b5B6C0a88F4779DBC077675, _to=0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1, _amount=858786314735489337618 ) => ( True )
            • MiniMeToken.balanceOf( _owner=0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1 ) => ( balance=2056880455884776264535509 )
            • MiniMeToken.balanceOf( _owner=0x65A8F07Bd9A8598E1b5B6C0a88F4779DBC077675 ) => ( balance=858786314735489337618 )
            • Lib_ResolvedDelegateProxy.3dbb202b( )
              • Lib_AddressManager.getAddress( _name=OVM_L1CrossDomainMessenger ) => ( 0xd9166833FF12A5F900ccfBf2c8B62a90F1Ca1FD5 )
              • L1CrossDomainMessenger.sendMessage( _target=0x4200000000000000000000000000000000000010, _message=0x662A633A000000000000000000000000D0CD466B34A24FCB2F87676278AF2005CA8A78C40000000000000000000000006F0FECBC276DE8FC69257065FE47C5A03D98639400000000000000000000000065A8F07BD9A8598E1B5B6C0A88F4779DBC07767500000000000000000000000065A8F07BD9A8598E1B5B6C0A88F4779DBC07767500000000000000000000000000000000000000000000002E8E0DE334FFA7491200000000000000000000000000000000000000000000000000000000000000C00000000000000000000000000000000000000000000000000000000000000000, _gasLimit=200000 )
                • Lib_AddressManager.getAddress( _name=CanonicalTransactionChain ) => ( 0x5E4e65926BA27467555EB562121fac00D24E9dD2 )
                • CanonicalTransactionChain.STATICCALL( )
                • CanonicalTransactionChain.enqueue( _target=0x4200000000000000000000000000000000000007, _gasLimit=200000, _data=0xCBD4ECE9000000000000000000000000420000000000000000000000000000000000001000000000000000000000000099C9FC46F92E8A1C0DEC1B1747D010903E884BE1000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000503BA00000000000000000000000000000000000000000000000000000000000000E4662A633A000000000000000000000000D0CD466B34A24FCB2F87676278AF2005CA8A78C40000000000000000000000006F0FECBC276DE8FC69257065FE47C5A03D98639400000000000000000000000065A8F07BD9A8598E1B5B6C0A88F4779DBC07767500000000000000000000000065A8F07BD9A8598E1B5B6C0A88F4779DBC07767500000000000000000000000000000000000000000000002E8E0DE334FFA7491200000000000000000000000000000000000000000000000000000000000000C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 )
                  File 1 of 14: L1ChugSplashProxy
                  // SPDX-License-Identifier: MIT
                  pragma solidity >0.5.0 <0.8.0;
                  import { iL1ChugSplashDeployer } from "./interfaces/iL1ChugSplashDeployer.sol";
                  /**
                   * @title L1ChugSplashProxy
                   * @dev Basic ChugSplash proxy contract for L1. Very close to being a normal proxy but has added
                   * functions `setCode` and `setStorage` for changing the code or storage of the contract. Nifty!
                   *
                   * Note for future developers: do NOT make anything in this contract 'public' unless you know what
                   * you're doing. Anything public can potentially have a function signature that conflicts with a
                   * signature attached to the implementation contract. Public functions SHOULD always have the
                   * 'proxyCallIfNotOwner' modifier unless there's some *really* good reason not to have that
                   * modifier. And there almost certainly is not a good reason to not have that modifier. Beware!
                   */
                  contract L1ChugSplashProxy {
                      /*************
                       * Constants *
                       *************/
                      // "Magic" prefix. When prepended to some arbitrary bytecode and used to create a contract, the
                      // appended bytecode will be deployed as given.
                      bytes13 constant internal DEPLOY_CODE_PREFIX = 0x600D380380600D6000396000f3;
                      // bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
                      bytes32 constant internal IMPLEMENTATION_KEY = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                      // bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)
                      bytes32 constant internal OWNER_KEY = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                      /***************
                       * Constructor *
                       ***************/
                      
                      /**
                       * @param _owner Address of the initial contract owner.
                       */
                      constructor(
                          address _owner
                      ) {
                          _setOwner(_owner);
                      }
                      /**********************
                       * Function Modifiers *
                       **********************/
                      /**
                       * Blocks a function from being called when the parent signals that the system should be paused
                       * via an isUpgrading function.
                       */
                      modifier onlyWhenNotPaused() {
                          address owner = _getOwner();
                          // We do a low-level call because there's no guarantee that the owner actually *is* an
                          // L1ChugSplashDeployer contract and Solidity will throw errors if we do a normal call and
                          // it turns out that it isn't the right type of contract.
                          (bool success, bytes memory returndata) = owner.staticcall(
                              abi.encodeWithSelector(
                                  iL1ChugSplashDeployer.isUpgrading.selector
                              )
                          );
                          // If the call was unsuccessful then we assume that there's no "isUpgrading" method and we
                          // can just continue as normal. We also expect that the return value is exactly 32 bytes
                          // long. If this isn't the case then we can safely ignore the result.
                          if (success && returndata.length == 32) {
                              // Although the expected value is a *boolean*, it's safer to decode as a uint256 in the
                              // case that the isUpgrading function returned something other than 0 or 1. But we only
                              // really care about the case where this value is 0 (= false).
                              uint256 ret = abi.decode(returndata, (uint256));
                              require(
                                  ret == 0,
                                  "L1ChugSplashProxy: system is currently being upgraded"
                              );
                          }
                          _;
                      }
                      /**
                       * Makes a proxy call instead of triggering the given function when the caller is either the
                       * owner or the zero address. Caller can only ever be the zero address if this function is
                       * being called off-chain via eth_call, which is totally fine and can be convenient for
                       * client-side tooling. Avoids situations where the proxy and implementation share a sighash
                       * and the proxy function ends up being called instead of the implementation one.
                       *
                       * Note: msg.sender == address(0) can ONLY be triggered off-chain via eth_call. If there's a
                       * way for someone to send a transaction with msg.sender == address(0) in any real context then
                       * we have much bigger problems. Primary reason to include this additional allowed sender is
                       * because the owner address can be changed dynamically and we do not want clients to have to
                       * keep track of the current owner in order to make an eth_call that doesn't trigger the
                       * proxied contract.
                       */
                      modifier proxyCallIfNotOwner() {
                          if (msg.sender == _getOwner() || msg.sender == address(0)) {
                              _;
                          } else {
                              // This WILL halt the call frame on completion.
                              _doProxyCall();
                          }
                      }
                      /*********************
                       * Fallback Function *
                       *********************/
                      fallback()
                          external
                          payable
                      {
                          // Proxy call by default.
                          _doProxyCall();
                      }
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * Sets the code that should be running behind this proxy. Note that this scheme is a bit
                       * different from the standard proxy scheme where one would typically deploy the code
                       * separately and then set the implementation address. We're doing it this way because it gives
                       * us a lot more freedom on the client side. Can only be triggered by the contract owner.
                       * @param _code New contract code to run inside this contract.
                       */
                      function setCode(
                          bytes memory _code
                      )
                          proxyCallIfNotOwner
                          public
                      {
                          // Get the code hash of the current implementation.
                          address implementation = _getImplementation();
                          // If the code hash matches the new implementation then we return early.
                          if (keccak256(_code) == _getAccountCodeHash(implementation)) {
                              return;
                          }
                          // Create the deploycode by appending the magic prefix.
                          bytes memory deploycode = abi.encodePacked(
                              DEPLOY_CODE_PREFIX,
                              _code
                          );
                          // Deploy the code and set the new implementation address.
                          address newImplementation;
                          assembly {
                              newImplementation := create(0x0, add(deploycode, 0x20), mload(deploycode))
                          }
                          // Check that the code was actually deployed correctly. I'm not sure if you can ever
                          // actually fail this check. Should only happen if the contract creation from above runs
                          // out of gas but this parent execution thread does NOT run out of gas. Seems like we
                          // should be doing this check anyway though.
                          require(
                              _getAccountCodeHash(newImplementation) == keccak256(_code),
                              "L1ChugSplashProxy: code was not correctly deployed."
                          );
                          _setImplementation(newImplementation);
                      }
                      /**
                       * Modifies some storage slot within the proxy contract. Gives us a lot of power to perform
                       * upgrades in a more transparent way. Only callable by the owner.
                       * @param _key Storage key to modify.
                       * @param _value New value for the storage key.
                       */
                      function setStorage(
                          bytes32 _key,
                          bytes32 _value
                      )
                          proxyCallIfNotOwner
                          public
                      {
                          assembly {
                              sstore(_key, _value)
                          }
                      }
                      /**
                       * Changes the owner of the proxy contract. Only callable by the owner.
                       * @param _owner New owner of the proxy contract.
                       */
                      function setOwner(
                          address _owner
                      )
                          proxyCallIfNotOwner
                          public
                      {
                          _setOwner(_owner);
                      }
                      /**
                       * Queries the owner of the proxy contract. Can only be called by the owner OR by making an
                       * eth_call and setting the "from" address to address(0).
                       * @return Owner address.
                       */
                      function getOwner()
                          proxyCallIfNotOwner
                          public
                          returns (
                              address
                          )
                      {
                          return _getOwner();
                      }
                      /**
                       * Queries the implementation address. Can only be called by the owner OR by making an
                       * eth_call and setting the "from" address to address(0).
                       * @return Implementation address.
                       */
                      function getImplementation()
                          proxyCallIfNotOwner
                          public
                          returns (
                              address
                          )
                      {
                          return _getImplementation();
                      }
                      /**********************
                       * Internal Functions *
                       **********************/
                      /**
                       * Sets the implementation address.
                       * @param _implementation New implementation address.
                       */
                      function _setImplementation(
                          address _implementation
                      )
                          internal
                      {
                          assembly {
                              sstore(IMPLEMENTATION_KEY, _implementation)
                          }
                      }
                      /**
                       * Queries the implementation address.
                       * @return Implementation address.
                       */
                      function _getImplementation()
                          internal
                          view
                          returns (
                              address
                          )
                      {
                          address implementation;
                          assembly {
                              implementation := sload(IMPLEMENTATION_KEY)
                          }
                          return implementation;
                      }
                      /**
                       * Changes the owner of the proxy contract.
                       * @param _owner New owner of the proxy contract.
                       */
                      function _setOwner(
                          address _owner
                      )
                          internal
                      {
                          assembly {
                              sstore(OWNER_KEY, _owner)
                          }
                      }
                      /**
                       * Queries the owner of the proxy contract.
                       * @return Owner address.
                       */
                      function _getOwner()
                          internal
                          view 
                          returns (
                              address
                          )
                      {
                          address owner;
                          assembly {
                              owner := sload(OWNER_KEY)
                          }
                          return owner;
                      }
                      /**
                       * Gets the code hash for a given account.
                       * @param _account Address of the account to get a code hash for.
                       * @return Code hash for the account.
                       */
                      function _getAccountCodeHash(
                          address _account
                      )
                          internal
                          view
                          returns (
                              bytes32
                          )
                      {
                          bytes32 codeHash;
                          assembly {
                              codeHash := extcodehash(_account)
                          }
                          return codeHash;
                      }
                      /**
                       * Performs the proxy call via a delegatecall.
                       */
                      function _doProxyCall()
                          onlyWhenNotPaused
                          internal
                      {
                          address implementation = _getImplementation();
                          require(
                              implementation != address(0),
                              "L1ChugSplashProxy: implementation is not set yet"
                          );
                          assembly {
                              // Copy calldata into memory at 0x0....calldatasize.
                              calldatacopy(0x0, 0x0, calldatasize())
                              // Perform the delegatecall, make sure to pass all available gas.
                              let success := delegatecall(gas(), implementation, 0x0, calldatasize(), 0x0, 0x0)
                              // Copy returndata into memory at 0x0....returndatasize. Note that this *will*
                              // overwrite the calldata that we just copied into memory but that doesn't really
                              // matter because we'll be returning in a second anyway.
                              returndatacopy(0x0, 0x0, returndatasize())
                              
                              // Success == 0 means a revert. We'll revert too and pass the data up.
                              if iszero(success) {
                                  revert(0x0, returndatasize())
                              }
                              // Otherwise we'll just return and pass the data up.
                              return(0x0, returndatasize())
                          }
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >0.5.0 <0.8.0;
                  /**
                   * @title iL1ChugSplashDeployer
                   */
                  interface iL1ChugSplashDeployer {
                      function isUpgrading()
                          external
                          view
                          returns (
                              bool
                          );
                  }
                  

                  File 2 of 14: MiniMeToken
                  pragma solidity ^0.4.24;
                  // File: @aragon/apps-shared-minime/contracts/ITokenController.sol
                  /// @dev The token controller contract must implement these functions
                  
                  
                  interface ITokenController {
                      /// @notice Called when `_owner` sends ether to the MiniMe Token contract
                      /// @param _owner The address that sent the ether to create tokens
                      /// @return True if the ether is accepted, false if it throws
                      function proxyPayment(address _owner) external payable returns(bool);
                  
                      /// @notice Notifies the controller about a token transfer allowing the
                      ///  controller to react if desired
                      /// @param _from The origin of the transfer
                      /// @param _to The destination of the transfer
                      /// @param _amount The amount of the transfer
                      /// @return False if the controller does not authorize the transfer
                      function onTransfer(address _from, address _to, uint _amount) external returns(bool);
                  
                      /// @notice Notifies the controller about an approval allowing the
                      ///  controller to react if desired
                      /// @param _owner The address that calls `approve()`
                      /// @param _spender The spender in the `approve()` call
                      /// @param _amount The amount in the `approve()` call
                      /// @return False if the controller does not authorize the approval
                      function onApprove(address _owner, address _spender, uint _amount) external returns(bool);
                  }
                  // File: @aragon/apps-shared-minime/contracts/MiniMeToken.sol
                  /*
                      Copyright 2016, Jordi Baylina
                      This program is free software: you can redistribute it and/or modify
                      it under the terms of the GNU General Public License as published by
                      the Free Software Foundation, either version 3 of the License, or
                      (at your option) any later version.
                      This program is distributed in the hope that it will be useful,
                      but WITHOUT ANY WARRANTY; without even the implied warranty of
                      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                      GNU General Public License for more details.
                      You should have received a copy of the GNU General Public License
                      along with this program.  If not, see <http://www.gnu.org/licenses/>.
                   */
                  
                  /// @title MiniMeToken Contract
                  /// @author Jordi Baylina
                  /// @dev This token contract's goal is to make it easy for anyone to clone this
                  ///  token using the token distribution at a given block, this will allow DAO's
                  ///  and DApps to upgrade their features in a decentralized manner without
                  ///  affecting the original token
                  /// @dev It is ERC20 compliant, but still needs to under go further testing.
                  
                  
                  contract Controlled {
                      /// @notice The address of the controller is the only address that can call
                      ///  a function with this modifier
                      modifier onlyController {
                          require(msg.sender == controller);
                          _;
                      }
                  
                      address public controller;
                  
                      function Controlled()  public { controller = msg.sender;}
                  
                      /// @notice Changes the controller of the contract
                      /// @param _newController The new controller of the contract
                      function changeController(address _newController) onlyController  public {
                          controller = _newController;
                      }
                  }
                  
                  contract ApproveAndCallFallBack {
                      function receiveApproval(
                          address from,
                          uint256 _amount,
                          address _token,
                          bytes _data
                      ) public;
                  }
                  
                  /// @dev The actual token contract, the default controller is the msg.sender
                  ///  that deploys the contract, so usually this token will be deployed by a
                  ///  token controller contract, which Giveth will call a "Campaign"
                  contract MiniMeToken is Controlled {
                  
                      string public name;                //The Token's name: e.g. DigixDAO Tokens
                      uint8 public decimals;             //Number of decimals of the smallest unit
                      string public symbol;              //An identifier: e.g. REP
                      string public version = "MMT_0.1"; //An arbitrary versioning scheme
                  
                  
                      /// @dev `Checkpoint` is the structure that attaches a block number to a
                      ///  given value, the block number attached is the one that last changed the
                      ///  value
                      struct Checkpoint {
                  
                          // `fromBlock` is the block number that the value was generated from
                          uint128 fromBlock;
                  
                          // `value` is the amount of tokens at a specific block number
                          uint128 value;
                      }
                  
                      // `parentToken` is the Token address that was cloned to produce this token;
                      //  it will be 0x0 for a token that was not cloned
                      MiniMeToken public parentToken;
                  
                      // `parentSnapShotBlock` is the block number from the Parent Token that was
                      //  used to determine the initial distribution of the Clone Token
                      uint public parentSnapShotBlock;
                  
                      // `creationBlock` is the block number that the Clone Token was created
                      uint public creationBlock;
                  
                      // `balances` is the map that tracks the balance of each address, in this
                      //  contract when the balance changes the block number that the change
                      //  occurred is also included in the map
                      mapping (address => Checkpoint[]) balances;
                  
                      // `allowed` tracks any extra transfer rights as in all ERC20 tokens
                      mapping (address => mapping (address => uint256)) allowed;
                  
                      // Tracks the history of the `totalSupply` of the token
                      Checkpoint[] totalSupplyHistory;
                  
                      // Flag that determines if the token is transferable or not.
                      bool public transfersEnabled;
                  
                      // The factory used to create new clone tokens
                      MiniMeTokenFactory public tokenFactory;
                  
                  ////////////////
                  // Constructor
                  ////////////////
                  
                      /// @notice Constructor to create a MiniMeToken
                      /// @param _tokenFactory The address of the MiniMeTokenFactory contract that
                      ///  will create the Clone token contracts, the token factory needs to be
                      ///  deployed first
                      /// @param _parentToken Address of the parent token, set to 0x0 if it is a
                      ///  new token
                      /// @param _parentSnapShotBlock Block of the parent token that will
                      ///  determine the initial distribution of the clone token, set to 0 if it
                      ///  is a new token
                      /// @param _tokenName Name of the new token
                      /// @param _decimalUnits Number of decimals of the new token
                      /// @param _tokenSymbol Token Symbol for the new token
                      /// @param _transfersEnabled If true, tokens will be able to be transferred
                      function MiniMeToken(
                          MiniMeTokenFactory _tokenFactory,
                          MiniMeToken _parentToken,
                          uint _parentSnapShotBlock,
                          string _tokenName,
                          uint8 _decimalUnits,
                          string _tokenSymbol,
                          bool _transfersEnabled
                      )  public
                      {
                          tokenFactory = _tokenFactory;
                          name = _tokenName;                                 // Set the name
                          decimals = _decimalUnits;                          // Set the decimals
                          symbol = _tokenSymbol;                             // Set the symbol
                          parentToken = _parentToken;
                          parentSnapShotBlock = _parentSnapShotBlock;
                          transfersEnabled = _transfersEnabled;
                          creationBlock = block.number;
                      }
                  
                  
                  ///////////////////
                  // ERC20 Methods
                  ///////////////////
                  
                      /// @notice Send `_amount` tokens to `_to` from `msg.sender`
                      /// @param _to The address of the recipient
                      /// @param _amount The amount of tokens to be transferred
                      /// @return Whether the transfer was successful or not
                      function transfer(address _to, uint256 _amount) public returns (bool success) {
                          require(transfersEnabled);
                          return doTransfer(msg.sender, _to, _amount);
                      }
                  
                      /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
                      ///  is approved by `_from`
                      /// @param _from The address holding the tokens being transferred
                      /// @param _to The address of the recipient
                      /// @param _amount The amount of tokens to be transferred
                      /// @return True if the transfer was successful
                      function transferFrom(address _from, address _to, uint256 _amount) public returns (bool success) {
                  
                          // The controller of this contract can move tokens around at will,
                          //  this is important to recognize! Confirm that you trust the
                          //  controller of this contract, which in most situations should be
                          //  another open source smart contract or 0x0
                          if (msg.sender != controller) {
                              require(transfersEnabled);
                  
                              // The standard ERC 20 transferFrom functionality
                              if (allowed[_from][msg.sender] < _amount)
                                  return false;
                              allowed[_from][msg.sender] -= _amount;
                          }
                          return doTransfer(_from, _to, _amount);
                      }
                  
                      /// @dev This is the actual transfer function in the token contract, it can
                      ///  only be called by other functions in this contract.
                      /// @param _from The address holding the tokens being transferred
                      /// @param _to The address of the recipient
                      /// @param _amount The amount of tokens to be transferred
                      /// @return True if the transfer was successful
                      function doTransfer(address _from, address _to, uint _amount) internal returns(bool) {
                          if (_amount == 0) {
                              return true;
                          }
                          require(parentSnapShotBlock < block.number);
                          // Do not allow transfer to 0x0 or the token contract itself
                          require((_to != 0) && (_to != address(this)));
                          // If the amount being transfered is more than the balance of the
                          //  account the transfer returns false
                          var previousBalanceFrom = balanceOfAt(_from, block.number);
                          if (previousBalanceFrom < _amount) {
                              return false;
                          }
                          // Alerts the token controller of the transfer
                          if (isContract(controller)) {
                              // Adding the ` == true` makes the linter shut up so...
                              require(ITokenController(controller).onTransfer(_from, _to, _amount) == true);
                          }
                          // First update the balance array with the new value for the address
                          //  sending the tokens
                          updateValueAtNow(balances[_from], previousBalanceFrom - _amount);
                          // Then update the balance array with the new value for the address
                          //  receiving the tokens
                          var previousBalanceTo = balanceOfAt(_to, block.number);
                          require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow
                          updateValueAtNow(balances[_to], previousBalanceTo + _amount);
                          // An event to make the transfer easy to find on the blockchain
                          Transfer(_from, _to, _amount);
                          return true;
                      }
                  
                      /// @param _owner The address that's balance is being requested
                      /// @return The balance of `_owner` at the current block
                      function balanceOf(address _owner) public constant returns (uint256 balance) {
                          return balanceOfAt(_owner, block.number);
                      }
                  
                      /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
                      ///  its behalf. This is a modified version of the ERC20 approve function
                      ///  to be a little bit safer
                      /// @param _spender The address of the account able to transfer the tokens
                      /// @param _amount The amount of tokens to be approved for transfer
                      /// @return True if the approval was successful
                      function approve(address _spender, uint256 _amount) public returns (bool success) {
                          require(transfersEnabled);
                  
                          // To change the approve amount you first have to reduce the addresses`
                          //  allowance to zero by calling `approve(_spender,0)` if it is not
                          //  already 0 to mitigate the race condition described here:
                          //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                          require((_amount == 0) || (allowed[msg.sender][_spender] == 0));
                  
                          // Alerts the token controller of the approve function call
                          if (isContract(controller)) {
                              // Adding the ` == true` makes the linter shut up so...
                              require(ITokenController(controller).onApprove(msg.sender, _spender, _amount) == true);
                          }
                  
                          allowed[msg.sender][_spender] = _amount;
                          Approval(msg.sender, _spender, _amount);
                          return true;
                      }
                  
                      /// @dev This function makes it easy to read the `allowed[]` map
                      /// @param _owner The address of the account that owns the token
                      /// @param _spender The address of the account able to transfer the tokens
                      /// @return Amount of remaining tokens of _owner that _spender is allowed
                      ///  to spend
                      function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {
                          return allowed[_owner][_spender];
                      }
                  
                      /// @notice `msg.sender` approves `_spender` to send `_amount` tokens on
                      ///  its behalf, and then a function is triggered in the contract that is
                      ///  being approved, `_spender`. This allows users to use their tokens to
                      ///  interact with contracts in one function call instead of two
                      /// @param _spender The address of the contract able to transfer the tokens
                      /// @param _amount The amount of tokens to be approved for transfer
                      /// @return True if the function call was successful
                      function approveAndCall(ApproveAndCallFallBack _spender, uint256 _amount, bytes _extraData) public returns (bool success) {
                          require(approve(_spender, _amount));
                  
                          _spender.receiveApproval(
                              msg.sender,
                              _amount,
                              this,
                              _extraData
                          );
                  
                          return true;
                      }
                  
                      /// @dev This function makes it easy to get the total number of tokens
                      /// @return The total number of tokens
                      function totalSupply() public constant returns (uint) {
                          return totalSupplyAt(block.number);
                      }
                  
                  
                  ////////////////
                  // Query balance and totalSupply in History
                  ////////////////
                  
                      /// @dev Queries the balance of `_owner` at a specific `_blockNumber`
                      /// @param _owner The address from which the balance will be retrieved
                      /// @param _blockNumber The block number when the balance is queried
                      /// @return The balance at `_blockNumber`
                      function balanceOfAt(address _owner, uint _blockNumber) public constant returns (uint) {
                  
                          // These next few lines are used when the balance of the token is
                          //  requested before a check point was ever created for this token, it
                          //  requires that the `parentToken.balanceOfAt` be queried at the
                          //  genesis block for that token as this contains initial balance of
                          //  this token
                          if ((balances[_owner].length == 0) || (balances[_owner][0].fromBlock > _blockNumber)) {
                              if (address(parentToken) != 0) {
                                  return parentToken.balanceOfAt(_owner, min(_blockNumber, parentSnapShotBlock));
                              } else {
                                  // Has no parent
                                  return 0;
                              }
                  
                          // This will return the expected balance during normal situations
                          } else {
                              return getValueAt(balances[_owner], _blockNumber);
                          }
                      }
                  
                      /// @notice Total amount of tokens at a specific `_blockNumber`.
                      /// @param _blockNumber The block number when the totalSupply is queried
                      /// @return The total amount of tokens at `_blockNumber`
                      function totalSupplyAt(uint _blockNumber) public constant returns(uint) {
                  
                          // These next few lines are used when the totalSupply of the token is
                          //  requested before a check point was ever created for this token, it
                          //  requires that the `parentToken.totalSupplyAt` be queried at the
                          //  genesis block for this token as that contains totalSupply of this
                          //  token at this block number.
                          if ((totalSupplyHistory.length == 0) || (totalSupplyHistory[0].fromBlock > _blockNumber)) {
                              if (address(parentToken) != 0) {
                                  return parentToken.totalSupplyAt(min(_blockNumber, parentSnapShotBlock));
                              } else {
                                  return 0;
                              }
                  
                          // This will return the expected totalSupply during normal situations
                          } else {
                              return getValueAt(totalSupplyHistory, _blockNumber);
                          }
                      }
                  
                  ////////////////
                  // Clone Token Method
                  ////////////////
                  
                      /// @notice Creates a new clone token with the initial distribution being
                      ///  this token at `_snapshotBlock`
                      /// @param _cloneTokenName Name of the clone token
                      /// @param _cloneDecimalUnits Number of decimals of the smallest unit
                      /// @param _cloneTokenSymbol Symbol of the clone token
                      /// @param _snapshotBlock Block when the distribution of the parent token is
                      ///  copied to set the initial distribution of the new clone token;
                      ///  if the block is zero than the actual block, the current block is used
                      /// @param _transfersEnabled True if transfers are allowed in the clone
                      /// @return The address of the new MiniMeToken Contract
                      function createCloneToken(
                          string _cloneTokenName,
                          uint8 _cloneDecimalUnits,
                          string _cloneTokenSymbol,
                          uint _snapshotBlock,
                          bool _transfersEnabled
                      ) public returns(MiniMeToken)
                      {
                          uint256 snapshot = _snapshotBlock == 0 ? block.number - 1 : _snapshotBlock;
                  
                          MiniMeToken cloneToken = tokenFactory.createCloneToken(
                              this,
                              snapshot,
                              _cloneTokenName,
                              _cloneDecimalUnits,
                              _cloneTokenSymbol,
                              _transfersEnabled
                          );
                  
                          cloneToken.changeController(msg.sender);
                  
                          // An event to make the token easy to find on the blockchain
                          NewCloneToken(address(cloneToken), snapshot);
                          return cloneToken;
                      }
                  
                  ////////////////
                  // Generate and destroy tokens
                  ////////////////
                  
                      /// @notice Generates `_amount` tokens that are assigned to `_owner`
                      /// @param _owner The address that will be assigned the new tokens
                      /// @param _amount The quantity of tokens generated
                      /// @return True if the tokens are generated correctly
                      function generateTokens(address _owner, uint _amount) onlyController public returns (bool) {
                          uint curTotalSupply = totalSupply();
                          require(curTotalSupply + _amount >= curTotalSupply); // Check for overflow
                          uint previousBalanceTo = balanceOf(_owner);
                          require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow
                          updateValueAtNow(totalSupplyHistory, curTotalSupply + _amount);
                          updateValueAtNow(balances[_owner], previousBalanceTo + _amount);
                          Transfer(0, _owner, _amount);
                          return true;
                      }
                  
                  
                      /// @notice Burns `_amount` tokens from `_owner`
                      /// @param _owner The address that will lose the tokens
                      /// @param _amount The quantity of tokens to burn
                      /// @return True if the tokens are burned correctly
                      function destroyTokens(address _owner, uint _amount) onlyController public returns (bool) {
                          uint curTotalSupply = totalSupply();
                          require(curTotalSupply >= _amount);
                          uint previousBalanceFrom = balanceOf(_owner);
                          require(previousBalanceFrom >= _amount);
                          updateValueAtNow(totalSupplyHistory, curTotalSupply - _amount);
                          updateValueAtNow(balances[_owner], previousBalanceFrom - _amount);
                          Transfer(_owner, 0, _amount);
                          return true;
                      }
                  
                  ////////////////
                  // Enable tokens transfers
                  ////////////////
                  
                  
                      /// @notice Enables token holders to transfer their tokens freely if true
                      /// @param _transfersEnabled True if transfers are allowed in the clone
                      function enableTransfers(bool _transfersEnabled) onlyController public {
                          transfersEnabled = _transfersEnabled;
                      }
                  
                  ////////////////
                  // Internal helper functions to query and set a value in a snapshot array
                  ////////////////
                  
                      /// @dev `getValueAt` retrieves the number of tokens at a given block number
                      /// @param checkpoints The history of values being queried
                      /// @param _block The block number to retrieve the value at
                      /// @return The number of tokens being queried
                      function getValueAt(Checkpoint[] storage checkpoints, uint _block) constant internal returns (uint) {
                          if (checkpoints.length == 0)
                              return 0;
                  
                          // Shortcut for the actual value
                          if (_block >= checkpoints[checkpoints.length-1].fromBlock)
                              return checkpoints[checkpoints.length-1].value;
                          if (_block < checkpoints[0].fromBlock)
                              return 0;
                  
                          // Binary search of the value in the array
                          uint min = 0;
                          uint max = checkpoints.length-1;
                          while (max > min) {
                              uint mid = (max + min + 1) / 2;
                              if (checkpoints[mid].fromBlock<=_block) {
                                  min = mid;
                              } else {
                                  max = mid-1;
                              }
                          }
                          return checkpoints[min].value;
                      }
                  
                      /// @dev `updateValueAtNow` used to update the `balances` map and the
                      ///  `totalSupplyHistory`
                      /// @param checkpoints The history of data being updated
                      /// @param _value The new number of tokens
                      function updateValueAtNow(Checkpoint[] storage checkpoints, uint _value) internal {
                          if ((checkpoints.length == 0) || (checkpoints[checkpoints.length - 1].fromBlock < block.number)) {
                              Checkpoint storage newCheckPoint = checkpoints[checkpoints.length++];
                              newCheckPoint.fromBlock = uint128(block.number);
                              newCheckPoint.value = uint128(_value);
                          } else {
                              Checkpoint storage oldCheckPoint = checkpoints[checkpoints.length - 1];
                              oldCheckPoint.value = uint128(_value);
                          }
                      }
                  
                      /// @dev Internal function to determine if an address is a contract
                      /// @param _addr The address being queried
                      /// @return True if `_addr` is a contract
                      function isContract(address _addr) constant internal returns(bool) {
                          uint size;
                          if (_addr == 0)
                              return false;
                  
                          assembly {
                              size := extcodesize(_addr)
                          }
                  
                          return size>0;
                      }
                  
                      /// @dev Helper function to return a min betwen the two uints
                      function min(uint a, uint b) pure internal returns (uint) {
                          return a < b ? a : b;
                      }
                  
                      /// @notice The fallback function: If the contract's controller has not been
                      ///  set to 0, then the `proxyPayment` method is called which relays the
                      ///  ether and creates tokens as described in the token controller contract
                      function () external payable {
                          require(isContract(controller));
                          // Adding the ` == true` makes the linter shut up so...
                          require(ITokenController(controller).proxyPayment.value(msg.value)(msg.sender) == true);
                      }
                  
                  //////////
                  // Safety Methods
                  //////////
                  
                      /// @notice This method can be used by the controller to extract mistakenly
                      ///  sent tokens to this contract.
                      /// @param _token The address of the token contract that you want to recover
                      ///  set to 0 in case you want to extract ether.
                      function claimTokens(address _token) onlyController public {
                          if (_token == 0x0) {
                              controller.transfer(this.balance);
                              return;
                          }
                  
                          MiniMeToken token = MiniMeToken(_token);
                          uint balance = token.balanceOf(this);
                          token.transfer(controller, balance);
                          ClaimedTokens(_token, controller, balance);
                      }
                  
                  ////////////////
                  // Events
                  ////////////////
                      event ClaimedTokens(address indexed _token, address indexed _controller, uint _amount);
                      event Transfer(address indexed _from, address indexed _to, uint256 _amount);
                      event NewCloneToken(address indexed _cloneToken, uint _snapshotBlock);
                      event Approval(
                          address indexed _owner,
                          address indexed _spender,
                          uint256 _amount
                          );
                  
                  }
                  
                  
                  ////////////////
                  // MiniMeTokenFactory
                  ////////////////
                  
                  /// @dev This contract is used to generate clone contracts from a contract.
                  ///  In solidity this is the way to create a contract from a contract of the
                  ///  same class
                  contract MiniMeTokenFactory {
                  
                      /// @notice Update the DApp by creating a new token with new functionalities
                      ///  the msg.sender becomes the controller of this clone token
                      /// @param _parentToken Address of the token being cloned
                      /// @param _snapshotBlock Block of the parent token that will
                      ///  determine the initial distribution of the clone token
                      /// @param _tokenName Name of the new token
                      /// @param _decimalUnits Number of decimals of the new token
                      /// @param _tokenSymbol Token Symbol for the new token
                      /// @param _transfersEnabled If true, tokens will be able to be transferred
                      /// @return The address of the new token contract
                      function createCloneToken(
                          MiniMeToken _parentToken,
                          uint _snapshotBlock,
                          string _tokenName,
                          uint8 _decimalUnits,
                          string _tokenSymbol,
                          bool _transfersEnabled
                      ) public returns (MiniMeToken)
                      {
                          MiniMeToken newToken = new MiniMeToken(
                              this,
                              _parentToken,
                              _snapshotBlock,
                              _tokenName,
                              _decimalUnits,
                              _tokenSymbol,
                              _transfersEnabled
                          );
                  
                          newToken.changeController(msg.sender);
                          return newToken;
                      }
                  }

                  File 3 of 14: CanonicalTransactionChain
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /* Library Imports */
                  import { AddressAliasHelper } from "../../standards/AddressAliasHelper.sol";
                  import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
                  import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
                  /* Interface Imports */
                  import { ICanonicalTransactionChain } from "./ICanonicalTransactionChain.sol";
                  import { IChainStorageContainer } from "./IChainStorageContainer.sol";
                  /**
                   * @title CanonicalTransactionChain
                   * @dev The Canonical Transaction Chain (CTC) contract is an append-only log of transactions
                   * which must be applied to the rollup state. It defines the ordering of rollup transactions by
                   * writing them to the 'CTC:batches' instance of the Chain Storage Container.
                   * The CTC also allows any account to 'enqueue' an L2 transaction, which will require that the
                   * Sequencer will eventually append it to the rollup state.
                   *
                   * Runtime target: EVM
                   */
                  contract CanonicalTransactionChain is ICanonicalTransactionChain, Lib_AddressResolver {
                      /*************
                       * Constants *
                       *************/
                      // L2 tx gas-related
                      uint256 public constant MIN_ROLLUP_TX_GAS = 100000;
                      uint256 public constant MAX_ROLLUP_TX_SIZE = 50000;
                      // The approximate cost of calling the enqueue function
                      uint256 public enqueueGasCost;
                      // The ratio of the cost of L1 gas to the cost of L2 gas
                      uint256 public l2GasDiscountDivisor;
                      // The amount of L2 gas which can be forwarded to L2 without spam prevention via 'gas burn'.
                      // Calculated as the product of l2GasDiscountDivisor * enqueueGasCost.
                      // See comments in enqueue() for further detail.
                      uint256 public enqueueL2GasPrepaid;
                      // Encoding-related (all in bytes)
                      uint256 internal constant BATCH_CONTEXT_SIZE = 16;
                      uint256 internal constant BATCH_CONTEXT_LENGTH_POS = 12;
                      uint256 internal constant BATCH_CONTEXT_START_POS = 15;
                      uint256 internal constant TX_DATA_HEADER_SIZE = 3;
                      uint256 internal constant BYTES_TILL_TX_DATA = 65;
                      /*************
                       * Variables *
                       *************/
                      uint256 public maxTransactionGasLimit;
                      /***************
                       * Queue State *
                       ***************/
                      uint40 private _nextQueueIndex; // index of the first queue element not yet included
                      Lib_OVMCodec.QueueElement[] queueElements;
                      /***************
                       * Constructor *
                       ***************/
                      constructor(
                          address _libAddressManager,
                          uint256 _maxTransactionGasLimit,
                          uint256 _l2GasDiscountDivisor,
                          uint256 _enqueueGasCost
                      ) Lib_AddressResolver(_libAddressManager) {
                          maxTransactionGasLimit = _maxTransactionGasLimit;
                          l2GasDiscountDivisor = _l2GasDiscountDivisor;
                          enqueueGasCost = _enqueueGasCost;
                          enqueueL2GasPrepaid = _l2GasDiscountDivisor * _enqueueGasCost;
                      }
                      /**********************
                       * Function Modifiers *
                       **********************/
                      /**
                       * Modifier to enforce that, if configured, only the Burn Admin may
                       * successfully call a method.
                       */
                      modifier onlyBurnAdmin() {
                          require(msg.sender == libAddressManager.owner(), "Only callable by the Burn Admin.");
                          _;
                      }
                      /*******************************
                       * Authorized Setter Functions *
                       *******************************/
                      /**
                       * Allows the Burn Admin to update the parameters which determine the amount of gas to burn.
                       * The value of enqueueL2GasPrepaid is immediately updated as well.
                       */
                      function setGasParams(uint256 _l2GasDiscountDivisor, uint256 _enqueueGasCost)
                          external
                          onlyBurnAdmin
                      {
                          enqueueGasCost = _enqueueGasCost;
                          l2GasDiscountDivisor = _l2GasDiscountDivisor;
                          // See the comment in enqueue() for the rationale behind this formula.
                          enqueueL2GasPrepaid = _l2GasDiscountDivisor * _enqueueGasCost;
                          emit L2GasParamsUpdated(l2GasDiscountDivisor, enqueueGasCost, enqueueL2GasPrepaid);
                      }
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * Accesses the batch storage container.
                       * @return Reference to the batch storage container.
                       */
                      function batches() public view returns (IChainStorageContainer) {
                          return IChainStorageContainer(resolve("ChainStorageContainer-CTC-batches"));
                      }
                      /**
                       * Retrieves the total number of elements submitted.
                       * @return _totalElements Total submitted elements.
                       */
                      function getTotalElements() public view returns (uint256 _totalElements) {
                          (uint40 totalElements, , , ) = _getBatchExtraData();
                          return uint256(totalElements);
                      }
                      /**
                       * Retrieves the total number of batches submitted.
                       * @return _totalBatches Total submitted batches.
                       */
                      function getTotalBatches() public view returns (uint256 _totalBatches) {
                          return batches().length();
                      }
                      /**
                       * Returns the index of the next element to be enqueued.
                       * @return Index for the next queue element.
                       */
                      function getNextQueueIndex() public view returns (uint40) {
                          return _nextQueueIndex;
                      }
                      /**
                       * Returns the timestamp of the last transaction.
                       * @return Timestamp for the last transaction.
                       */
                      function getLastTimestamp() public view returns (uint40) {
                          (, , uint40 lastTimestamp, ) = _getBatchExtraData();
                          return lastTimestamp;
                      }
                      /**
                       * Returns the blocknumber of the last transaction.
                       * @return Blocknumber for the last transaction.
                       */
                      function getLastBlockNumber() public view returns (uint40) {
                          (, , , uint40 lastBlockNumber) = _getBatchExtraData();
                          return lastBlockNumber;
                      }
                      /**
                       * Gets the queue element at a particular index.
                       * @param _index Index of the queue element to access.
                       * @return _element Queue element at the given index.
                       */
                      function getQueueElement(uint256 _index)
                          public
                          view
                          returns (Lib_OVMCodec.QueueElement memory _element)
                      {
                          return queueElements[_index];
                      }
                      /**
                       * Get the number of queue elements which have not yet been included.
                       * @return Number of pending queue elements.
                       */
                      function getNumPendingQueueElements() public view returns (uint40) {
                          return uint40(queueElements.length) - _nextQueueIndex;
                      }
                      /**
                       * Retrieves the length of the queue, including
                       * both pending and canonical transactions.
                       * @return Length of the queue.
                       */
                      function getQueueLength() public view returns (uint40) {
                          return uint40(queueElements.length);
                      }
                      /**
                       * Adds a transaction to the queue.
                       * @param _target Target L2 contract to send the transaction to.
                       * @param _gasLimit Gas limit for the enqueued L2 transaction.
                       * @param _data Transaction data.
                       */
                      function enqueue(
                          address _target,
                          uint256 _gasLimit,
                          bytes memory _data
                      ) external {
                          require(
                              _data.length <= MAX_ROLLUP_TX_SIZE,
                              "Transaction data size exceeds maximum for rollup transaction."
                          );
                          require(
                              _gasLimit <= maxTransactionGasLimit,
                              "Transaction gas limit exceeds maximum for rollup transaction."
                          );
                          require(_gasLimit >= MIN_ROLLUP_TX_GAS, "Transaction gas limit too low to enqueue.");
                          // Transactions submitted to the queue lack a method for paying gas fees to the Sequencer.
                          // So we need to prevent spam attacks by ensuring that the cost of enqueueing a transaction
                          // from L1 to L2 is not underpriced. For transaction with a high L2 gas limit, we do this by
                          // burning some extra gas on L1. Of course there is also some intrinsic cost to enqueueing a
                          // transaction, so we want to make sure not to over-charge (by burning too much L1 gas).
                          // Therefore, we define 'enqueueL2GasPrepaid' as the L2 gas limit above which we must burn
                          // additional gas on L1. This threshold is the product of two inputs:
                          // 1. enqueueGasCost: the base cost of calling this function.
                          // 2. l2GasDiscountDivisor: the ratio between the cost of gas on L1 and L2. This is a
                          //    positive integer, meaning we assume L2 gas is always less costly.
                          // The calculation below for gasToConsume can be seen as converting the difference (between
                          // the specified L2 gas limit and the prepaid L2 gas limit) to an L1 gas amount.
                          if (_gasLimit > enqueueL2GasPrepaid) {
                              uint256 gasToConsume = (_gasLimit - enqueueL2GasPrepaid) / l2GasDiscountDivisor;
                              uint256 startingGas = gasleft();
                              // Although this check is not necessary (burn below will run out of gas if not true), it
                              // gives the user an explicit reason as to why the enqueue attempt failed.
                              require(startingGas > gasToConsume, "Insufficient gas for L2 rate limiting burn.");
                              uint256 i;
                              while (startingGas - gasleft() < gasToConsume) {
                                  i++;
                              }
                          }
                          // Apply an aliasing unless msg.sender == tx.origin. This prevents an attack in which a
                          // contract on L1 has the same address as a contract on L2 but doesn't have the same code.
                          // We can safely ignore this for EOAs because they're guaranteed to have the same "code"
                          // (i.e. no code at all). This also makes it possible for users to interact with contracts
                          // on L2 even when the Sequencer is down.
                          address sender;
                          if (msg.sender == tx.origin) {
                              sender = msg.sender;
                          } else {
                              sender = AddressAliasHelper.applyL1ToL2Alias(msg.sender);
                          }
                          bytes32 transactionHash = keccak256(abi.encode(sender, _target, _gasLimit, _data));
                          queueElements.push(
                              Lib_OVMCodec.QueueElement({
                                  transactionHash: transactionHash,
                                  timestamp: uint40(block.timestamp),
                                  blockNumber: uint40(block.number)
                              })
                          );
                          uint256 queueIndex = queueElements.length - 1;
                          emit TransactionEnqueued(sender, _target, _gasLimit, _data, queueIndex, block.timestamp);
                      }
                      /**
                       * Allows the sequencer to append a batch of transactions.
                       * @dev This function uses a custom encoding scheme for efficiency reasons.
                       * .param _shouldStartAtElement Specific batch we expect to start appending to.
                       * .param _totalElementsToAppend Total number of batch elements we expect to append.
                       * .param _contexts Array of batch contexts.
                       * .param _transactionDataFields Array of raw transaction data.
                       */
                      function appendSequencerBatch() external {
                          uint40 shouldStartAtElement;
                          uint24 totalElementsToAppend;
                          uint24 numContexts;
                          assembly {
                              shouldStartAtElement := shr(216, calldataload(4))
                              totalElementsToAppend := shr(232, calldataload(9))
                              numContexts := shr(232, calldataload(12))
                          }
                          require(
                              shouldStartAtElement == getTotalElements(),
                              "Actual batch start index does not match expected start index."
                          );
                          require(
                              msg.sender == resolve("OVM_Sequencer"),
                              "Function can only be called by the Sequencer."
                          );
                          uint40 nextTransactionPtr = uint40(
                              BATCH_CONTEXT_START_POS + BATCH_CONTEXT_SIZE * numContexts
                          );
                          require(msg.data.length >= nextTransactionPtr, "Not enough BatchContexts provided.");
                          // Counter for number of sequencer transactions appended so far.
                          uint32 numSequencerTransactions = 0;
                          // Cache the _nextQueueIndex storage variable to a temporary stack variable.
                          // This is safe as long as nothing reads or writes to the storage variable
                          // until it is updated by the temp variable.
                          uint40 nextQueueIndex = _nextQueueIndex;
                          BatchContext memory curContext;
                          for (uint32 i = 0; i < numContexts; i++) {
                              BatchContext memory nextContext = _getBatchContext(i);
                              // Now we can update our current context.
                              curContext = nextContext;
                              // Process sequencer transactions first.
                              numSequencerTransactions += uint32(curContext.numSequencedTransactions);
                              // Now process any subsequent queue transactions.
                              nextQueueIndex += uint40(curContext.numSubsequentQueueTransactions);
                          }
                          require(
                              nextQueueIndex <= queueElements.length,
                              "Attempted to append more elements than are available in the queue."
                          );
                          // Generate the required metadata that we need to append this batch
                          uint40 numQueuedTransactions = totalElementsToAppend - numSequencerTransactions;
                          uint40 blockTimestamp;
                          uint40 blockNumber;
                          if (curContext.numSubsequentQueueTransactions == 0) {
                              // The last element is a sequencer tx, therefore pull timestamp and block number from
                              // the last context.
                              blockTimestamp = uint40(curContext.timestamp);
                              blockNumber = uint40(curContext.blockNumber);
                          } else {
                              // The last element is a queue tx, therefore pull timestamp and block number from the
                              // queue element.
                              // curContext.numSubsequentQueueTransactions > 0 which means that we've processed at
                              // least one queue element. We increment nextQueueIndex after processing each queue
                              // element, so the index of the last element we processed is nextQueueIndex - 1.
                              Lib_OVMCodec.QueueElement memory lastElement = queueElements[nextQueueIndex - 1];
                              blockTimestamp = lastElement.timestamp;
                              blockNumber = lastElement.blockNumber;
                          }
                          // Cache the previous blockhash to ensure all transaction data can be retrieved efficiently.
                          _appendBatch(
                              blockhash(block.number - 1),
                              totalElementsToAppend,
                              numQueuedTransactions,
                              blockTimestamp,
                              blockNumber
                          );
                          emit SequencerBatchAppended(
                              nextQueueIndex - numQueuedTransactions,
                              numQueuedTransactions,
                              getTotalElements()
                          );
                          // Update the _nextQueueIndex storage variable.
                          _nextQueueIndex = nextQueueIndex;
                      }
                      /**********************
                       * Internal Functions *
                       **********************/
                      /**
                       * Returns the BatchContext located at a particular index.
                       * @param _index The index of the BatchContext
                       * @return The BatchContext at the specified index.
                       */
                      function _getBatchContext(uint256 _index) internal pure returns (BatchContext memory) {
                          uint256 contextPtr = 15 + _index * BATCH_CONTEXT_SIZE;
                          uint256 numSequencedTransactions;
                          uint256 numSubsequentQueueTransactions;
                          uint256 ctxTimestamp;
                          uint256 ctxBlockNumber;
                          assembly {
                              numSequencedTransactions := shr(232, calldataload(contextPtr))
                              numSubsequentQueueTransactions := shr(232, calldataload(add(contextPtr, 3)))
                              ctxTimestamp := shr(216, calldataload(add(contextPtr, 6)))
                              ctxBlockNumber := shr(216, calldataload(add(contextPtr, 11)))
                          }
                          return
                              BatchContext({
                                  numSequencedTransactions: numSequencedTransactions,
                                  numSubsequentQueueTransactions: numSubsequentQueueTransactions,
                                  timestamp: ctxTimestamp,
                                  blockNumber: ctxBlockNumber
                              });
                      }
                      /**
                       * Parses the batch context from the extra data.
                       * @return Total number of elements submitted.
                       * @return Index of the next queue element.
                       */
                      function _getBatchExtraData()
                          internal
                          view
                          returns (
                              uint40,
                              uint40,
                              uint40,
                              uint40
                          )
                      {
                          bytes27 extraData = batches().getGlobalMetadata();
                          uint40 totalElements;
                          uint40 nextQueueIndex;
                          uint40 lastTimestamp;
                          uint40 lastBlockNumber;
                          // solhint-disable max-line-length
                          assembly {
                              extraData := shr(40, extraData)
                              totalElements := and(
                                  extraData,
                                  0x000000000000000000000000000000000000000000000000000000FFFFFFFFFF
                              )
                              nextQueueIndex := shr(
                                  40,
                                  and(extraData, 0x00000000000000000000000000000000000000000000FFFFFFFFFF0000000000)
                              )
                              lastTimestamp := shr(
                                  80,
                                  and(extraData, 0x0000000000000000000000000000000000FFFFFFFFFF00000000000000000000)
                              )
                              lastBlockNumber := shr(
                                  120,
                                  and(extraData, 0x000000000000000000000000FFFFFFFFFF000000000000000000000000000000)
                              )
                          }
                          // solhint-enable max-line-length
                          return (totalElements, nextQueueIndex, lastTimestamp, lastBlockNumber);
                      }
                      /**
                       * Encodes the batch context for the extra data.
                       * @param _totalElements Total number of elements submitted.
                       * @param _nextQueueIdx Index of the next queue element.
                       * @param _timestamp Timestamp for the last batch.
                       * @param _blockNumber Block number of the last batch.
                       * @return Encoded batch context.
                       */
                      function _makeBatchExtraData(
                          uint40 _totalElements,
                          uint40 _nextQueueIdx,
                          uint40 _timestamp,
                          uint40 _blockNumber
                      ) internal pure returns (bytes27) {
                          bytes27 extraData;
                          assembly {
                              extraData := _totalElements
                              extraData := or(extraData, shl(40, _nextQueueIdx))
                              extraData := or(extraData, shl(80, _timestamp))
                              extraData := or(extraData, shl(120, _blockNumber))
                              extraData := shl(40, extraData)
                          }
                          return extraData;
                      }
                      /**
                       * Inserts a batch into the chain of batches.
                       * @param _transactionRoot Root of the transaction tree for this batch.
                       * @param _batchSize Number of elements in the batch.
                       * @param _numQueuedTransactions Number of queue transactions in the batch.
                       * @param _timestamp The latest batch timestamp.
                       * @param _blockNumber The latest batch blockNumber.
                       */
                      function _appendBatch(
                          bytes32 _transactionRoot,
                          uint256 _batchSize,
                          uint256 _numQueuedTransactions,
                          uint40 _timestamp,
                          uint40 _blockNumber
                      ) internal {
                          IChainStorageContainer batchesRef = batches();
                          (uint40 totalElements, uint40 nextQueueIndex, , ) = _getBatchExtraData();
                          Lib_OVMCodec.ChainBatchHeader memory header = Lib_OVMCodec.ChainBatchHeader({
                              batchIndex: batchesRef.length(),
                              batchRoot: _transactionRoot,
                              batchSize: _batchSize,
                              prevTotalElements: totalElements,
                              extraData: hex""
                          });
                          emit TransactionBatchAppended(
                              header.batchIndex,
                              header.batchRoot,
                              header.batchSize,
                              header.prevTotalElements,
                              header.extraData
                          );
                          bytes32 batchHeaderHash = Lib_OVMCodec.hashBatchHeader(header);
                          bytes27 latestBatchContext = _makeBatchExtraData(
                              totalElements + uint40(header.batchSize),
                              nextQueueIndex + uint40(_numQueuedTransactions),
                              _timestamp,
                              _blockNumber
                          );
                          batchesRef.push(batchHeaderHash, latestBatchContext);
                      }
                  }
                  // SPDX-License-Identifier: Apache-2.0
                  /*
                   * Copyright 2019-2021, Offchain Labs, Inc.
                   *
                   * 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
                   *
                   *    http://www.apache.org/licenses/LICENSE-2.0
                   *
                   * 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.8.7;
                  library AddressAliasHelper {
                      uint160 constant offset = uint160(0x1111000000000000000000000000000000001111);
                      /// @notice Utility function that converts the address in the L1 that submitted a tx to
                      /// the inbox to the msg.sender viewed in the L2
                      /// @param l1Address the address in the L1 that triggered the tx to L2
                      /// @return l2Address L2 address as viewed in msg.sender
                      function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {
                          unchecked {
                              l2Address = address(uint160(l1Address) + offset);
                          }
                      }
                      /// @notice Utility function that converts the msg.sender viewed in the L2 to the
                      /// address in the L1 that submitted a tx to the inbox
                      /// @param l2Address L2 address as viewed in msg.sender
                      /// @return l1Address the address in the L1 that triggered the tx to L2
                      function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) {
                          unchecked {
                              l1Address = address(uint160(l2Address) - offset);
                          }
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /* Library Imports */
                  import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol";
                  import { Lib_RLPWriter } from "../rlp/Lib_RLPWriter.sol";
                  import { Lib_BytesUtils } from "../utils/Lib_BytesUtils.sol";
                  import { Lib_Bytes32Utils } from "../utils/Lib_Bytes32Utils.sol";
                  /**
                   * @title Lib_OVMCodec
                   */
                  library Lib_OVMCodec {
                      /*********
                       * Enums *
                       *********/
                      enum QueueOrigin {
                          SEQUENCER_QUEUE,
                          L1TOL2_QUEUE
                      }
                      /***********
                       * Structs *
                       ***********/
                      struct EVMAccount {
                          uint256 nonce;
                          uint256 balance;
                          bytes32 storageRoot;
                          bytes32 codeHash;
                      }
                      struct ChainBatchHeader {
                          uint256 batchIndex;
                          bytes32 batchRoot;
                          uint256 batchSize;
                          uint256 prevTotalElements;
                          bytes extraData;
                      }
                      struct ChainInclusionProof {
                          uint256 index;
                          bytes32[] siblings;
                      }
                      struct Transaction {
                          uint256 timestamp;
                          uint256 blockNumber;
                          QueueOrigin l1QueueOrigin;
                          address l1TxOrigin;
                          address entrypoint;
                          uint256 gasLimit;
                          bytes data;
                      }
                      struct TransactionChainElement {
                          bool isSequenced;
                          uint256 queueIndex; // QUEUED TX ONLY
                          uint256 timestamp; // SEQUENCER TX ONLY
                          uint256 blockNumber; // SEQUENCER TX ONLY
                          bytes txData; // SEQUENCER TX ONLY
                      }
                      struct QueueElement {
                          bytes32 transactionHash;
                          uint40 timestamp;
                          uint40 blockNumber;
                      }
                      /**********************
                       * Internal Functions *
                       **********************/
                      /**
                       * Encodes a standard OVM transaction.
                       * @param _transaction OVM transaction to encode.
                       * @return Encoded transaction bytes.
                       */
                      function encodeTransaction(Transaction memory _transaction)
                          internal
                          pure
                          returns (bytes memory)
                      {
                          return
                              abi.encodePacked(
                                  _transaction.timestamp,
                                  _transaction.blockNumber,
                                  _transaction.l1QueueOrigin,
                                  _transaction.l1TxOrigin,
                                  _transaction.entrypoint,
                                  _transaction.gasLimit,
                                  _transaction.data
                              );
                      }
                      /**
                       * Hashes a standard OVM transaction.
                       * @param _transaction OVM transaction to encode.
                       * @return Hashed transaction
                       */
                      function hashTransaction(Transaction memory _transaction) internal pure returns (bytes32) {
                          return keccak256(encodeTransaction(_transaction));
                      }
                      /**
                       * @notice Decodes an RLP-encoded account state into a useful struct.
                       * @param _encoded RLP-encoded account state.
                       * @return Account state struct.
                       */
                      function decodeEVMAccount(bytes memory _encoded) internal pure returns (EVMAccount memory) {
                          Lib_RLPReader.RLPItem[] memory accountState = Lib_RLPReader.readList(_encoded);
                          return
                              EVMAccount({
                                  nonce: Lib_RLPReader.readUint256(accountState[0]),
                                  balance: Lib_RLPReader.readUint256(accountState[1]),
                                  storageRoot: Lib_RLPReader.readBytes32(accountState[2]),
                                  codeHash: Lib_RLPReader.readBytes32(accountState[3])
                              });
                      }
                      /**
                       * Calculates a hash for a given batch header.
                       * @param _batchHeader Header to hash.
                       * @return Hash of the header.
                       */
                      function hashBatchHeader(Lib_OVMCodec.ChainBatchHeader memory _batchHeader)
                          internal
                          pure
                          returns (bytes32)
                      {
                          return
                              keccak256(
                                  abi.encode(
                                      _batchHeader.batchRoot,
                                      _batchHeader.batchSize,
                                      _batchHeader.prevTotalElements,
                                      _batchHeader.extraData
                                  )
                              );
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /* Library Imports */
                  import { Lib_AddressManager } from "./Lib_AddressManager.sol";
                  /**
                   * @title Lib_AddressResolver
                   */
                  abstract contract Lib_AddressResolver {
                      /*************
                       * Variables *
                       *************/
                      Lib_AddressManager public libAddressManager;
                      /***************
                       * Constructor *
                       ***************/
                      /**
                       * @param _libAddressManager Address of the Lib_AddressManager.
                       */
                      constructor(address _libAddressManager) {
                          libAddressManager = Lib_AddressManager(_libAddressManager);
                      }
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * Resolves the address associated with a given name.
                       * @param _name Name to resolve an address for.
                       * @return Address associated with the given name.
                       */
                      function resolve(string memory _name) public view returns (address) {
                          return libAddressManager.getAddress(_name);
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >0.5.0 <0.9.0;
                  /* Library Imports */
                  import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
                  /* Interface Imports */
                  import { IChainStorageContainer } from "./IChainStorageContainer.sol";
                  /**
                   * @title ICanonicalTransactionChain
                   */
                  interface ICanonicalTransactionChain {
                      /**********
                       * Events *
                       **********/
                      event L2GasParamsUpdated(
                          uint256 l2GasDiscountDivisor,
                          uint256 enqueueGasCost,
                          uint256 enqueueL2GasPrepaid
                      );
                      event TransactionEnqueued(
                          address indexed _l1TxOrigin,
                          address indexed _target,
                          uint256 _gasLimit,
                          bytes _data,
                          uint256 indexed _queueIndex,
                          uint256 _timestamp
                      );
                      event QueueBatchAppended(
                          uint256 _startingQueueIndex,
                          uint256 _numQueueElements,
                          uint256 _totalElements
                      );
                      event SequencerBatchAppended(
                          uint256 _startingQueueIndex,
                          uint256 _numQueueElements,
                          uint256 _totalElements
                      );
                      event TransactionBatchAppended(
                          uint256 indexed _batchIndex,
                          bytes32 _batchRoot,
                          uint256 _batchSize,
                          uint256 _prevTotalElements,
                          bytes _extraData
                      );
                      /***********
                       * Structs *
                       ***********/
                      struct BatchContext {
                          uint256 numSequencedTransactions;
                          uint256 numSubsequentQueueTransactions;
                          uint256 timestamp;
                          uint256 blockNumber;
                      }
                      /*******************************
                       * Authorized Setter Functions *
                       *******************************/
                      /**
                       * Allows the Burn Admin to update the parameters which determine the amount of gas to burn.
                       * The value of enqueueL2GasPrepaid is immediately updated as well.
                       */
                      function setGasParams(uint256 _l2GasDiscountDivisor, uint256 _enqueueGasCost) external;
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * Accesses the batch storage container.
                       * @return Reference to the batch storage container.
                       */
                      function batches() external view returns (IChainStorageContainer);
                      /**
                       * Retrieves the total number of elements submitted.
                       * @return _totalElements Total submitted elements.
                       */
                      function getTotalElements() external view returns (uint256 _totalElements);
                      /**
                       * Retrieves the total number of batches submitted.
                       * @return _totalBatches Total submitted batches.
                       */
                      function getTotalBatches() external view returns (uint256 _totalBatches);
                      /**
                       * Returns the index of the next element to be enqueued.
                       * @return Index for the next queue element.
                       */
                      function getNextQueueIndex() external view returns (uint40);
                      /**
                       * Gets the queue element at a particular index.
                       * @param _index Index of the queue element to access.
                       * @return _element Queue element at the given index.
                       */
                      function getQueueElement(uint256 _index)
                          external
                          view
                          returns (Lib_OVMCodec.QueueElement memory _element);
                      /**
                       * Returns the timestamp of the last transaction.
                       * @return Timestamp for the last transaction.
                       */
                      function getLastTimestamp() external view returns (uint40);
                      /**
                       * Returns the blocknumber of the last transaction.
                       * @return Blocknumber for the last transaction.
                       */
                      function getLastBlockNumber() external view returns (uint40);
                      /**
                       * Get the number of queue elements which have not yet been included.
                       * @return Number of pending queue elements.
                       */
                      function getNumPendingQueueElements() external view returns (uint40);
                      /**
                       * Retrieves the length of the queue, including
                       * both pending and canonical transactions.
                       * @return Length of the queue.
                       */
                      function getQueueLength() external view returns (uint40);
                      /**
                       * Adds a transaction to the queue.
                       * @param _target Target contract to send the transaction to.
                       * @param _gasLimit Gas limit for the given transaction.
                       * @param _data Transaction data.
                       */
                      function enqueue(
                          address _target,
                          uint256 _gasLimit,
                          bytes memory _data
                      ) external;
                      /**
                       * Allows the sequencer to append a batch of transactions.
                       * @dev This function uses a custom encoding scheme for efficiency reasons.
                       * .param _shouldStartAtElement Specific batch we expect to start appending to.
                       * .param _totalElementsToAppend Total number of batch elements we expect to append.
                       * .param _contexts Array of batch contexts.
                       * .param _transactionDataFields Array of raw transaction data.
                       */
                      function appendSequencerBatch(
                          // uint40 _shouldStartAtElement,
                          // uint24 _totalElementsToAppend,
                          // BatchContext[] _contexts,
                          // bytes[] _transactionDataFields
                      ) external;
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >0.5.0 <0.9.0;
                  /**
                   * @title IChainStorageContainer
                   */
                  interface IChainStorageContainer {
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * Sets the container's global metadata field. We're using `bytes27` here because we use five
                       * bytes to maintain the length of the underlying data structure, meaning we have an extra
                       * 27 bytes to store arbitrary data.
                       * @param _globalMetadata New global metadata to set.
                       */
                      function setGlobalMetadata(bytes27 _globalMetadata) external;
                      /**
                       * Retrieves the container's global metadata field.
                       * @return Container global metadata field.
                       */
                      function getGlobalMetadata() external view returns (bytes27);
                      /**
                       * Retrieves the number of objects stored in the container.
                       * @return Number of objects in the container.
                       */
                      function length() external view returns (uint256);
                      /**
                       * Pushes an object into the container.
                       * @param _object A 32 byte value to insert into the container.
                       */
                      function push(bytes32 _object) external;
                      /**
                       * Pushes an object into the container. Function allows setting the global metadata since
                       * we'll need to touch the "length" storage slot anyway, which also contains the global
                       * metadata (it's an optimization).
                       * @param _object A 32 byte value to insert into the container.
                       * @param _globalMetadata New global metadata for the container.
                       */
                      function push(bytes32 _object, bytes27 _globalMetadata) external;
                      /**
                       * Retrieves an object from the container.
                       * @param _index Index of the particular object to access.
                       * @return 32 byte object value.
                       */
                      function get(uint256 _index) external view returns (bytes32);
                      /**
                       * Removes all objects after and including a given index.
                       * @param _index Object index to delete from.
                       */
                      function deleteElementsAfterInclusive(uint256 _index) external;
                      /**
                       * Removes all objects after and including a given index. Also allows setting the global
                       * metadata field.
                       * @param _index Object index to delete from.
                       * @param _globalMetadata New global metadata for the container.
                       */
                      function deleteElementsAfterInclusive(uint256 _index, bytes27 _globalMetadata) external;
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /**
                   * @title Lib_RLPReader
                   * @dev Adapted from "RLPReader" by Hamdi Allam ([email protected]).
                   */
                  library Lib_RLPReader {
                      /*************
                       * Constants *
                       *************/
                      uint256 internal constant MAX_LIST_LENGTH = 32;
                      /*********
                       * Enums *
                       *********/
                      enum RLPItemType {
                          DATA_ITEM,
                          LIST_ITEM
                      }
                      /***********
                       * Structs *
                       ***********/
                      struct RLPItem {
                          uint256 length;
                          uint256 ptr;
                      }
                      /**********************
                       * Internal Functions *
                       **********************/
                      /**
                       * Converts bytes to a reference to memory position and length.
                       * @param _in Input bytes to convert.
                       * @return Output memory reference.
                       */
                      function toRLPItem(bytes memory _in) internal pure returns (RLPItem memory) {
                          uint256 ptr;
                          assembly {
                              ptr := add(_in, 32)
                          }
                          return RLPItem({ length: _in.length, ptr: ptr });
                      }
                      /**
                       * Reads an RLP list value into a list of RLP items.
                       * @param _in RLP list value.
                       * @return Decoded RLP list items.
                       */
                      function readList(RLPItem memory _in) internal pure returns (RLPItem[] memory) {
                          (uint256 listOffset, , RLPItemType itemType) = _decodeLength(_in);
                          require(itemType == RLPItemType.LIST_ITEM, "Invalid RLP list value.");
                          // Solidity in-memory arrays can't be increased in size, but *can* be decreased in size by
                          // writing to the length. Since we can't know the number of RLP items without looping over
                          // the entire input, we'd have to loop twice to accurately size this array. It's easier to
                          // simply set a reasonable maximum list length and decrease the size before we finish.
                          RLPItem[] memory out = new RLPItem[](MAX_LIST_LENGTH);
                          uint256 itemCount = 0;
                          uint256 offset = listOffset;
                          while (offset < _in.length) {
                              require(itemCount < MAX_LIST_LENGTH, "Provided RLP list exceeds max list length.");
                              (uint256 itemOffset, uint256 itemLength, ) = _decodeLength(
                                  RLPItem({ length: _in.length - offset, ptr: _in.ptr + offset })
                              );
                              out[itemCount] = RLPItem({ length: itemLength + itemOffset, ptr: _in.ptr + offset });
                              itemCount += 1;
                              offset += itemOffset + itemLength;
                          }
                          // Decrease the array size to match the actual item count.
                          assembly {
                              mstore(out, itemCount)
                          }
                          return out;
                      }
                      /**
                       * Reads an RLP list value into a list of RLP items.
                       * @param _in RLP list value.
                       * @return Decoded RLP list items.
                       */
                      function readList(bytes memory _in) internal pure returns (RLPItem[] memory) {
                          return readList(toRLPItem(_in));
                      }
                      /**
                       * Reads an RLP bytes value into bytes.
                       * @param _in RLP bytes value.
                       * @return Decoded bytes.
                       */
                      function readBytes(RLPItem memory _in) internal pure returns (bytes memory) {
                          (uint256 itemOffset, uint256 itemLength, RLPItemType itemType) = _decodeLength(_in);
                          require(itemType == RLPItemType.DATA_ITEM, "Invalid RLP bytes value.");
                          return _copy(_in.ptr, itemOffset, itemLength);
                      }
                      /**
                       * Reads an RLP bytes value into bytes.
                       * @param _in RLP bytes value.
                       * @return Decoded bytes.
                       */
                      function readBytes(bytes memory _in) internal pure returns (bytes memory) {
                          return readBytes(toRLPItem(_in));
                      }
                      /**
                       * Reads an RLP string value into a string.
                       * @param _in RLP string value.
                       * @return Decoded string.
                       */
                      function readString(RLPItem memory _in) internal pure returns (string memory) {
                          return string(readBytes(_in));
                      }
                      /**
                       * Reads an RLP string value into a string.
                       * @param _in RLP string value.
                       * @return Decoded string.
                       */
                      function readString(bytes memory _in) internal pure returns (string memory) {
                          return readString(toRLPItem(_in));
                      }
                      /**
                       * Reads an RLP bytes32 value into a bytes32.
                       * @param _in RLP bytes32 value.
                       * @return Decoded bytes32.
                       */
                      function readBytes32(RLPItem memory _in) internal pure returns (bytes32) {
                          require(_in.length <= 33, "Invalid RLP bytes32 value.");
                          (uint256 itemOffset, uint256 itemLength, RLPItemType itemType) = _decodeLength(_in);
                          require(itemType == RLPItemType.DATA_ITEM, "Invalid RLP bytes32 value.");
                          uint256 ptr = _in.ptr + itemOffset;
                          bytes32 out;
                          assembly {
                              out := mload(ptr)
                              // Shift the bytes over to match the item size.
                              if lt(itemLength, 32) {
                                  out := div(out, exp(256, sub(32, itemLength)))
                              }
                          }
                          return out;
                      }
                      /**
                       * Reads an RLP bytes32 value into a bytes32.
                       * @param _in RLP bytes32 value.
                       * @return Decoded bytes32.
                       */
                      function readBytes32(bytes memory _in) internal pure returns (bytes32) {
                          return readBytes32(toRLPItem(_in));
                      }
                      /**
                       * Reads an RLP uint256 value into a uint256.
                       * @param _in RLP uint256 value.
                       * @return Decoded uint256.
                       */
                      function readUint256(RLPItem memory _in) internal pure returns (uint256) {
                          return uint256(readBytes32(_in));
                      }
                      /**
                       * Reads an RLP uint256 value into a uint256.
                       * @param _in RLP uint256 value.
                       * @return Decoded uint256.
                       */
                      function readUint256(bytes memory _in) internal pure returns (uint256) {
                          return readUint256(toRLPItem(_in));
                      }
                      /**
                       * Reads an RLP bool value into a bool.
                       * @param _in RLP bool value.
                       * @return Decoded bool.
                       */
                      function readBool(RLPItem memory _in) internal pure returns (bool) {
                          require(_in.length == 1, "Invalid RLP boolean value.");
                          uint256 ptr = _in.ptr;
                          uint256 out;
                          assembly {
                              out := byte(0, mload(ptr))
                          }
                          require(out == 0 || out == 1, "Lib_RLPReader: Invalid RLP boolean value, must be 0 or 1");
                          return out != 0;
                      }
                      /**
                       * Reads an RLP bool value into a bool.
                       * @param _in RLP bool value.
                       * @return Decoded bool.
                       */
                      function readBool(bytes memory _in) internal pure returns (bool) {
                          return readBool(toRLPItem(_in));
                      }
                      /**
                       * Reads an RLP address value into a address.
                       * @param _in RLP address value.
                       * @return Decoded address.
                       */
                      function readAddress(RLPItem memory _in) internal pure returns (address) {
                          if (_in.length == 1) {
                              return address(0);
                          }
                          require(_in.length == 21, "Invalid RLP address value.");
                          return address(uint160(readUint256(_in)));
                      }
                      /**
                       * Reads an RLP address value into a address.
                       * @param _in RLP address value.
                       * @return Decoded address.
                       */
                      function readAddress(bytes memory _in) internal pure returns (address) {
                          return readAddress(toRLPItem(_in));
                      }
                      /**
                       * Reads the raw bytes of an RLP item.
                       * @param _in RLP item to read.
                       * @return Raw RLP bytes.
                       */
                      function readRawBytes(RLPItem memory _in) internal pure returns (bytes memory) {
                          return _copy(_in);
                      }
                      /*********************
                       * Private Functions *
                       *********************/
                      /**
                       * Decodes the length of an RLP item.
                       * @param _in RLP item to decode.
                       * @return Offset of the encoded data.
                       * @return Length of the encoded data.
                       * @return RLP item type (LIST_ITEM or DATA_ITEM).
                       */
                      function _decodeLength(RLPItem memory _in)
                          private
                          pure
                          returns (
                              uint256,
                              uint256,
                              RLPItemType
                          )
                      {
                          require(_in.length > 0, "RLP item cannot be null.");
                          uint256 ptr = _in.ptr;
                          uint256 prefix;
                          assembly {
                              prefix := byte(0, mload(ptr))
                          }
                          if (prefix <= 0x7f) {
                              // Single byte.
                              return (0, 1, RLPItemType.DATA_ITEM);
                          } else if (prefix <= 0xb7) {
                              // Short string.
                              uint256 strLen = prefix - 0x80;
                              require(_in.length > strLen, "Invalid RLP short string.");
                              return (1, strLen, RLPItemType.DATA_ITEM);
                          } else if (prefix <= 0xbf) {
                              // Long string.
                              uint256 lenOfStrLen = prefix - 0xb7;
                              require(_in.length > lenOfStrLen, "Invalid RLP long string length.");
                              uint256 strLen;
                              assembly {
                                  // Pick out the string length.
                                  strLen := div(mload(add(ptr, 1)), exp(256, sub(32, lenOfStrLen)))
                              }
                              require(_in.length > lenOfStrLen + strLen, "Invalid RLP long string.");
                              return (1 + lenOfStrLen, strLen, RLPItemType.DATA_ITEM);
                          } else if (prefix <= 0xf7) {
                              // Short list.
                              uint256 listLen = prefix - 0xc0;
                              require(_in.length > listLen, "Invalid RLP short list.");
                              return (1, listLen, RLPItemType.LIST_ITEM);
                          } else {
                              // Long list.
                              uint256 lenOfListLen = prefix - 0xf7;
                              require(_in.length > lenOfListLen, "Invalid RLP long list length.");
                              uint256 listLen;
                              assembly {
                                  // Pick out the list length.
                                  listLen := div(mload(add(ptr, 1)), exp(256, sub(32, lenOfListLen)))
                              }
                              require(_in.length > lenOfListLen + listLen, "Invalid RLP long list.");
                              return (1 + lenOfListLen, listLen, RLPItemType.LIST_ITEM);
                          }
                      }
                      /**
                       * Copies the bytes from a memory location.
                       * @param _src Pointer to the location to read from.
                       * @param _offset Offset to start reading from.
                       * @param _length Number of bytes to read.
                       * @return Copied bytes.
                       */
                      function _copy(
                          uint256 _src,
                          uint256 _offset,
                          uint256 _length
                      ) private pure returns (bytes memory) {
                          bytes memory out = new bytes(_length);
                          if (out.length == 0) {
                              return out;
                          }
                          uint256 src = _src + _offset;
                          uint256 dest;
                          assembly {
                              dest := add(out, 32)
                          }
                          // Copy over as many complete words as we can.
                          for (uint256 i = 0; i < _length / 32; i++) {
                              assembly {
                                  mstore(dest, mload(src))
                              }
                              src += 32;
                              dest += 32;
                          }
                          // Pick out the remaining bytes.
                          uint256 mask;
                          unchecked {
                              mask = 256**(32 - (_length % 32)) - 1;
                          }
                          assembly {
                              mstore(dest, or(and(mload(src), not(mask)), and(mload(dest), mask)))
                          }
                          return out;
                      }
                      /**
                       * Copies an RLP item into bytes.
                       * @param _in RLP item to copy.
                       * @return Copied bytes.
                       */
                      function _copy(RLPItem memory _in) private pure returns (bytes memory) {
                          return _copy(_in.ptr, 0, _in.length);
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /**
                   * @title Lib_RLPWriter
                   * @author Bakaoh (with modifications)
                   */
                  library Lib_RLPWriter {
                      /**********************
                       * Internal Functions *
                       **********************/
                      /**
                       * RLP encodes a byte string.
                       * @param _in The byte string to encode.
                       * @return The RLP encoded string in bytes.
                       */
                      function writeBytes(bytes memory _in) internal pure returns (bytes memory) {
                          bytes memory encoded;
                          if (_in.length == 1 && uint8(_in[0]) < 128) {
                              encoded = _in;
                          } else {
                              encoded = abi.encodePacked(_writeLength(_in.length, 128), _in);
                          }
                          return encoded;
                      }
                      /**
                       * RLP encodes a list of RLP encoded byte byte strings.
                       * @param _in The list of RLP encoded byte strings.
                       * @return The RLP encoded list of items in bytes.
                       */
                      function writeList(bytes[] memory _in) internal pure returns (bytes memory) {
                          bytes memory list = _flatten(_in);
                          return abi.encodePacked(_writeLength(list.length, 192), list);
                      }
                      /**
                       * RLP encodes a string.
                       * @param _in The string to encode.
                       * @return The RLP encoded string in bytes.
                       */
                      function writeString(string memory _in) internal pure returns (bytes memory) {
                          return writeBytes(bytes(_in));
                      }
                      /**
                       * RLP encodes an address.
                       * @param _in The address to encode.
                       * @return The RLP encoded address in bytes.
                       */
                      function writeAddress(address _in) internal pure returns (bytes memory) {
                          return writeBytes(abi.encodePacked(_in));
                      }
                      /**
                       * RLP encodes a uint.
                       * @param _in The uint256 to encode.
                       * @return The RLP encoded uint256 in bytes.
                       */
                      function writeUint(uint256 _in) internal pure returns (bytes memory) {
                          return writeBytes(_toBinary(_in));
                      }
                      /**
                       * RLP encodes a bool.
                       * @param _in The bool to encode.
                       * @return The RLP encoded bool in bytes.
                       */
                      function writeBool(bool _in) internal pure returns (bytes memory) {
                          bytes memory encoded = new bytes(1);
                          encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80));
                          return encoded;
                      }
                      /*********************
                       * Private Functions *
                       *********************/
                      /**
                       * Encode the first byte, followed by the `len` in binary form if `length` is more than 55.
                       * @param _len The length of the string or the payload.
                       * @param _offset 128 if item is string, 192 if item is list.
                       * @return RLP encoded bytes.
                       */
                      function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) {
                          bytes memory encoded;
                          if (_len < 56) {
                              encoded = new bytes(1);
                              encoded[0] = bytes1(uint8(_len) + uint8(_offset));
                          } else {
                              uint256 lenLen;
                              uint256 i = 1;
                              while (_len / i != 0) {
                                  lenLen++;
                                  i *= 256;
                              }
                              encoded = new bytes(lenLen + 1);
                              encoded[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55);
                              for (i = 1; i <= lenLen; i++) {
                                  encoded[i] = bytes1(uint8((_len / (256**(lenLen - i))) % 256));
                              }
                          }
                          return encoded;
                      }
                      /**
                       * Encode integer in big endian binary form with no leading zeroes.
                       * @notice TODO: This should be optimized with assembly to save gas costs.
                       * @param _x The integer to encode.
                       * @return RLP encoded bytes.
                       */
                      function _toBinary(uint256 _x) private pure returns (bytes memory) {
                          bytes memory b = abi.encodePacked(_x);
                          uint256 i = 0;
                          for (; i < 32; i++) {
                              if (b[i] != 0) {
                                  break;
                              }
                          }
                          bytes memory res = new bytes(32 - i);
                          for (uint256 j = 0; j < res.length; j++) {
                              res[j] = b[i++];
                          }
                          return res;
                      }
                      /**
                       * Copies a piece of memory to another location.
                       * @notice From: https://github.com/Arachnid/solidity-stringutils/blob/master/src/strings.sol.
                       * @param _dest Destination location.
                       * @param _src Source location.
                       * @param _len Length of memory to copy.
                       */
                      function _memcpy(
                          uint256 _dest,
                          uint256 _src,
                          uint256 _len
                      ) private pure {
                          uint256 dest = _dest;
                          uint256 src = _src;
                          uint256 len = _len;
                          for (; len >= 32; len -= 32) {
                              assembly {
                                  mstore(dest, mload(src))
                              }
                              dest += 32;
                              src += 32;
                          }
                          uint256 mask;
                          unchecked {
                              mask = 256**(32 - len) - 1;
                          }
                          assembly {
                              let srcpart := and(mload(src), not(mask))
                              let destpart := and(mload(dest), mask)
                              mstore(dest, or(destpart, srcpart))
                          }
                      }
                      /**
                       * Flattens a list of byte strings into one byte string.
                       * @notice From: https://github.com/sammayo/solidity-rlp-encoder/blob/master/RLPEncode.sol.
                       * @param _list List of byte strings to flatten.
                       * @return The flattened byte string.
                       */
                      function _flatten(bytes[] memory _list) private pure returns (bytes memory) {
                          if (_list.length == 0) {
                              return new bytes(0);
                          }
                          uint256 len;
                          uint256 i = 0;
                          for (; i < _list.length; i++) {
                              len += _list[i].length;
                          }
                          bytes memory flattened = new bytes(len);
                          uint256 flattenedPtr;
                          assembly {
                              flattenedPtr := add(flattened, 0x20)
                          }
                          for (i = 0; i < _list.length; i++) {
                              bytes memory item = _list[i];
                              uint256 listPtr;
                              assembly {
                                  listPtr := add(item, 0x20)
                              }
                              _memcpy(flattenedPtr, listPtr, item.length);
                              flattenedPtr += _list[i].length;
                          }
                          return flattened;
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /**
                   * @title Lib_BytesUtils
                   */
                  library Lib_BytesUtils {
                      /**********************
                       * Internal Functions *
                       **********************/
                      function slice(
                          bytes memory _bytes,
                          uint256 _start,
                          uint256 _length
                      ) internal pure returns (bytes memory) {
                          require(_length + 31 >= _length, "slice_overflow");
                          require(_start + _length >= _start, "slice_overflow");
                          require(_bytes.length >= _start + _length, "slice_outOfBounds");
                          bytes memory tempBytes;
                          assembly {
                              switch iszero(_length)
                              case 0 {
                                  // Get a location of some free memory and store it in tempBytes as
                                  // Solidity does for memory variables.
                                  tempBytes := mload(0x40)
                                  // The first word of the slice result is potentially a partial
                                  // word read from the original array. To read it, we calculate
                                  // the length of that partial word and start copying that many
                                  // bytes into the array. The first word we copy will start with
                                  // data we don't care about, but the last `lengthmod` bytes will
                                  // land at the beginning of the contents of the new array. When
                                  // we're done copying, we overwrite the full first word with
                                  // the actual length of the slice.
                                  let lengthmod := and(_length, 31)
                                  // The multiplication in the next line is necessary
                                  // because when slicing multiples of 32 bytes (lengthmod == 0)
                                  // the following copy loop was copying the origin's length
                                  // and then ending prematurely not copying everything it should.
                                  let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                                  let end := add(mc, _length)
                                  for {
                                      // The multiplication in the next line has the same exact purpose
                                      // as the one above.
                                      let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                                  } lt(mc, end) {
                                      mc := add(mc, 0x20)
                                      cc := add(cc, 0x20)
                                  } {
                                      mstore(mc, mload(cc))
                                  }
                                  mstore(tempBytes, _length)
                                  //update free-memory pointer
                                  //allocating the array padded to 32 bytes like the compiler does now
                                  mstore(0x40, and(add(mc, 31), not(31)))
                              }
                              //if we want a zero-length slice let's just return a zero-length array
                              default {
                                  tempBytes := mload(0x40)
                                  //zero out the 32 bytes slice we are about to return
                                  //we need to do it because Solidity does not garbage collect
                                  mstore(tempBytes, 0)
                                  mstore(0x40, add(tempBytes, 0x20))
                              }
                          }
                          return tempBytes;
                      }
                      function slice(bytes memory _bytes, uint256 _start) internal pure returns (bytes memory) {
                          if (_start >= _bytes.length) {
                              return bytes("");
                          }
                          return slice(_bytes, _start, _bytes.length - _start);
                      }
                      function toBytes32(bytes memory _bytes) internal pure returns (bytes32) {
                          if (_bytes.length < 32) {
                              bytes32 ret;
                              assembly {
                                  ret := mload(add(_bytes, 32))
                              }
                              return ret;
                          }
                          return abi.decode(_bytes, (bytes32)); // will truncate if input length > 32 bytes
                      }
                      function toUint256(bytes memory _bytes) internal pure returns (uint256) {
                          return uint256(toBytes32(_bytes));
                      }
                      function toNibbles(bytes memory _bytes) internal pure returns (bytes memory) {
                          bytes memory nibbles = new bytes(_bytes.length * 2);
                          for (uint256 i = 0; i < _bytes.length; i++) {
                              nibbles[i * 2] = _bytes[i] >> 4;
                              nibbles[i * 2 + 1] = bytes1(uint8(_bytes[i]) % 16);
                          }
                          return nibbles;
                      }
                      function fromNibbles(bytes memory _bytes) internal pure returns (bytes memory) {
                          bytes memory ret = new bytes(_bytes.length / 2);
                          for (uint256 i = 0; i < ret.length; i++) {
                              ret[i] = (_bytes[i * 2] << 4) | (_bytes[i * 2 + 1]);
                          }
                          return ret;
                      }
                      function equal(bytes memory _bytes, bytes memory _other) internal pure returns (bool) {
                          return keccak256(_bytes) == keccak256(_other);
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /**
                   * @title Lib_Byte32Utils
                   */
                  library Lib_Bytes32Utils {
                      /**********************
                       * Internal Functions *
                       **********************/
                      /**
                       * Converts a bytes32 value to a boolean. Anything non-zero will be converted to "true."
                       * @param _in Input bytes32 value.
                       * @return Bytes32 as a boolean.
                       */
                      function toBool(bytes32 _in) internal pure returns (bool) {
                          return _in != 0;
                      }
                      /**
                       * Converts a boolean to a bytes32 value.
                       * @param _in Input boolean value.
                       * @return Boolean as a bytes32.
                       */
                      function fromBool(bool _in) internal pure returns (bytes32) {
                          return bytes32(uint256(_in ? 1 : 0));
                      }
                      /**
                       * Converts a bytes32 value to an address. Takes the *last* 20 bytes.
                       * @param _in Input bytes32 value.
                       * @return Bytes32 as an address.
                       */
                      function toAddress(bytes32 _in) internal pure returns (address) {
                          return address(uint160(uint256(_in)));
                      }
                      /**
                       * Converts an address to a bytes32.
                       * @param _in Input address value.
                       * @return Address as a bytes32.
                       */
                      function fromAddress(address _in) internal pure returns (bytes32) {
                          return bytes32(uint256(uint160(_in)));
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /* External Imports */
                  import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
                  /**
                   * @title Lib_AddressManager
                   */
                  contract Lib_AddressManager is Ownable {
                      /**********
                       * Events *
                       **********/
                      event AddressSet(string indexed _name, address _newAddress, address _oldAddress);
                      /*************
                       * Variables *
                       *************/
                      mapping(bytes32 => address) private addresses;
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * Changes the address associated with a particular name.
                       * @param _name String name to associate an address with.
                       * @param _address Address to associate with the name.
                       */
                      function setAddress(string memory _name, address _address) external onlyOwner {
                          bytes32 nameHash = _getNameHash(_name);
                          address oldAddress = addresses[nameHash];
                          addresses[nameHash] = _address;
                          emit AddressSet(_name, _address, oldAddress);
                      }
                      /**
                       * Retrieves the address associated with a given name.
                       * @param _name Name to retrieve an address for.
                       * @return Address associated with the given name.
                       */
                      function getAddress(string memory _name) external view returns (address) {
                          return addresses[_getNameHash(_name)];
                      }
                      /**********************
                       * Internal Functions *
                       **********************/
                      /**
                       * Computes the hash of a name.
                       * @param _name Name to compute a hash for.
                       * @return Hash of the given name.
                       */
                      function _getNameHash(string memory _name) internal pure returns (bytes32) {
                          return keccak256(abi.encodePacked(_name));
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.0;
                  import "../utils/Context.sol";
                  /**
                   * @dev Contract module which provides a basic access control mechanism, where
                   * there is an account (an owner) that can be granted exclusive access to
                   * specific functions.
                   *
                   * By default, the owner account will be the one that deploys the contract. This
                   * can later be changed with {transferOwnership}.
                   *
                   * This module is used through inheritance. It will make available the modifier
                   * `onlyOwner`, which can be applied to your functions to restrict their use to
                   * the owner.
                   */
                  abstract contract Ownable is Context {
                      address private _owner;
                      event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                      /**
                       * @dev Initializes the contract setting the deployer as the initial owner.
                       */
                      constructor() {
                          _setOwner(_msgSender());
                      }
                      /**
                       * @dev Returns the address of the current owner.
                       */
                      function owner() public view virtual returns (address) {
                          return _owner;
                      }
                      /**
                       * @dev Throws if called by any account other than the owner.
                       */
                      modifier onlyOwner() {
                          require(owner() == _msgSender(), "Ownable: caller is not the owner");
                          _;
                      }
                      /**
                       * @dev Leaves the contract without owner. It will not be possible to call
                       * `onlyOwner` functions anymore. Can only be called by the current owner.
                       *
                       * NOTE: Renouncing ownership will leave the contract without an owner,
                       * thereby removing any functionality that is only available to the owner.
                       */
                      function renounceOwnership() public virtual onlyOwner {
                          _setOwner(address(0));
                      }
                      /**
                       * @dev Transfers ownership of the contract to a new account (`newOwner`).
                       * Can only be called by the current owner.
                       */
                      function transferOwnership(address newOwner) public virtual onlyOwner {
                          require(newOwner != address(0), "Ownable: new owner is the zero address");
                          _setOwner(newOwner);
                      }
                      function _setOwner(address newOwner) private {
                          address oldOwner = _owner;
                          _owner = newOwner;
                          emit OwnershipTransferred(oldOwner, newOwner);
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.0;
                  /**
                   * @dev Provides information about the current execution context, including the
                   * sender of the transaction and its data. While these are generally available
                   * via msg.sender and msg.data, they should not be accessed in such a direct
                   * manner, since when dealing with meta-transactions the account sending and
                   * paying for execution may not be the actual sender (as far as an application
                   * is concerned).
                   *
                   * This contract is only required for intermediate, library-like contracts.
                   */
                  abstract contract Context {
                      function _msgSender() internal view virtual returns (address) {
                          return msg.sender;
                      }
                      function _msgData() internal view virtual returns (bytes calldata) {
                          return msg.data;
                      }
                  }
                  

                  File 4 of 14: Lib_ResolvedDelegateProxy
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  import "../utils/Context.sol";
                  /**
                   * @dev Contract module which provides a basic access control mechanism, where
                   * there is an account (an owner) that can be granted exclusive access to
                   * specific functions.
                   *
                   * By default, the owner account will be the one that deploys the contract. This
                   * can later be changed with {transferOwnership}.
                   *
                   * This module is used through inheritance. It will make available the modifier
                   * `onlyOwner`, which can be applied to your functions to restrict their use to
                   * the owner.
                   */
                  abstract contract Ownable is Context {
                      address private _owner;
                      event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                      /**
                       * @dev Initializes the contract setting the deployer as the initial owner.
                       */
                      constructor () internal {
                          address msgSender = _msgSender();
                          _owner = msgSender;
                          emit OwnershipTransferred(address(0), msgSender);
                      }
                      /**
                       * @dev Returns the address of the current owner.
                       */
                      function owner() public view virtual returns (address) {
                          return _owner;
                      }
                      /**
                       * @dev Throws if called by any account other than the owner.
                       */
                      modifier onlyOwner() {
                          require(owner() == _msgSender(), "Ownable: caller is not the owner");
                          _;
                      }
                      /**
                       * @dev Leaves the contract without owner. It will not be possible to call
                       * `onlyOwner` functions anymore. Can only be called by the current owner.
                       *
                       * NOTE: Renouncing ownership will leave the contract without an owner,
                       * thereby removing any functionality that is only available to the owner.
                       */
                      function renounceOwnership() public virtual onlyOwner {
                          emit OwnershipTransferred(_owner, address(0));
                          _owner = address(0);
                      }
                      /**
                       * @dev Transfers ownership of the contract to a new account (`newOwner`).
                       * Can only be called by the current owner.
                       */
                      function transferOwnership(address newOwner) public virtual onlyOwner {
                          require(newOwner != address(0), "Ownable: new owner is the zero address");
                          emit OwnershipTransferred(_owner, newOwner);
                          _owner = newOwner;
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  /*
                   * @dev Provides information about the current execution context, including the
                   * sender of the transaction and its data. While these are generally available
                   * via msg.sender and msg.data, they should not be accessed in such a direct
                   * manner, since when dealing with GSN meta-transactions the account sending and
                   * paying for execution may not be the actual sender (as far as an application
                   * is concerned).
                   *
                   * This contract is only required for intermediate, library-like contracts.
                   */
                  abstract contract Context {
                      function _msgSender() internal view virtual returns (address payable) {
                          return msg.sender;
                      }
                      function _msgData() internal view virtual returns (bytes memory) {
                          this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                          return msg.data;
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >0.5.0 <0.8.0;
                  /* External Imports */
                  import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
                  /**
                   * @title Lib_AddressManager
                   */
                  contract Lib_AddressManager is Ownable {
                      /**********
                       * Events *
                       **********/
                      event AddressSet(
                          string indexed _name,
                          address _newAddress,
                          address _oldAddress
                      );
                      /*************
                       * Variables *
                       *************/
                      mapping (bytes32 => address) private addresses;
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * Changes the address associated with a particular name.
                       * @param _name String name to associate an address with.
                       * @param _address Address to associate with the name.
                       */
                      function setAddress(
                          string memory _name,
                          address _address
                      )
                          external
                          onlyOwner
                      {
                          bytes32 nameHash = _getNameHash(_name);
                          address oldAddress = addresses[nameHash];
                          addresses[nameHash] = _address;
                          emit AddressSet(
                              _name,
                              _address,
                              oldAddress
                          );
                      }
                      /**
                       * Retrieves the address associated with a given name.
                       * @param _name Name to retrieve an address for.
                       * @return Address associated with the given name.
                       */
                      function getAddress(
                          string memory _name
                      )
                          external
                          view
                          returns (
                              address
                          )
                      {
                          return addresses[_getNameHash(_name)];
                      }
                      /**********************
                       * Internal Functions *
                       **********************/
                      /**
                       * Computes the hash of a name.
                       * @param _name Name to compute a hash for.
                       * @return Hash of the given name.
                       */
                      function _getNameHash(
                          string memory _name
                      )
                          internal
                          pure
                          returns (
                              bytes32
                          )
                      {
                          return keccak256(abi.encodePacked(_name));
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >0.5.0 <0.8.0;
                  /* Library Imports */
                  import { Lib_AddressManager } from "./Lib_AddressManager.sol";
                  /**
                   * @title Lib_ResolvedDelegateProxy
                   */
                  contract Lib_ResolvedDelegateProxy {
                      /*************
                       * Variables *
                       *************/
                      // Using mappings to store fields to avoid overwriting storage slots in the
                      // implementation contract. For example, instead of storing these fields at
                      // storage slot `0` & `1`, they are stored at `keccak256(key + slot)`.
                      // See: https://solidity.readthedocs.io/en/v0.7.0/internals/layout_in_storage.html
                      // NOTE: Do not use this code in your own contract system.
                      //      There is a known flaw in this contract, and we will remove it from the repository
                      //      in the near future. Due to the very limited way that we are using it, this flaw is
                      //      not an issue in our system.
                      mapping (address => string) private implementationName;
                      mapping (address => Lib_AddressManager) private addressManager;
                      /***************
                       * Constructor *
                       ***************/
                      /**
                       * @param _libAddressManager Address of the Lib_AddressManager.
                       * @param _implementationName implementationName of the contract to proxy to.
                       */
                      constructor(
                          address _libAddressManager,
                          string memory _implementationName
                      ) {
                          addressManager[address(this)] = Lib_AddressManager(_libAddressManager);
                          implementationName[address(this)] = _implementationName;
                      }
                      /*********************
                       * Fallback Function *
                       *********************/
                      fallback()
                          external
                          payable
                      {
                          address target = addressManager[address(this)].getAddress(
                              (implementationName[address(this)])
                          );
                          require(
                              target != address(0),
                              "Target address must be initialized."
                          );
                          (bool success, bytes memory returndata) = target.delegatecall(msg.data);
                          if (success == true) {
                              assembly {
                                  return(add(returndata, 0x20), mload(returndata))
                              }
                          } else {
                              assembly {
                                  revert(add(returndata, 0x20), mload(returndata))
                              }
                          }
                      }
                  }
                  

                  File 5 of 14: Proxy
                  pragma solidity ^0.5.3;
                  
                  /// @title Proxy - Generic proxy contract allows to execute all transactions applying the code of a master contract.
                  /// @author Stefan George - <[email protected]>
                  /// @author Richard Meissner - <[email protected]>
                  contract Proxy {
                  
                      // masterCopy always needs to be first declared variable, to ensure that it is at the same location in the contracts to which calls are delegated.
                      // To reduce deployment costs this variable is internal and needs to be retrieved via `getStorageAt`
                      address internal masterCopy;
                  
                      /// @dev Constructor function sets address of master copy contract.
                      /// @param _masterCopy Master copy address.
                      constructor(address _masterCopy)
                          public
                      {
                          require(_masterCopy != address(0), "Invalid master copy address provided");
                          masterCopy = _masterCopy;
                      }
                  
                      /// @dev Fallback function forwards all transactions and returns all received return data.
                      function ()
                          external
                          payable
                      {
                          // solium-disable-next-line security/no-inline-assembly
                          assembly {
                              let masterCopy := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)
                              // 0xa619486e == keccak("masterCopy()"). The value is right padded to 32-bytes with 0s
                              if eq(calldataload(0), 0xa619486e00000000000000000000000000000000000000000000000000000000) {
                                  mstore(0, masterCopy)
                                  return(0, 0x20)
                              }
                              calldatacopy(0, 0, calldatasize())
                              let success := delegatecall(gas, masterCopy, 0, calldatasize(), 0, 0)
                              returndatacopy(0, 0, returndatasize())
                              if eq(success, 0) { revert(0, returndatasize()) }
                              return(0, returndatasize())
                          }
                      }
                  }

                  File 6 of 14: GnosisSafe
                  pragma solidity >=0.5.0 <0.7.0;
                  
                  /// @title SelfAuthorized - authorizes current contract to perform actions
                  /// @author Richard Meissner - <[email protected]>
                  contract SelfAuthorized {
                      modifier authorized() {
                          require(msg.sender == address(this), "Method can only be called from this contract");
                          _;
                      }
                  }
                  
                  
                  
                  /// @title MasterCopy - Base for master copy contracts (should always be first super contract)
                  ///         This contract is tightly coupled to our proxy contract (see `proxies/Proxy.sol`)
                  /// @author Richard Meissner - <[email protected]>
                  contract MasterCopy is SelfAuthorized {
                  
                      event ChangedMasterCopy(address masterCopy);
                  
                      // masterCopy always needs to be first declared variable, to ensure that it is at the same location as in the Proxy contract.
                      // It should also always be ensured that the address is stored alone (uses a full word)
                      address private masterCopy;
                  
                      /// @dev Allows to upgrade the contract. This can only be done via a Safe transaction.
                      /// @param _masterCopy New contract address.
                      function changeMasterCopy(address _masterCopy)
                          public
                          authorized
                      {
                          // Master copy address cannot be null.
                          require(_masterCopy != address(0), "Invalid master copy address provided");
                          masterCopy = _masterCopy;
                          emit ChangedMasterCopy(_masterCopy);
                      }
                  }
                  
                  
                  /// @title Module - Base class for modules.
                  /// @author Stefan George - <[email protected]>
                  /// @author Richard Meissner - <[email protected]>
                  contract Module is MasterCopy {
                  
                      ModuleManager public manager;
                  
                      modifier authorized() {
                          require(msg.sender == address(manager), "Method can only be called from manager");
                          _;
                      }
                  
                      function setManager()
                          internal
                      {
                          // manager can only be 0 at initalization of contract.
                          // Check ensures that setup function can only be called once.
                          require(address(manager) == address(0), "Manager has already been set");
                          manager = ModuleManager(msg.sender);
                      }
                  }
                  
                  
                  
                  
                  
                  /// @title Enum - Collection of enums
                  /// @author Richard Meissner - <[email protected]>
                  contract Enum {
                      enum Operation {
                          Call,
                          DelegateCall
                      }
                  }
                  
                  
                  
                  
                  
                  /// @title Executor - A contract that can execute transactions
                  /// @author Richard Meissner - <[email protected]>
                  contract Executor {
                  
                      function execute(address to, uint256 value, bytes memory data, Enum.Operation operation, uint256 txGas)
                          internal
                          returns (bool success)
                      {
                          if (operation == Enum.Operation.Call)
                              success = executeCall(to, value, data, txGas);
                          else if (operation == Enum.Operation.DelegateCall)
                              success = executeDelegateCall(to, data, txGas);
                          else
                              success = false;
                      }
                  
                      function executeCall(address to, uint256 value, bytes memory data, uint256 txGas)
                          internal
                          returns (bool success)
                      {
                          // solium-disable-next-line security/no-inline-assembly
                          assembly {
                              success := call(txGas, to, value, add(data, 0x20), mload(data), 0, 0)
                          }
                      }
                  
                      function executeDelegateCall(address to, bytes memory data, uint256 txGas)
                          internal
                          returns (bool success)
                      {
                          // solium-disable-next-line security/no-inline-assembly
                          assembly {
                              success := delegatecall(txGas, to, add(data, 0x20), mload(data), 0, 0)
                          }
                      }
                  }
                  
                  
                  
                  /// @title SecuredTokenTransfer - Secure token transfer
                  /// @author Richard Meissner - <[email protected]>
                  contract SecuredTokenTransfer {
                  
                      /// @dev Transfers a token and returns if it was a success
                      /// @param token Token that should be transferred
                      /// @param receiver Receiver to whom the token should be transferred
                      /// @param amount The amount of tokens that should be transferred
                      function transferToken (
                          address token,
                          address receiver,
                          uint256 amount
                      )
                          internal
                          returns (bool transferred)
                      {
                          bytes memory data = abi.encodeWithSignature("transfer(address,uint256)", receiver, amount);
                          // solium-disable-next-line security/no-inline-assembly
                          assembly {
                              let success := call(sub(gas, 10000), token, 0, add(data, 0x20), mload(data), 0, 0)
                              let ptr := mload(0x40)
                              mstore(0x40, add(ptr, returndatasize()))
                              returndatacopy(ptr, 0, returndatasize())
                              switch returndatasize()
                              case 0 { transferred := success }
                              case 0x20 { transferred := iszero(or(iszero(success), iszero(mload(ptr)))) }
                              default { transferred := 0 }
                          }
                      }
                  }
                  
                  
                  
                  
                  
                  
                  
                  
                  
                  
                  /// @title Module Manager - A contract that manages modules that can execute transactions via this contract
                  /// @author Stefan George - <[email protected]>
                  /// @author Richard Meissner - <[email protected]>
                  contract ModuleManager is SelfAuthorized, Executor {
                  
                      event EnabledModule(Module module);
                      event DisabledModule(Module module);
                      event ExecutionFromModuleSuccess(address indexed module);
                      event ExecutionFromModuleFailure(address indexed module);
                  
                      address internal constant SENTINEL_MODULES = address(0x1);
                  
                      mapping (address => address) internal modules;
                  
                      function setupModules(address to, bytes memory data)
                          internal
                      {
                          require(modules[SENTINEL_MODULES] == address(0), "Modules have already been initialized");
                          modules[SENTINEL_MODULES] = SENTINEL_MODULES;
                          if (to != address(0))
                              // Setup has to complete successfully or transaction fails.
                              require(executeDelegateCall(to, data, gasleft()), "Could not finish initialization");
                      }
                  
                      /// @dev Allows to add a module to the whitelist.
                      ///      This can only be done via a Safe transaction.
                      /// @param module Module to be whitelisted.
                      function enableModule(Module module)
                          public
                          authorized
                      {
                          // Module address cannot be null or sentinel.
                          require(address(module) != address(0) && address(module) != SENTINEL_MODULES, "Invalid module address provided");
                          // Module cannot be added twice.
                          require(modules[address(module)] == address(0), "Module has already been added");
                          modules[address(module)] = modules[SENTINEL_MODULES];
                          modules[SENTINEL_MODULES] = address(module);
                          emit EnabledModule(module);
                      }
                  
                      /// @dev Allows to remove a module from the whitelist.
                      ///      This can only be done via a Safe transaction.
                      /// @param prevModule Module that pointed to the module to be removed in the linked list
                      /// @param module Module to be removed.
                      function disableModule(Module prevModule, Module module)
                          public
                          authorized
                      {
                          // Validate module address and check that it corresponds to module index.
                          require(address(module) != address(0) && address(module) != SENTINEL_MODULES, "Invalid module address provided");
                          require(modules[address(prevModule)] == address(module), "Invalid prevModule, module pair provided");
                          modules[address(prevModule)] = modules[address(module)];
                          modules[address(module)] = address(0);
                          emit DisabledModule(module);
                      }
                  
                      /// @dev Allows a Module to execute a Safe transaction without any further confirmations.
                      /// @param to Destination address of module transaction.
                      /// @param value Ether value of module transaction.
                      /// @param data Data payload of module transaction.
                      /// @param operation Operation type of module transaction.
                      function execTransactionFromModule(address to, uint256 value, bytes memory data, Enum.Operation operation)
                          public
                          returns (bool success)
                      {
                          // Only whitelisted modules are allowed.
                          require(msg.sender != SENTINEL_MODULES && modules[msg.sender] != address(0), "Method can only be called from an enabled module");
                          // Execute transaction without further confirmations.
                          success = execute(to, value, data, operation, gasleft());
                          if (success) emit ExecutionFromModuleSuccess(msg.sender);
                          else emit ExecutionFromModuleFailure(msg.sender);
                      }
                  
                      /// @dev Allows a Module to execute a Safe transaction without any further confirmations and return data
                      /// @param to Destination address of module transaction.
                      /// @param value Ether value of module transaction.
                      /// @param data Data payload of module transaction.
                      /// @param operation Operation type of module transaction.
                      function execTransactionFromModuleReturnData(address to, uint256 value, bytes memory data, Enum.Operation operation)
                          public
                          returns (bool success, bytes memory returnData)
                      {
                          success = execTransactionFromModule(to, value, data, operation);
                          // solium-disable-next-line security/no-inline-assembly
                          assembly {
                              // Load free memory location
                              let ptr := mload(0x40)
                              // We allocate memory for the return data by setting the free memory location to
                              // current free memory location + data size + 32 bytes for data size value
                              mstore(0x40, add(ptr, add(returndatasize(), 0x20)))
                              // Store the size
                              mstore(ptr, returndatasize())
                              // Store the data
                              returndatacopy(add(ptr, 0x20), 0, returndatasize())
                              // Point the return data to the correct memory location
                              returnData := ptr
                          }
                      }
                  
                      /// @dev Returns array of first 10 modules.
                      /// @return Array of modules.
                      function getModules()
                          public
                          view
                          returns (address[] memory)
                      {
                          (address[] memory array,) = getModulesPaginated(SENTINEL_MODULES, 10);
                          return array;
                      }
                  
                      /// @dev Returns array of modules.
                      /// @param start Start of the page.
                      /// @param pageSize Maximum number of modules that should be returned.
                      /// @return Array of modules.
                      function getModulesPaginated(address start, uint256 pageSize)
                          public
                          view
                          returns (address[] memory array, address next)
                      {
                          // Init array with max page size
                          array = new address[](pageSize);
                  
                          // Populate return array
                          uint256 moduleCount = 0;
                          address currentModule = modules[start];
                          while(currentModule != address(0x0) && currentModule != SENTINEL_MODULES && moduleCount < pageSize) {
                              array[moduleCount] = currentModule;
                              currentModule = modules[currentModule];
                              moduleCount++;
                          }
                          next = currentModule;
                          // Set correct size of returned array
                          // solium-disable-next-line security/no-inline-assembly
                          assembly {
                              mstore(array, moduleCount)
                          }
                      }
                  }
                  
                  
                  
                  
                  /// @title OwnerManager - Manages a set of owners and a threshold to perform actions.
                  /// @author Stefan George - <[email protected]>
                  /// @author Richard Meissner - <[email protected]>
                  contract OwnerManager is SelfAuthorized {
                  
                      event AddedOwner(address owner);
                      event RemovedOwner(address owner);
                      event ChangedThreshold(uint256 threshold);
                  
                      address internal constant SENTINEL_OWNERS = address(0x1);
                  
                      mapping(address => address) internal owners;
                      uint256 ownerCount;
                      uint256 internal threshold;
                  
                      /// @dev Setup function sets initial storage of contract.
                      /// @param _owners List of Safe owners.
                      /// @param _threshold Number of required confirmations for a Safe transaction.
                      function setupOwners(address[] memory _owners, uint256 _threshold)
                          internal
                      {
                          // Threshold can only be 0 at initialization.
                          // Check ensures that setup function can only be called once.
                          require(threshold == 0, "Owners have already been setup");
                          // Validate that threshold is smaller than number of added owners.
                          require(_threshold <= _owners.length, "Threshold cannot exceed owner count");
                          // There has to be at least one Safe owner.
                          require(_threshold >= 1, "Threshold needs to be greater than 0");
                          // Initializing Safe owners.
                          address currentOwner = SENTINEL_OWNERS;
                          for (uint256 i = 0; i < _owners.length; i++) {
                              // Owner address cannot be null.
                              address owner = _owners[i];
                              require(owner != address(0) && owner != SENTINEL_OWNERS, "Invalid owner address provided");
                              // No duplicate owners allowed.
                              require(owners[owner] == address(0), "Duplicate owner address provided");
                              owners[currentOwner] = owner;
                              currentOwner = owner;
                          }
                          owners[currentOwner] = SENTINEL_OWNERS;
                          ownerCount = _owners.length;
                          threshold = _threshold;
                      }
                  
                      /// @dev Allows to add a new owner to the Safe and update the threshold at the same time.
                      ///      This can only be done via a Safe transaction.
                      /// @param owner New owner address.
                      /// @param _threshold New threshold.
                      function addOwnerWithThreshold(address owner, uint256 _threshold)
                          public
                          authorized
                      {
                          // Owner address cannot be null.
                          require(owner != address(0) && owner != SENTINEL_OWNERS, "Invalid owner address provided");
                          // No duplicate owners allowed.
                          require(owners[owner] == address(0), "Address is already an owner");
                          owners[owner] = owners[SENTINEL_OWNERS];
                          owners[SENTINEL_OWNERS] = owner;
                          ownerCount++;
                          emit AddedOwner(owner);
                          // Change threshold if threshold was changed.
                          if (threshold != _threshold)
                              changeThreshold(_threshold);
                      }
                  
                      /// @dev Allows to remove an owner from the Safe and update the threshold at the same time.
                      ///      This can only be done via a Safe transaction.
                      /// @param prevOwner Owner that pointed to the owner to be removed in the linked list
                      /// @param owner Owner address to be removed.
                      /// @param _threshold New threshold.
                      function removeOwner(address prevOwner, address owner, uint256 _threshold)
                          public
                          authorized
                      {
                          // Only allow to remove an owner, if threshold can still be reached.
                          require(ownerCount - 1 >= _threshold, "New owner count needs to be larger than new threshold");
                          // Validate owner address and check that it corresponds to owner index.
                          require(owner != address(0) && owner != SENTINEL_OWNERS, "Invalid owner address provided");
                          require(owners[prevOwner] == owner, "Invalid prevOwner, owner pair provided");
                          owners[prevOwner] = owners[owner];
                          owners[owner] = address(0);
                          ownerCount--;
                          emit RemovedOwner(owner);
                          // Change threshold if threshold was changed.
                          if (threshold != _threshold)
                              changeThreshold(_threshold);
                      }
                  
                      /// @dev Allows to swap/replace an owner from the Safe with another address.
                      ///      This can only be done via a Safe transaction.
                      /// @param prevOwner Owner that pointed to the owner to be replaced in the linked list
                      /// @param oldOwner Owner address to be replaced.
                      /// @param newOwner New owner address.
                      function swapOwner(address prevOwner, address oldOwner, address newOwner)
                          public
                          authorized
                      {
                          // Owner address cannot be null.
                          require(newOwner != address(0) && newOwner != SENTINEL_OWNERS, "Invalid owner address provided");
                          // No duplicate owners allowed.
                          require(owners[newOwner] == address(0), "Address is already an owner");
                          // Validate oldOwner address and check that it corresponds to owner index.
                          require(oldOwner != address(0) && oldOwner != SENTINEL_OWNERS, "Invalid owner address provided");
                          require(owners[prevOwner] == oldOwner, "Invalid prevOwner, owner pair provided");
                          owners[newOwner] = owners[oldOwner];
                          owners[prevOwner] = newOwner;
                          owners[oldOwner] = address(0);
                          emit RemovedOwner(oldOwner);
                          emit AddedOwner(newOwner);
                      }
                  
                      /// @dev Allows to update the number of required confirmations by Safe owners.
                      ///      This can only be done via a Safe transaction.
                      /// @param _threshold New threshold.
                      function changeThreshold(uint256 _threshold)
                          public
                          authorized
                      {
                          // Validate that threshold is smaller than number of owners.
                          require(_threshold <= ownerCount, "Threshold cannot exceed owner count");
                          // There has to be at least one Safe owner.
                          require(_threshold >= 1, "Threshold needs to be greater than 0");
                          threshold = _threshold;
                          emit ChangedThreshold(threshold);
                      }
                  
                      function getThreshold()
                          public
                          view
                          returns (uint256)
                      {
                          return threshold;
                      }
                  
                      function isOwner(address owner)
                          public
                          view
                          returns (bool)
                      {
                          return owner != SENTINEL_OWNERS && owners[owner] != address(0);
                      }
                  
                      /// @dev Returns array of owners.
                      /// @return Array of Safe owners.
                      function getOwners()
                          public
                          view
                          returns (address[] memory)
                      {
                          address[] memory array = new address[](ownerCount);
                  
                          // populate return array
                          uint256 index = 0;
                          address currentOwner = owners[SENTINEL_OWNERS];
                          while(currentOwner != SENTINEL_OWNERS) {
                              array[index] = currentOwner;
                              currentOwner = owners[currentOwner];
                              index ++;
                          }
                          return array;
                      }
                  }
                  
                  
                  
                  
                  
                  /// @title Fallback Manager - A contract that manages fallback calls made to this contract
                  /// @author Richard Meissner - <[email protected]>
                  contract FallbackManager is SelfAuthorized {
                  
                      // keccak256("fallback_manager.handler.address")
                      bytes32 internal constant FALLBACK_HANDLER_STORAGE_SLOT = 0x6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d5;
                  
                      function internalSetFallbackHandler(address handler) internal {
                          bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;
                          // solium-disable-next-line security/no-inline-assembly
                          assembly {
                              sstore(slot, handler)
                          }
                      }
                  
                      /// @dev Allows to add a contract to handle fallback calls.
                      ///      Only fallback calls without value and with data will be forwarded.
                      ///      This can only be done via a Safe transaction.
                      /// @param handler contract to handle fallbacks calls.
                      function setFallbackHandler(address handler)
                          public
                          authorized
                      {
                          internalSetFallbackHandler(handler);
                      }
                  
                      function ()
                          external
                          payable
                      {
                          // Only calls without value and with data will be forwarded
                          if (msg.value > 0 || msg.data.length == 0) {
                              return;
                          }
                          bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;
                          address handler;
                          // solium-disable-next-line security/no-inline-assembly
                          assembly {
                              handler := sload(slot)
                          }
                  
                          if (handler != address(0)) {
                              // solium-disable-next-line security/no-inline-assembly
                              assembly {
                                  calldatacopy(0, 0, calldatasize())
                                  let success := call(gas, handler, 0, 0, calldatasize(), 0, 0)
                                  returndatacopy(0, 0, returndatasize())
                                  if eq(success, 0) { revert(0, returndatasize()) }
                                  return(0, returndatasize())
                              }
                          }
                      }
                  }
                  
                  
                  
                  
                  
                  
                  
                  /// @title SignatureDecoder - Decodes signatures that a encoded as bytes
                  /// @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
                  /// @author Richard Meissner - <[email protected]>
                  contract SignatureDecoder {
                      
                      /// @dev Recovers address who signed the message
                      /// @param messageHash operation ethereum signed message hash
                      /// @param messageSignature message `txHash` signature
                      /// @param pos which signature to read
                      function recoverKey (
                          bytes32 messageHash,
                          bytes memory messageSignature,
                          uint256 pos
                      )
                          internal
                          pure
                          returns (address)
                      {
                          uint8 v;
                          bytes32 r;
                          bytes32 s;
                          (v, r, s) = signatureSplit(messageSignature, pos);
                          return ecrecover(messageHash, v, r, s);
                      }
                  
                      /// @dev divides bytes signature into `uint8 v, bytes32 r, bytes32 s`.
                      /// @notice Make sure to peform a bounds check for @param pos, to avoid out of bounds access on @param signatures
                      /// @param pos which signature to read. A prior bounds check of this parameter should be performed, to avoid out of bounds access
                      /// @param signatures concatenated rsv signatures
                      function signatureSplit(bytes memory signatures, uint256 pos)
                          internal
                          pure
                          returns (uint8 v, bytes32 r, bytes32 s)
                      {
                          // The signature format is a compact form of:
                          //   {bytes32 r}{bytes32 s}{uint8 v}
                          // Compact means, uint8 is not padded to 32 bytes.
                          // solium-disable-next-line security/no-inline-assembly
                          assembly {
                              let signaturePos := mul(0x41, pos)
                              r := mload(add(signatures, add(signaturePos, 0x20)))
                              s := mload(add(signatures, add(signaturePos, 0x40)))
                              // Here we are loading the last 32 bytes, including 31 bytes
                              // of 's'. There is no 'mload8' to do this.
                              //
                              // 'byte' is not working due to the Solidity parser, so lets
                              // use the second best option, 'and'
                              v := and(mload(add(signatures, add(signaturePos, 0x41))), 0xff)
                          }
                      }
                  }
                  
                  
                  
                  
                  contract ISignatureValidatorConstants {
                      // bytes4(keccak256("isValidSignature(bytes,bytes)")
                      bytes4 constant internal EIP1271_MAGIC_VALUE = 0x20c13b0b;
                  }
                  
                  contract ISignatureValidator is ISignatureValidatorConstants {
                  
                      /**
                      * @dev Should return whether the signature provided is valid for the provided data
                      * @param _data Arbitrary length data signed on the behalf of address(this)
                      * @param _signature Signature byte array associated with _data
                      *
                      * MUST return the bytes4 magic value 0x20c13b0b when function passes.
                      * MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
                      * MUST allow external calls
                      */
                      function isValidSignature(
                          bytes memory _data,
                          bytes memory _signature)
                          public
                          view
                          returns (bytes4);
                  }
                  
                  
                  /**
                   * @title SafeMath
                   * @dev Math operations with safety checks that revert on error
                   * TODO: remove once open zeppelin update to solc 0.5.0
                   */
                  library SafeMath {
                  
                    /**
                    * @dev Multiplies two numbers, reverts on 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-solidity/pull/522
                      if (a == 0) {
                        return 0;
                      }
                  
                      uint256 c = a * b;
                      require(c / a == b);
                  
                      return c;
                    }
                  
                    /**
                    * @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
                    */
                    function div(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b > 0); // Solidity only automatically asserts when dividing by 0
                      uint256 c = a / b;
                      // assert(a == b * c + a % b); // There is no case in which this doesn't hold
                  
                      return c;
                    }
                  
                    /**
                    * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                    */
                    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b <= a);
                      uint256 c = a - b;
                  
                      return c;
                    }
                  
                    /**
                    * @dev Adds two numbers, reverts on overflow.
                    */
                    function add(uint256 a, uint256 b) internal pure returns (uint256) {
                      uint256 c = a + b;
                      require(c >= a);
                  
                      return c;
                    }
                  
                    /**
                    * @dev Divides two numbers and returns the remainder (unsigned integer modulo),
                    * reverts when dividing by zero.
                    */
                    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b != 0);
                      return a % b;
                    }
                  }
                  
                  /// @title Gnosis Safe - A multisignature wallet with support for confirmations using signed messages based on ERC191.
                  /// @author Stefan George - <[email protected]>
                  /// @author Richard Meissner - <[email protected]>
                  /// @author Ricardo Guilherme Schmidt - (Status Research & Development GmbH) - Gas Token Payment
                  contract GnosisSafe
                      is MasterCopy, ModuleManager, OwnerManager, SignatureDecoder, SecuredTokenTransfer, ISignatureValidatorConstants, FallbackManager {
                  
                      using SafeMath for uint256;
                  
                      string public constant NAME = "Gnosis Safe";
                      string public constant VERSION = "1.1.1";
                  
                      //keccak256(
                      //    "EIP712Domain(address verifyingContract)"
                      //);
                      bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = 0x035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d4749;
                  
                      //keccak256(
                      //    "SafeTx(address to,uint256 value,bytes data,uint8 operation,uint256 safeTxGas,uint256 baseGas,uint256 gasPrice,address gasToken,address refundReceiver,uint256 nonce)"
                      //);
                      bytes32 private constant SAFE_TX_TYPEHASH = 0xbb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d8;
                  
                      //keccak256(
                      //    "SafeMessage(bytes message)"
                      //);
                      bytes32 private constant SAFE_MSG_TYPEHASH = 0x60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca;
                  
                      event ApproveHash(
                          bytes32 indexed approvedHash,
                          address indexed owner
                      );
                      event SignMsg(
                          bytes32 indexed msgHash
                      );
                      event ExecutionFailure(
                          bytes32 txHash, uint256 payment
                      );
                      event ExecutionSuccess(
                          bytes32 txHash, uint256 payment
                      );
                  
                      uint256 public nonce;
                      bytes32 public domainSeparator;
                      // Mapping to keep track of all message hashes that have been approve by ALL REQUIRED owners
                      mapping(bytes32 => uint256) public signedMessages;
                      // Mapping to keep track of all hashes (message or transaction) that have been approve by ANY owners
                      mapping(address => mapping(bytes32 => uint256)) public approvedHashes;
                  
                      // This constructor ensures that this contract can only be used as a master copy for Proxy contracts
                      constructor() public {
                          // By setting the threshold it is not possible to call setup anymore,
                          // so we create a Safe with 0 owners and threshold 1.
                          // This is an unusable Safe, perfect for the mastercopy
                          threshold = 1;
                      }
                  
                      /// @dev Setup function sets initial storage of contract.
                      /// @param _owners List of Safe owners.
                      /// @param _threshold Number of required confirmations for a Safe transaction.
                      /// @param to Contract address for optional delegate call.
                      /// @param data Data payload for optional delegate call.
                      /// @param fallbackHandler Handler for fallback calls to this contract
                      /// @param paymentToken Token that should be used for the payment (0 is ETH)
                      /// @param payment Value that should be paid
                      /// @param paymentReceiver Adddress that should receive the payment (or 0 if tx.origin)
                      function setup(
                          address[] calldata _owners,
                          uint256 _threshold,
                          address to,
                          bytes calldata data,
                          address fallbackHandler,
                          address paymentToken,
                          uint256 payment,
                          address payable paymentReceiver
                      )
                          external
                      {
                          require(domainSeparator == 0, "Domain Separator already set!");
                          domainSeparator = keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, this));
                          setupOwners(_owners, _threshold);
                          if (fallbackHandler != address(0)) internalSetFallbackHandler(fallbackHandler);
                          // As setupOwners can only be called if the contract has not been initialized we don't need a check for setupModules
                          setupModules(to, data);
                  
                          if (payment > 0) {
                              // To avoid running into issues with EIP-170 we reuse the handlePayment function (to avoid adjusting code of that has been verified we do not adjust the method itself)
                              // baseGas = 0, gasPrice = 1 and gas = payment => amount = (payment + 0) * 1 = payment
                              handlePayment(payment, 0, 1, paymentToken, paymentReceiver);
                          }
                      }
                  
                      /// @dev Allows to execute a Safe transaction confirmed by required number of owners and then pays the account that submitted the transaction.
                      ///      Note: The fees are always transfered, even if the user transaction fails.
                      /// @param to Destination address of Safe transaction.
                      /// @param value Ether value of Safe transaction.
                      /// @param data Data payload of Safe transaction.
                      /// @param operation Operation type of Safe transaction.
                      /// @param safeTxGas Gas that should be used for the Safe transaction.
                      /// @param baseGas Gas costs for that are indipendent of the transaction execution(e.g. base transaction fee, signature check, payment of the refund)
                      /// @param gasPrice Gas price that should be used for the payment calculation.
                      /// @param gasToken Token address (or 0 if ETH) that is used for the payment.
                      /// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
                      /// @param signatures Packed signature data ({bytes32 r}{bytes32 s}{uint8 v})
                      function execTransaction(
                          address to,
                          uint256 value,
                          bytes calldata data,
                          Enum.Operation operation,
                          uint256 safeTxGas,
                          uint256 baseGas,
                          uint256 gasPrice,
                          address gasToken,
                          address payable refundReceiver,
                          bytes calldata signatures
                      )
                          external
                          returns (bool success)
                      {
                          bytes32 txHash;
                          // Use scope here to limit variable lifetime and prevent `stack too deep` errors
                          {
                              bytes memory txHashData = encodeTransactionData(
                                  to, value, data, operation, // Transaction info
                                  safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, // Payment info
                                  nonce
                              );
                              // Increase nonce and execute transaction.
                              nonce++;
                              txHash = keccak256(txHashData);
                              checkSignatures(txHash, txHashData, signatures, true);
                          }
                          require(gasleft() >= safeTxGas, "Not enough gas to execute safe transaction");
                          // Use scope here to limit variable lifetime and prevent `stack too deep` errors
                          {
                              uint256 gasUsed = gasleft();
                              // If no safeTxGas has been set and the gasPrice is 0 we assume that all available gas can be used
                              success = execute(to, value, data, operation, safeTxGas == 0 && gasPrice == 0 ? gasleft() : safeTxGas);
                              gasUsed = gasUsed.sub(gasleft());
                              // We transfer the calculated tx costs to the tx.origin to avoid sending it to intermediate contracts that have made calls
                              uint256 payment = 0;
                              if (gasPrice > 0) {
                                  payment = handlePayment(gasUsed, baseGas, gasPrice, gasToken, refundReceiver);
                              }
                              if (success) emit ExecutionSuccess(txHash, payment);
                              else emit ExecutionFailure(txHash, payment);
                          }
                      }
                  
                      function handlePayment(
                          uint256 gasUsed,
                          uint256 baseGas,
                          uint256 gasPrice,
                          address gasToken,
                          address payable refundReceiver
                      )
                          private
                          returns (uint256 payment)
                      {
                          // solium-disable-next-line security/no-tx-origin
                          address payable receiver = refundReceiver == address(0) ? tx.origin : refundReceiver;
                          if (gasToken == address(0)) {
                              // For ETH we will only adjust the gas price to not be higher than the actual used gas price
                              payment = gasUsed.add(baseGas).mul(gasPrice < tx.gasprice ? gasPrice : tx.gasprice);
                              // solium-disable-next-line security/no-send
                              require(receiver.send(payment), "Could not pay gas costs with ether");
                          } else {
                              payment = gasUsed.add(baseGas).mul(gasPrice);
                              require(transferToken(gasToken, receiver, payment), "Could not pay gas costs with token");
                          }
                      }
                  
                      /**
                      * @dev Checks whether the signature provided is valid for the provided data, hash. Will revert otherwise.
                      * @param dataHash Hash of the data (could be either a message hash or transaction hash)
                      * @param data That should be signed (this is passed to an external validator contract)
                      * @param signatures Signature data that should be verified. Can be ECDSA signature, contract signature (EIP-1271) or approved hash.
                      * @param consumeHash Indicates that in case of an approved hash the storage can be freed to save gas
                      */
                      function checkSignatures(bytes32 dataHash, bytes memory data, bytes memory signatures, bool consumeHash)
                          internal
                      {
                          // Load threshold to avoid multiple storage loads
                          uint256 _threshold = threshold;
                          // Check that a threshold is set
                          require(_threshold > 0, "Threshold needs to be defined!");
                          // Check that the provided signature data is not too short
                          require(signatures.length >= _threshold.mul(65), "Signatures data too short");
                          // There cannot be an owner with address 0.
                          address lastOwner = address(0);
                          address currentOwner;
                          uint8 v;
                          bytes32 r;
                          bytes32 s;
                          uint256 i;
                          for (i = 0; i < _threshold; i++) {
                              (v, r, s) = signatureSplit(signatures, i);
                              // If v is 0 then it is a contract signature
                              if (v == 0) {
                                  // When handling contract signatures the address of the contract is encoded into r
                                  currentOwner = address(uint256(r));
                  
                                  // Check that signature data pointer (s) is not pointing inside the static part of the signatures bytes
                                  // This check is not completely accurate, since it is possible that more signatures than the threshold are send.
                                  // Here we only check that the pointer is not pointing inside the part that is being processed
                                  require(uint256(s) >= _threshold.mul(65), "Invalid contract signature location: inside static part");
                  
                                  // Check that signature data pointer (s) is in bounds (points to the length of data -> 32 bytes)
                                  require(uint256(s).add(32) <= signatures.length, "Invalid contract signature location: length not present");
                  
                                  // Check if the contract signature is in bounds: start of data is s + 32 and end is start + signature length
                                  uint256 contractSignatureLen;
                                  // solium-disable-next-line security/no-inline-assembly
                                  assembly {
                                      contractSignatureLen := mload(add(add(signatures, s), 0x20))
                                  }
                                  require(uint256(s).add(32).add(contractSignatureLen) <= signatures.length, "Invalid contract signature location: data not complete");
                  
                                  // Check signature
                                  bytes memory contractSignature;
                                  // solium-disable-next-line security/no-inline-assembly
                                  assembly {
                                      // The signature data for contract signatures is appended to the concatenated signatures and the offset is stored in s
                                      contractSignature := add(add(signatures, s), 0x20)
                                  }
                                  require(ISignatureValidator(currentOwner).isValidSignature(data, contractSignature) == EIP1271_MAGIC_VALUE, "Invalid contract signature provided");
                              // If v is 1 then it is an approved hash
                              } else if (v == 1) {
                                  // When handling approved hashes the address of the approver is encoded into r
                                  currentOwner = address(uint256(r));
                                  // Hashes are automatically approved by the sender of the message or when they have been pre-approved via a separate transaction
                                  require(msg.sender == currentOwner || approvedHashes[currentOwner][dataHash] != 0, "Hash has not been approved");
                                  // Hash has been marked for consumption. If this hash was pre-approved free storage
                                  if (consumeHash && msg.sender != currentOwner) {
                                      approvedHashes[currentOwner][dataHash] = 0;
                                  }
                              } else if (v > 30) {
                                  // To support eth_sign and similar we adjust v and hash the messageHash with the Ethereum message prefix before applying ecrecover
                                  currentOwner = ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", dataHash)), v - 4, r, s);
                              } else {
                                  // Use ecrecover with the messageHash for EOA signatures
                                  currentOwner = ecrecover(dataHash, v, r, s);
                              }
                              require (
                                  currentOwner > lastOwner && owners[currentOwner] != address(0) && currentOwner != SENTINEL_OWNERS,
                                  "Invalid owner provided"
                              );
                              lastOwner = currentOwner;
                          }
                      }
                  
                      /// @dev Allows to estimate a Safe transaction.
                      ///      This method is only meant for estimation purpose, therefore two different protection mechanism against execution in a transaction have been made:
                      ///      1.) The method can only be called from the safe itself
                      ///      2.) The response is returned with a revert
                      ///      When estimating set `from` to the address of the safe.
                      ///      Since the `estimateGas` function includes refunds, call this method to get an estimated of the costs that are deducted from the safe with `execTransaction`
                      /// @param to Destination address of Safe transaction.
                      /// @param value Ether value of Safe transaction.
                      /// @param data Data payload of Safe transaction.
                      /// @param operation Operation type of Safe transaction.
                      /// @return Estimate without refunds and overhead fees (base transaction and payload data gas costs).
                      function requiredTxGas(address to, uint256 value, bytes calldata data, Enum.Operation operation)
                          external
                          authorized
                          returns (uint256)
                      {
                          uint256 startGas = gasleft();
                          // We don't provide an error message here, as we use it to return the estimate
                          // solium-disable-next-line error-reason
                          require(execute(to, value, data, operation, gasleft()));
                          uint256 requiredGas = startGas - gasleft();
                          // Convert response to string and return via error message
                          revert(string(abi.encodePacked(requiredGas)));
                      }
                  
                      /**
                      * @dev Marks a hash as approved. This can be used to validate a hash that is used by a signature.
                      * @param hashToApprove The hash that should be marked as approved for signatures that are verified by this contract.
                      */
                      function approveHash(bytes32 hashToApprove)
                          external
                      {
                          require(owners[msg.sender] != address(0), "Only owners can approve a hash");
                          approvedHashes[msg.sender][hashToApprove] = 1;
                          emit ApproveHash(hashToApprove, msg.sender);
                      }
                  
                      /**
                      * @dev Marks a message as signed
                      * @param _data Arbitrary length data that should be marked as signed on the behalf of address(this)
                      */
                      function signMessage(bytes calldata _data)
                          external
                          authorized
                      {
                          bytes32 msgHash = getMessageHash(_data);
                          signedMessages[msgHash] = 1;
                          emit SignMsg(msgHash);
                      }
                  
                      /**
                      * Implementation of ISignatureValidator (see `interfaces/ISignatureValidator.sol`)
                      * @dev Should return whether the signature provided is valid for the provided data.
                      *       The save does not implement the interface since `checkSignatures` is not a view method.
                      *       The method will not perform any state changes (see parameters of `checkSignatures`)
                      * @param _data Arbitrary length data signed on the behalf of address(this)
                      * @param _signature Signature byte array associated with _data
                      * @return a bool upon valid or invalid signature with corresponding _data
                      */
                      function isValidSignature(bytes calldata _data, bytes calldata _signature)
                          external
                          returns (bytes4)
                      {
                          bytes32 messageHash = getMessageHash(_data);
                          if (_signature.length == 0) {
                              require(signedMessages[messageHash] != 0, "Hash not approved");
                          } else {
                              // consumeHash needs to be false, as the state should not be changed
                              checkSignatures(messageHash, _data, _signature, false);
                          }
                          return EIP1271_MAGIC_VALUE;
                      }
                  
                      /// @dev Returns hash of a message that can be signed by owners.
                      /// @param message Message that should be hashed
                      /// @return Message hash.
                      function getMessageHash(
                          bytes memory message
                      )
                          public
                          view
                          returns (bytes32)
                      {
                          bytes32 safeMessageHash = keccak256(
                              abi.encode(SAFE_MSG_TYPEHASH, keccak256(message))
                          );
                          return keccak256(
                              abi.encodePacked(byte(0x19), byte(0x01), domainSeparator, safeMessageHash)
                          );
                      }
                  
                      /// @dev Returns the bytes that are hashed to be signed by owners.
                      /// @param to Destination address.
                      /// @param value Ether value.
                      /// @param data Data payload.
                      /// @param operation Operation type.
                      /// @param safeTxGas Fas that should be used for the safe transaction.
                      /// @param baseGas Gas costs for data used to trigger the safe transaction.
                      /// @param gasPrice Maximum gas price that should be used for this transaction.
                      /// @param gasToken Token address (or 0 if ETH) that is used for the payment.
                      /// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
                      /// @param _nonce Transaction nonce.
                      /// @return Transaction hash bytes.
                      function encodeTransactionData(
                          address to,
                          uint256 value,
                          bytes memory data,
                          Enum.Operation operation,
                          uint256 safeTxGas,
                          uint256 baseGas,
                          uint256 gasPrice,
                          address gasToken,
                          address refundReceiver,
                          uint256 _nonce
                      )
                          public
                          view
                          returns (bytes memory)
                      {
                          bytes32 safeTxHash = keccak256(
                              abi.encode(SAFE_TX_TYPEHASH, to, value, keccak256(data), operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, _nonce)
                          );
                          return abi.encodePacked(byte(0x19), byte(0x01), domainSeparator, safeTxHash);
                      }
                  
                      /// @dev Returns hash to be signed by owners.
                      /// @param to Destination address.
                      /// @param value Ether value.
                      /// @param data Data payload.
                      /// @param operation Operation type.
                      /// @param safeTxGas Fas that should be used for the safe transaction.
                      /// @param baseGas Gas costs for data used to trigger the safe transaction.
                      /// @param gasPrice Maximum gas price that should be used for this transaction.
                      /// @param gasToken Token address (or 0 if ETH) that is used for the payment.
                      /// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
                      /// @param _nonce Transaction nonce.
                      /// @return Transaction hash.
                      function getTransactionHash(
                          address to,
                          uint256 value,
                          bytes memory data,
                          Enum.Operation operation,
                          uint256 safeTxGas,
                          uint256 baseGas,
                          uint256 gasPrice,
                          address gasToken,
                          address refundReceiver,
                          uint256 _nonce
                      )
                          public
                          view
                          returns (bytes32)
                      {
                          return keccak256(encodeTransactionData(to, value, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, _nonce));
                      }
                  }

                  File 7 of 14: DefaultCallbackHandler
                  pragma solidity >=0.5.0 <0.7.0;
                  
                  interface ERC777TokensRecipient {
                      function tokensReceived(
                          address operator,
                          address from,
                          address to,
                          uint256 amount,
                          bytes calldata data,
                          bytes calldata operatorData
                      ) external;
                  }
                  
                  
                  
                  /**
                      Note: The ERC-165 identifier for this interface is 0x4e2312e0.
                  */
                  interface ERC1155TokenReceiver {
                      /**
                          @notice Handle the receipt of a single ERC1155 token type.
                          @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated.        
                          This function MUST return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` (i.e. 0xf23a6e61) if it accepts the transfer.
                          This function MUST revert if it rejects the transfer.
                          Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.
                          @param _operator  The address which initiated the transfer (i.e. msg.sender)
                          @param _from      The address which previously owned the token
                          @param _id        The ID of the token being transferred
                          @param _value     The amount of tokens being transferred
                          @param _data      Additional data with no specified format
                          @return           `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
                      */
                      function onERC1155Received(address _operator, address _from, uint256 _id, uint256 _value, bytes calldata _data) external returns(bytes4);
                  
                      /**
                          @notice Handle the receipt of multiple ERC1155 token types.
                          @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated.        
                          This function MUST return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` (i.e. 0xbc197c81) if it accepts the transfer(s).
                          This function MUST revert if it rejects the transfer(s).
                          Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.
                          @param _operator  The address which initiated the batch transfer (i.e. msg.sender)
                          @param _from      The address which previously owned the token
                          @param _ids       An array containing ids of each token being transferred (order and length must match _values array)
                          @param _values    An array containing amounts of each token being transferred (order and length must match _ids array)
                          @param _data      Additional data with no specified format
                          @return           `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
                      */
                      function onERC1155BatchReceived(address _operator, address _from, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external returns(bytes4);       
                  }
                  
                  
                  /// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02.
                  interface ERC721TokenReceiver {
                      /// @notice Handle the receipt of an NFT
                      /// @dev The ERC721 smart contract calls this function on the recipient
                      ///  after a `transfer`. This function MAY throw to revert and reject the
                      ///  transfer. Return of other than the magic value MUST result in the
                      ///  transaction being reverted.
                      ///  Note: the contract address is always the message sender.
                      /// @param _operator The address which called `safeTransferFrom` function
                      /// @param _from The address which previously owned the token
                      /// @param _tokenId The NFT identifier which is being transferred
                      /// @param _data Additional data with no specified format
                      /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
                      ///  unless throwing
                      function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) external returns(bytes4);
                  }
                  
                  
                  /// @title Default Callback Handler - returns true for known token callbacks
                  /// @author Richard Meissner - <[email protected]>
                  contract DefaultCallbackHandler is ERC1155TokenReceiver, ERC777TokensRecipient, ERC721TokenReceiver {
                  
                      string public constant NAME = "Default Callback Handler";
                      string public constant VERSION = "1.0.0";
                  
                      function onERC1155Received(address, address, uint256, uint256, bytes calldata)
                          external
                          returns(bytes4)
                      {
                          return 0xf23a6e61;
                      }
                  
                      function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata)
                          external
                          returns(bytes4)
                      {
                          return 0xbc197c81;
                      }
                  
                      function onERC721Received(address, address, uint256, bytes calldata)
                          external
                          returns(bytes4)
                      {
                          return 0x150b7a02;
                      }
                  
                      // solium-disable-next-line no-empty-blocks
                      function tokensReceived(address, address, address, uint256, bytes calldata, bytes calldata) external {
                          // We implement this for completeness, doesn't really have any value
                      }
                  
                  }

                  File 8 of 14: L1StandardBridge
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /* Interface Imports */
                  import { IL1StandardBridge } from "./IL1StandardBridge.sol";
                  import { IL1ERC20Bridge } from "./IL1ERC20Bridge.sol";
                  import { IL2ERC20Bridge } from "../../L2/messaging/IL2ERC20Bridge.sol";
                  import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
                  /* Library Imports */
                  import { CrossDomainEnabled } from "../../libraries/bridge/CrossDomainEnabled.sol";
                  import { Lib_PredeployAddresses } from "../../libraries/constants/Lib_PredeployAddresses.sol";
                  import { Address } from "@openzeppelin/contracts/utils/Address.sol";
                  import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
                  /**
                   * @title L1StandardBridge
                   * @dev The L1 ETH and ERC20 Bridge is a contract which stores deposited L1 funds and standard
                   * tokens that are in use on L2. It synchronizes a corresponding L2 Bridge, informing it of deposits
                   * and listening to it for newly finalized withdrawals.
                   *
                   * Runtime target: EVM
                   */
                  contract L1StandardBridge is IL1StandardBridge, CrossDomainEnabled {
                      using SafeERC20 for IERC20;
                      /********************************
                       * External Contract References *
                       ********************************/
                      address public l2TokenBridge;
                      // Maps L1 token to L2 token to balance of the L1 token deposited
                      mapping(address => mapping(address => uint256)) public deposits;
                      /***************
                       * Constructor *
                       ***************/
                      // This contract lives behind a proxy, so the constructor parameters will go unused.
                      constructor() CrossDomainEnabled(address(0)) {}
                      /******************
                       * Initialization *
                       ******************/
                      /**
                       * @param _l1messenger L1 Messenger address being used for cross-chain communications.
                       * @param _l2TokenBridge L2 standard bridge address.
                       */
                      function initialize(address _l1messenger, address _l2TokenBridge) public {
                          require(messenger == address(0), "Contract has already been initialized.");
                          messenger = _l1messenger;
                          l2TokenBridge = _l2TokenBridge;
                      }
                      /**************
                       * Depositing *
                       **************/
                      /** @dev Modifier requiring sender to be EOA.  This check could be bypassed by a malicious
                       *  contract via initcode, but it takes care of the user error we want to avoid.
                       */
                      modifier onlyEOA() {
                          // Used to stop deposits from contracts (avoid accidentally lost tokens)
                          require(!Address.isContract(msg.sender), "Account not EOA");
                          _;
                      }
                      /**
                       * @dev This function can be called with no data
                       * to deposit an amount of ETH to the caller's balance on L2.
                       * Since the receive function doesn't take data, a conservative
                       * default amount is forwarded to L2.
                       */
                      receive() external payable onlyEOA {
                          _initiateETHDeposit(msg.sender, msg.sender, 200_000, bytes(""));
                      }
                      /**
                       * @inheritdoc IL1StandardBridge
                       */
                      function depositETH(uint32 _l2Gas, bytes calldata _data) external payable onlyEOA {
                          _initiateETHDeposit(msg.sender, msg.sender, _l2Gas, _data);
                      }
                      /**
                       * @inheritdoc IL1StandardBridge
                       */
                      function depositETHTo(
                          address _to,
                          uint32 _l2Gas,
                          bytes calldata _data
                      ) external payable {
                          _initiateETHDeposit(msg.sender, _to, _l2Gas, _data);
                      }
                      /**
                       * @dev Performs the logic for deposits by storing the ETH and informing the L2 ETH Gateway of
                       * the deposit.
                       * @param _from Account to pull the deposit from on L1.
                       * @param _to Account to give the deposit to on L2.
                       * @param _l2Gas Gas limit required to complete the deposit on L2.
                       * @param _data Optional data to forward to L2. This data is provided
                       *        solely as a convenience for external contracts. Aside from enforcing a maximum
                       *        length, these contracts provide no guarantees about its content.
                       */
                      function _initiateETHDeposit(
                          address _from,
                          address _to,
                          uint32 _l2Gas,
                          bytes memory _data
                      ) internal {
                          // Construct calldata for finalizeDeposit call
                          bytes memory message = abi.encodeWithSelector(
                              IL2ERC20Bridge.finalizeDeposit.selector,
                              address(0),
                              Lib_PredeployAddresses.OVM_ETH,
                              _from,
                              _to,
                              msg.value,
                              _data
                          );
                          // Send calldata into L2
                          sendCrossDomainMessage(l2TokenBridge, _l2Gas, message);
                          emit ETHDepositInitiated(_from, _to, msg.value, _data);
                      }
                      /**
                       * @inheritdoc IL1ERC20Bridge
                       */
                      function depositERC20(
                          address _l1Token,
                          address _l2Token,
                          uint256 _amount,
                          uint32 _l2Gas,
                          bytes calldata _data
                      ) external virtual onlyEOA {
                          _initiateERC20Deposit(_l1Token, _l2Token, msg.sender, msg.sender, _amount, _l2Gas, _data);
                      }
                      /**
                       * @inheritdoc IL1ERC20Bridge
                       */
                      function depositERC20To(
                          address _l1Token,
                          address _l2Token,
                          address _to,
                          uint256 _amount,
                          uint32 _l2Gas,
                          bytes calldata _data
                      ) external virtual {
                          _initiateERC20Deposit(_l1Token, _l2Token, msg.sender, _to, _amount, _l2Gas, _data);
                      }
                      /**
                       * @dev Performs the logic for deposits by informing the L2 Deposited Token
                       * contract of the deposit and calling a handler to lock the L1 funds. (e.g. transferFrom)
                       *
                       * @param _l1Token Address of the L1 ERC20 we are depositing
                       * @param _l2Token Address of the L1 respective L2 ERC20
                       * @param _from Account to pull the deposit from on L1
                       * @param _to Account to give the deposit to on L2
                       * @param _amount Amount of the ERC20 to deposit.
                       * @param _l2Gas Gas limit required to complete the deposit on L2.
                       * @param _data Optional data to forward to L2. This data is provided
                       *        solely as a convenience for external contracts. Aside from enforcing a maximum
                       *        length, these contracts provide no guarantees about its content.
                       */
                      function _initiateERC20Deposit(
                          address _l1Token,
                          address _l2Token,
                          address _from,
                          address _to,
                          uint256 _amount,
                          uint32 _l2Gas,
                          bytes calldata _data
                      ) internal {
                          // When a deposit is initiated on L1, the L1 Bridge transfers the funds to itself for future
                          // withdrawals. safeTransferFrom also checks if the contract has code, so this will fail if
                          // _from is an EOA or address(0).
                          IERC20(_l1Token).safeTransferFrom(_from, address(this), _amount);
                          // Construct calldata for _l2Token.finalizeDeposit(_to, _amount)
                          bytes memory message = abi.encodeWithSelector(
                              IL2ERC20Bridge.finalizeDeposit.selector,
                              _l1Token,
                              _l2Token,
                              _from,
                              _to,
                              _amount,
                              _data
                          );
                          // Send calldata into L2
                          sendCrossDomainMessage(l2TokenBridge, _l2Gas, message);
                          deposits[_l1Token][_l2Token] = deposits[_l1Token][_l2Token] + _amount;
                          emit ERC20DepositInitiated(_l1Token, _l2Token, _from, _to, _amount, _data);
                      }
                      /*************************
                       * Cross-chain Functions *
                       *************************/
                      /**
                       * @inheritdoc IL1StandardBridge
                       */
                      function finalizeETHWithdrawal(
                          address _from,
                          address _to,
                          uint256 _amount,
                          bytes calldata _data
                      ) external onlyFromCrossDomainAccount(l2TokenBridge) {
                          (bool success, ) = _to.call{ value: _amount }(new bytes(0));
                          require(success, "TransferHelper::safeTransferETH: ETH transfer failed");
                          emit ETHWithdrawalFinalized(_from, _to, _amount, _data);
                      }
                      /**
                       * @inheritdoc IL1ERC20Bridge
                       */
                      function finalizeERC20Withdrawal(
                          address _l1Token,
                          address _l2Token,
                          address _from,
                          address _to,
                          uint256 _amount,
                          bytes calldata _data
                      ) external onlyFromCrossDomainAccount(l2TokenBridge) {
                          deposits[_l1Token][_l2Token] = deposits[_l1Token][_l2Token] - _amount;
                          // When a withdrawal is finalized on L1, the L1 Bridge transfers the funds to the withdrawer
                          IERC20(_l1Token).safeTransfer(_to, _amount);
                          emit ERC20WithdrawalFinalized(_l1Token, _l2Token, _from, _to, _amount, _data);
                      }
                      /*****************************
                       * Temporary - Migrating ETH *
                       *****************************/
                      /**
                       * @dev Adds ETH balance to the account. This is meant to allow for ETH
                       * to be migrated from an old gateway to a new gateway.
                       * NOTE: This is left for one upgrade only so we are able to receive the migrated ETH from the
                       * old contract
                       */
                      function donateETH() external payable {}
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >0.5.0 <0.9.0;
                  import "./IL1ERC20Bridge.sol";
                  /**
                   * @title IL1StandardBridge
                   */
                  interface IL1StandardBridge is IL1ERC20Bridge {
                      /**********
                       * Events *
                       **********/
                      event ETHDepositInitiated(
                          address indexed _from,
                          address indexed _to,
                          uint256 _amount,
                          bytes _data
                      );
                      event ETHWithdrawalFinalized(
                          address indexed _from,
                          address indexed _to,
                          uint256 _amount,
                          bytes _data
                      );
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * @dev Deposit an amount of the ETH to the caller's balance on L2.
                       * @param _l2Gas Gas limit required to complete the deposit on L2.
                       * @param _data Optional data to forward to L2. This data is provided
                       *        solely as a convenience for external contracts. Aside from enforcing a maximum
                       *        length, these contracts provide no guarantees about its content.
                       */
                      function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;
                      /**
                       * @dev Deposit an amount of ETH to a recipient's balance on L2.
                       * @param _to L2 address to credit the withdrawal to.
                       * @param _l2Gas Gas limit required to complete the deposit on L2.
                       * @param _data Optional data to forward to L2. This data is provided
                       *        solely as a convenience for external contracts. Aside from enforcing a maximum
                       *        length, these contracts provide no guarantees about its content.
                       */
                      function depositETHTo(
                          address _to,
                          uint32 _l2Gas,
                          bytes calldata _data
                      ) external payable;
                      /*************************
                       * Cross-chain Functions *
                       *************************/
                      /**
                       * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the
                       * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called
                       * before the withdrawal is finalized.
                       * @param _from L2 address initiating the transfer.
                       * @param _to L1 address to credit the withdrawal to.
                       * @param _amount Amount of the ERC20 to deposit.
                       * @param _data Optional data to forward to L2. This data is provided
                       *        solely as a convenience for external contracts. Aside from enforcing a maximum
                       *        length, these contracts provide no guarantees about its content.
                       */
                      function finalizeETHWithdrawal(
                          address _from,
                          address _to,
                          uint256 _amount,
                          bytes calldata _data
                      ) external;
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >0.5.0 <0.9.0;
                  /**
                   * @title IL1ERC20Bridge
                   */
                  interface IL1ERC20Bridge {
                      /**********
                       * Events *
                       **********/
                      event ERC20DepositInitiated(
                          address indexed _l1Token,
                          address indexed _l2Token,
                          address indexed _from,
                          address _to,
                          uint256 _amount,
                          bytes _data
                      );
                      event ERC20WithdrawalFinalized(
                          address indexed _l1Token,
                          address indexed _l2Token,
                          address indexed _from,
                          address _to,
                          uint256 _amount,
                          bytes _data
                      );
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * @dev get the address of the corresponding L2 bridge contract.
                       * @return Address of the corresponding L2 bridge contract.
                       */
                      function l2TokenBridge() external returns (address);
                      /**
                       * @dev deposit an amount of the ERC20 to the caller's balance on L2.
                       * @param _l1Token Address of the L1 ERC20 we are depositing
                       * @param _l2Token Address of the L1 respective L2 ERC20
                       * @param _amount Amount of the ERC20 to deposit
                       * @param _l2Gas Gas limit required to complete the deposit on L2.
                       * @param _data Optional data to forward to L2. This data is provided
                       *        solely as a convenience for external contracts. Aside from enforcing a maximum
                       *        length, these contracts provide no guarantees about its content.
                       */
                      function depositERC20(
                          address _l1Token,
                          address _l2Token,
                          uint256 _amount,
                          uint32 _l2Gas,
                          bytes calldata _data
                      ) external;
                      /**
                       * @dev deposit an amount of ERC20 to a recipient's balance on L2.
                       * @param _l1Token Address of the L1 ERC20 we are depositing
                       * @param _l2Token Address of the L1 respective L2 ERC20
                       * @param _to L2 address to credit the withdrawal to.
                       * @param _amount Amount of the ERC20 to deposit.
                       * @param _l2Gas Gas limit required to complete the deposit on L2.
                       * @param _data Optional data to forward to L2. This data is provided
                       *        solely as a convenience for external contracts. Aside from enforcing a maximum
                       *        length, these contracts provide no guarantees about its content.
                       */
                      function depositERC20To(
                          address _l1Token,
                          address _l2Token,
                          address _to,
                          uint256 _amount,
                          uint32 _l2Gas,
                          bytes calldata _data
                      ) external;
                      /*************************
                       * Cross-chain Functions *
                       *************************/
                      /**
                       * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the
                       * L1 ERC20 token.
                       * This call will fail if the initialized withdrawal from L2 has not been finalized.
                       *
                       * @param _l1Token Address of L1 token to finalizeWithdrawal for.
                       * @param _l2Token Address of L2 token where withdrawal was initiated.
                       * @param _from L2 address initiating the transfer.
                       * @param _to L1 address to credit the withdrawal to.
                       * @param _amount Amount of the ERC20 to deposit.
                       * @param _data Data provided by the sender on L2. This data is provided
                       *   solely as a convenience for external contracts. Aside from enforcing a maximum
                       *   length, these contracts provide no guarantees about its content.
                       */
                      function finalizeERC20Withdrawal(
                          address _l1Token,
                          address _l2Token,
                          address _from,
                          address _to,
                          uint256 _amount,
                          bytes calldata _data
                      ) external;
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /**
                   * @title IL2ERC20Bridge
                   */
                  interface IL2ERC20Bridge {
                      /**********
                       * Events *
                       **********/
                      event WithdrawalInitiated(
                          address indexed _l1Token,
                          address indexed _l2Token,
                          address indexed _from,
                          address _to,
                          uint256 _amount,
                          bytes _data
                      );
                      event DepositFinalized(
                          address indexed _l1Token,
                          address indexed _l2Token,
                          address indexed _from,
                          address _to,
                          uint256 _amount,
                          bytes _data
                      );
                      event DepositFailed(
                          address indexed _l1Token,
                          address indexed _l2Token,
                          address indexed _from,
                          address _to,
                          uint256 _amount,
                          bytes _data
                      );
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * @dev get the address of the corresponding L1 bridge contract.
                       * @return Address of the corresponding L1 bridge contract.
                       */
                      function l1TokenBridge() external returns (address);
                      /**
                       * @dev initiate a withdraw of some tokens to the caller's account on L1
                       * @param _l2Token Address of L2 token where withdrawal was initiated.
                       * @param _amount Amount of the token to withdraw.
                       * param _l1Gas Unused, but included for potential forward compatibility considerations.
                       * @param _data Optional data to forward to L1. This data is provided
                       *        solely as a convenience for external contracts. Aside from enforcing a maximum
                       *        length, these contracts provide no guarantees about its content.
                       */
                      function withdraw(
                          address _l2Token,
                          uint256 _amount,
                          uint32 _l1Gas,
                          bytes calldata _data
                      ) external;
                      /**
                       * @dev initiate a withdraw of some token to a recipient's account on L1.
                       * @param _l2Token Address of L2 token where withdrawal is initiated.
                       * @param _to L1 adress to credit the withdrawal to.
                       * @param _amount Amount of the token to withdraw.
                       * param _l1Gas Unused, but included for potential forward compatibility considerations.
                       * @param _data Optional data to forward to L1. This data is provided
                       *        solely as a convenience for external contracts. Aside from enforcing a maximum
                       *        length, these contracts provide no guarantees about its content.
                       */
                      function withdrawTo(
                          address _l2Token,
                          address _to,
                          uint256 _amount,
                          uint32 _l1Gas,
                          bytes calldata _data
                      ) external;
                      /*************************
                       * Cross-chain Functions *
                       *************************/
                      /**
                       * @dev Complete a deposit from L1 to L2, and credits funds to the recipient's balance of this
                       * L2 token. This call will fail if it did not originate from a corresponding deposit in
                       * L1StandardTokenBridge.
                       * @param _l1Token Address for the l1 token this is called with
                       * @param _l2Token Address for the l2 token this is called with
                       * @param _from Account to pull the deposit from on L2.
                       * @param _to Address to receive the withdrawal at
                       * @param _amount Amount of the token to withdraw
                       * @param _data Data provider by the sender on L1. This data is provided
                       *        solely as a convenience for external contracts. Aside from enforcing a maximum
                       *        length, these contracts provide no guarantees about its content.
                       */
                      function finalizeDeposit(
                          address _l1Token,
                          address _l2Token,
                          address _from,
                          address _to,
                          uint256 _amount,
                          bytes calldata _data
                      ) external;
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.0;
                  /**
                   * @dev Interface of the ERC20 standard as defined in the EIP.
                   */
                  interface IERC20 {
                      /**
                       * @dev Returns the amount of tokens in existence.
                       */
                      function totalSupply() external view returns (uint256);
                      /**
                       * @dev Returns the amount of tokens owned by `account`.
                       */
                      function balanceOf(address account) external view returns (uint256);
                      /**
                       * @dev Moves `amount` tokens from the caller's account to `recipient`.
                       *
                       * Returns a boolean value indicating whether the operation succeeded.
                       *
                       * Emits a {Transfer} event.
                       */
                      function transfer(address recipient, uint256 amount) external returns (bool);
                      /**
                       * @dev Returns the remaining number of tokens that `spender` will be
                       * allowed to spend on behalf of `owner` through {transferFrom}. This is
                       * zero by default.
                       *
                       * This value changes when {approve} or {transferFrom} are called.
                       */
                      function allowance(address owner, address spender) external view returns (uint256);
                      /**
                       * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
                       *
                       * Returns a boolean value indicating whether the operation succeeded.
                       *
                       * IMPORTANT: Beware that changing an allowance with this method brings the risk
                       * that someone may use both the old and the new allowance by unfortunate
                       * transaction ordering. One possible solution to mitigate this race
                       * condition is to first reduce the spender's allowance to 0 and set the
                       * desired value afterwards:
                       * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                       *
                       * Emits an {Approval} event.
                       */
                      function approve(address spender, uint256 amount) external returns (bool);
                      /**
                       * @dev Moves `amount` tokens from `sender` to `recipient` using the
                       * allowance mechanism. `amount` is then deducted from the caller's
                       * allowance.
                       *
                       * Returns a boolean value indicating whether the operation succeeded.
                       *
                       * Emits a {Transfer} event.
                       */
                      function transferFrom(
                          address sender,
                          address recipient,
                          uint256 amount
                      ) external returns (bool);
                      /**
                       * @dev Emitted when `value` tokens are moved from one account (`from`) to
                       * another (`to`).
                       *
                       * Note that `value` may be zero.
                       */
                      event Transfer(address indexed from, address indexed to, uint256 value);
                      /**
                       * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                       * a call to {approve}. `value` is the new allowance.
                       */
                      event Approval(address indexed owner, address indexed spender, uint256 value);
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >0.5.0 <0.9.0;
                  /* Interface Imports */
                  import { ICrossDomainMessenger } from "./ICrossDomainMessenger.sol";
                  /**
                   * @title CrossDomainEnabled
                   * @dev Helper contract for contracts performing cross-domain communications
                   *
                   * Compiler used: defined by inheriting contract
                   * Runtime target: defined by inheriting contract
                   */
                  contract CrossDomainEnabled {
                      /*************
                       * Variables *
                       *************/
                      // Messenger contract used to send and recieve messages from the other domain.
                      address public messenger;
                      /***************
                       * Constructor *
                       ***************/
                      /**
                       * @param _messenger Address of the CrossDomainMessenger on the current layer.
                       */
                      constructor(address _messenger) {
                          messenger = _messenger;
                      }
                      /**********************
                       * Function Modifiers *
                       **********************/
                      /**
                       * Enforces that the modified function is only callable by a specific cross-domain account.
                       * @param _sourceDomainAccount The only account on the originating domain which is
                       *  authenticated to call this function.
                       */
                      modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {
                          require(
                              msg.sender == address(getCrossDomainMessenger()),
                              "OVM_XCHAIN: messenger contract unauthenticated"
                          );
                          require(
                              getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,
                              "OVM_XCHAIN: wrong sender of cross-domain message"
                          );
                          _;
                      }
                      /**********************
                       * Internal Functions *
                       **********************/
                      /**
                       * Gets the messenger, usually from storage. This function is exposed in case a child contract
                       * needs to override.
                       * @return The address of the cross-domain messenger contract which should be used.
                       */
                      function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {
                          return ICrossDomainMessenger(messenger);
                      }
                      /**q
                       * Sends a message to an account on another domain
                       * @param _crossDomainTarget The intended recipient on the destination domain
                       * @param _message The data to send to the target (usually calldata to a function with
                       *  `onlyFromCrossDomainAccount()`)
                       * @param _gasLimit The gasLimit for the receipt of the message on the target domain.
                       */
                      function sendCrossDomainMessage(
                          address _crossDomainTarget,
                          uint32 _gasLimit,
                          bytes memory _message
                      ) internal {
                          getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /**
                   * @title Lib_PredeployAddresses
                   */
                  library Lib_PredeployAddresses {
                      address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000;
                      address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001;
                      address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002;
                      address payable internal constant OVM_ETH = payable(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000);
                      address internal constant L2_CROSS_DOMAIN_MESSENGER =
                          0x4200000000000000000000000000000000000007;
                      address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008;
                      address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009;
                      address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;
                      address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;
                      address internal constant L2_STANDARD_TOKEN_FACTORY =
                          0x4200000000000000000000000000000000000012;
                      address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013;
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.0;
                  /**
                   * @dev Collection of functions related to the address type
                   */
                  library Address {
                      /**
                       * @dev Returns true if `account` is a contract.
                       *
                       * [IMPORTANT]
                       * ====
                       * It is unsafe to assume that an address for which this function returns
                       * false is an externally-owned account (EOA) and not a contract.
                       *
                       * Among others, `isContract` will return false for the following
                       * types of addresses:
                       *
                       *  - an externally-owned account
                       *  - a contract in construction
                       *  - an address where a contract will be created
                       *  - an address where a contract lived, but was destroyed
                       * ====
                       */
                      function isContract(address account) internal view returns (bool) {
                          // This method relies on extcodesize, which returns 0 for contracts in
                          // construction, since the code is only stored at the end of the
                          // constructor execution.
                          uint256 size;
                          assembly {
                              size := extcodesize(account)
                          }
                          return size > 0;
                      }
                      /**
                       * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                       * `recipient`, forwarding all available gas and reverting on errors.
                       *
                       * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                       * of certain opcodes, possibly making contracts go over the 2300 gas limit
                       * imposed by `transfer`, making them unable to receive funds via
                       * `transfer`. {sendValue} removes this limitation.
                       *
                       * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                       *
                       * IMPORTANT: because control is transferred to `recipient`, care must be
                       * taken to not create reentrancy vulnerabilities. Consider using
                       * {ReentrancyGuard} or the
                       * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                       */
                      function sendValue(address payable recipient, uint256 amount) internal {
                          require(address(this).balance >= amount, "Address: insufficient balance");
                          (bool success, ) = recipient.call{value: amount}("");
                          require(success, "Address: unable to send value, recipient may have reverted");
                      }
                      /**
                       * @dev Performs a Solidity function call using a low level `call`. A
                       * plain `call` is an unsafe replacement for a function call: use this
                       * function instead.
                       *
                       * If `target` reverts with a revert reason, it is bubbled up by this
                       * function (like regular Solidity function calls).
                       *
                       * Returns the raw returned data. To convert to the expected return value,
                       * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                       *
                       * Requirements:
                       *
                       * - `target` must be a contract.
                       * - calling `target` with `data` must not revert.
                       *
                       * _Available since v3.1._
                       */
                      function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                          return functionCall(target, data, "Address: low-level call failed");
                      }
                      /**
                       * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                       * `errorMessage` as a fallback revert reason when `target` reverts.
                       *
                       * _Available since v3.1._
                       */
                      function functionCall(
                          address target,
                          bytes memory data,
                          string memory errorMessage
                      ) internal returns (bytes memory) {
                          return functionCallWithValue(target, data, 0, errorMessage);
                      }
                      /**
                       * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                       * but also transferring `value` wei to `target`.
                       *
                       * Requirements:
                       *
                       * - the calling contract must have an ETH balance of at least `value`.
                       * - the called Solidity function must be `payable`.
                       *
                       * _Available since v3.1._
                       */
                      function functionCallWithValue(
                          address target,
                          bytes memory data,
                          uint256 value
                      ) internal returns (bytes memory) {
                          return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                      }
                      /**
                       * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                       * with `errorMessage` as a fallback revert reason when `target` reverts.
                       *
                       * _Available since v3.1._
                       */
                      function functionCallWithValue(
                          address target,
                          bytes memory data,
                          uint256 value,
                          string memory errorMessage
                      ) internal returns (bytes memory) {
                          require(address(this).balance >= value, "Address: insufficient balance for call");
                          require(isContract(target), "Address: call to non-contract");
                          (bool success, bytes memory returndata) = target.call{value: value}(data);
                          return verifyCallResult(success, returndata, errorMessage);
                      }
                      /**
                       * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                       * but performing a static call.
                       *
                       * _Available since v3.3._
                       */
                      function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                          return functionStaticCall(target, data, "Address: low-level static call failed");
                      }
                      /**
                       * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                       * but performing a static call.
                       *
                       * _Available since v3.3._
                       */
                      function functionStaticCall(
                          address target,
                          bytes memory data,
                          string memory errorMessage
                      ) internal view returns (bytes memory) {
                          require(isContract(target), "Address: static call to non-contract");
                          (bool success, bytes memory returndata) = target.staticcall(data);
                          return verifyCallResult(success, returndata, errorMessage);
                      }
                      /**
                       * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                       * but performing a delegate call.
                       *
                       * _Available since v3.4._
                       */
                      function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                          return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                      }
                      /**
                       * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                       * but performing a delegate call.
                       *
                       * _Available since v3.4._
                       */
                      function functionDelegateCall(
                          address target,
                          bytes memory data,
                          string memory errorMessage
                      ) internal returns (bytes memory) {
                          require(isContract(target), "Address: delegate call to non-contract");
                          (bool success, bytes memory returndata) = target.delegatecall(data);
                          return verifyCallResult(success, returndata, errorMessage);
                      }
                      /**
                       * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
                       * revert reason using the provided one.
                       *
                       * _Available since v4.3._
                       */
                      function verifyCallResult(
                          bool success,
                          bytes memory returndata,
                          string memory errorMessage
                      ) internal pure returns (bytes memory) {
                          if (success) {
                              return returndata;
                          } else {
                              // Look for revert reason and bubble it up if present
                              if (returndata.length > 0) {
                                  // The easiest way to bubble the revert reason is using memory via assembly
                                  assembly {
                                      let returndata_size := mload(returndata)
                                      revert(add(32, returndata), returndata_size)
                                  }
                              } else {
                                  revert(errorMessage);
                              }
                          }
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.0;
                  import "../IERC20.sol";
                  import "../../../utils/Address.sol";
                  /**
                   * @title SafeERC20
                   * @dev Wrappers around ERC20 operations that throw on failure (when the token
                   * contract returns false). Tokens that return no value (and instead revert or
                   * throw on failure) are also supported, non-reverting calls are assumed to be
                   * successful.
                   * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
                   * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
                   */
                  library SafeERC20 {
                      using Address for address;
                      function safeTransfer(
                          IERC20 token,
                          address to,
                          uint256 value
                      ) internal {
                          _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
                      }
                      function safeTransferFrom(
                          IERC20 token,
                          address from,
                          address to,
                          uint256 value
                      ) internal {
                          _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
                      }
                      /**
                       * @dev Deprecated. This function has issues similar to the ones found in
                       * {IERC20-approve}, and its usage is discouraged.
                       *
                       * Whenever possible, use {safeIncreaseAllowance} and
                       * {safeDecreaseAllowance} instead.
                       */
                      function safeApprove(
                          IERC20 token,
                          address spender,
                          uint256 value
                      ) internal {
                          // safeApprove should only be called when setting an initial allowance,
                          // or when resetting it to zero. To increase and decrease it, use
                          // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
                          require(
                              (value == 0) || (token.allowance(address(this), spender) == 0),
                              "SafeERC20: approve from non-zero to non-zero allowance"
                          );
                          _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
                      }
                      function safeIncreaseAllowance(
                          IERC20 token,
                          address spender,
                          uint256 value
                      ) internal {
                          uint256 newAllowance = token.allowance(address(this), spender) + value;
                          _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                      }
                      function safeDecreaseAllowance(
                          IERC20 token,
                          address spender,
                          uint256 value
                      ) internal {
                          unchecked {
                              uint256 oldAllowance = token.allowance(address(this), spender);
                              require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
                              uint256 newAllowance = oldAllowance - value;
                              _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                          }
                      }
                      /**
                       * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
                       * on the return value: the return value is optional (but if data is returned, it must not be false).
                       * @param token The token targeted by the call.
                       * @param data The call data (encoded using abi.encode or one of its variants).
                       */
                      function _callOptionalReturn(IERC20 token, bytes memory data) private {
                          // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                          // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
                          // the target address contains contract code and also asserts for success in the low-level call.
                          bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
                          if (returndata.length > 0) {
                              // Return data is optional
                              require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
                          }
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >0.5.0 <0.9.0;
                  /**
                   * @title ICrossDomainMessenger
                   */
                  interface ICrossDomainMessenger {
                      /**********
                       * Events *
                       **********/
                      event SentMessage(
                          address indexed target,
                          address sender,
                          bytes message,
                          uint256 messageNonce,
                          uint256 gasLimit
                      );
                      event RelayedMessage(bytes32 indexed msgHash);
                      event FailedRelayedMessage(bytes32 indexed msgHash);
                      /*************
                       * Variables *
                       *************/
                      function xDomainMessageSender() external view returns (address);
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * Sends a cross domain message to the target messenger.
                       * @param _target Target contract address.
                       * @param _message Message to send to the target.
                       * @param _gasLimit Gas limit for the provided message.
                       */
                      function sendMessage(
                          address _target,
                          bytes calldata _message,
                          uint32 _gasLimit
                      ) external;
                  }
                  

                  File 9 of 14: AppProxyUpgradeable
                  // File: contracts/common/UnstructuredStorage.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  library UnstructuredStorage {
                      function getStorageBool(bytes32 position) internal view returns (bool data) {
                          assembly { data := sload(position) }
                      }
                  
                      function getStorageAddress(bytes32 position) internal view returns (address data) {
                          assembly { data := sload(position) }
                      }
                  
                      function getStorageBytes32(bytes32 position) internal view returns (bytes32 data) {
                          assembly { data := sload(position) }
                      }
                  
                      function getStorageUint256(bytes32 position) internal view returns (uint256 data) {
                          assembly { data := sload(position) }
                      }
                  
                      function setStorageBool(bytes32 position, bool data) internal {
                          assembly { sstore(position, data) }
                      }
                  
                      function setStorageAddress(bytes32 position, address data) internal {
                          assembly { sstore(position, data) }
                      }
                  
                      function setStorageBytes32(bytes32 position, bytes32 data) internal {
                          assembly { sstore(position, data) }
                      }
                  
                      function setStorageUint256(bytes32 position, uint256 data) internal {
                          assembly { sstore(position, data) }
                      }
                  }
                  
                  // File: contracts/acl/IACL.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  interface IACL {
                      function initialize(address permissionsCreator) external;
                  
                      // TODO: this should be external
                      // See https://github.com/ethereum/solidity/issues/4832
                      function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                  }
                  
                  // File: contracts/common/IVaultRecoverable.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  interface IVaultRecoverable {
                      event RecoverToVault(address indexed vault, address indexed token, uint256 amount);
                  
                      function transferToVault(address token) external;
                  
                      function allowRecoverability(address token) external view returns (bool);
                      function getRecoveryVault() external view returns (address);
                  }
                  
                  // File: contracts/kernel/IKernel.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  
                  interface IKernelEvents {
                      event SetApp(bytes32 indexed namespace, bytes32 indexed appId, address app);
                  }
                  
                  
                  // This should be an interface, but interfaces can't inherit yet :(
                  contract IKernel is IKernelEvents, IVaultRecoverable {
                      function acl() public view returns (IACL);
                      function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                  
                      function setApp(bytes32 namespace, bytes32 appId, address app) public;
                      function getApp(bytes32 namespace, bytes32 appId) public view returns (address);
                  }
                  
                  // File: contracts/apps/AppStorage.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  
                  contract AppStorage {
                      using UnstructuredStorage for bytes32;
                  
                      /* Hardcoded constants to save gas
                      bytes32 internal constant KERNEL_POSITION = keccak256("aragonOS.appStorage.kernel");
                      bytes32 internal constant APP_ID_POSITION = keccak256("aragonOS.appStorage.appId");
                      */
                      bytes32 internal constant KERNEL_POSITION = 0x4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b;
                      bytes32 internal constant APP_ID_POSITION = 0xd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b;
                  
                      function kernel() public view returns (IKernel) {
                          return IKernel(KERNEL_POSITION.getStorageAddress());
                      }
                  
                      function appId() public view returns (bytes32) {
                          return APP_ID_POSITION.getStorageBytes32();
                      }
                  
                      function setKernel(IKernel _kernel) internal {
                          KERNEL_POSITION.setStorageAddress(address(_kernel));
                      }
                  
                      function setAppId(bytes32 _appId) internal {
                          APP_ID_POSITION.setStorageBytes32(_appId);
                      }
                  }
                  
                  // File: contracts/common/IsContract.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  contract IsContract {
                      /*
                      * NOTE: this should NEVER be used for authentication
                      * (see pitfalls: https://github.com/fergarrui/ethereum-security/tree/master/contracts/extcodesize).
                      *
                      * This is only intended to be used as a sanity check that an address is actually a contract,
                      * RATHER THAN an address not being a contract.
                      */
                      function isContract(address _target) internal view returns (bool) {
                          if (_target == address(0)) {
                              return false;
                          }
                  
                          uint256 size;
                          assembly { size := extcodesize(_target) }
                          return size > 0;
                      }
                  }
                  
                  // File: contracts/lib/misc/ERCProxy.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  contract ERCProxy {
                      uint256 internal constant FORWARDING = 1;
                      uint256 internal constant UPGRADEABLE = 2;
                  
                      function proxyType() public pure returns (uint256 proxyTypeId);
                      function implementation() public view returns (address codeAddr);
                  }
                  
                  // File: contracts/common/DelegateProxy.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  
                  
                  contract DelegateProxy is ERCProxy, IsContract {
                      uint256 internal constant FWD_GAS_LIMIT = 10000;
                  
                      /**
                      * @dev Performs a delegatecall and returns whatever the delegatecall returned (entire context execution will return!)
                      * @param _dst Destination address to perform the delegatecall
                      * @param _calldata Calldata for the delegatecall
                      */
                      function delegatedFwd(address _dst, bytes _calldata) internal {
                          require(isContract(_dst));
                          uint256 fwdGasLimit = FWD_GAS_LIMIT;
                  
                          assembly {
                              let result := delegatecall(sub(gas, fwdGasLimit), _dst, add(_calldata, 0x20), mload(_calldata), 0, 0)
                              let size := returndatasize
                              let ptr := mload(0x40)
                              returndatacopy(ptr, 0, size)
                  
                              // revert instead of invalid() bc if the underlying call failed with invalid() it already wasted gas.
                              // if the call returned error data, forward it
                              switch result case 0 { revert(ptr, size) }
                              default { return(ptr, size) }
                          }
                      }
                  }
                  
                  // File: contracts/common/DepositableStorage.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  
                  contract DepositableStorage {
                      using UnstructuredStorage for bytes32;
                  
                      // keccak256("aragonOS.depositableStorage.depositable")
                      bytes32 internal constant DEPOSITABLE_POSITION = 0x665fd576fbbe6f247aff98f5c94a561e3f71ec2d3c988d56f12d342396c50cea;
                  
                      function isDepositable() public view returns (bool) {
                          return DEPOSITABLE_POSITION.getStorageBool();
                      }
                  
                      function setDepositable(bool _depositable) internal {
                          DEPOSITABLE_POSITION.setStorageBool(_depositable);
                      }
                  }
                  
                  // File: contracts/common/DepositableDelegateProxy.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  
                  
                  contract DepositableDelegateProxy is DepositableStorage, DelegateProxy {
                      event ProxyDeposit(address sender, uint256 value);
                  
                      function () external payable {
                          uint256 forwardGasThreshold = FWD_GAS_LIMIT;
                          bytes32 isDepositablePosition = DEPOSITABLE_POSITION;
                  
                          // Optimized assembly implementation to prevent EIP-1884 from breaking deposits, reference code in Solidity:
                          // https://github.com/aragon/aragonOS/blob/v4.2.1/contracts/common/DepositableDelegateProxy.sol#L10-L20
                          assembly {
                              // Continue only if the gas left is lower than the threshold for forwarding to the implementation code,
                              // otherwise continue outside of the assembly block.
                              if lt(gas, forwardGasThreshold) {
                                  // Only accept the deposit and emit an event if all of the following are true:
                                  // the proxy accepts deposits (isDepositable), msg.data.length == 0, and msg.value > 0
                                  if and(and(sload(isDepositablePosition), iszero(calldatasize)), gt(callvalue, 0)) {
                                      // Equivalent Solidity code for emitting the event:
                                      // emit ProxyDeposit(msg.sender, msg.value);
                  
                                      let logData := mload(0x40) // free memory pointer
                                      mstore(logData, caller) // add 'msg.sender' to the log data (first event param)
                                      mstore(add(logData, 0x20), callvalue) // add 'msg.value' to the log data (second event param)
                  
                                      // Emit an event with one topic to identify the event: keccak256('ProxyDeposit(address,uint256)') = 0x15ee...dee1
                                      log1(logData, 0x40, 0x15eeaa57c7bd188c1388020bcadc2c436ec60d647d36ef5b9eb3c742217ddee1)
                  
                                      stop() // Stop. Exits execution context
                                  }
                  
                                  // If any of above checks failed, revert the execution (if ETH was sent, it is returned to the sender)
                                  revert(0, 0)
                              }
                          }
                  
                          address target = implementation();
                          delegatedFwd(target, msg.data);
                      }
                  }
                  
                  // File: contracts/kernel/KernelConstants.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  contract KernelAppIds {
                      /* Hardcoded constants to save gas
                      bytes32 internal constant KERNEL_CORE_APP_ID = apmNamehash("kernel");
                      bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = apmNamehash("acl");
                      bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = apmNamehash("vault");
                      */
                      bytes32 internal constant KERNEL_CORE_APP_ID = 0x3b4bf6bf3ad5000ecf0f989d5befde585c6860fea3e574a4fab4c49d1c177d9c;
                      bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = 0xe3262375f45a6e2026b7e7b18c2b807434f2508fe1a2a3dfb493c7df8f4aad6a;
                      bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = 0x7e852e0fcfce6551c13800f1e7476f982525c2b5277ba14b24339c68416336d1;
                  }
                  
                  
                  contract KernelNamespaceConstants {
                      /* Hardcoded constants to save gas
                      bytes32 internal constant KERNEL_CORE_NAMESPACE = keccak256("core");
                      bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = keccak256("base");
                      bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = keccak256("app");
                      */
                      bytes32 internal constant KERNEL_CORE_NAMESPACE = 0xc681a85306374a5ab27f0bbc385296a54bcd314a1948b6cf61c4ea1bc44bb9f8;
                      bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = 0xf1f3eb40f5bc1ad1344716ced8b8a0431d840b5783aea1fd01786bc26f35ac0f;
                      bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
                  }
                  
                  // File: contracts/apps/AppProxyBase.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  
                  
                  
                  
                  contract AppProxyBase is AppStorage, DepositableDelegateProxy, KernelNamespaceConstants {
                      /**
                      * @dev Initialize AppProxy
                      * @param _kernel Reference to organization kernel for the app
                      * @param _appId Identifier for app
                      * @param _initializePayload Payload for call to be made after setup to initialize
                      */
                      constructor(IKernel _kernel, bytes32 _appId, bytes _initializePayload) public {
                          setKernel(_kernel);
                          setAppId(_appId);
                  
                          // Implicit check that kernel is actually a Kernel
                          // The EVM doesn't actually provide a way for us to make sure, but we can force a revert to
                          // occur if the kernel is set to 0x0 or a non-code address when we try to call a method on
                          // it.
                          address appCode = getAppBase(_appId);
                  
                          // If initialize payload is provided, it will be executed
                          if (_initializePayload.length > 0) {
                              require(isContract(appCode));
                              // Cannot make delegatecall as a delegateproxy.delegatedFwd as it
                              // returns ending execution context and halts contract deployment
                              require(appCode.delegatecall(_initializePayload));
                          }
                      }
                  
                      function getAppBase(bytes32 _appId) internal view returns (address) {
                          return kernel().getApp(KERNEL_APP_BASES_NAMESPACE, _appId);
                      }
                  }
                  
                  // File: contracts/apps/AppProxyUpgradeable.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  
                  contract AppProxyUpgradeable is AppProxyBase {
                      /**
                      * @dev Initialize AppProxyUpgradeable (makes it an upgradeable Aragon app)
                      * @param _kernel Reference to organization kernel for the app
                      * @param _appId Identifier for app
                      * @param _initializePayload Payload for call to be made after setup to initialize
                      */
                      constructor(IKernel _kernel, bytes32 _appId, bytes _initializePayload)
                          AppProxyBase(_kernel, _appId, _initializePayload)
                          public // solium-disable-line visibility-first
                      {
                          // solium-disable-previous-line no-empty-blocks
                      }
                  
                      /**
                       * @dev ERC897, the address the proxy would delegate calls to
                       */
                      function implementation() public view returns (address) {
                          return getAppBase(appId());
                      }
                  
                      /**
                       * @dev ERC897, whether it is a forwarding (1) or an upgradeable (2) proxy
                       */
                      function proxyType() public pure returns (uint256 proxyTypeId) {
                          return UPGRADEABLE;
                      }
                  }

                  File 10 of 14: KernelProxy
                  // File: contracts/acl/IACL.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  interface IACL {
                      function initialize(address permissionsCreator) external;
                  
                      // TODO: this should be external
                      // See https://github.com/ethereum/solidity/issues/4832
                      function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                  }
                  
                  // File: contracts/common/IVaultRecoverable.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  interface IVaultRecoverable {
                      event RecoverToVault(address indexed vault, address indexed token, uint256 amount);
                  
                      function transferToVault(address token) external;
                  
                      function allowRecoverability(address token) external view returns (bool);
                      function getRecoveryVault() external view returns (address);
                  }
                  
                  // File: contracts/kernel/IKernel.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  
                  interface IKernelEvents {
                      event SetApp(bytes32 indexed namespace, bytes32 indexed appId, address app);
                  }
                  
                  
                  // This should be an interface, but interfaces can't inherit yet :(
                  contract IKernel is IKernelEvents, IVaultRecoverable {
                      function acl() public view returns (IACL);
                      function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                  
                      function setApp(bytes32 namespace, bytes32 appId, address app) public;
                      function getApp(bytes32 namespace, bytes32 appId) public view returns (address);
                  }
                  
                  // File: contracts/kernel/KernelConstants.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  contract KernelAppIds {
                      /* Hardcoded constants to save gas
                      bytes32 internal constant KERNEL_CORE_APP_ID = apmNamehash("kernel");
                      bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = apmNamehash("acl");
                      bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = apmNamehash("vault");
                      */
                      bytes32 internal constant KERNEL_CORE_APP_ID = 0x3b4bf6bf3ad5000ecf0f989d5befde585c6860fea3e574a4fab4c49d1c177d9c;
                      bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = 0xe3262375f45a6e2026b7e7b18c2b807434f2508fe1a2a3dfb493c7df8f4aad6a;
                      bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = 0x7e852e0fcfce6551c13800f1e7476f982525c2b5277ba14b24339c68416336d1;
                  }
                  
                  
                  contract KernelNamespaceConstants {
                      /* Hardcoded constants to save gas
                      bytes32 internal constant KERNEL_CORE_NAMESPACE = keccak256("core");
                      bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = keccak256("base");
                      bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = keccak256("app");
                      */
                      bytes32 internal constant KERNEL_CORE_NAMESPACE = 0xc681a85306374a5ab27f0bbc385296a54bcd314a1948b6cf61c4ea1bc44bb9f8;
                      bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = 0xf1f3eb40f5bc1ad1344716ced8b8a0431d840b5783aea1fd01786bc26f35ac0f;
                      bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
                  }
                  
                  // File: contracts/kernel/KernelStorage.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  contract KernelStorage {
                      // namespace => app id => address
                      mapping (bytes32 => mapping (bytes32 => address)) public apps;
                      bytes32 public recoveryVaultAppId;
                  }
                  
                  // File: contracts/common/IsContract.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  contract IsContract {
                      /*
                      * NOTE: this should NEVER be used for authentication
                      * (see pitfalls: https://github.com/fergarrui/ethereum-security/tree/master/contracts/extcodesize).
                      *
                      * This is only intended to be used as a sanity check that an address is actually a contract,
                      * RATHER THAN an address not being a contract.
                      */
                      function isContract(address _target) internal view returns (bool) {
                          if (_target == address(0)) {
                              return false;
                          }
                  
                          uint256 size;
                          assembly { size := extcodesize(_target) }
                          return size > 0;
                      }
                  }
                  
                  // File: contracts/lib/misc/ERCProxy.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  contract ERCProxy {
                      uint256 internal constant FORWARDING = 1;
                      uint256 internal constant UPGRADEABLE = 2;
                  
                      function proxyType() public pure returns (uint256 proxyTypeId);
                      function implementation() public view returns (address codeAddr);
                  }
                  
                  // File: contracts/common/DelegateProxy.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  
                  
                  contract DelegateProxy is ERCProxy, IsContract {
                      uint256 internal constant FWD_GAS_LIMIT = 10000;
                  
                      /**
                      * @dev Performs a delegatecall and returns whatever the delegatecall returned (entire context execution will return!)
                      * @param _dst Destination address to perform the delegatecall
                      * @param _calldata Calldata for the delegatecall
                      */
                      function delegatedFwd(address _dst, bytes _calldata) internal {
                          require(isContract(_dst));
                          uint256 fwdGasLimit = FWD_GAS_LIMIT;
                  
                          assembly {
                              let result := delegatecall(sub(gas, fwdGasLimit), _dst, add(_calldata, 0x20), mload(_calldata), 0, 0)
                              let size := returndatasize
                              let ptr := mload(0x40)
                              returndatacopy(ptr, 0, size)
                  
                              // revert instead of invalid() bc if the underlying call failed with invalid() it already wasted gas.
                              // if the call returned error data, forward it
                              switch result case 0 { revert(ptr, size) }
                              default { return(ptr, size) }
                          }
                      }
                  }
                  
                  // File: contracts/common/UnstructuredStorage.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  library UnstructuredStorage {
                      function getStorageBool(bytes32 position) internal view returns (bool data) {
                          assembly { data := sload(position) }
                      }
                  
                      function getStorageAddress(bytes32 position) internal view returns (address data) {
                          assembly { data := sload(position) }
                      }
                  
                      function getStorageBytes32(bytes32 position) internal view returns (bytes32 data) {
                          assembly { data := sload(position) }
                      }
                  
                      function getStorageUint256(bytes32 position) internal view returns (uint256 data) {
                          assembly { data := sload(position) }
                      }
                  
                      function setStorageBool(bytes32 position, bool data) internal {
                          assembly { sstore(position, data) }
                      }
                  
                      function setStorageAddress(bytes32 position, address data) internal {
                          assembly { sstore(position, data) }
                      }
                  
                      function setStorageBytes32(bytes32 position, bytes32 data) internal {
                          assembly { sstore(position, data) }
                      }
                  
                      function setStorageUint256(bytes32 position, uint256 data) internal {
                          assembly { sstore(position, data) }
                      }
                  }
                  
                  // File: contracts/common/DepositableStorage.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  
                  contract DepositableStorage {
                      using UnstructuredStorage for bytes32;
                  
                      // keccak256("aragonOS.depositableStorage.depositable")
                      bytes32 internal constant DEPOSITABLE_POSITION = 0x665fd576fbbe6f247aff98f5c94a561e3f71ec2d3c988d56f12d342396c50cea;
                  
                      function isDepositable() public view returns (bool) {
                          return DEPOSITABLE_POSITION.getStorageBool();
                      }
                  
                      function setDepositable(bool _depositable) internal {
                          DEPOSITABLE_POSITION.setStorageBool(_depositable);
                      }
                  }
                  
                  // File: contracts/common/DepositableDelegateProxy.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  
                  
                  contract DepositableDelegateProxy is DepositableStorage, DelegateProxy {
                      event ProxyDeposit(address sender, uint256 value);
                  
                      function () external payable {
                          uint256 forwardGasThreshold = FWD_GAS_LIMIT;
                          bytes32 isDepositablePosition = DEPOSITABLE_POSITION;
                  
                          // Optimized assembly implementation to prevent EIP-1884 from breaking deposits, reference code in Solidity:
                          // https://github.com/aragon/aragonOS/blob/v4.2.1/contracts/common/DepositableDelegateProxy.sol#L10-L20
                          assembly {
                              // Continue only if the gas left is lower than the threshold for forwarding to the implementation code,
                              // otherwise continue outside of the assembly block.
                              if lt(gas, forwardGasThreshold) {
                                  // Only accept the deposit and emit an event if all of the following are true:
                                  // the proxy accepts deposits (isDepositable), msg.data.length == 0, and msg.value > 0
                                  if and(and(sload(isDepositablePosition), iszero(calldatasize)), gt(callvalue, 0)) {
                                      // Equivalent Solidity code for emitting the event:
                                      // emit ProxyDeposit(msg.sender, msg.value);
                  
                                      let logData := mload(0x40) // free memory pointer
                                      mstore(logData, caller) // add 'msg.sender' to the log data (first event param)
                                      mstore(add(logData, 0x20), callvalue) // add 'msg.value' to the log data (second event param)
                  
                                      // Emit an event with one topic to identify the event: keccak256('ProxyDeposit(address,uint256)') = 0x15ee...dee1
                                      log1(logData, 0x40, 0x15eeaa57c7bd188c1388020bcadc2c436ec60d647d36ef5b9eb3c742217ddee1)
                  
                                      stop() // Stop. Exits execution context
                                  }
                  
                                  // If any of above checks failed, revert the execution (if ETH was sent, it is returned to the sender)
                                  revert(0, 0)
                              }
                          }
                  
                          address target = implementation();
                          delegatedFwd(target, msg.data);
                      }
                  }
                  
                  // File: contracts/kernel/KernelProxy.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  
                  
                  
                  
                  
                  contract KernelProxy is IKernelEvents, KernelStorage, KernelAppIds, KernelNamespaceConstants, IsContract, DepositableDelegateProxy {
                      /**
                      * @dev KernelProxy is a proxy contract to a kernel implementation. The implementation
                      *      can update the reference, which effectively upgrades the contract
                      * @param _kernelImpl Address of the contract used as implementation for kernel
                      */
                      constructor(IKernel _kernelImpl) public {
                          require(isContract(address(_kernelImpl)));
                          apps[KERNEL_CORE_NAMESPACE][KERNEL_CORE_APP_ID] = _kernelImpl;
                  
                          // Note that emitting this event is important for verifying that a KernelProxy instance
                          // was never upgraded to a malicious Kernel logic contract over its lifespan.
                          // This starts the "chain of trust", that can be followed through later SetApp() events
                          // emitted during kernel upgrades.
                          emit SetApp(KERNEL_CORE_NAMESPACE, KERNEL_CORE_APP_ID, _kernelImpl);
                      }
                  
                      /**
                       * @dev ERC897, whether it is a forwarding (1) or an upgradeable (2) proxy
                       */
                      function proxyType() public pure returns (uint256 proxyTypeId) {
                          return UPGRADEABLE;
                      }
                  
                      /**
                      * @dev ERC897, the address the proxy would delegate calls to
                      */
                      function implementation() public view returns (address) {
                          return apps[KERNEL_CORE_NAMESPACE][KERNEL_CORE_APP_ID];
                      }
                  }

                  File 11 of 14: Kernel
                  // File: contracts/acl/IACL.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  interface IACL {
                      function initialize(address permissionsCreator) external;
                  
                      // TODO: this should be external
                      // See https://github.com/ethereum/solidity/issues/4832
                      function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                  }
                  
                  // File: contracts/common/IVaultRecoverable.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  interface IVaultRecoverable {
                      event RecoverToVault(address indexed vault, address indexed token, uint256 amount);
                  
                      function transferToVault(address token) external;
                  
                      function allowRecoverability(address token) external view returns (bool);
                      function getRecoveryVault() external view returns (address);
                  }
                  
                  // File: contracts/kernel/IKernel.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  
                  interface IKernelEvents {
                      event SetApp(bytes32 indexed namespace, bytes32 indexed appId, address app);
                  }
                  
                  
                  // This should be an interface, but interfaces can't inherit yet :(
                  contract IKernel is IKernelEvents, IVaultRecoverable {
                      function acl() public view returns (IACL);
                      function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                  
                      function setApp(bytes32 namespace, bytes32 appId, address app) public;
                      function getApp(bytes32 namespace, bytes32 appId) public view returns (address);
                  }
                  
                  // File: contracts/kernel/KernelConstants.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  contract KernelAppIds {
                      /* Hardcoded constants to save gas
                      bytes32 internal constant KERNEL_CORE_APP_ID = apmNamehash("kernel");
                      bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = apmNamehash("acl");
                      bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = apmNamehash("vault");
                      */
                      bytes32 internal constant KERNEL_CORE_APP_ID = 0x3b4bf6bf3ad5000ecf0f989d5befde585c6860fea3e574a4fab4c49d1c177d9c;
                      bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = 0xe3262375f45a6e2026b7e7b18c2b807434f2508fe1a2a3dfb493c7df8f4aad6a;
                      bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = 0x7e852e0fcfce6551c13800f1e7476f982525c2b5277ba14b24339c68416336d1;
                  }
                  
                  
                  contract KernelNamespaceConstants {
                      /* Hardcoded constants to save gas
                      bytes32 internal constant KERNEL_CORE_NAMESPACE = keccak256("core");
                      bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = keccak256("base");
                      bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = keccak256("app");
                      */
                      bytes32 internal constant KERNEL_CORE_NAMESPACE = 0xc681a85306374a5ab27f0bbc385296a54bcd314a1948b6cf61c4ea1bc44bb9f8;
                      bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = 0xf1f3eb40f5bc1ad1344716ced8b8a0431d840b5783aea1fd01786bc26f35ac0f;
                      bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
                  }
                  
                  // File: contracts/kernel/KernelStorage.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  contract KernelStorage {
                      // namespace => app id => address
                      mapping (bytes32 => mapping (bytes32 => address)) public apps;
                      bytes32 public recoveryVaultAppId;
                  }
                  
                  // File: contracts/acl/ACLSyntaxSugar.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  contract ACLSyntaxSugar {
                      function arr() internal pure returns (uint256[]) {
                          return new uint256[](0);
                      }
                  
                      function arr(bytes32 _a) internal pure returns (uint256[] r) {
                          return arr(uint256(_a));
                      }
                  
                      function arr(bytes32 _a, bytes32 _b) internal pure returns (uint256[] r) {
                          return arr(uint256(_a), uint256(_b));
                      }
                  
                      function arr(address _a) internal pure returns (uint256[] r) {
                          return arr(uint256(_a));
                      }
                  
                      function arr(address _a, address _b) internal pure returns (uint256[] r) {
                          return arr(uint256(_a), uint256(_b));
                      }
                  
                      function arr(address _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) {
                          return arr(uint256(_a), _b, _c);
                      }
                  
                      function arr(address _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) {
                          return arr(uint256(_a), _b, _c, _d);
                      }
                  
                      function arr(address _a, uint256 _b) internal pure returns (uint256[] r) {
                          return arr(uint256(_a), uint256(_b));
                      }
                  
                      function arr(address _a, address _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) {
                          return arr(uint256(_a), uint256(_b), _c, _d, _e);
                      }
                  
                      function arr(address _a, address _b, address _c) internal pure returns (uint256[] r) {
                          return arr(uint256(_a), uint256(_b), uint256(_c));
                      }
                  
                      function arr(address _a, address _b, uint256 _c) internal pure returns (uint256[] r) {
                          return arr(uint256(_a), uint256(_b), uint256(_c));
                      }
                  
                      function arr(uint256 _a) internal pure returns (uint256[] r) {
                          r = new uint256[](1);
                          r[0] = _a;
                      }
                  
                      function arr(uint256 _a, uint256 _b) internal pure returns (uint256[] r) {
                          r = new uint256[](2);
                          r[0] = _a;
                          r[1] = _b;
                      }
                  
                      function arr(uint256 _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) {
                          r = new uint256[](3);
                          r[0] = _a;
                          r[1] = _b;
                          r[2] = _c;
                      }
                  
                      function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) {
                          r = new uint256[](4);
                          r[0] = _a;
                          r[1] = _b;
                          r[2] = _c;
                          r[3] = _d;
                      }
                  
                      function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) {
                          r = new uint256[](5);
                          r[0] = _a;
                          r[1] = _b;
                          r[2] = _c;
                          r[3] = _d;
                          r[4] = _e;
                      }
                  }
                  
                  
                  contract ACLHelpers {
                      function decodeParamOp(uint256 _x) internal pure returns (uint8 b) {
                          return uint8(_x >> (8 * 30));
                      }
                  
                      function decodeParamId(uint256 _x) internal pure returns (uint8 b) {
                          return uint8(_x >> (8 * 31));
                      }
                  
                      function decodeParamsList(uint256 _x) internal pure returns (uint32 a, uint32 b, uint32 c) {
                          a = uint32(_x);
                          b = uint32(_x >> (8 * 4));
                          c = uint32(_x >> (8 * 8));
                      }
                  }
                  
                  // File: contracts/common/ConversionHelpers.sol
                  
                  pragma solidity ^0.4.24;
                  
                  
                  library ConversionHelpers {
                      string private constant ERROR_IMPROPER_LENGTH = "CONVERSION_IMPROPER_LENGTH";
                  
                      function dangerouslyCastUintArrayToBytes(uint256[] memory _input) internal pure returns (bytes memory output) {
                          // Force cast the uint256[] into a bytes array, by overwriting its length
                          // Note that the bytes array doesn't need to be initialized as we immediately overwrite it
                          // with the input and a new length. The input becomes invalid from this point forward.
                          uint256 byteLength = _input.length * 32;
                          assembly {
                              output := _input
                              mstore(output, byteLength)
                          }
                      }
                  
                      function dangerouslyCastBytesToUintArray(bytes memory _input) internal pure returns (uint256[] memory output) {
                          // Force cast the bytes array into a uint256[], by overwriting its length
                          // Note that the uint256[] doesn't need to be initialized as we immediately overwrite it
                          // with the input and a new length. The input becomes invalid from this point forward.
                          uint256 intsLength = _input.length / 32;
                          require(_input.length == intsLength * 32, ERROR_IMPROPER_LENGTH);
                  
                          assembly {
                              output := _input
                              mstore(output, intsLength)
                          }
                      }
                  }
                  
                  // File: contracts/common/IsContract.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  contract IsContract {
                      /*
                      * NOTE: this should NEVER be used for authentication
                      * (see pitfalls: https://github.com/fergarrui/ethereum-security/tree/master/contracts/extcodesize).
                      *
                      * This is only intended to be used as a sanity check that an address is actually a contract,
                      * RATHER THAN an address not being a contract.
                      */
                      function isContract(address _target) internal view returns (bool) {
                          if (_target == address(0)) {
                              return false;
                          }
                  
                          uint256 size;
                          assembly { size := extcodesize(_target) }
                          return size > 0;
                      }
                  }
                  
                  // File: contracts/common/Uint256Helpers.sol
                  
                  pragma solidity ^0.4.24;
                  
                  
                  library Uint256Helpers {
                      uint256 private constant MAX_UINT64 = uint64(-1);
                  
                      string private constant ERROR_NUMBER_TOO_BIG = "UINT64_NUMBER_TOO_BIG";
                  
                      function toUint64(uint256 a) internal pure returns (uint64) {
                          require(a <= MAX_UINT64, ERROR_NUMBER_TOO_BIG);
                          return uint64(a);
                      }
                  }
                  
                  // File: contracts/common/TimeHelpers.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  contract TimeHelpers {
                      using Uint256Helpers for uint256;
                  
                      /**
                      * @dev Returns the current block number.
                      *      Using a function rather than `block.number` allows us to easily mock the block number in
                      *      tests.
                      */
                      function getBlockNumber() internal view returns (uint256) {
                          return block.number;
                      }
                  
                      /**
                      * @dev Returns the current block number, converted to uint64.
                      *      Using a function rather than `block.number` allows us to easily mock the block number in
                      *      tests.
                      */
                      function getBlockNumber64() internal view returns (uint64) {
                          return getBlockNumber().toUint64();
                      }
                  
                      /**
                      * @dev Returns the current timestamp.
                      *      Using a function rather than `block.timestamp` allows us to easily mock it in
                      *      tests.
                      */
                      function getTimestamp() internal view returns (uint256) {
                          return block.timestamp; // solium-disable-line security/no-block-members
                      }
                  
                      /**
                      * @dev Returns the current timestamp, converted to uint64.
                      *      Using a function rather than `block.timestamp` allows us to easily mock it in
                      *      tests.
                      */
                      function getTimestamp64() internal view returns (uint64) {
                          return getTimestamp().toUint64();
                      }
                  }
                  
                  // File: contracts/common/UnstructuredStorage.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  library UnstructuredStorage {
                      function getStorageBool(bytes32 position) internal view returns (bool data) {
                          assembly { data := sload(position) }
                      }
                  
                      function getStorageAddress(bytes32 position) internal view returns (address data) {
                          assembly { data := sload(position) }
                      }
                  
                      function getStorageBytes32(bytes32 position) internal view returns (bytes32 data) {
                          assembly { data := sload(position) }
                      }
                  
                      function getStorageUint256(bytes32 position) internal view returns (uint256 data) {
                          assembly { data := sload(position) }
                      }
                  
                      function setStorageBool(bytes32 position, bool data) internal {
                          assembly { sstore(position, data) }
                      }
                  
                      function setStorageAddress(bytes32 position, address data) internal {
                          assembly { sstore(position, data) }
                      }
                  
                      function setStorageBytes32(bytes32 position, bytes32 data) internal {
                          assembly { sstore(position, data) }
                      }
                  
                      function setStorageUint256(bytes32 position, uint256 data) internal {
                          assembly { sstore(position, data) }
                      }
                  }
                  
                  // File: contracts/common/Initializable.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  
                  contract Initializable is TimeHelpers {
                      using UnstructuredStorage for bytes32;
                  
                      // keccak256("aragonOS.initializable.initializationBlock")
                      bytes32 internal constant INITIALIZATION_BLOCK_POSITION = 0xebb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e;
                  
                      string private constant ERROR_ALREADY_INITIALIZED = "INIT_ALREADY_INITIALIZED";
                      string private constant ERROR_NOT_INITIALIZED = "INIT_NOT_INITIALIZED";
                  
                      modifier onlyInit {
                          require(getInitializationBlock() == 0, ERROR_ALREADY_INITIALIZED);
                          _;
                      }
                  
                      modifier isInitialized {
                          require(hasInitialized(), ERROR_NOT_INITIALIZED);
                          _;
                      }
                  
                      /**
                      * @return Block number in which the contract was initialized
                      */
                      function getInitializationBlock() public view returns (uint256) {
                          return INITIALIZATION_BLOCK_POSITION.getStorageUint256();
                      }
                  
                      /**
                      * @return Whether the contract has been initialized by the time of the current block
                      */
                      function hasInitialized() public view returns (bool) {
                          uint256 initializationBlock = getInitializationBlock();
                          return initializationBlock != 0 && getBlockNumber() >= initializationBlock;
                      }
                  
                      /**
                      * @dev Function to be called by top level contract after initialization has finished.
                      */
                      function initialized() internal onlyInit {
                          INITIALIZATION_BLOCK_POSITION.setStorageUint256(getBlockNumber());
                      }
                  
                      /**
                      * @dev Function to be called by top level contract after initialization to enable the contract
                      *      at a future block number rather than immediately.
                      */
                      function initializedAt(uint256 _blockNumber) internal onlyInit {
                          INITIALIZATION_BLOCK_POSITION.setStorageUint256(_blockNumber);
                      }
                  }
                  
                  // File: contracts/common/Petrifiable.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  contract Petrifiable is Initializable {
                      // Use block UINT256_MAX (which should be never) as the initializable date
                      uint256 internal constant PETRIFIED_BLOCK = uint256(-1);
                  
                      function isPetrified() public view returns (bool) {
                          return getInitializationBlock() == PETRIFIED_BLOCK;
                      }
                  
                      /**
                      * @dev Function to be called by top level contract to prevent being initialized.
                      *      Useful for freezing base contracts when they're used behind proxies.
                      */
                      function petrify() internal onlyInit {
                          initializedAt(PETRIFIED_BLOCK);
                      }
                  }
                  
                  // File: contracts/lib/token/ERC20.sol
                  
                  // See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/a9f910d34f0ab33a1ae5e714f69f9596a02b4d91/contracts/token/ERC20/ERC20.sol
                  
                  pragma solidity ^0.4.24;
                  
                  
                  /**
                   * @title ERC20 interface
                   * @dev see https://github.com/ethereum/EIPs/issues/20
                   */
                  contract ERC20 {
                      function totalSupply() public view returns (uint256);
                  
                      function balanceOf(address _who) public view returns (uint256);
                  
                      function allowance(address _owner, address _spender)
                          public view returns (uint256);
                  
                      function transfer(address _to, uint256 _value) public returns (bool);
                  
                      function approve(address _spender, uint256 _value)
                          public returns (bool);
                  
                      function transferFrom(address _from, address _to, uint256 _value)
                          public returns (bool);
                  
                      event Transfer(
                          address indexed from,
                          address indexed to,
                          uint256 value
                      );
                  
                      event Approval(
                          address indexed owner,
                          address indexed spender,
                          uint256 value
                      );
                  }
                  
                  // File: contracts/common/EtherTokenConstant.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  // aragonOS and aragon-apps rely on address(0) to denote native ETH, in
                  // contracts where both tokens and ETH are accepted
                  contract EtherTokenConstant {
                      address internal constant ETH = address(0);
                  }
                  
                  // File: contracts/common/SafeERC20.sol
                  
                  // Inspired by AdEx (https://github.com/AdExNetwork/adex-protocol-eth/blob/b9df617829661a7518ee10f4cb6c4108659dd6d5/contracts/libs/SafeERC20.sol)
                  // and 0x (https://github.com/0xProject/0x-monorepo/blob/737d1dc54d72872e24abce5a1dbe1b66d35fa21a/contracts/protocol/contracts/protocol/AssetProxy/ERC20Proxy.sol#L143)
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  library SafeERC20 {
                      // Before 0.5, solidity has a mismatch between `address.transfer()` and `token.transfer()`:
                      // https://github.com/ethereum/solidity/issues/3544
                      bytes4 private constant TRANSFER_SELECTOR = 0xa9059cbb;
                  
                      string private constant ERROR_TOKEN_BALANCE_REVERTED = "SAFE_ERC_20_BALANCE_REVERTED";
                      string private constant ERROR_TOKEN_ALLOWANCE_REVERTED = "SAFE_ERC_20_ALLOWANCE_REVERTED";
                  
                      function invokeAndCheckSuccess(address _addr, bytes memory _calldata)
                          private
                          returns (bool)
                      {
                          bool ret;
                          assembly {
                              let ptr := mload(0x40)    // free memory pointer
                  
                              let success := call(
                                  gas,                  // forward all gas
                                  _addr,                // address
                                  0,                    // no value
                                  add(_calldata, 0x20), // calldata start
                                  mload(_calldata),     // calldata length
                                  ptr,                  // write output over free memory
                                  0x20                  // uint256 return
                              )
                  
                              if gt(success, 0) {
                                  // Check number of bytes returned from last function call
                                  switch returndatasize
                  
                                  // No bytes returned: assume success
                                  case 0 {
                                      ret := 1
                                  }
                  
                                  // 32 bytes returned: check if non-zero
                                  case 0x20 {
                                      // Only return success if returned data was true
                                      // Already have output in ptr
                                      ret := eq(mload(ptr), 1)
                                  }
                  
                                  // Not sure what was returned: don't mark as success
                                  default { }
                              }
                          }
                          return ret;
                      }
                  
                      function staticInvoke(address _addr, bytes memory _calldata)
                          private
                          view
                          returns (bool, uint256)
                      {
                          bool success;
                          uint256 ret;
                          assembly {
                              let ptr := mload(0x40)    // free memory pointer
                  
                              success := staticcall(
                                  gas,                  // forward all gas
                                  _addr,                // address
                                  add(_calldata, 0x20), // calldata start
                                  mload(_calldata),     // calldata length
                                  ptr,                  // write output over free memory
                                  0x20                  // uint256 return
                              )
                  
                              if gt(success, 0) {
                                  ret := mload(ptr)
                              }
                          }
                          return (success, ret);
                      }
                  
                      /**
                      * @dev Same as a standards-compliant ERC20.transfer() that never reverts (returns false).
                      *      Note that this makes an external call to the token.
                      */
                      function safeTransfer(ERC20 _token, address _to, uint256 _amount) internal returns (bool) {
                          bytes memory transferCallData = abi.encodeWithSelector(
                              TRANSFER_SELECTOR,
                              _to,
                              _amount
                          );
                          return invokeAndCheckSuccess(_token, transferCallData);
                      }
                  
                      /**
                      * @dev Same as a standards-compliant ERC20.transferFrom() that never reverts (returns false).
                      *      Note that this makes an external call to the token.
                      */
                      function safeTransferFrom(ERC20 _token, address _from, address _to, uint256 _amount) internal returns (bool) {
                          bytes memory transferFromCallData = abi.encodeWithSelector(
                              _token.transferFrom.selector,
                              _from,
                              _to,
                              _amount
                          );
                          return invokeAndCheckSuccess(_token, transferFromCallData);
                      }
                  
                      /**
                      * @dev Same as a standards-compliant ERC20.approve() that never reverts (returns false).
                      *      Note that this makes an external call to the token.
                      */
                      function safeApprove(ERC20 _token, address _spender, uint256 _amount) internal returns (bool) {
                          bytes memory approveCallData = abi.encodeWithSelector(
                              _token.approve.selector,
                              _spender,
                              _amount
                          );
                          return invokeAndCheckSuccess(_token, approveCallData);
                      }
                  
                      /**
                      * @dev Static call into ERC20.balanceOf().
                      * Reverts if the call fails for some reason (should never fail).
                      */
                      function staticBalanceOf(ERC20 _token, address _owner) internal view returns (uint256) {
                          bytes memory balanceOfCallData = abi.encodeWithSelector(
                              _token.balanceOf.selector,
                              _owner
                          );
                  
                          (bool success, uint256 tokenBalance) = staticInvoke(_token, balanceOfCallData);
                          require(success, ERROR_TOKEN_BALANCE_REVERTED);
                  
                          return tokenBalance;
                      }
                  
                      /**
                      * @dev Static call into ERC20.allowance().
                      * Reverts if the call fails for some reason (should never fail).
                      */
                      function staticAllowance(ERC20 _token, address _owner, address _spender) internal view returns (uint256) {
                          bytes memory allowanceCallData = abi.encodeWithSelector(
                              _token.allowance.selector,
                              _owner,
                              _spender
                          );
                  
                          (bool success, uint256 allowance) = staticInvoke(_token, allowanceCallData);
                          require(success, ERROR_TOKEN_ALLOWANCE_REVERTED);
                  
                          return allowance;
                      }
                  
                      /**
                      * @dev Static call into ERC20.totalSupply().
                      * Reverts if the call fails for some reason (should never fail).
                      */
                      function staticTotalSupply(ERC20 _token) internal view returns (uint256) {
                          bytes memory totalSupplyCallData = abi.encodeWithSelector(_token.totalSupply.selector);
                  
                          (bool success, uint256 totalSupply) = staticInvoke(_token, totalSupplyCallData);
                          require(success, ERROR_TOKEN_ALLOWANCE_REVERTED);
                  
                          return totalSupply;
                      }
                  }
                  
                  // File: contracts/common/VaultRecoverable.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  
                  
                  
                  
                  contract VaultRecoverable is IVaultRecoverable, EtherTokenConstant, IsContract {
                      using SafeERC20 for ERC20;
                  
                      string private constant ERROR_DISALLOWED = "RECOVER_DISALLOWED";
                      string private constant ERROR_VAULT_NOT_CONTRACT = "RECOVER_VAULT_NOT_CONTRACT";
                      string private constant ERROR_TOKEN_TRANSFER_FAILED = "RECOVER_TOKEN_TRANSFER_FAILED";
                  
                      /**
                       * @notice Send funds to recovery Vault. This contract should never receive funds,
                       *         but in case it does, this function allows one to recover them.
                       * @param _token Token balance to be sent to recovery vault.
                       */
                      function transferToVault(address _token) external {
                          require(allowRecoverability(_token), ERROR_DISALLOWED);
                          address vault = getRecoveryVault();
                          require(isContract(vault), ERROR_VAULT_NOT_CONTRACT);
                  
                          uint256 balance;
                          if (_token == ETH) {
                              balance = address(this).balance;
                              vault.transfer(balance);
                          } else {
                              ERC20 token = ERC20(_token);
                              balance = token.staticBalanceOf(this);
                              require(token.safeTransfer(vault, balance), ERROR_TOKEN_TRANSFER_FAILED);
                          }
                  
                          emit RecoverToVault(vault, _token, balance);
                      }
                  
                      /**
                      * @dev By default deriving from AragonApp makes it recoverable
                      * @param token Token address that would be recovered
                      * @return bool whether the app allows the recovery
                      */
                      function allowRecoverability(address token) public view returns (bool) {
                          return true;
                      }
                  
                      // Cast non-implemented interface to be public so we can use it internally
                      function getRecoveryVault() public view returns (address);
                  }
                  
                  // File: contracts/apps/AppStorage.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  
                  contract AppStorage {
                      using UnstructuredStorage for bytes32;
                  
                      /* Hardcoded constants to save gas
                      bytes32 internal constant KERNEL_POSITION = keccak256("aragonOS.appStorage.kernel");
                      bytes32 internal constant APP_ID_POSITION = keccak256("aragonOS.appStorage.appId");
                      */
                      bytes32 internal constant KERNEL_POSITION = 0x4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b;
                      bytes32 internal constant APP_ID_POSITION = 0xd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b;
                  
                      function kernel() public view returns (IKernel) {
                          return IKernel(KERNEL_POSITION.getStorageAddress());
                      }
                  
                      function appId() public view returns (bytes32) {
                          return APP_ID_POSITION.getStorageBytes32();
                      }
                  
                      function setKernel(IKernel _kernel) internal {
                          KERNEL_POSITION.setStorageAddress(address(_kernel));
                      }
                  
                      function setAppId(bytes32 _appId) internal {
                          APP_ID_POSITION.setStorageBytes32(_appId);
                      }
                  }
                  
                  // File: contracts/lib/misc/ERCProxy.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  contract ERCProxy {
                      uint256 internal constant FORWARDING = 1;
                      uint256 internal constant UPGRADEABLE = 2;
                  
                      function proxyType() public pure returns (uint256 proxyTypeId);
                      function implementation() public view returns (address codeAddr);
                  }
                  
                  // File: contracts/common/DelegateProxy.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  
                  
                  contract DelegateProxy is ERCProxy, IsContract {
                      uint256 internal constant FWD_GAS_LIMIT = 10000;
                  
                      /**
                      * @dev Performs a delegatecall and returns whatever the delegatecall returned (entire context execution will return!)
                      * @param _dst Destination address to perform the delegatecall
                      * @param _calldata Calldata for the delegatecall
                      */
                      function delegatedFwd(address _dst, bytes _calldata) internal {
                          require(isContract(_dst));
                          uint256 fwdGasLimit = FWD_GAS_LIMIT;
                  
                          assembly {
                              let result := delegatecall(sub(gas, fwdGasLimit), _dst, add(_calldata, 0x20), mload(_calldata), 0, 0)
                              let size := returndatasize
                              let ptr := mload(0x40)
                              returndatacopy(ptr, 0, size)
                  
                              // revert instead of invalid() bc if the underlying call failed with invalid() it already wasted gas.
                              // if the call returned error data, forward it
                              switch result case 0 { revert(ptr, size) }
                              default { return(ptr, size) }
                          }
                      }
                  }
                  
                  // File: contracts/common/DepositableStorage.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  
                  contract DepositableStorage {
                      using UnstructuredStorage for bytes32;
                  
                      // keccak256("aragonOS.depositableStorage.depositable")
                      bytes32 internal constant DEPOSITABLE_POSITION = 0x665fd576fbbe6f247aff98f5c94a561e3f71ec2d3c988d56f12d342396c50cea;
                  
                      function isDepositable() public view returns (bool) {
                          return DEPOSITABLE_POSITION.getStorageBool();
                      }
                  
                      function setDepositable(bool _depositable) internal {
                          DEPOSITABLE_POSITION.setStorageBool(_depositable);
                      }
                  }
                  
                  // File: contracts/common/DepositableDelegateProxy.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  
                  
                  contract DepositableDelegateProxy is DepositableStorage, DelegateProxy {
                      event ProxyDeposit(address sender, uint256 value);
                  
                      function () external payable {
                          uint256 forwardGasThreshold = FWD_GAS_LIMIT;
                          bytes32 isDepositablePosition = DEPOSITABLE_POSITION;
                  
                          // Optimized assembly implementation to prevent EIP-1884 from breaking deposits, reference code in Solidity:
                          // https://github.com/aragon/aragonOS/blob/v4.2.1/contracts/common/DepositableDelegateProxy.sol#L10-L20
                          assembly {
                              // Continue only if the gas left is lower than the threshold for forwarding to the implementation code,
                              // otherwise continue outside of the assembly block.
                              if lt(gas, forwardGasThreshold) {
                                  // Only accept the deposit and emit an event if all of the following are true:
                                  // the proxy accepts deposits (isDepositable), msg.data.length == 0, and msg.value > 0
                                  if and(and(sload(isDepositablePosition), iszero(calldatasize)), gt(callvalue, 0)) {
                                      // Equivalent Solidity code for emitting the event:
                                      // emit ProxyDeposit(msg.sender, msg.value);
                  
                                      let logData := mload(0x40) // free memory pointer
                                      mstore(logData, caller) // add 'msg.sender' to the log data (first event param)
                                      mstore(add(logData, 0x20), callvalue) // add 'msg.value' to the log data (second event param)
                  
                                      // Emit an event with one topic to identify the event: keccak256('ProxyDeposit(address,uint256)') = 0x15ee...dee1
                                      log1(logData, 0x40, 0x15eeaa57c7bd188c1388020bcadc2c436ec60d647d36ef5b9eb3c742217ddee1)
                  
                                      stop() // Stop. Exits execution context
                                  }
                  
                                  // If any of above checks failed, revert the execution (if ETH was sent, it is returned to the sender)
                                  revert(0, 0)
                              }
                          }
                  
                          address target = implementation();
                          delegatedFwd(target, msg.data);
                      }
                  }
                  
                  // File: contracts/apps/AppProxyBase.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  
                  
                  
                  
                  contract AppProxyBase is AppStorage, DepositableDelegateProxy, KernelNamespaceConstants {
                      /**
                      * @dev Initialize AppProxy
                      * @param _kernel Reference to organization kernel for the app
                      * @param _appId Identifier for app
                      * @param _initializePayload Payload for call to be made after setup to initialize
                      */
                      constructor(IKernel _kernel, bytes32 _appId, bytes _initializePayload) public {
                          setKernel(_kernel);
                          setAppId(_appId);
                  
                          // Implicit check that kernel is actually a Kernel
                          // The EVM doesn't actually provide a way for us to make sure, but we can force a revert to
                          // occur if the kernel is set to 0x0 or a non-code address when we try to call a method on
                          // it.
                          address appCode = getAppBase(_appId);
                  
                          // If initialize payload is provided, it will be executed
                          if (_initializePayload.length > 0) {
                              require(isContract(appCode));
                              // Cannot make delegatecall as a delegateproxy.delegatedFwd as it
                              // returns ending execution context and halts contract deployment
                              require(appCode.delegatecall(_initializePayload));
                          }
                      }
                  
                      function getAppBase(bytes32 _appId) internal view returns (address) {
                          return kernel().getApp(KERNEL_APP_BASES_NAMESPACE, _appId);
                      }
                  }
                  
                  // File: contracts/apps/AppProxyUpgradeable.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  
                  contract AppProxyUpgradeable is AppProxyBase {
                      /**
                      * @dev Initialize AppProxyUpgradeable (makes it an upgradeable Aragon app)
                      * @param _kernel Reference to organization kernel for the app
                      * @param _appId Identifier for app
                      * @param _initializePayload Payload for call to be made after setup to initialize
                      */
                      constructor(IKernel _kernel, bytes32 _appId, bytes _initializePayload)
                          AppProxyBase(_kernel, _appId, _initializePayload)
                          public // solium-disable-line visibility-first
                      {
                          // solium-disable-previous-line no-empty-blocks
                      }
                  
                      /**
                       * @dev ERC897, the address the proxy would delegate calls to
                       */
                      function implementation() public view returns (address) {
                          return getAppBase(appId());
                      }
                  
                      /**
                       * @dev ERC897, whether it is a forwarding (1) or an upgradeable (2) proxy
                       */
                      function proxyType() public pure returns (uint256 proxyTypeId) {
                          return UPGRADEABLE;
                      }
                  }
                  
                  // File: contracts/apps/AppProxyPinned.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  
                  
                  
                  contract AppProxyPinned is IsContract, AppProxyBase {
                      using UnstructuredStorage for bytes32;
                  
                      // keccak256("aragonOS.appStorage.pinnedCode")
                      bytes32 internal constant PINNED_CODE_POSITION = 0xdee64df20d65e53d7f51cb6ab6d921a0a6a638a91e942e1d8d02df28e31c038e;
                  
                      /**
                      * @dev Initialize AppProxyPinned (makes it an un-upgradeable Aragon app)
                      * @param _kernel Reference to organization kernel for the app
                      * @param _appId Identifier for app
                      * @param _initializePayload Payload for call to be made after setup to initialize
                      */
                      constructor(IKernel _kernel, bytes32 _appId, bytes _initializePayload)
                          AppProxyBase(_kernel, _appId, _initializePayload)
                          public // solium-disable-line visibility-first
                      {
                          setPinnedCode(getAppBase(_appId));
                          require(isContract(pinnedCode()));
                      }
                  
                      /**
                       * @dev ERC897, the address the proxy would delegate calls to
                       */
                      function implementation() public view returns (address) {
                          return pinnedCode();
                      }
                  
                      /**
                       * @dev ERC897, whether it is a forwarding (1) or an upgradeable (2) proxy
                       */
                      function proxyType() public pure returns (uint256 proxyTypeId) {
                          return FORWARDING;
                      }
                  
                      function setPinnedCode(address _pinnedCode) internal {
                          PINNED_CODE_POSITION.setStorageAddress(_pinnedCode);
                      }
                  
                      function pinnedCode() internal view returns (address) {
                          return PINNED_CODE_POSITION.getStorageAddress();
                      }
                  }
                  
                  // File: contracts/factory/AppProxyFactory.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  
                  
                  contract AppProxyFactory {
                      event NewAppProxy(address proxy, bool isUpgradeable, bytes32 appId);
                  
                      /**
                      * @notice Create a new upgradeable app instance on `_kernel` with identifier `_appId`
                      * @param _kernel App's Kernel reference
                      * @param _appId Identifier for app
                      * @return AppProxyUpgradeable
                      */
                      function newAppProxy(IKernel _kernel, bytes32 _appId) public returns (AppProxyUpgradeable) {
                          return newAppProxy(_kernel, _appId, new bytes(0));
                      }
                  
                      /**
                      * @notice Create a new upgradeable app instance on `_kernel` with identifier `_appId` and initialization payload `_initializePayload`
                      * @param _kernel App's Kernel reference
                      * @param _appId Identifier for app
                      * @return AppProxyUpgradeable
                      */
                      function newAppProxy(IKernel _kernel, bytes32 _appId, bytes _initializePayload) public returns (AppProxyUpgradeable) {
                          AppProxyUpgradeable proxy = new AppProxyUpgradeable(_kernel, _appId, _initializePayload);
                          emit NewAppProxy(address(proxy), true, _appId);
                          return proxy;
                      }
                  
                      /**
                      * @notice Create a new pinned app instance on `_kernel` with identifier `_appId`
                      * @param _kernel App's Kernel reference
                      * @param _appId Identifier for app
                      * @return AppProxyPinned
                      */
                      function newAppProxyPinned(IKernel _kernel, bytes32 _appId) public returns (AppProxyPinned) {
                          return newAppProxyPinned(_kernel, _appId, new bytes(0));
                      }
                  
                      /**
                      * @notice Create a new pinned app instance on `_kernel` with identifier `_appId` and initialization payload `_initializePayload`
                      * @param _kernel App's Kernel reference
                      * @param _appId Identifier for app
                      * @param _initializePayload Proxy initialization payload
                      * @return AppProxyPinned
                      */
                      function newAppProxyPinned(IKernel _kernel, bytes32 _appId, bytes _initializePayload) public returns (AppProxyPinned) {
                          AppProxyPinned proxy = new AppProxyPinned(_kernel, _appId, _initializePayload);
                          emit NewAppProxy(address(proxy), false, _appId);
                          return proxy;
                      }
                  }
                  
                  // File: contracts/kernel/Kernel.sol
                  
                  pragma solidity 0.4.24;
                  
                  
                  
                  
                  
                  
                  
                  
                  
                  
                  
                  
                  
                  // solium-disable-next-line max-len
                  contract Kernel is IKernel, KernelStorage, KernelAppIds, KernelNamespaceConstants, Petrifiable, IsContract, VaultRecoverable, AppProxyFactory, ACLSyntaxSugar {
                      /* Hardcoded constants to save gas
                      bytes32 public constant APP_MANAGER_ROLE = keccak256("APP_MANAGER_ROLE");
                      */
                      bytes32 public constant APP_MANAGER_ROLE = 0xb6d92708f3d4817afc106147d969e229ced5c46e65e0a5002a0d391287762bd0;
                  
                      string private constant ERROR_APP_NOT_CONTRACT = "KERNEL_APP_NOT_CONTRACT";
                      string private constant ERROR_INVALID_APP_CHANGE = "KERNEL_INVALID_APP_CHANGE";
                      string private constant ERROR_AUTH_FAILED = "KERNEL_AUTH_FAILED";
                  
                      /**
                      * @dev Constructor that allows the deployer to choose if the base instance should be petrified immediately.
                      * @param _shouldPetrify Immediately petrify this instance so that it can never be initialized
                      */
                      constructor(bool _shouldPetrify) public {
                          if (_shouldPetrify) {
                              petrify();
                          }
                      }
                  
                      /**
                      * @dev Initialize can only be called once. It saves the block number in which it was initialized.
                      * @notice Initialize this kernel instance along with its ACL and set `_permissionsCreator` as the entity that can create other permissions
                      * @param _baseAcl Address of base ACL app
                      * @param _permissionsCreator Entity that will be given permission over createPermission
                      */
                      function initialize(IACL _baseAcl, address _permissionsCreator) public onlyInit {
                          initialized();
                  
                          // Set ACL base
                          _setApp(KERNEL_APP_BASES_NAMESPACE, KERNEL_DEFAULT_ACL_APP_ID, _baseAcl);
                  
                          // Create ACL instance and attach it as the default ACL app
                          IACL acl = IACL(newAppProxy(this, KERNEL_DEFAULT_ACL_APP_ID));
                          acl.initialize(_permissionsCreator);
                          _setApp(KERNEL_APP_ADDR_NAMESPACE, KERNEL_DEFAULT_ACL_APP_ID, acl);
                  
                          recoveryVaultAppId = KERNEL_DEFAULT_VAULT_APP_ID;
                      }
                  
                      /**
                      * @dev Create a new instance of an app linked to this kernel
                      * @notice Create a new upgradeable instance of `_appId` app linked to the Kernel, setting its code to `_appBase`
                      * @param _appId Identifier for app
                      * @param _appBase Address of the app's base implementation
                      * @return AppProxy instance
                      */
                      function newAppInstance(bytes32 _appId, address _appBase)
                          public
                          auth(APP_MANAGER_ROLE, arr(KERNEL_APP_BASES_NAMESPACE, _appId))
                          returns (ERCProxy appProxy)
                      {
                          return newAppInstance(_appId, _appBase, new bytes(0), false);
                      }
                  
                      /**
                      * @dev Create a new instance of an app linked to this kernel and set its base
                      *      implementation if it was not already set
                      * @notice Create a new upgradeable instance of `_appId` app linked to the Kernel, setting its code to `_appBase`. `_setDefault ? 'Also sets it as the default app instance.':''`
                      * @param _appId Identifier for app
                      * @param _appBase Address of the app's base implementation
                      * @param _initializePayload Payload for call made by the proxy during its construction to initialize
                      * @param _setDefault Whether the app proxy app is the default one.
                      *        Useful when the Kernel needs to know of an instance of a particular app,
                      *        like Vault for escape hatch mechanism.
                      * @return AppProxy instance
                      */
                      function newAppInstance(bytes32 _appId, address _appBase, bytes _initializePayload, bool _setDefault)
                          public
                          auth(APP_MANAGER_ROLE, arr(KERNEL_APP_BASES_NAMESPACE, _appId))
                          returns (ERCProxy appProxy)
                      {
                          _setAppIfNew(KERNEL_APP_BASES_NAMESPACE, _appId, _appBase);
                          appProxy = newAppProxy(this, _appId, _initializePayload);
                          // By calling setApp directly and not the internal functions, we make sure the params are checked
                          // and it will only succeed if sender has permissions to set something to the namespace.
                          if (_setDefault) {
                              setApp(KERNEL_APP_ADDR_NAMESPACE, _appId, appProxy);
                          }
                      }
                  
                      /**
                      * @dev Create a new pinned instance of an app linked to this kernel
                      * @notice Create a new non-upgradeable instance of `_appId` app linked to the Kernel, setting its code to `_appBase`.
                      * @param _appId Identifier for app
                      * @param _appBase Address of the app's base implementation
                      * @return AppProxy instance
                      */
                      function newPinnedAppInstance(bytes32 _appId, address _appBase)
                          public
                          auth(APP_MANAGER_ROLE, arr(KERNEL_APP_BASES_NAMESPACE, _appId))
                          returns (ERCProxy appProxy)
                      {
                          return newPinnedAppInstance(_appId, _appBase, new bytes(0), false);
                      }
                  
                      /**
                      * @dev Create a new pinned instance of an app linked to this kernel and set
                      *      its base implementation if it was not already set
                      * @notice Create a new non-upgradeable instance of `_appId` app linked to the Kernel, setting its code to `_appBase`. `_setDefault ? 'Also sets it as the default app instance.':''`
                      * @param _appId Identifier for app
                      * @param _appBase Address of the app's base implementation
                      * @param _initializePayload Payload for call made by the proxy during its construction to initialize
                      * @param _setDefault Whether the app proxy app is the default one.
                      *        Useful when the Kernel needs to know of an instance of a particular app,
                      *        like Vault for escape hatch mechanism.
                      * @return AppProxy instance
                      */
                      function newPinnedAppInstance(bytes32 _appId, address _appBase, bytes _initializePayload, bool _setDefault)
                          public
                          auth(APP_MANAGER_ROLE, arr(KERNEL_APP_BASES_NAMESPACE, _appId))
                          returns (ERCProxy appProxy)
                      {
                          _setAppIfNew(KERNEL_APP_BASES_NAMESPACE, _appId, _appBase);
                          appProxy = newAppProxyPinned(this, _appId, _initializePayload);
                          // By calling setApp directly and not the internal functions, we make sure the params are checked
                          // and it will only succeed if sender has permissions to set something to the namespace.
                          if (_setDefault) {
                              setApp(KERNEL_APP_ADDR_NAMESPACE, _appId, appProxy);
                          }
                      }
                  
                      /**
                      * @dev Set the resolving address of an app instance or base implementation
                      * @notice Set the resolving address of `_appId` in namespace `_namespace` to `_app`
                      * @param _namespace App namespace to use
                      * @param _appId Identifier for app
                      * @param _app Address of the app instance or base implementation
                      * @return ID of app
                      */
                      function setApp(bytes32 _namespace, bytes32 _appId, address _app)
                          public
                          auth(APP_MANAGER_ROLE, arr(_namespace, _appId))
                      {
                          _setApp(_namespace, _appId, _app);
                      }
                  
                      /**
                      * @dev Set the default vault id for the escape hatch mechanism
                      * @param _recoveryVaultAppId Identifier of the recovery vault app
                      */
                      function setRecoveryVaultAppId(bytes32 _recoveryVaultAppId)
                          public
                          auth(APP_MANAGER_ROLE, arr(KERNEL_APP_ADDR_NAMESPACE, _recoveryVaultAppId))
                      {
                          recoveryVaultAppId = _recoveryVaultAppId;
                      }
                  
                      // External access to default app id and namespace constants to mimic default getters for constants
                      /* solium-disable function-order, mixedcase */
                      function CORE_NAMESPACE() external pure returns (bytes32) { return KERNEL_CORE_NAMESPACE; }
                      function APP_BASES_NAMESPACE() external pure returns (bytes32) { return KERNEL_APP_BASES_NAMESPACE; }
                      function APP_ADDR_NAMESPACE() external pure returns (bytes32) { return KERNEL_APP_ADDR_NAMESPACE; }
                      function KERNEL_APP_ID() external pure returns (bytes32) { return KERNEL_CORE_APP_ID; }
                      function DEFAULT_ACL_APP_ID() external pure returns (bytes32) { return KERNEL_DEFAULT_ACL_APP_ID; }
                      /* solium-enable function-order, mixedcase */
                  
                      /**
                      * @dev Get the address of an app instance or base implementation
                      * @param _namespace App namespace to use
                      * @param _appId Identifier for app
                      * @return Address of the app
                      */
                      function getApp(bytes32 _namespace, bytes32 _appId) public view returns (address) {
                          return apps[_namespace][_appId];
                      }
                  
                      /**
                      * @dev Get the address of the recovery Vault instance (to recover funds)
                      * @return Address of the Vault
                      */
                      function getRecoveryVault() public view returns (address) {
                          return apps[KERNEL_APP_ADDR_NAMESPACE][recoveryVaultAppId];
                      }
                  
                      /**
                      * @dev Get the installed ACL app
                      * @return ACL app
                      */
                      function acl() public view returns (IACL) {
                          return IACL(getApp(KERNEL_APP_ADDR_NAMESPACE, KERNEL_DEFAULT_ACL_APP_ID));
                      }
                  
                      /**
                      * @dev Function called by apps to check ACL on kernel or to check permission status
                      * @param _who Sender of the original call
                      * @param _where Address of the app
                      * @param _what Identifier for a group of actions in app
                      * @param _how Extra data for ACL auth
                      * @return Boolean indicating whether the ACL allows the role or not.
                      *         Always returns false if the kernel hasn't been initialized yet.
                      */
                      function hasPermission(address _who, address _where, bytes32 _what, bytes _how) public view returns (bool) {
                          IACL defaultAcl = acl();
                          return address(defaultAcl) != address(0) && // Poor man's initialization check (saves gas)
                              defaultAcl.hasPermission(_who, _where, _what, _how);
                      }
                  
                      function _setApp(bytes32 _namespace, bytes32 _appId, address _app) internal {
                          require(isContract(_app), ERROR_APP_NOT_CONTRACT);
                          apps[_namespace][_appId] = _app;
                          emit SetApp(_namespace, _appId, _app);
                      }
                  
                      function _setAppIfNew(bytes32 _namespace, bytes32 _appId, address _app) internal {
                          address app = getApp(_namespace, _appId);
                          if (app != address(0)) {
                              // The only way to set an app is if it passes the isContract check, so no need to check it again
                              require(app == _app, ERROR_INVALID_APP_CHANGE);
                          } else {
                              _setApp(_namespace, _appId, _app);
                          }
                      }
                  
                      modifier auth(bytes32 _role, uint256[] memory _params) {
                          require(
                              hasPermission(msg.sender, address(this), _role, ConversionHelpers.dangerouslyCastUintArrayToBytes(_params)),
                              ERROR_AUTH_FAILED
                          );
                          _;
                      }
                  }

                  File 12 of 14: TokenManager
                  // File: @aragon/os/contracts/common/UnstructuredStorage.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  library UnstructuredStorage {
                      function getStorageBool(bytes32 position) internal view returns (bool data) {
                          assembly { data := sload(position) }
                      }
                  
                      function getStorageAddress(bytes32 position) internal view returns (address data) {
                          assembly { data := sload(position) }
                      }
                  
                      function getStorageBytes32(bytes32 position) internal view returns (bytes32 data) {
                          assembly { data := sload(position) }
                      }
                  
                      function getStorageUint256(bytes32 position) internal view returns (uint256 data) {
                          assembly { data := sload(position) }
                      }
                  
                      function setStorageBool(bytes32 position, bool data) internal {
                          assembly { sstore(position, data) }
                      }
                  
                      function setStorageAddress(bytes32 position, address data) internal {
                          assembly { sstore(position, data) }
                      }
                  
                      function setStorageBytes32(bytes32 position, bytes32 data) internal {
                          assembly { sstore(position, data) }
                      }
                  
                      function setStorageUint256(bytes32 position, uint256 data) internal {
                          assembly { sstore(position, data) }
                      }
                  }
                  
                  // File: @aragon/os/contracts/acl/IACL.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  interface IACL {
                      function initialize(address permissionsCreator) external;
                  
                      // TODO: this should be external
                      // See https://github.com/ethereum/solidity/issues/4832
                      function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                  }
                  
                  // File: @aragon/os/contracts/common/IVaultRecoverable.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  interface IVaultRecoverable {
                      event RecoverToVault(address indexed vault, address indexed token, uint256 amount);
                  
                      function transferToVault(address token) external;
                  
                      function allowRecoverability(address token) external view returns (bool);
                      function getRecoveryVault() external view returns (address);
                  }
                  
                  // File: @aragon/os/contracts/kernel/IKernel.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  
                  interface IKernelEvents {
                      event SetApp(bytes32 indexed namespace, bytes32 indexed appId, address app);
                  }
                  
                  
                  // This should be an interface, but interfaces can't inherit yet :(
                  contract IKernel is IKernelEvents, IVaultRecoverable {
                      function acl() public view returns (IACL);
                      function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                  
                      function setApp(bytes32 namespace, bytes32 appId, address app) public;
                      function getApp(bytes32 namespace, bytes32 appId) public view returns (address);
                  }
                  
                  // File: @aragon/os/contracts/apps/AppStorage.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  
                  contract AppStorage {
                      using UnstructuredStorage for bytes32;
                  
                      /* Hardcoded constants to save gas
                      bytes32 internal constant KERNEL_POSITION = keccak256("aragonOS.appStorage.kernel");
                      bytes32 internal constant APP_ID_POSITION = keccak256("aragonOS.appStorage.appId");
                      */
                      bytes32 internal constant KERNEL_POSITION = 0x4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b;
                      bytes32 internal constant APP_ID_POSITION = 0xd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b;
                  
                      function kernel() public view returns (IKernel) {
                          return IKernel(KERNEL_POSITION.getStorageAddress());
                      }
                  
                      function appId() public view returns (bytes32) {
                          return APP_ID_POSITION.getStorageBytes32();
                      }
                  
                      function setKernel(IKernel _kernel) internal {
                          KERNEL_POSITION.setStorageAddress(address(_kernel));
                      }
                  
                      function setAppId(bytes32 _appId) internal {
                          APP_ID_POSITION.setStorageBytes32(_appId);
                      }
                  }
                  
                  // File: @aragon/os/contracts/acl/ACLSyntaxSugar.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  contract ACLSyntaxSugar {
                      function arr() internal pure returns (uint256[]) {
                          return new uint256[](0);
                      }
                  
                      function arr(bytes32 _a) internal pure returns (uint256[] r) {
                          return arr(uint256(_a));
                      }
                  
                      function arr(bytes32 _a, bytes32 _b) internal pure returns (uint256[] r) {
                          return arr(uint256(_a), uint256(_b));
                      }
                  
                      function arr(address _a) internal pure returns (uint256[] r) {
                          return arr(uint256(_a));
                      }
                  
                      function arr(address _a, address _b) internal pure returns (uint256[] r) {
                          return arr(uint256(_a), uint256(_b));
                      }
                  
                      function arr(address _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) {
                          return arr(uint256(_a), _b, _c);
                      }
                  
                      function arr(address _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) {
                          return arr(uint256(_a), _b, _c, _d);
                      }
                  
                      function arr(address _a, uint256 _b) internal pure returns (uint256[] r) {
                          return arr(uint256(_a), uint256(_b));
                      }
                  
                      function arr(address _a, address _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) {
                          return arr(uint256(_a), uint256(_b), _c, _d, _e);
                      }
                  
                      function arr(address _a, address _b, address _c) internal pure returns (uint256[] r) {
                          return arr(uint256(_a), uint256(_b), uint256(_c));
                      }
                  
                      function arr(address _a, address _b, uint256 _c) internal pure returns (uint256[] r) {
                          return arr(uint256(_a), uint256(_b), uint256(_c));
                      }
                  
                      function arr(uint256 _a) internal pure returns (uint256[] r) {
                          r = new uint256[](1);
                          r[0] = _a;
                      }
                  
                      function arr(uint256 _a, uint256 _b) internal pure returns (uint256[] r) {
                          r = new uint256[](2);
                          r[0] = _a;
                          r[1] = _b;
                      }
                  
                      function arr(uint256 _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) {
                          r = new uint256[](3);
                          r[0] = _a;
                          r[1] = _b;
                          r[2] = _c;
                      }
                  
                      function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) {
                          r = new uint256[](4);
                          r[0] = _a;
                          r[1] = _b;
                          r[2] = _c;
                          r[3] = _d;
                      }
                  
                      function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) {
                          r = new uint256[](5);
                          r[0] = _a;
                          r[1] = _b;
                          r[2] = _c;
                          r[3] = _d;
                          r[4] = _e;
                      }
                  }
                  
                  
                  contract ACLHelpers {
                      function decodeParamOp(uint256 _x) internal pure returns (uint8 b) {
                          return uint8(_x >> (8 * 30));
                      }
                  
                      function decodeParamId(uint256 _x) internal pure returns (uint8 b) {
                          return uint8(_x >> (8 * 31));
                      }
                  
                      function decodeParamsList(uint256 _x) internal pure returns (uint32 a, uint32 b, uint32 c) {
                          a = uint32(_x);
                          b = uint32(_x >> (8 * 4));
                          c = uint32(_x >> (8 * 8));
                      }
                  }
                  
                  // File: @aragon/os/contracts/common/Uint256Helpers.sol
                  
                  pragma solidity ^0.4.24;
                  
                  
                  library Uint256Helpers {
                      uint256 private constant MAX_UINT64 = uint64(-1);
                  
                      string private constant ERROR_NUMBER_TOO_BIG = "UINT64_NUMBER_TOO_BIG";
                  
                      function toUint64(uint256 a) internal pure returns (uint64) {
                          require(a <= MAX_UINT64, ERROR_NUMBER_TOO_BIG);
                          return uint64(a);
                      }
                  }
                  
                  // File: @aragon/os/contracts/common/TimeHelpers.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  contract TimeHelpers {
                      using Uint256Helpers for uint256;
                  
                      /**
                      * @dev Returns the current block number.
                      *      Using a function rather than `block.number` allows us to easily mock the block number in
                      *      tests.
                      */
                      function getBlockNumber() internal view returns (uint256) {
                          return block.number;
                      }
                  
                      /**
                      * @dev Returns the current block number, converted to uint64.
                      *      Using a function rather than `block.number` allows us to easily mock the block number in
                      *      tests.
                      */
                      function getBlockNumber64() internal view returns (uint64) {
                          return getBlockNumber().toUint64();
                      }
                  
                      /**
                      * @dev Returns the current timestamp.
                      *      Using a function rather than `block.timestamp` allows us to easily mock it in
                      *      tests.
                      */
                      function getTimestamp() internal view returns (uint256) {
                          return block.timestamp; // solium-disable-line security/no-block-members
                      }
                  
                      /**
                      * @dev Returns the current timestamp, converted to uint64.
                      *      Using a function rather than `block.timestamp` allows us to easily mock it in
                      *      tests.
                      */
                      function getTimestamp64() internal view returns (uint64) {
                          return getTimestamp().toUint64();
                      }
                  }
                  
                  // File: @aragon/os/contracts/common/Initializable.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  
                  contract Initializable is TimeHelpers {
                      using UnstructuredStorage for bytes32;
                  
                      // keccak256("aragonOS.initializable.initializationBlock")
                      bytes32 internal constant INITIALIZATION_BLOCK_POSITION = 0xebb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e;
                  
                      string private constant ERROR_ALREADY_INITIALIZED = "INIT_ALREADY_INITIALIZED";
                      string private constant ERROR_NOT_INITIALIZED = "INIT_NOT_INITIALIZED";
                  
                      modifier onlyInit {
                          require(getInitializationBlock() == 0, ERROR_ALREADY_INITIALIZED);
                          _;
                      }
                  
                      modifier isInitialized {
                          require(hasInitialized(), ERROR_NOT_INITIALIZED);
                          _;
                      }
                  
                      /**
                      * @return Block number in which the contract was initialized
                      */
                      function getInitializationBlock() public view returns (uint256) {
                          return INITIALIZATION_BLOCK_POSITION.getStorageUint256();
                      }
                  
                      /**
                      * @return Whether the contract has been initialized by the time of the current block
                      */
                      function hasInitialized() public view returns (bool) {
                          uint256 initializationBlock = getInitializationBlock();
                          return initializationBlock != 0 && getBlockNumber() >= initializationBlock;
                      }
                  
                      /**
                      * @dev Function to be called by top level contract after initialization has finished.
                      */
                      function initialized() internal onlyInit {
                          INITIALIZATION_BLOCK_POSITION.setStorageUint256(getBlockNumber());
                      }
                  
                      /**
                      * @dev Function to be called by top level contract after initialization to enable the contract
                      *      at a future block number rather than immediately.
                      */
                      function initializedAt(uint256 _blockNumber) internal onlyInit {
                          INITIALIZATION_BLOCK_POSITION.setStorageUint256(_blockNumber);
                      }
                  }
                  
                  // File: @aragon/os/contracts/common/Petrifiable.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  contract Petrifiable is Initializable {
                      // Use block UINT256_MAX (which should be never) as the initializable date
                      uint256 internal constant PETRIFIED_BLOCK = uint256(-1);
                  
                      function isPetrified() public view returns (bool) {
                          return getInitializationBlock() == PETRIFIED_BLOCK;
                      }
                  
                      /**
                      * @dev Function to be called by top level contract to prevent being initialized.
                      *      Useful for freezing base contracts when they're used behind proxies.
                      */
                      function petrify() internal onlyInit {
                          initializedAt(PETRIFIED_BLOCK);
                      }
                  }
                  
                  // File: @aragon/os/contracts/common/Autopetrified.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  contract Autopetrified is Petrifiable {
                      constructor() public {
                          // Immediately petrify base (non-proxy) instances of inherited contracts on deploy.
                          // This renders them uninitializable (and unusable without a proxy).
                          petrify();
                      }
                  }
                  
                  // File: @aragon/os/contracts/common/ConversionHelpers.sol
                  
                  pragma solidity ^0.4.24;
                  
                  
                  library ConversionHelpers {
                      string private constant ERROR_IMPROPER_LENGTH = "CONVERSION_IMPROPER_LENGTH";
                  
                      function dangerouslyCastUintArrayToBytes(uint256[] memory _input) internal pure returns (bytes memory output) {
                          // Force cast the uint256[] into a bytes array, by overwriting its length
                          // Note that the bytes array doesn't need to be initialized as we immediately overwrite it
                          // with the input and a new length. The input becomes invalid from this point forward.
                          uint256 byteLength = _input.length * 32;
                          assembly {
                              output := _input
                              mstore(output, byteLength)
                          }
                      }
                  
                      function dangerouslyCastBytesToUintArray(bytes memory _input) internal pure returns (uint256[] memory output) {
                          // Force cast the bytes array into a uint256[], by overwriting its length
                          // Note that the uint256[] doesn't need to be initialized as we immediately overwrite it
                          // with the input and a new length. The input becomes invalid from this point forward.
                          uint256 intsLength = _input.length / 32;
                          require(_input.length == intsLength * 32, ERROR_IMPROPER_LENGTH);
                  
                          assembly {
                              output := _input
                              mstore(output, intsLength)
                          }
                      }
                  }
                  
                  // File: @aragon/os/contracts/common/ReentrancyGuard.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  contract ReentrancyGuard {
                      using UnstructuredStorage for bytes32;
                  
                      /* Hardcoded constants to save gas
                      bytes32 internal constant REENTRANCY_MUTEX_POSITION = keccak256("aragonOS.reentrancyGuard.mutex");
                      */
                      bytes32 private constant REENTRANCY_MUTEX_POSITION = 0xe855346402235fdd185c890e68d2c4ecad599b88587635ee285bce2fda58dacb;
                  
                      string private constant ERROR_REENTRANT = "REENTRANCY_REENTRANT_CALL";
                  
                      modifier nonReentrant() {
                          // Ensure mutex is unlocked
                          require(!REENTRANCY_MUTEX_POSITION.getStorageBool(), ERROR_REENTRANT);
                  
                          // Lock mutex before function call
                          REENTRANCY_MUTEX_POSITION.setStorageBool(true);
                  
                          // Perform function call
                          _;
                  
                          // Unlock mutex after function call
                          REENTRANCY_MUTEX_POSITION.setStorageBool(false);
                      }
                  }
                  
                  // File: @aragon/os/contracts/lib/token/ERC20.sol
                  
                  // See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/a9f910d34f0ab33a1ae5e714f69f9596a02b4d91/contracts/token/ERC20/ERC20.sol
                  
                  pragma solidity ^0.4.24;
                  
                  
                  /**
                   * @title ERC20 interface
                   * @dev see https://github.com/ethereum/EIPs/issues/20
                   */
                  contract ERC20 {
                      function totalSupply() public view returns (uint256);
                  
                      function balanceOf(address _who) public view returns (uint256);
                  
                      function allowance(address _owner, address _spender)
                          public view returns (uint256);
                  
                      function transfer(address _to, uint256 _value) public returns (bool);
                  
                      function approve(address _spender, uint256 _value)
                          public returns (bool);
                  
                      function transferFrom(address _from, address _to, uint256 _value)
                          public returns (bool);
                  
                      event Transfer(
                          address indexed from,
                          address indexed to,
                          uint256 value
                      );
                  
                      event Approval(
                          address indexed owner,
                          address indexed spender,
                          uint256 value
                      );
                  }
                  
                  // File: @aragon/os/contracts/common/EtherTokenConstant.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  // aragonOS and aragon-apps rely on address(0) to denote native ETH, in
                  // contracts where both tokens and ETH are accepted
                  contract EtherTokenConstant {
                      address internal constant ETH = address(0);
                  }
                  
                  // File: @aragon/os/contracts/common/IsContract.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  contract IsContract {
                      /*
                      * NOTE: this should NEVER be used for authentication
                      * (see pitfalls: https://github.com/fergarrui/ethereum-security/tree/master/contracts/extcodesize).
                      *
                      * This is only intended to be used as a sanity check that an address is actually a contract,
                      * RATHER THAN an address not being a contract.
                      */
                      function isContract(address _target) internal view returns (bool) {
                          if (_target == address(0)) {
                              return false;
                          }
                  
                          uint256 size;
                          assembly { size := extcodesize(_target) }
                          return size > 0;
                      }
                  }
                  
                  // File: @aragon/os/contracts/common/SafeERC20.sol
                  
                  // Inspired by AdEx (https://github.com/AdExNetwork/adex-protocol-eth/blob/b9df617829661a7518ee10f4cb6c4108659dd6d5/contracts/libs/SafeERC20.sol)
                  // and 0x (https://github.com/0xProject/0x-monorepo/blob/737d1dc54d72872e24abce5a1dbe1b66d35fa21a/contracts/protocol/contracts/protocol/AssetProxy/ERC20Proxy.sol#L143)
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  library SafeERC20 {
                      // Before 0.5, solidity has a mismatch between `address.transfer()` and `token.transfer()`:
                      // https://github.com/ethereum/solidity/issues/3544
                      bytes4 private constant TRANSFER_SELECTOR = 0xa9059cbb;
                  
                      string private constant ERROR_TOKEN_BALANCE_REVERTED = "SAFE_ERC_20_BALANCE_REVERTED";
                      string private constant ERROR_TOKEN_ALLOWANCE_REVERTED = "SAFE_ERC_20_ALLOWANCE_REVERTED";
                  
                      function invokeAndCheckSuccess(address _addr, bytes memory _calldata)
                          private
                          returns (bool)
                      {
                          bool ret;
                          assembly {
                              let ptr := mload(0x40)    // free memory pointer
                  
                              let success := call(
                                  gas,                  // forward all gas
                                  _addr,                // address
                                  0,                    // no value
                                  add(_calldata, 0x20), // calldata start
                                  mload(_calldata),     // calldata length
                                  ptr,                  // write output over free memory
                                  0x20                  // uint256 return
                              )
                  
                              if gt(success, 0) {
                                  // Check number of bytes returned from last function call
                                  switch returndatasize
                  
                                  // No bytes returned: assume success
                                  case 0 {
                                      ret := 1
                                  }
                  
                                  // 32 bytes returned: check if non-zero
                                  case 0x20 {
                                      // Only return success if returned data was true
                                      // Already have output in ptr
                                      ret := eq(mload(ptr), 1)
                                  }
                  
                                  // Not sure what was returned: don't mark as success
                                  default { }
                              }
                          }
                          return ret;
                      }
                  
                      function staticInvoke(address _addr, bytes memory _calldata)
                          private
                          view
                          returns (bool, uint256)
                      {
                          bool success;
                          uint256 ret;
                          assembly {
                              let ptr := mload(0x40)    // free memory pointer
                  
                              success := staticcall(
                                  gas,                  // forward all gas
                                  _addr,                // address
                                  add(_calldata, 0x20), // calldata start
                                  mload(_calldata),     // calldata length
                                  ptr,                  // write output over free memory
                                  0x20                  // uint256 return
                              )
                  
                              if gt(success, 0) {
                                  ret := mload(ptr)
                              }
                          }
                          return (success, ret);
                      }
                  
                      /**
                      * @dev Same as a standards-compliant ERC20.transfer() that never reverts (returns false).
                      *      Note that this makes an external call to the token.
                      */
                      function safeTransfer(ERC20 _token, address _to, uint256 _amount) internal returns (bool) {
                          bytes memory transferCallData = abi.encodeWithSelector(
                              TRANSFER_SELECTOR,
                              _to,
                              _amount
                          );
                          return invokeAndCheckSuccess(_token, transferCallData);
                      }
                  
                      /**
                      * @dev Same as a standards-compliant ERC20.transferFrom() that never reverts (returns false).
                      *      Note that this makes an external call to the token.
                      */
                      function safeTransferFrom(ERC20 _token, address _from, address _to, uint256 _amount) internal returns (bool) {
                          bytes memory transferFromCallData = abi.encodeWithSelector(
                              _token.transferFrom.selector,
                              _from,
                              _to,
                              _amount
                          );
                          return invokeAndCheckSuccess(_token, transferFromCallData);
                      }
                  
                      /**
                      * @dev Same as a standards-compliant ERC20.approve() that never reverts (returns false).
                      *      Note that this makes an external call to the token.
                      */
                      function safeApprove(ERC20 _token, address _spender, uint256 _amount) internal returns (bool) {
                          bytes memory approveCallData = abi.encodeWithSelector(
                              _token.approve.selector,
                              _spender,
                              _amount
                          );
                          return invokeAndCheckSuccess(_token, approveCallData);
                      }
                  
                      /**
                      * @dev Static call into ERC20.balanceOf().
                      * Reverts if the call fails for some reason (should never fail).
                      */
                      function staticBalanceOf(ERC20 _token, address _owner) internal view returns (uint256) {
                          bytes memory balanceOfCallData = abi.encodeWithSelector(
                              _token.balanceOf.selector,
                              _owner
                          );
                  
                          (bool success, uint256 tokenBalance) = staticInvoke(_token, balanceOfCallData);
                          require(success, ERROR_TOKEN_BALANCE_REVERTED);
                  
                          return tokenBalance;
                      }
                  
                      /**
                      * @dev Static call into ERC20.allowance().
                      * Reverts if the call fails for some reason (should never fail).
                      */
                      function staticAllowance(ERC20 _token, address _owner, address _spender) internal view returns (uint256) {
                          bytes memory allowanceCallData = abi.encodeWithSelector(
                              _token.allowance.selector,
                              _owner,
                              _spender
                          );
                  
                          (bool success, uint256 allowance) = staticInvoke(_token, allowanceCallData);
                          require(success, ERROR_TOKEN_ALLOWANCE_REVERTED);
                  
                          return allowance;
                      }
                  }
                  
                  // File: @aragon/os/contracts/common/VaultRecoverable.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  
                  
                  
                  
                  contract VaultRecoverable is IVaultRecoverable, EtherTokenConstant, IsContract {
                      using SafeERC20 for ERC20;
                  
                      string private constant ERROR_DISALLOWED = "RECOVER_DISALLOWED";
                      string private constant ERROR_VAULT_NOT_CONTRACT = "RECOVER_VAULT_NOT_CONTRACT";
                      string private constant ERROR_TOKEN_TRANSFER_FAILED = "RECOVER_TOKEN_TRANSFER_FAILED";
                  
                      /**
                       * @notice Send funds to recovery Vault. This contract should never receive funds,
                       *         but in case it does, this function allows one to recover them.
                       * @param _token Token balance to be sent to recovery vault.
                       */
                      function transferToVault(address _token) external {
                          require(allowRecoverability(_token), ERROR_DISALLOWED);
                          address vault = getRecoveryVault();
                          require(isContract(vault), ERROR_VAULT_NOT_CONTRACT);
                  
                          uint256 balance;
                          if (_token == ETH) {
                              balance = address(this).balance;
                              vault.transfer(balance);
                          } else {
                              ERC20 token = ERC20(_token);
                              balance = token.staticBalanceOf(this);
                              require(token.safeTransfer(vault, balance), ERROR_TOKEN_TRANSFER_FAILED);
                          }
                  
                          emit RecoverToVault(vault, _token, balance);
                      }
                  
                      /**
                      * @dev By default deriving from AragonApp makes it recoverable
                      * @param token Token address that would be recovered
                      * @return bool whether the app allows the recovery
                      */
                      function allowRecoverability(address token) public view returns (bool) {
                          return true;
                      }
                  
                      // Cast non-implemented interface to be public so we can use it internally
                      function getRecoveryVault() public view returns (address);
                  }
                  
                  // File: @aragon/os/contracts/evmscript/IEVMScriptExecutor.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  interface IEVMScriptExecutor {
                      function execScript(bytes script, bytes input, address[] blacklist) external returns (bytes);
                      function executorType() external pure returns (bytes32);
                  }
                  
                  // File: @aragon/os/contracts/evmscript/IEVMScriptRegistry.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  contract EVMScriptRegistryConstants {
                      /* Hardcoded constants to save gas
                      bytes32 internal constant EVMSCRIPT_REGISTRY_APP_ID = apmNamehash("evmreg");
                      */
                      bytes32 internal constant EVMSCRIPT_REGISTRY_APP_ID = 0xddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd61;
                  }
                  
                  
                  interface IEVMScriptRegistry {
                      function addScriptExecutor(IEVMScriptExecutor executor) external returns (uint id);
                      function disableScriptExecutor(uint256 executorId) external;
                  
                      // TODO: this should be external
                      // See https://github.com/ethereum/solidity/issues/4832
                      function getScriptExecutor(bytes script) public view returns (IEVMScriptExecutor);
                  }
                  
                  // File: @aragon/os/contracts/kernel/KernelConstants.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  contract KernelAppIds {
                      /* Hardcoded constants to save gas
                      bytes32 internal constant KERNEL_CORE_APP_ID = apmNamehash("kernel");
                      bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = apmNamehash("acl");
                      bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = apmNamehash("vault");
                      */
                      bytes32 internal constant KERNEL_CORE_APP_ID = 0x3b4bf6bf3ad5000ecf0f989d5befde585c6860fea3e574a4fab4c49d1c177d9c;
                      bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = 0xe3262375f45a6e2026b7e7b18c2b807434f2508fe1a2a3dfb493c7df8f4aad6a;
                      bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = 0x7e852e0fcfce6551c13800f1e7476f982525c2b5277ba14b24339c68416336d1;
                  }
                  
                  
                  contract KernelNamespaceConstants {
                      /* Hardcoded constants to save gas
                      bytes32 internal constant KERNEL_CORE_NAMESPACE = keccak256("core");
                      bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = keccak256("base");
                      bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = keccak256("app");
                      */
                      bytes32 internal constant KERNEL_CORE_NAMESPACE = 0xc681a85306374a5ab27f0bbc385296a54bcd314a1948b6cf61c4ea1bc44bb9f8;
                      bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = 0xf1f3eb40f5bc1ad1344716ced8b8a0431d840b5783aea1fd01786bc26f35ac0f;
                      bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
                  }
                  
                  // File: @aragon/os/contracts/evmscript/EVMScriptRunner.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  
                  
                  
                  
                  contract EVMScriptRunner is AppStorage, Initializable, EVMScriptRegistryConstants, KernelNamespaceConstants {
                      string private constant ERROR_EXECUTOR_UNAVAILABLE = "EVMRUN_EXECUTOR_UNAVAILABLE";
                      string private constant ERROR_PROTECTED_STATE_MODIFIED = "EVMRUN_PROTECTED_STATE_MODIFIED";
                  
                      /* This is manually crafted in assembly
                      string private constant ERROR_EXECUTOR_INVALID_RETURN = "EVMRUN_EXECUTOR_INVALID_RETURN";
                      */
                  
                      event ScriptResult(address indexed executor, bytes script, bytes input, bytes returnData);
                  
                      function getEVMScriptExecutor(bytes _script) public view returns (IEVMScriptExecutor) {
                          return IEVMScriptExecutor(getEVMScriptRegistry().getScriptExecutor(_script));
                      }
                  
                      function getEVMScriptRegistry() public view returns (IEVMScriptRegistry) {
                          address registryAddr = kernel().getApp(KERNEL_APP_ADDR_NAMESPACE, EVMSCRIPT_REGISTRY_APP_ID);
                          return IEVMScriptRegistry(registryAddr);
                      }
                  
                      function runScript(bytes _script, bytes _input, address[] _blacklist)
                          internal
                          isInitialized
                          protectState
                          returns (bytes)
                      {
                          IEVMScriptExecutor executor = getEVMScriptExecutor(_script);
                          require(address(executor) != address(0), ERROR_EXECUTOR_UNAVAILABLE);
                  
                          bytes4 sig = executor.execScript.selector;
                          bytes memory data = abi.encodeWithSelector(sig, _script, _input, _blacklist);
                  
                          bytes memory output;
                          assembly {
                              let success := delegatecall(
                                  gas,                // forward all gas
                                  executor,           // address
                                  add(data, 0x20),    // calldata start
                                  mload(data),        // calldata length
                                  0,                  // don't write output (we'll handle this ourselves)
                                  0                   // don't write output
                              )
                  
                              output := mload(0x40) // free mem ptr get
                  
                              switch success
                              case 0 {
                                  // If the call errored, forward its full error data
                                  returndatacopy(output, 0, returndatasize)
                                  revert(output, returndatasize)
                              }
                              default {
                                  switch gt(returndatasize, 0x3f)
                                  case 0 {
                                      // Need at least 0x40 bytes returned for properly ABI-encoded bytes values,
                                      // revert with "EVMRUN_EXECUTOR_INVALID_RETURN"
                                      // See remix: doing a `revert("EVMRUN_EXECUTOR_INVALID_RETURN")` always results in
                                      // this memory layout
                                      mstore(output, 0x08c379a000000000000000000000000000000000000000000000000000000000)         // error identifier
                                      mstore(add(output, 0x04), 0x0000000000000000000000000000000000000000000000000000000000000020) // starting offset
                                      mstore(add(output, 0x24), 0x000000000000000000000000000000000000000000000000000000000000001e) // reason length
                                      mstore(add(output, 0x44), 0x45564d52554e5f4558454355544f525f494e56414c49445f52455455524e0000) // reason
                  
                                      revert(output, 100) // 100 = 4 + 3 * 32 (error identifier + 3 words for the ABI encoded error)
                                  }
                                  default {
                                      // Copy result
                                      //
                                      // Needs to perform an ABI decode for the expected `bytes` return type of
                                      // `executor.execScript()` as solidity will automatically ABI encode the returned bytes as:
                                      //    [ position of the first dynamic length return value = 0x20 (32 bytes) ]
                                      //    [ output length (32 bytes) ]
                                      //    [ output content (N bytes) ]
                                      //
                                      // Perform the ABI decode by ignoring the first 32 bytes of the return data
                                      let copysize := sub(returndatasize, 0x20)
                                      returndatacopy(output, 0x20, copysize)
                  
                                      mstore(0x40, add(output, copysize)) // free mem ptr set
                                  }
                              }
                          }
                  
                          emit ScriptResult(address(executor), _script, _input, output);
                  
                          return output;
                      }
                  
                      modifier protectState {
                          address preKernel = address(kernel());
                          bytes32 preAppId = appId();
                          _; // exec
                          require(address(kernel()) == preKernel, ERROR_PROTECTED_STATE_MODIFIED);
                          require(appId() == preAppId, ERROR_PROTECTED_STATE_MODIFIED);
                      }
                  }
                  
                  // File: @aragon/os/contracts/apps/AragonApp.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  
                  
                  
                  
                  
                  
                  
                  // Contracts inheriting from AragonApp are, by default, immediately petrified upon deployment so
                  // that they can never be initialized.
                  // Unless overriden, this behaviour enforces those contracts to be usable only behind an AppProxy.
                  // ReentrancyGuard, EVMScriptRunner, and ACLSyntaxSugar are not directly used by this contract, but
                  // are included so that they are automatically usable by subclassing contracts
                  contract AragonApp is AppStorage, Autopetrified, VaultRecoverable, ReentrancyGuard, EVMScriptRunner, ACLSyntaxSugar {
                      string private constant ERROR_AUTH_FAILED = "APP_AUTH_FAILED";
                  
                      modifier auth(bytes32 _role) {
                          require(canPerform(msg.sender, _role, new uint256[](0)), ERROR_AUTH_FAILED);
                          _;
                      }
                  
                      modifier authP(bytes32 _role, uint256[] _params) {
                          require(canPerform(msg.sender, _role, _params), ERROR_AUTH_FAILED);
                          _;
                      }
                  
                      /**
                      * @dev Check whether an action can be performed by a sender for a particular role on this app
                      * @param _sender Sender of the call
                      * @param _role Role on this app
                      * @param _params Permission params for the role
                      * @return Boolean indicating whether the sender has the permissions to perform the action.
                      *         Always returns false if the app hasn't been initialized yet.
                      */
                      function canPerform(address _sender, bytes32 _role, uint256[] _params) public view returns (bool) {
                          if (!hasInitialized()) {
                              return false;
                          }
                  
                          IKernel linkedKernel = kernel();
                          if (address(linkedKernel) == address(0)) {
                              return false;
                          }
                  
                          return linkedKernel.hasPermission(
                              _sender,
                              address(this),
                              _role,
                              ConversionHelpers.dangerouslyCastUintArrayToBytes(_params)
                          );
                      }
                  
                      /**
                      * @dev Get the recovery vault for the app
                      * @return Recovery vault address for the app
                      */
                      function getRecoveryVault() public view returns (address) {
                          // Funds recovery via a vault is only available when used with a kernel
                          return kernel().getRecoveryVault(); // if kernel is not set, it will revert
                      }
                  }
                  
                  // File: @aragon/os/contracts/common/IForwarder.sol
                  
                  /*
                   * SPDX-License-Identitifer:    MIT
                   */
                  
                  pragma solidity ^0.4.24;
                  
                  
                  interface IForwarder {
                      function isForwarder() external pure returns (bool);
                  
                      // TODO: this should be external
                      // See https://github.com/ethereum/solidity/issues/4832
                      function canForward(address sender, bytes evmCallScript) public view returns (bool);
                  
                      // TODO: this should be external
                      // See https://github.com/ethereum/solidity/issues/4832
                      function forward(bytes evmCallScript) public;
                  }
                  
                  // File: @aragon/os/contracts/lib/math/SafeMath.sol
                  
                  // See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/d51e38758e1d985661534534d5c61e27bece5042/contracts/math/SafeMath.sol
                  // Adapted to use pragma ^0.4.24 and satisfy our linter rules
                  
                  pragma solidity ^0.4.24;
                  
                  
                  /**
                   * @title SafeMath
                   * @dev Math operations with safety checks that revert on error
                   */
                  library SafeMath {
                      string private constant ERROR_ADD_OVERFLOW = "MATH_ADD_OVERFLOW";
                      string private constant ERROR_SUB_UNDERFLOW = "MATH_SUB_UNDERFLOW";
                      string private constant ERROR_MUL_OVERFLOW = "MATH_MUL_OVERFLOW";
                      string private constant ERROR_DIV_ZERO = "MATH_DIV_ZERO";
                  
                      /**
                      * @dev Multiplies two numbers, reverts on 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-solidity/pull/522
                          if (_a == 0) {
                              return 0;
                          }
                  
                          uint256 c = _a * _b;
                          require(c / _a == _b, ERROR_MUL_OVERFLOW);
                  
                          return c;
                      }
                  
                      /**
                      * @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
                      */
                      function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
                          require(_b > 0, ERROR_DIV_ZERO); // Solidity only automatically asserts when dividing by 0
                          uint256 c = _a / _b;
                          // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
                  
                          return c;
                      }
                  
                      /**
                      * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                      */
                      function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
                          require(_b <= _a, ERROR_SUB_UNDERFLOW);
                          uint256 c = _a - _b;
                  
                          return c;
                      }
                  
                      /**
                      * @dev Adds two numbers, reverts on overflow.
                      */
                      function add(uint256 _a, uint256 _b) internal pure returns (uint256) {
                          uint256 c = _a + _b;
                          require(c >= _a, ERROR_ADD_OVERFLOW);
                  
                          return c;
                      }
                  
                      /**
                      * @dev Divides two numbers and returns the remainder (unsigned integer modulo),
                      * reverts when dividing by zero.
                      */
                      function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b != 0, ERROR_DIV_ZERO);
                          return a % b;
                      }
                  }
                  
                  // File: @aragon/apps-shared-minime/contracts/ITokenController.sol
                  
                  pragma solidity ^0.4.24;
                  
                  /// @dev The token controller contract must implement these functions
                  
                  
                  interface ITokenController {
                      /// @notice Called when `_owner` sends ether to the MiniMe Token contract
                      /// @param _owner The address that sent the ether to create tokens
                      /// @return True if the ether is accepted, false if it throws
                      function proxyPayment(address _owner) external payable returns(bool);
                  
                      /// @notice Notifies the controller about a token transfer allowing the
                      ///  controller to react if desired
                      /// @param _from The origin of the transfer
                      /// @param _to The destination of the transfer
                      /// @param _amount The amount of the transfer
                      /// @return False if the controller does not authorize the transfer
                      function onTransfer(address _from, address _to, uint _amount) external returns(bool);
                  
                      /// @notice Notifies the controller about an approval allowing the
                      ///  controller to react if desired
                      /// @param _owner The address that calls `approve()`
                      /// @param _spender The spender in the `approve()` call
                      /// @param _amount The amount in the `approve()` call
                      /// @return False if the controller does not authorize the approval
                      function onApprove(address _owner, address _spender, uint _amount) external returns(bool);
                  }
                  
                  // File: @aragon/apps-shared-minime/contracts/MiniMeToken.sol
                  
                  pragma solidity ^0.4.24;
                  
                  /*
                      Copyright 2016, Jordi Baylina
                      This program is free software: you can redistribute it and/or modify
                      it under the terms of the GNU General Public License as published by
                      the Free Software Foundation, either version 3 of the License, or
                      (at your option) any later version.
                      This program is distributed in the hope that it will be useful,
                      but WITHOUT ANY WARRANTY; without even the implied warranty of
                      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                      GNU General Public License for more details.
                      You should have received a copy of the GNU General Public License
                      along with this program.  If not, see <http://www.gnu.org/licenses/>.
                   */
                  
                  /// @title MiniMeToken Contract
                  /// @author Jordi Baylina
                  /// @dev This token contract's goal is to make it easy for anyone to clone this
                  ///  token using the token distribution at a given block, this will allow DAO's
                  ///  and DApps to upgrade their features in a decentralized manner without
                  ///  affecting the original token
                  /// @dev It is ERC20 compliant, but still needs to under go further testing.
                  
                  
                  contract Controlled {
                      /// @notice The address of the controller is the only address that can call
                      ///  a function with this modifier
                      modifier onlyController {
                          require(msg.sender == controller);
                          _;
                      }
                  
                      address public controller;
                  
                      function Controlled()  public { controller = msg.sender;}
                  
                      /// @notice Changes the controller of the contract
                      /// @param _newController The new controller of the contract
                      function changeController(address _newController) onlyController  public {
                          controller = _newController;
                      }
                  }
                  
                  contract ApproveAndCallFallBack {
                      function receiveApproval(
                          address from,
                          uint256 _amount,
                          address _token,
                          bytes _data
                      ) public;
                  }
                  
                  /// @dev The actual token contract, the default controller is the msg.sender
                  ///  that deploys the contract, so usually this token will be deployed by a
                  ///  token controller contract, which Giveth will call a "Campaign"
                  contract MiniMeToken is Controlled {
                  
                      string public name;                //The Token's name: e.g. DigixDAO Tokens
                      uint8 public decimals;             //Number of decimals of the smallest unit
                      string public symbol;              //An identifier: e.g. REP
                      string public version = "MMT_0.1"; //An arbitrary versioning scheme
                  
                  
                      /// @dev `Checkpoint` is the structure that attaches a block number to a
                      ///  given value, the block number attached is the one that last changed the
                      ///  value
                      struct Checkpoint {
                  
                          // `fromBlock` is the block number that the value was generated from
                          uint128 fromBlock;
                  
                          // `value` is the amount of tokens at a specific block number
                          uint128 value;
                      }
                  
                      // `parentToken` is the Token address that was cloned to produce this token;
                      //  it will be 0x0 for a token that was not cloned
                      MiniMeToken public parentToken;
                  
                      // `parentSnapShotBlock` is the block number from the Parent Token that was
                      //  used to determine the initial distribution of the Clone Token
                      uint public parentSnapShotBlock;
                  
                      // `creationBlock` is the block number that the Clone Token was created
                      uint public creationBlock;
                  
                      // `balances` is the map that tracks the balance of each address, in this
                      //  contract when the balance changes the block number that the change
                      //  occurred is also included in the map
                      mapping (address => Checkpoint[]) balances;
                  
                      // `allowed` tracks any extra transfer rights as in all ERC20 tokens
                      mapping (address => mapping (address => uint256)) allowed;
                  
                      // Tracks the history of the `totalSupply` of the token
                      Checkpoint[] totalSupplyHistory;
                  
                      // Flag that determines if the token is transferable or not.
                      bool public transfersEnabled;
                  
                      // The factory used to create new clone tokens
                      MiniMeTokenFactory public tokenFactory;
                  
                  ////////////////
                  // Constructor
                  ////////////////
                  
                      /// @notice Constructor to create a MiniMeToken
                      /// @param _tokenFactory The address of the MiniMeTokenFactory contract that
                      ///  will create the Clone token contracts, the token factory needs to be
                      ///  deployed first
                      /// @param _parentToken Address of the parent token, set to 0x0 if it is a
                      ///  new token
                      /// @param _parentSnapShotBlock Block of the parent token that will
                      ///  determine the initial distribution of the clone token, set to 0 if it
                      ///  is a new token
                      /// @param _tokenName Name of the new token
                      /// @param _decimalUnits Number of decimals of the new token
                      /// @param _tokenSymbol Token Symbol for the new token
                      /// @param _transfersEnabled If true, tokens will be able to be transferred
                      function MiniMeToken(
                          MiniMeTokenFactory _tokenFactory,
                          MiniMeToken _parentToken,
                          uint _parentSnapShotBlock,
                          string _tokenName,
                          uint8 _decimalUnits,
                          string _tokenSymbol,
                          bool _transfersEnabled
                      )  public
                      {
                          tokenFactory = _tokenFactory;
                          name = _tokenName;                                 // Set the name
                          decimals = _decimalUnits;                          // Set the decimals
                          symbol = _tokenSymbol;                             // Set the symbol
                          parentToken = _parentToken;
                          parentSnapShotBlock = _parentSnapShotBlock;
                          transfersEnabled = _transfersEnabled;
                          creationBlock = block.number;
                      }
                  
                  
                  ///////////////////
                  // ERC20 Methods
                  ///////////////////
                  
                      /// @notice Send `_amount` tokens to `_to` from `msg.sender`
                      /// @param _to The address of the recipient
                      /// @param _amount The amount of tokens to be transferred
                      /// @return Whether the transfer was successful or not
                      function transfer(address _to, uint256 _amount) public returns (bool success) {
                          require(transfersEnabled);
                          return doTransfer(msg.sender, _to, _amount);
                      }
                  
                      /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
                      ///  is approved by `_from`
                      /// @param _from The address holding the tokens being transferred
                      /// @param _to The address of the recipient
                      /// @param _amount The amount of tokens to be transferred
                      /// @return True if the transfer was successful
                      function transferFrom(address _from, address _to, uint256 _amount) public returns (bool success) {
                  
                          // The controller of this contract can move tokens around at will,
                          //  this is important to recognize! Confirm that you trust the
                          //  controller of this contract, which in most situations should be
                          //  another open source smart contract or 0x0
                          if (msg.sender != controller) {
                              require(transfersEnabled);
                  
                              // The standard ERC 20 transferFrom functionality
                              if (allowed[_from][msg.sender] < _amount)
                                  return false;
                              allowed[_from][msg.sender] -= _amount;
                          }
                          return doTransfer(_from, _to, _amount);
                      }
                  
                      /// @dev This is the actual transfer function in the token contract, it can
                      ///  only be called by other functions in this contract.
                      /// @param _from The address holding the tokens being transferred
                      /// @param _to The address of the recipient
                      /// @param _amount The amount of tokens to be transferred
                      /// @return True if the transfer was successful
                      function doTransfer(address _from, address _to, uint _amount) internal returns(bool) {
                          if (_amount == 0) {
                              return true;
                          }
                          require(parentSnapShotBlock < block.number);
                          // Do not allow transfer to 0x0 or the token contract itself
                          require((_to != 0) && (_to != address(this)));
                          // If the amount being transfered is more than the balance of the
                          //  account the transfer returns false
                          var previousBalanceFrom = balanceOfAt(_from, block.number);
                          if (previousBalanceFrom < _amount) {
                              return false;
                          }
                          // Alerts the token controller of the transfer
                          if (isContract(controller)) {
                              // Adding the ` == true` makes the linter shut up so...
                              require(ITokenController(controller).onTransfer(_from, _to, _amount) == true);
                          }
                          // First update the balance array with the new value for the address
                          //  sending the tokens
                          updateValueAtNow(balances[_from], previousBalanceFrom - _amount);
                          // Then update the balance array with the new value for the address
                          //  receiving the tokens
                          var previousBalanceTo = balanceOfAt(_to, block.number);
                          require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow
                          updateValueAtNow(balances[_to], previousBalanceTo + _amount);
                          // An event to make the transfer easy to find on the blockchain
                          Transfer(_from, _to, _amount);
                          return true;
                      }
                  
                      /// @param _owner The address that's balance is being requested
                      /// @return The balance of `_owner` at the current block
                      function balanceOf(address _owner) public constant returns (uint256 balance) {
                          return balanceOfAt(_owner, block.number);
                      }
                  
                      /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
                      ///  its behalf. This is a modified version of the ERC20 approve function
                      ///  to be a little bit safer
                      /// @param _spender The address of the account able to transfer the tokens
                      /// @param _amount The amount of tokens to be approved for transfer
                      /// @return True if the approval was successful
                      function approve(address _spender, uint256 _amount) public returns (bool success) {
                          require(transfersEnabled);
                  
                          // To change the approve amount you first have to reduce the addresses`
                          //  allowance to zero by calling `approve(_spender,0)` if it is not
                          //  already 0 to mitigate the race condition described here:
                          //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                          require((_amount == 0) || (allowed[msg.sender][_spender] == 0));
                  
                          // Alerts the token controller of the approve function call
                          if (isContract(controller)) {
                              // Adding the ` == true` makes the linter shut up so...
                              require(ITokenController(controller).onApprove(msg.sender, _spender, _amount) == true);
                          }
                  
                          allowed[msg.sender][_spender] = _amount;
                          Approval(msg.sender, _spender, _amount);
                          return true;
                      }
                  
                      /// @dev This function makes it easy to read the `allowed[]` map
                      /// @param _owner The address of the account that owns the token
                      /// @param _spender The address of the account able to transfer the tokens
                      /// @return Amount of remaining tokens of _owner that _spender is allowed
                      ///  to spend
                      function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {
                          return allowed[_owner][_spender];
                      }
                  
                      /// @notice `msg.sender` approves `_spender` to send `_amount` tokens on
                      ///  its behalf, and then a function is triggered in the contract that is
                      ///  being approved, `_spender`. This allows users to use their tokens to
                      ///  interact with contracts in one function call instead of two
                      /// @param _spender The address of the contract able to transfer the tokens
                      /// @param _amount The amount of tokens to be approved for transfer
                      /// @return True if the function call was successful
                      function approveAndCall(ApproveAndCallFallBack _spender, uint256 _amount, bytes _extraData) public returns (bool success) {
                          require(approve(_spender, _amount));
                  
                          _spender.receiveApproval(
                              msg.sender,
                              _amount,
                              this,
                              _extraData
                          );
                  
                          return true;
                      }
                  
                      /// @dev This function makes it easy to get the total number of tokens
                      /// @return The total number of tokens
                      function totalSupply() public constant returns (uint) {
                          return totalSupplyAt(block.number);
                      }
                  
                  
                  ////////////////
                  // Query balance and totalSupply in History
                  ////////////////
                  
                      /// @dev Queries the balance of `_owner` at a specific `_blockNumber`
                      /// @param _owner The address from which the balance will be retrieved
                      /// @param _blockNumber The block number when the balance is queried
                      /// @return The balance at `_blockNumber`
                      function balanceOfAt(address _owner, uint _blockNumber) public constant returns (uint) {
                  
                          // These next few lines are used when the balance of the token is
                          //  requested before a check point was ever created for this token, it
                          //  requires that the `parentToken.balanceOfAt` be queried at the
                          //  genesis block for that token as this contains initial balance of
                          //  this token
                          if ((balances[_owner].length == 0) || (balances[_owner][0].fromBlock > _blockNumber)) {
                              if (address(parentToken) != 0) {
                                  return parentToken.balanceOfAt(_owner, min(_blockNumber, parentSnapShotBlock));
                              } else {
                                  // Has no parent
                                  return 0;
                              }
                  
                          // This will return the expected balance during normal situations
                          } else {
                              return getValueAt(balances[_owner], _blockNumber);
                          }
                      }
                  
                      /// @notice Total amount of tokens at a specific `_blockNumber`.
                      /// @param _blockNumber The block number when the totalSupply is queried
                      /// @return The total amount of tokens at `_blockNumber`
                      function totalSupplyAt(uint _blockNumber) public constant returns(uint) {
                  
                          // These next few lines are used when the totalSupply of the token is
                          //  requested before a check point was ever created for this token, it
                          //  requires that the `parentToken.totalSupplyAt` be queried at the
                          //  genesis block for this token as that contains totalSupply of this
                          //  token at this block number.
                          if ((totalSupplyHistory.length == 0) || (totalSupplyHistory[0].fromBlock > _blockNumber)) {
                              if (address(parentToken) != 0) {
                                  return parentToken.totalSupplyAt(min(_blockNumber, parentSnapShotBlock));
                              } else {
                                  return 0;
                              }
                  
                          // This will return the expected totalSupply during normal situations
                          } else {
                              return getValueAt(totalSupplyHistory, _blockNumber);
                          }
                      }
                  
                  ////////////////
                  // Clone Token Method
                  ////////////////
                  
                      /// @notice Creates a new clone token with the initial distribution being
                      ///  this token at `_snapshotBlock`
                      /// @param _cloneTokenName Name of the clone token
                      /// @param _cloneDecimalUnits Number of decimals of the smallest unit
                      /// @param _cloneTokenSymbol Symbol of the clone token
                      /// @param _snapshotBlock Block when the distribution of the parent token is
                      ///  copied to set the initial distribution of the new clone token;
                      ///  if the block is zero than the actual block, the current block is used
                      /// @param _transfersEnabled True if transfers are allowed in the clone
                      /// @return The address of the new MiniMeToken Contract
                      function createCloneToken(
                          string _cloneTokenName,
                          uint8 _cloneDecimalUnits,
                          string _cloneTokenSymbol,
                          uint _snapshotBlock,
                          bool _transfersEnabled
                      ) public returns(MiniMeToken)
                      {
                          uint256 snapshot = _snapshotBlock == 0 ? block.number - 1 : _snapshotBlock;
                  
                          MiniMeToken cloneToken = tokenFactory.createCloneToken(
                              this,
                              snapshot,
                              _cloneTokenName,
                              _cloneDecimalUnits,
                              _cloneTokenSymbol,
                              _transfersEnabled
                          );
                  
                          cloneToken.changeController(msg.sender);
                  
                          // An event to make the token easy to find on the blockchain
                          NewCloneToken(address(cloneToken), snapshot);
                          return cloneToken;
                      }
                  
                  ////////////////
                  // Generate and destroy tokens
                  ////////////////
                  
                      /// @notice Generates `_amount` tokens that are assigned to `_owner`
                      /// @param _owner The address that will be assigned the new tokens
                      /// @param _amount The quantity of tokens generated
                      /// @return True if the tokens are generated correctly
                      function generateTokens(address _owner, uint _amount) onlyController public returns (bool) {
                          uint curTotalSupply = totalSupply();
                          require(curTotalSupply + _amount >= curTotalSupply); // Check for overflow
                          uint previousBalanceTo = balanceOf(_owner);
                          require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow
                          updateValueAtNow(totalSupplyHistory, curTotalSupply + _amount);
                          updateValueAtNow(balances[_owner], previousBalanceTo + _amount);
                          Transfer(0, _owner, _amount);
                          return true;
                      }
                  
                  
                      /// @notice Burns `_amount` tokens from `_owner`
                      /// @param _owner The address that will lose the tokens
                      /// @param _amount The quantity of tokens to burn
                      /// @return True if the tokens are burned correctly
                      function destroyTokens(address _owner, uint _amount) onlyController public returns (bool) {
                          uint curTotalSupply = totalSupply();
                          require(curTotalSupply >= _amount);
                          uint previousBalanceFrom = balanceOf(_owner);
                          require(previousBalanceFrom >= _amount);
                          updateValueAtNow(totalSupplyHistory, curTotalSupply - _amount);
                          updateValueAtNow(balances[_owner], previousBalanceFrom - _amount);
                          Transfer(_owner, 0, _amount);
                          return true;
                      }
                  
                  ////////////////
                  // Enable tokens transfers
                  ////////////////
                  
                  
                      /// @notice Enables token holders to transfer their tokens freely if true
                      /// @param _transfersEnabled True if transfers are allowed in the clone
                      function enableTransfers(bool _transfersEnabled) onlyController public {
                          transfersEnabled = _transfersEnabled;
                      }
                  
                  ////////////////
                  // Internal helper functions to query and set a value in a snapshot array
                  ////////////////
                  
                      /// @dev `getValueAt` retrieves the number of tokens at a given block number
                      /// @param checkpoints The history of values being queried
                      /// @param _block The block number to retrieve the value at
                      /// @return The number of tokens being queried
                      function getValueAt(Checkpoint[] storage checkpoints, uint _block) constant internal returns (uint) {
                          if (checkpoints.length == 0)
                              return 0;
                  
                          // Shortcut for the actual value
                          if (_block >= checkpoints[checkpoints.length-1].fromBlock)
                              return checkpoints[checkpoints.length-1].value;
                          if (_block < checkpoints[0].fromBlock)
                              return 0;
                  
                          // Binary search of the value in the array
                          uint min = 0;
                          uint max = checkpoints.length-1;
                          while (max > min) {
                              uint mid = (max + min + 1) / 2;
                              if (checkpoints[mid].fromBlock<=_block) {
                                  min = mid;
                              } else {
                                  max = mid-1;
                              }
                          }
                          return checkpoints[min].value;
                      }
                  
                      /// @dev `updateValueAtNow` used to update the `balances` map and the
                      ///  `totalSupplyHistory`
                      /// @param checkpoints The history of data being updated
                      /// @param _value The new number of tokens
                      function updateValueAtNow(Checkpoint[] storage checkpoints, uint _value) internal {
                          if ((checkpoints.length == 0) || (checkpoints[checkpoints.length - 1].fromBlock < block.number)) {
                              Checkpoint storage newCheckPoint = checkpoints[checkpoints.length++];
                              newCheckPoint.fromBlock = uint128(block.number);
                              newCheckPoint.value = uint128(_value);
                          } else {
                              Checkpoint storage oldCheckPoint = checkpoints[checkpoints.length - 1];
                              oldCheckPoint.value = uint128(_value);
                          }
                      }
                  
                      /// @dev Internal function to determine if an address is a contract
                      /// @param _addr The address being queried
                      /// @return True if `_addr` is a contract
                      function isContract(address _addr) constant internal returns(bool) {
                          uint size;
                          if (_addr == 0)
                              return false;
                  
                          assembly {
                              size := extcodesize(_addr)
                          }
                  
                          return size>0;
                      }
                  
                      /// @dev Helper function to return a min betwen the two uints
                      function min(uint a, uint b) pure internal returns (uint) {
                          return a < b ? a : b;
                      }
                  
                      /// @notice The fallback function: If the contract's controller has not been
                      ///  set to 0, then the `proxyPayment` method is called which relays the
                      ///  ether and creates tokens as described in the token controller contract
                      function () external payable {
                          require(isContract(controller));
                          // Adding the ` == true` makes the linter shut up so...
                          require(ITokenController(controller).proxyPayment.value(msg.value)(msg.sender) == true);
                      }
                  
                  //////////
                  // Safety Methods
                  //////////
                  
                      /// @notice This method can be used by the controller to extract mistakenly
                      ///  sent tokens to this contract.
                      /// @param _token The address of the token contract that you want to recover
                      ///  set to 0 in case you want to extract ether.
                      function claimTokens(address _token) onlyController public {
                          if (_token == 0x0) {
                              controller.transfer(this.balance);
                              return;
                          }
                  
                          MiniMeToken token = MiniMeToken(_token);
                          uint balance = token.balanceOf(this);
                          token.transfer(controller, balance);
                          ClaimedTokens(_token, controller, balance);
                      }
                  
                  ////////////////
                  // Events
                  ////////////////
                      event ClaimedTokens(address indexed _token, address indexed _controller, uint _amount);
                      event Transfer(address indexed _from, address indexed _to, uint256 _amount);
                      event NewCloneToken(address indexed _cloneToken, uint _snapshotBlock);
                      event Approval(
                          address indexed _owner,
                          address indexed _spender,
                          uint256 _amount
                          );
                  
                  }
                  
                  
                  ////////////////
                  // MiniMeTokenFactory
                  ////////////////
                  
                  /// @dev This contract is used to generate clone contracts from a contract.
                  ///  In solidity this is the way to create a contract from a contract of the
                  ///  same class
                  contract MiniMeTokenFactory {
                  
                      /// @notice Update the DApp by creating a new token with new functionalities
                      ///  the msg.sender becomes the controller of this clone token
                      /// @param _parentToken Address of the token being cloned
                      /// @param _snapshotBlock Block of the parent token that will
                      ///  determine the initial distribution of the clone token
                      /// @param _tokenName Name of the new token
                      /// @param _decimalUnits Number of decimals of the new token
                      /// @param _tokenSymbol Token Symbol for the new token
                      /// @param _transfersEnabled If true, tokens will be able to be transferred
                      /// @return The address of the new token contract
                      function createCloneToken(
                          MiniMeToken _parentToken,
                          uint _snapshotBlock,
                          string _tokenName,
                          uint8 _decimalUnits,
                          string _tokenSymbol,
                          bool _transfersEnabled
                      ) public returns (MiniMeToken)
                      {
                          MiniMeToken newToken = new MiniMeToken(
                              this,
                              _parentToken,
                              _snapshotBlock,
                              _tokenName,
                              _decimalUnits,
                              _tokenSymbol,
                              _transfersEnabled
                          );
                  
                          newToken.changeController(msg.sender);
                          return newToken;
                      }
                  }
                  
                  // File: contracts/TokenManager.sol
                  
                  /*
                   * SPDX-License-Identitifer:    GPL-3.0-or-later
                   */
                  
                  /* solium-disable function-order */
                  
                  pragma solidity 0.4.24;
                  
                  
                  
                  
                  
                  
                  
                  contract TokenManager is ITokenController, IForwarder, AragonApp {
                      using SafeMath for uint256;
                  
                      bytes32 public constant MINT_ROLE = keccak256("MINT_ROLE");
                      bytes32 public constant ISSUE_ROLE = keccak256("ISSUE_ROLE");
                      bytes32 public constant ASSIGN_ROLE = keccak256("ASSIGN_ROLE");
                      bytes32 public constant REVOKE_VESTINGS_ROLE = keccak256("REVOKE_VESTINGS_ROLE");
                      bytes32 public constant BURN_ROLE = keccak256("BURN_ROLE");
                  
                      uint256 public constant MAX_VESTINGS_PER_ADDRESS = 50;
                  
                      string private constant ERROR_CALLER_NOT_TOKEN = "TM_CALLER_NOT_TOKEN";
                      string private constant ERROR_NO_VESTING = "TM_NO_VESTING";
                      string private constant ERROR_TOKEN_CONTROLLER = "TM_TOKEN_CONTROLLER";
                      string private constant ERROR_MINT_RECEIVER_IS_TM = "TM_MINT_RECEIVER_IS_TM";
                      string private constant ERROR_VESTING_TO_TM = "TM_VESTING_TO_TM";
                      string private constant ERROR_TOO_MANY_VESTINGS = "TM_TOO_MANY_VESTINGS";
                      string private constant ERROR_WRONG_CLIFF_DATE = "TM_WRONG_CLIFF_DATE";
                      string private constant ERROR_VESTING_NOT_REVOKABLE = "TM_VESTING_NOT_REVOKABLE";
                      string private constant ERROR_REVOKE_TRANSFER_FROM_REVERTED = "TM_REVOKE_TRANSFER_FROM_REVERTED";
                      string private constant ERROR_CAN_NOT_FORWARD = "TM_CAN_NOT_FORWARD";
                      string private constant ERROR_BALANCE_INCREASE_NOT_ALLOWED = "TM_BALANCE_INC_NOT_ALLOWED";
                      string private constant ERROR_ASSIGN_TRANSFER_FROM_REVERTED = "TM_ASSIGN_TRANSFER_FROM_REVERTED";
                  
                      struct TokenVesting {
                          uint256 amount;
                          uint64 start;
                          uint64 cliff;
                          uint64 vesting;
                          bool revokable;
                      }
                  
                      // Note that we COMPLETELY trust this MiniMeToken to not be malicious for proper operation of this contract
                      MiniMeToken public token;
                      uint256 public maxAccountTokens;
                  
                      // We are mimicing an array in the inner mapping, we use a mapping instead to make app upgrade more graceful
                      mapping (address => mapping (uint256 => TokenVesting)) internal vestings;
                      mapping (address => uint256) public vestingsLengths;
                  
                      // Other token specific events can be watched on the token address directly (avoids duplication)
                      event NewVesting(address indexed receiver, uint256 vestingId, uint256 amount);
                      event RevokeVesting(address indexed receiver, uint256 vestingId, uint256 nonVestedAmount);
                  
                      modifier onlyToken() {
                          require(msg.sender == address(token), ERROR_CALLER_NOT_TOKEN);
                          _;
                      }
                  
                      modifier vestingExists(address _holder, uint256 _vestingId) {
                          // TODO: it's not checking for gaps that may appear because of deletes in revokeVesting function
                          require(_vestingId < vestingsLengths[_holder], ERROR_NO_VESTING);
                          _;
                      }
                  
                      /**
                      * @notice Initialize Token Manager for `_token.symbol(): string`, whose tokens are `transferable ? 'not' : ''` transferable`_maxAccountTokens > 0 ? ' and limited to a maximum of ' + @tokenAmount(_token, _maxAccountTokens, false) + ' per account' : ''`
                      * @param _token MiniMeToken address for the managed token (Token Manager instance must be already set as the token controller)
                      * @param _transferable whether the token can be transferred by holders
                      * @param _maxAccountTokens Maximum amount of tokens an account can have (0 for infinite tokens)
                      */
                      function initialize(
                          MiniMeToken _token,
                          bool _transferable,
                          uint256 _maxAccountTokens
                      )
                          external
                          onlyInit
                      {
                          initialized();
                  
                          require(_token.controller() == address(this), ERROR_TOKEN_CONTROLLER);
                  
                          token = _token;
                          maxAccountTokens = _maxAccountTokens == 0 ? uint256(-1) : _maxAccountTokens;
                  
                          if (token.transfersEnabled() != _transferable) {
                              token.enableTransfers(_transferable);
                          }
                      }
                  
                      /**
                      * @notice Mint `@tokenAmount(self.token(): address, _amount, false)` tokens for `_receiver`
                      * @param _receiver The address receiving the tokens, cannot be the Token Manager itself (use `issue()` instead)
                      * @param _amount Number of tokens minted
                      */
                      function mint(address _receiver, uint256 _amount) external authP(MINT_ROLE, arr(_receiver, _amount)) {
                          require(_receiver != address(this), ERROR_MINT_RECEIVER_IS_TM);
                          _mint(_receiver, _amount);
                      }
                  
                      /**
                      * @notice Mint `@tokenAmount(self.token(): address, _amount, false)` tokens for the Token Manager
                      * @param _amount Number of tokens minted
                      */
                      function issue(uint256 _amount) external authP(ISSUE_ROLE, arr(_amount)) {
                          _mint(address(this), _amount);
                      }
                  
                      /**
                      * @notice Assign `@tokenAmount(self.token(): address, _amount, false)` tokens to `_receiver` from the Token Manager's holdings
                      * @param _receiver The address receiving the tokens
                      * @param _amount Number of tokens transferred
                      */
                      function assign(address _receiver, uint256 _amount) external authP(ASSIGN_ROLE, arr(_receiver, _amount)) {
                          _assign(_receiver, _amount);
                      }
                  
                      /**
                      * @notice Burn `@tokenAmount(self.token(): address, _amount, false)` tokens from `_holder`
                      * @param _holder Holder of tokens being burned
                      * @param _amount Number of tokens being burned
                      */
                      function burn(address _holder, uint256 _amount) external authP(BURN_ROLE, arr(_holder, _amount)) {
                          // minime.destroyTokens() never returns false, only reverts on failure
                          token.destroyTokens(_holder, _amount);
                      }
                  
                      /**
                      * @notice Assign `@tokenAmount(self.token(): address, _amount, false)` tokens to `_receiver` from the Token Manager's holdings with a `_revokable : 'revokable' : ''` vesting starting at `@formatDate(_start)`, cliff at `@formatDate(_cliff)` (first portion of tokens transferable), and completed vesting at `@formatDate(_vested)` (all tokens transferable)
                      * @param _receiver The address receiving the tokens, cannot be Token Manager itself
                      * @param _amount Number of tokens vested
                      * @param _start Date the vesting calculations start
                      * @param _cliff Date when the initial portion of tokens are transferable
                      * @param _vested Date when all tokens are transferable
                      * @param _revokable Whether the vesting can be revoked by the Token Manager
                      */
                      function assignVested(
                          address _receiver,
                          uint256 _amount,
                          uint64 _start,
                          uint64 _cliff,
                          uint64 _vested,
                          bool _revokable
                      )
                          external
                          authP(ASSIGN_ROLE, arr(_receiver, _amount))
                          returns (uint256)
                      {
                          require(_receiver != address(this), ERROR_VESTING_TO_TM);
                          require(vestingsLengths[_receiver] < MAX_VESTINGS_PER_ADDRESS, ERROR_TOO_MANY_VESTINGS);
                          require(_start <= _cliff && _cliff <= _vested, ERROR_WRONG_CLIFF_DATE);
                  
                          uint256 vestingId = vestingsLengths[_receiver]++;
                          vestings[_receiver][vestingId] = TokenVesting(
                              _amount,
                              _start,
                              _cliff,
                              _vested,
                              _revokable
                          );
                  
                          _assign(_receiver, _amount);
                  
                          emit NewVesting(_receiver, vestingId, _amount);
                  
                          return vestingId;
                      }
                  
                      /**
                      * @notice Revoke vesting #`_vestingId` from `_holder`, returning unvested tokens to the Token Manager
                      * @param _holder Address whose vesting to revoke
                      * @param _vestingId Numeric id of the vesting
                      */
                      function revokeVesting(address _holder, uint256 _vestingId)
                          external
                          authP(REVOKE_VESTINGS_ROLE, arr(_holder))
                          vestingExists(_holder, _vestingId)
                      {
                          TokenVesting storage v = vestings[_holder][_vestingId];
                          require(v.revokable, ERROR_VESTING_NOT_REVOKABLE);
                  
                          uint256 nonVested = _calculateNonVestedTokens(
                              v.amount,
                              getTimestamp(),
                              v.start,
                              v.cliff,
                              v.vesting
                          );
                  
                          // To make vestingIds immutable over time, we just zero out the revoked vesting
                          // Clearing this out also allows the token transfer back to the Token Manager to succeed
                          delete vestings[_holder][_vestingId];
                  
                          // transferFrom always works as controller
                          // onTransfer hook always allows if transfering to token controller
                          require(token.transferFrom(_holder, address(this), nonVested), ERROR_REVOKE_TRANSFER_FROM_REVERTED);
                  
                          emit RevokeVesting(_holder, _vestingId, nonVested);
                      }
                  
                      // ITokenController fns
                      // `onTransfer()`, `onApprove()`, and `proxyPayment()` are callbacks from the MiniMe token
                      // contract and are only meant to be called through the managed MiniMe token that gets assigned
                      // during initialization.
                  
                      /*
                      * @dev Notifies the controller about a token transfer allowing the controller to decide whether
                      *      to allow it or react if desired (only callable from the token).
                      *      Initialization check is implicitly provided by `onlyToken()`.
                      * @param _from The origin of the transfer
                      * @param _to The destination of the transfer
                      * @param _amount The amount of the transfer
                      * @return False if the controller does not authorize the transfer
                      */
                      function onTransfer(address _from, address _to, uint256 _amount) external onlyToken returns (bool) {
                          return _isBalanceIncreaseAllowed(_to, _amount) && _transferableBalance(_from, getTimestamp()) >= _amount;
                      }
                  
                      /**
                      * @dev Notifies the controller about an approval allowing the controller to react if desired
                      *      Initialization check is implicitly provided by `onlyToken()`.
                      * @return False if the controller does not authorize the approval
                      */
                      function onApprove(address, address, uint) external onlyToken returns (bool) {
                          return true;
                      }
                  
                      /**
                      * @dev Called when ether is sent to the MiniMe Token contract
                      *      Initialization check is implicitly provided by `onlyToken()`.
                      * @return True if the ether is accepted, false for it to throw
                      */
                      function proxyPayment(address) external payable onlyToken returns (bool) {
                          return false;
                      }
                  
                      // Forwarding fns
                  
                      function isForwarder() external pure returns (bool) {
                          return true;
                      }
                  
                      /**
                      * @notice Execute desired action as a token holder
                      * @dev IForwarder interface conformance. Forwards any token holder action.
                      * @param _evmScript Script being executed
                      */
                      function forward(bytes _evmScript) public {
                          require(canForward(msg.sender, _evmScript), ERROR_CAN_NOT_FORWARD);
                          bytes memory input = new bytes(0); // TODO: Consider input for this
                  
                          // Add the managed token to the blacklist to disallow a token holder from executing actions
                          // on the token controller's (this contract) behalf
                          address[] memory blacklist = new address[](1);
                          blacklist[0] = address(token);
                  
                          runScript(_evmScript, input, blacklist);
                      }
                  
                      function canForward(address _sender, bytes) public view returns (bool) {
                          return hasInitialized() && token.balanceOf(_sender) > 0;
                      }
                  
                      // Getter fns
                  
                      function getVesting(
                          address _recipient,
                          uint256 _vestingId
                      )
                          public
                          view
                          vestingExists(_recipient, _vestingId)
                          returns (
                              uint256 amount,
                              uint64 start,
                              uint64 cliff,
                              uint64 vesting,
                              bool revokable
                          )
                      {
                          TokenVesting storage tokenVesting = vestings[_recipient][_vestingId];
                          amount = tokenVesting.amount;
                          start = tokenVesting.start;
                          cliff = tokenVesting.cliff;
                          vesting = tokenVesting.vesting;
                          revokable = tokenVesting.revokable;
                      }
                  
                      function spendableBalanceOf(address _holder) public view isInitialized returns (uint256) {
                          return _transferableBalance(_holder, getTimestamp());
                      }
                  
                      function transferableBalance(address _holder, uint256 _time) public view isInitialized returns (uint256) {
                          return _transferableBalance(_holder, _time);
                      }
                  
                      /**
                      * @dev Disable recovery escape hatch for own token,
                      *      as the it has the concept of issuing tokens without assigning them
                      */
                      function allowRecoverability(address _token) public view returns (bool) {
                          return _token != address(token);
                      }
                  
                      // Internal fns
                  
                      function _assign(address _receiver, uint256 _amount) internal {
                          require(_isBalanceIncreaseAllowed(_receiver, _amount), ERROR_BALANCE_INCREASE_NOT_ALLOWED);
                          // Must use transferFrom() as transfer() does not give the token controller full control
                          require(token.transferFrom(address(this), _receiver, _amount), ERROR_ASSIGN_TRANSFER_FROM_REVERTED);
                      }
                  
                      function _mint(address _receiver, uint256 _amount) internal {
                          require(_isBalanceIncreaseAllowed(_receiver, _amount), ERROR_BALANCE_INCREASE_NOT_ALLOWED);
                          token.generateTokens(_receiver, _amount); // minime.generateTokens() never returns false
                      }
                  
                      function _isBalanceIncreaseAllowed(address _receiver, uint256 _inc) internal view returns (bool) {
                          // Max balance doesn't apply to the token manager itself
                          if (_receiver == address(this)) {
                              return true;
                          }
                          return token.balanceOf(_receiver).add(_inc) <= maxAccountTokens;
                      }
                  
                      /**
                      * @dev Calculate amount of non-vested tokens at a specifc time
                      * @param tokens The total amount of tokens vested
                      * @param time The time at which to check
                      * @param start The date vesting started
                      * @param cliff The cliff period
                      * @param vested The fully vested date
                      * @return The amount of non-vested tokens of a specific grant
                      *  transferableTokens
                      *   |                         _/--------   vestedTokens rect
                      *   |                       _/
                      *   |                     _/
                      *   |                   _/
                      *   |                 _/
                      *   |                /
                      *   |              .|
                      *   |            .  |
                      *   |          .    |
                      *   |        .      |
                      *   |      .        |
                      *   |    .          |
                      *   +===+===========+---------+----------> time
                      *      Start       Cliff    Vested
                      */
                      function _calculateNonVestedTokens(
                          uint256 tokens,
                          uint256 time,
                          uint256 start,
                          uint256 cliff,
                          uint256 vested
                      )
                          private
                          pure
                          returns (uint256)
                      {
                          // Shortcuts for before cliff and after vested cases.
                          if (time >= vested) {
                              return 0;
                          }
                          if (time < cliff) {
                              return tokens;
                          }
                  
                          // Interpolate all vested tokens.
                          // As before cliff the shortcut returns 0, we can just calculate a value
                          // in the vesting rect (as shown in above's figure)
                  
                          // vestedTokens = tokens * (time - start) / (vested - start)
                          // In assignVesting we enforce start <= cliff <= vested
                          // Here we shortcut time >= vested and time < cliff,
                          // so no division by 0 is possible
                          uint256 vestedTokens = tokens.mul(time.sub(start)) / vested.sub(start);
                  
                          // tokens - vestedTokens
                          return tokens.sub(vestedTokens);
                      }
                  
                      function _transferableBalance(address _holder, uint256 _time) internal view returns (uint256) {
                          uint256 transferable = token.balanceOf(_holder);
                  
                          // This check is not strictly necessary for the current version of this contract, as
                          // Token Managers now cannot assign vestings to themselves.
                          // However, this was a possibility in the past, so in case there were vestings assigned to
                          // themselves, this will still return the correct value (entire balance, as the Token
                          // Manager does not have a spending limit on its own balance).
                          if (_holder != address(this)) {
                              uint256 vestingsCount = vestingsLengths[_holder];
                              for (uint256 i = 0; i < vestingsCount; i++) {
                                  TokenVesting storage v = vestings[_holder][i];
                                  uint256 nonTransferable = _calculateNonVestedTokens(
                                      v.amount,
                                      _time,
                                      v.start,
                                      v.cliff,
                                      v.vesting
                                  );
                                  transferable = transferable.sub(nonTransferable);
                              }
                          }
                  
                          return transferable;
                      }
                  }

                  File 13 of 14: Lib_AddressManager
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  import "../utils/Context.sol";
                  /**
                   * @dev Contract module which provides a basic access control mechanism, where
                   * there is an account (an owner) that can be granted exclusive access to
                   * specific functions.
                   *
                   * By default, the owner account will be the one that deploys the contract. This
                   * can later be changed with {transferOwnership}.
                   *
                   * This module is used through inheritance. It will make available the modifier
                   * `onlyOwner`, which can be applied to your functions to restrict their use to
                   * the owner.
                   */
                  abstract contract Ownable is Context {
                      address private _owner;
                      event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                      /**
                       * @dev Initializes the contract setting the deployer as the initial owner.
                       */
                      constructor () internal {
                          address msgSender = _msgSender();
                          _owner = msgSender;
                          emit OwnershipTransferred(address(0), msgSender);
                      }
                      /**
                       * @dev Returns the address of the current owner.
                       */
                      function owner() public view virtual returns (address) {
                          return _owner;
                      }
                      /**
                       * @dev Throws if called by any account other than the owner.
                       */
                      modifier onlyOwner() {
                          require(owner() == _msgSender(), "Ownable: caller is not the owner");
                          _;
                      }
                      /**
                       * @dev Leaves the contract without owner. It will not be possible to call
                       * `onlyOwner` functions anymore. Can only be called by the current owner.
                       *
                       * NOTE: Renouncing ownership will leave the contract without an owner,
                       * thereby removing any functionality that is only available to the owner.
                       */
                      function renounceOwnership() public virtual onlyOwner {
                          emit OwnershipTransferred(_owner, address(0));
                          _owner = address(0);
                      }
                      /**
                       * @dev Transfers ownership of the contract to a new account (`newOwner`).
                       * Can only be called by the current owner.
                       */
                      function transferOwnership(address newOwner) public virtual onlyOwner {
                          require(newOwner != address(0), "Ownable: new owner is the zero address");
                          emit OwnershipTransferred(_owner, newOwner);
                          _owner = newOwner;
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  /*
                   * @dev Provides information about the current execution context, including the
                   * sender of the transaction and its data. While these are generally available
                   * via msg.sender and msg.data, they should not be accessed in such a direct
                   * manner, since when dealing with GSN meta-transactions the account sending and
                   * paying for execution may not be the actual sender (as far as an application
                   * is concerned).
                   *
                   * This contract is only required for intermediate, library-like contracts.
                   */
                  abstract contract Context {
                      function _msgSender() internal view virtual returns (address payable) {
                          return msg.sender;
                      }
                      function _msgData() internal view virtual returns (bytes memory) {
                          this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                          return msg.data;
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >0.5.0 <0.8.0;
                  /* External Imports */
                  import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
                  /**
                   * @title Lib_AddressManager
                   */
                  contract Lib_AddressManager is Ownable {
                      /**********
                       * Events *
                       **********/
                      event AddressSet(
                          string indexed _name,
                          address _newAddress,
                          address _oldAddress
                      );
                      /*************
                       * Variables *
                       *************/
                      mapping (bytes32 => address) private addresses;
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * Changes the address associated with a particular name.
                       * @param _name String name to associate an address with.
                       * @param _address Address to associate with the name.
                       */
                      function setAddress(
                          string memory _name,
                          address _address
                      )
                          external
                          onlyOwner
                      {
                          bytes32 nameHash = _getNameHash(_name);
                          address oldAddress = addresses[nameHash];
                          addresses[nameHash] = _address;
                          emit AddressSet(
                              _name,
                              _address,
                              oldAddress
                          );
                      }
                      /**
                       * Retrieves the address associated with a given name.
                       * @param _name Name to retrieve an address for.
                       * @return Address associated with the given name.
                       */
                      function getAddress(
                          string memory _name
                      )
                          external
                          view
                          returns (
                              address
                          )
                      {
                          return addresses[_getNameHash(_name)];
                      }
                      /**********************
                       * Internal Functions *
                       **********************/
                      /**
                       * Computes the hash of a name.
                       * @param _name Name to compute a hash for.
                       * @return Hash of the given name.
                       */
                      function _getNameHash(
                          string memory _name
                      )
                          internal
                          pure
                          returns (
                              bytes32
                          )
                      {
                          return keccak256(abi.encodePacked(_name));
                      }
                  }
                  

                  File 14 of 14: L1CrossDomainMessenger
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.0;
                  import "../utils/ContextUpgradeable.sol";
                  import "../proxy/utils/Initializable.sol";
                  /**
                   * @dev Contract module which provides a basic access control mechanism, where
                   * there is an account (an owner) that can be granted exclusive access to
                   * specific functions.
                   *
                   * By default, the owner account will be the one that deploys the contract. This
                   * can later be changed with {transferOwnership}.
                   *
                   * This module is used through inheritance. It will make available the modifier
                   * `onlyOwner`, which can be applied to your functions to restrict their use to
                   * the owner.
                   */
                  abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
                      address private _owner;
                      event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                      /**
                       * @dev Initializes the contract setting the deployer as the initial owner.
                       */
                      function __Ownable_init() internal initializer {
                          __Context_init_unchained();
                          __Ownable_init_unchained();
                      }
                      function __Ownable_init_unchained() internal initializer {
                          _setOwner(_msgSender());
                      }
                      /**
                       * @dev Returns the address of the current owner.
                       */
                      function owner() public view virtual returns (address) {
                          return _owner;
                      }
                      /**
                       * @dev Throws if called by any account other than the owner.
                       */
                      modifier onlyOwner() {
                          require(owner() == _msgSender(), "Ownable: caller is not the owner");
                          _;
                      }
                      /**
                       * @dev Leaves the contract without owner. It will not be possible to call
                       * `onlyOwner` functions anymore. Can only be called by the current owner.
                       *
                       * NOTE: Renouncing ownership will leave the contract without an owner,
                       * thereby removing any functionality that is only available to the owner.
                       */
                      function renounceOwnership() public virtual onlyOwner {
                          _setOwner(address(0));
                      }
                      /**
                       * @dev Transfers ownership of the contract to a new account (`newOwner`).
                       * Can only be called by the current owner.
                       */
                      function transferOwnership(address newOwner) public virtual onlyOwner {
                          require(newOwner != address(0), "Ownable: new owner is the zero address");
                          _setOwner(newOwner);
                      }
                      function _setOwner(address newOwner) private {
                          address oldOwner = _owner;
                          _owner = newOwner;
                          emit OwnershipTransferred(oldOwner, newOwner);
                      }
                      uint256[49] private __gap;
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.0;
                  /**
                   * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
                   * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
                   * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
                   * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
                   *
                   * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
                   * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
                   *
                   * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
                   * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
                   */
                  abstract contract Initializable {
                      /**
                       * @dev Indicates that the contract has been initialized.
                       */
                      bool private _initialized;
                      /**
                       * @dev Indicates that the contract is in the process of being initialized.
                       */
                      bool private _initializing;
                      /**
                       * @dev Modifier to protect an initializer function from being invoked twice.
                       */
                      modifier initializer() {
                          require(_initializing || !_initialized, "Initializable: contract is already initialized");
                          bool isTopLevelCall = !_initializing;
                          if (isTopLevelCall) {
                              _initializing = true;
                              _initialized = true;
                          }
                          _;
                          if (isTopLevelCall) {
                              _initializing = false;
                          }
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.0;
                  import "../utils/ContextUpgradeable.sol";
                  import "../proxy/utils/Initializable.sol";
                  /**
                   * @dev Contract module which allows children to implement an emergency stop
                   * mechanism that can be triggered by an authorized account.
                   *
                   * This module is used through inheritance. It will make available the
                   * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
                   * the functions of your contract. Note that they will not be pausable by
                   * simply including this module, only once the modifiers are put in place.
                   */
                  abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
                      /**
                       * @dev Emitted when the pause is triggered by `account`.
                       */
                      event Paused(address account);
                      /**
                       * @dev Emitted when the pause is lifted by `account`.
                       */
                      event Unpaused(address account);
                      bool private _paused;
                      /**
                       * @dev Initializes the contract in unpaused state.
                       */
                      function __Pausable_init() internal initializer {
                          __Context_init_unchained();
                          __Pausable_init_unchained();
                      }
                      function __Pausable_init_unchained() internal initializer {
                          _paused = false;
                      }
                      /**
                       * @dev Returns true if the contract is paused, and false otherwise.
                       */
                      function paused() public view virtual returns (bool) {
                          return _paused;
                      }
                      /**
                       * @dev Modifier to make a function callable only when the contract is not paused.
                       *
                       * Requirements:
                       *
                       * - The contract must not be paused.
                       */
                      modifier whenNotPaused() {
                          require(!paused(), "Pausable: paused");
                          _;
                      }
                      /**
                       * @dev Modifier to make a function callable only when the contract is paused.
                       *
                       * Requirements:
                       *
                       * - The contract must be paused.
                       */
                      modifier whenPaused() {
                          require(paused(), "Pausable: not paused");
                          _;
                      }
                      /**
                       * @dev Triggers stopped state.
                       *
                       * Requirements:
                       *
                       * - The contract must not be paused.
                       */
                      function _pause() internal virtual whenNotPaused {
                          _paused = true;
                          emit Paused(_msgSender());
                      }
                      /**
                       * @dev Returns to normal state.
                       *
                       * Requirements:
                       *
                       * - The contract must be paused.
                       */
                      function _unpause() internal virtual whenPaused {
                          _paused = false;
                          emit Unpaused(_msgSender());
                      }
                      uint256[49] private __gap;
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.0;
                  import "../proxy/utils/Initializable.sol";
                  /**
                   * @dev Contract module that helps prevent reentrant calls to a function.
                   *
                   * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
                   * available, which can be applied to functions to make sure there are no nested
                   * (reentrant) calls to them.
                   *
                   * Note that because there is a single `nonReentrant` guard, functions marked as
                   * `nonReentrant` may not call one another. This can be worked around by making
                   * those functions `private`, and then adding `external` `nonReentrant` entry
                   * points to them.
                   *
                   * TIP: If you would like to learn more about reentrancy and alternative ways
                   * to protect against it, check out our blog post
                   * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
                   */
                  abstract contract ReentrancyGuardUpgradeable is Initializable {
                      // Booleans are more expensive than uint256 or any type that takes up a full
                      // word because each write operation emits an extra SLOAD to first read the
                      // slot's contents, replace the bits taken up by the boolean, and then write
                      // back. This is the compiler's defense against contract upgrades and
                      // pointer aliasing, and it cannot be disabled.
                      // The values being non-zero value makes deployment a bit more expensive,
                      // but in exchange the refund on every call to nonReentrant will be lower in
                      // amount. Since refunds are capped to a percentage of the total
                      // transaction's gas, it is best to keep them low in cases like this one, to
                      // increase the likelihood of the full refund coming into effect.
                      uint256 private constant _NOT_ENTERED = 1;
                      uint256 private constant _ENTERED = 2;
                      uint256 private _status;
                      function __ReentrancyGuard_init() internal initializer {
                          __ReentrancyGuard_init_unchained();
                      }
                      function __ReentrancyGuard_init_unchained() internal initializer {
                          _status = _NOT_ENTERED;
                      }
                      /**
                       * @dev Prevents a contract from calling itself, directly or indirectly.
                       * Calling a `nonReentrant` function from another `nonReentrant`
                       * function is not supported. It is possible to prevent this from happening
                       * by making the `nonReentrant` function external, and make it call a
                       * `private` function that does the actual work.
                       */
                      modifier nonReentrant() {
                          // On the first call to nonReentrant, _notEntered will be true
                          require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
                          // Any calls to nonReentrant after this point will fail
                          _status = _ENTERED;
                          _;
                          // By storing the original value once again, a refund is triggered (see
                          // https://eips.ethereum.org/EIPS/eip-2200)
                          _status = _NOT_ENTERED;
                      }
                      uint256[49] private __gap;
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.0;
                  import "../proxy/utils/Initializable.sol";
                  /**
                   * @dev Provides information about the current execution context, including the
                   * sender of the transaction and its data. While these are generally available
                   * via msg.sender and msg.data, they should not be accessed in such a direct
                   * manner, since when dealing with meta-transactions the account sending and
                   * paying for execution may not be the actual sender (as far as an application
                   * is concerned).
                   *
                   * This contract is only required for intermediate, library-like contracts.
                   */
                  abstract contract ContextUpgradeable is Initializable {
                      function __Context_init() internal initializer {
                          __Context_init_unchained();
                      }
                      function __Context_init_unchained() internal initializer {
                      }
                      function _msgSender() internal view virtual returns (address) {
                          return msg.sender;
                      }
                      function _msgData() internal view virtual returns (bytes calldata) {
                          return msg.data;
                      }
                      uint256[50] private __gap;
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.0;
                  import "../utils/Context.sol";
                  /**
                   * @dev Contract module which provides a basic access control mechanism, where
                   * there is an account (an owner) that can be granted exclusive access to
                   * specific functions.
                   *
                   * By default, the owner account will be the one that deploys the contract. This
                   * can later be changed with {transferOwnership}.
                   *
                   * This module is used through inheritance. It will make available the modifier
                   * `onlyOwner`, which can be applied to your functions to restrict their use to
                   * the owner.
                   */
                  abstract contract Ownable is Context {
                      address private _owner;
                      event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                      /**
                       * @dev Initializes the contract setting the deployer as the initial owner.
                       */
                      constructor() {
                          _setOwner(_msgSender());
                      }
                      /**
                       * @dev Returns the address of the current owner.
                       */
                      function owner() public view virtual returns (address) {
                          return _owner;
                      }
                      /**
                       * @dev Throws if called by any account other than the owner.
                       */
                      modifier onlyOwner() {
                          require(owner() == _msgSender(), "Ownable: caller is not the owner");
                          _;
                      }
                      /**
                       * @dev Leaves the contract without owner. It will not be possible to call
                       * `onlyOwner` functions anymore. Can only be called by the current owner.
                       *
                       * NOTE: Renouncing ownership will leave the contract without an owner,
                       * thereby removing any functionality that is only available to the owner.
                       */
                      function renounceOwnership() public virtual onlyOwner {
                          _setOwner(address(0));
                      }
                      /**
                       * @dev Transfers ownership of the contract to a new account (`newOwner`).
                       * Can only be called by the current owner.
                       */
                      function transferOwnership(address newOwner) public virtual onlyOwner {
                          require(newOwner != address(0), "Ownable: new owner is the zero address");
                          _setOwner(newOwner);
                      }
                      function _setOwner(address newOwner) private {
                          address oldOwner = _owner;
                          _owner = newOwner;
                          emit OwnershipTransferred(oldOwner, newOwner);
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.0;
                  /**
                   * @dev Provides information about the current execution context, including the
                   * sender of the transaction and its data. While these are generally available
                   * via msg.sender and msg.data, they should not be accessed in such a direct
                   * manner, since when dealing with meta-transactions the account sending and
                   * paying for execution may not be the actual sender (as far as an application
                   * is concerned).
                   *
                   * This contract is only required for intermediate, library-like contracts.
                   */
                  abstract contract Context {
                      function _msgSender() internal view virtual returns (address) {
                          return msg.sender;
                      }
                      function _msgData() internal view virtual returns (bytes calldata) {
                          return msg.data;
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /* Library Imports */
                  import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
                  /* Interface Imports */
                  import { ICrossDomainMessenger } from "../../libraries/bridge/ICrossDomainMessenger.sol";
                  /**
                   * @title IL1CrossDomainMessenger
                   */
                  interface IL1CrossDomainMessenger is ICrossDomainMessenger {
                      /*******************
                       * Data Structures *
                       *******************/
                      struct L2MessageInclusionProof {
                          bytes32 stateRoot;
                          Lib_OVMCodec.ChainBatchHeader stateRootBatchHeader;
                          Lib_OVMCodec.ChainInclusionProof stateRootProof;
                          bytes stateTrieWitness;
                          bytes storageTrieWitness;
                      }
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * Relays a cross domain message to a contract.
                       * @param _target Target contract address.
                       * @param _sender Message sender address.
                       * @param _message Message to send to the target.
                       * @param _messageNonce Nonce for the provided message.
                       * @param _proof Inclusion proof for the given message.
                       */
                      function relayMessage(
                          address _target,
                          address _sender,
                          bytes memory _message,
                          uint256 _messageNonce,
                          L2MessageInclusionProof memory _proof
                      ) external;
                      /**
                       * Replays a cross domain message to the target messenger.
                       * @param _target Target contract address.
                       * @param _sender Original sender address.
                       * @param _message Message to send to the target.
                       * @param _queueIndex CTC Queue index for the message to replay.
                       * @param _oldGasLimit Original gas limit used to send the message.
                       * @param _newGasLimit New gas limit to be used for this message.
                       */
                      function replayMessage(
                          address _target,
                          address _sender,
                          bytes memory _message,
                          uint256 _queueIndex,
                          uint32 _oldGasLimit,
                          uint32 _newGasLimit
                      ) external;
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /* Library Imports */
                  import { AddressAliasHelper } from "../../standards/AddressAliasHelper.sol";
                  import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
                  import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
                  import { Lib_AddressManager } from "../../libraries/resolver/Lib_AddressManager.sol";
                  import { Lib_SecureMerkleTrie } from "../../libraries/trie/Lib_SecureMerkleTrie.sol";
                  import { Lib_DefaultValues } from "../../libraries/constants/Lib_DefaultValues.sol";
                  import { Lib_PredeployAddresses } from "../../libraries/constants/Lib_PredeployAddresses.sol";
                  import { Lib_CrossDomainUtils } from "../../libraries/bridge/Lib_CrossDomainUtils.sol";
                  /* Interface Imports */
                  import { IL1CrossDomainMessenger } from "./IL1CrossDomainMessenger.sol";
                  import { ICanonicalTransactionChain } from "../rollup/ICanonicalTransactionChain.sol";
                  import { IStateCommitmentChain } from "../rollup/IStateCommitmentChain.sol";
                  /* External Imports */
                  import {
                      OwnableUpgradeable
                  } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
                  import {
                      PausableUpgradeable
                  } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
                  import {
                      ReentrancyGuardUpgradeable
                  } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
                  /**
                   * @title L1CrossDomainMessenger
                   * @dev The L1 Cross Domain Messenger contract sends messages from L1 to L2, and relays messages
                   * from L2 onto L1. In the event that a message sent from L1 to L2 is rejected for exceeding the L2
                   * epoch gas limit, it can be resubmitted via this contract's replay function.
                   *
                   * Runtime target: EVM
                   */
                  contract L1CrossDomainMessenger is
                      IL1CrossDomainMessenger,
                      Lib_AddressResolver,
                      OwnableUpgradeable,
                      PausableUpgradeable,
                      ReentrancyGuardUpgradeable
                  {
                      /**********
                       * Events *
                       **********/
                      event MessageBlocked(bytes32 indexed _xDomainCalldataHash);
                      event MessageAllowed(bytes32 indexed _xDomainCalldataHash);
                      /**********************
                       * Contract Variables *
                       **********************/
                      mapping(bytes32 => bool) public blockedMessages;
                      mapping(bytes32 => bool) public relayedMessages;
                      mapping(bytes32 => bool) public successfulMessages;
                      address internal xDomainMsgSender = Lib_DefaultValues.DEFAULT_XDOMAIN_SENDER;
                      /***************
                       * Constructor *
                       ***************/
                      /**
                       * This contract is intended to be behind a delegate proxy.
                       * We pass the zero address to the address resolver just to satisfy the constructor.
                       * We still need to set this value in initialize().
                       */
                      constructor() Lib_AddressResolver(address(0)) {}
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * @param _libAddressManager Address of the Address Manager.
                       */
                      function initialize(address _libAddressManager) public initializer {
                          require(
                              address(libAddressManager) == address(0),
                              "L1CrossDomainMessenger already intialized."
                          );
                          libAddressManager = Lib_AddressManager(_libAddressManager);
                          xDomainMsgSender = Lib_DefaultValues.DEFAULT_XDOMAIN_SENDER;
                          // Initialize upgradable OZ contracts
                          __Context_init_unchained(); // Context is a dependency for both Ownable and Pausable
                          __Ownable_init_unchained();
                          __Pausable_init_unchained();
                          __ReentrancyGuard_init_unchained();
                      }
                      /**
                       * Pause relaying.
                       */
                      function pause() external onlyOwner {
                          _pause();
                      }
                      /**
                       * Block a message.
                       * @param _xDomainCalldataHash Hash of the message to block.
                       */
                      function blockMessage(bytes32 _xDomainCalldataHash) external onlyOwner {
                          blockedMessages[_xDomainCalldataHash] = true;
                          emit MessageBlocked(_xDomainCalldataHash);
                      }
                      /**
                       * Allow a message.
                       * @param _xDomainCalldataHash Hash of the message to block.
                       */
                      function allowMessage(bytes32 _xDomainCalldataHash) external onlyOwner {
                          blockedMessages[_xDomainCalldataHash] = false;
                          emit MessageAllowed(_xDomainCalldataHash);
                      }
                      function xDomainMessageSender() public view returns (address) {
                          require(
                              xDomainMsgSender != Lib_DefaultValues.DEFAULT_XDOMAIN_SENDER,
                              "xDomainMessageSender is not set"
                          );
                          return xDomainMsgSender;
                      }
                      /**
                       * Sends a cross domain message to the target messenger.
                       * @param _target Target contract address.
                       * @param _message Message to send to the target.
                       * @param _gasLimit Gas limit for the provided message.
                       */
                      function sendMessage(
                          address _target,
                          bytes memory _message,
                          uint32 _gasLimit
                      ) public {
                          address ovmCanonicalTransactionChain = resolve("CanonicalTransactionChain");
                          // Use the CTC queue length as nonce
                          uint40 nonce = ICanonicalTransactionChain(ovmCanonicalTransactionChain).getQueueLength();
                          bytes memory xDomainCalldata = Lib_CrossDomainUtils.encodeXDomainCalldata(
                              _target,
                              msg.sender,
                              _message,
                              nonce
                          );
                          _sendXDomainMessage(ovmCanonicalTransactionChain, xDomainCalldata, _gasLimit);
                          emit SentMessage(_target, msg.sender, _message, nonce, _gasLimit);
                      }
                      /**
                       * Relays a cross domain message to a contract.
                       * @inheritdoc IL1CrossDomainMessenger
                       */
                      function relayMessage(
                          address _target,
                          address _sender,
                          bytes memory _message,
                          uint256 _messageNonce,
                          L2MessageInclusionProof memory _proof
                      ) public nonReentrant whenNotPaused {
                          bytes memory xDomainCalldata = Lib_CrossDomainUtils.encodeXDomainCalldata(
                              _target,
                              _sender,
                              _message,
                              _messageNonce
                          );
                          require(
                              _verifyXDomainMessage(xDomainCalldata, _proof) == true,
                              "Provided message could not be verified."
                          );
                          bytes32 xDomainCalldataHash = keccak256(xDomainCalldata);
                          require(
                              successfulMessages[xDomainCalldataHash] == false,
                              "Provided message has already been received."
                          );
                          require(
                              blockedMessages[xDomainCalldataHash] == false,
                              "Provided message has been blocked."
                          );
                          require(
                              _target != resolve("CanonicalTransactionChain"),
                              "Cannot send L2->L1 messages to L1 system contracts."
                          );
                          xDomainMsgSender = _sender;
                          (bool success, ) = _target.call(_message);
                          xDomainMsgSender = Lib_DefaultValues.DEFAULT_XDOMAIN_SENDER;
                          // Mark the message as received if the call was successful. Ensures that a message can be
                          // relayed multiple times in the case that the call reverted.
                          if (success == true) {
                              successfulMessages[xDomainCalldataHash] = true;
                              emit RelayedMessage(xDomainCalldataHash);
                          } else {
                              emit FailedRelayedMessage(xDomainCalldataHash);
                          }
                          // Store an identifier that can be used to prove that the given message was relayed by some
                          // user. Gives us an easy way to pay relayers for their work.
                          bytes32 relayId = keccak256(abi.encodePacked(xDomainCalldata, msg.sender, block.number));
                          relayedMessages[relayId] = true;
                      }
                      /**
                       * Replays a cross domain message to the target messenger.
                       * @inheritdoc IL1CrossDomainMessenger
                       */
                      function replayMessage(
                          address _target,
                          address _sender,
                          bytes memory _message,
                          uint256 _queueIndex,
                          uint32 _oldGasLimit,
                          uint32 _newGasLimit
                      ) public {
                          // Verify that the message is in the queue:
                          address canonicalTransactionChain = resolve("CanonicalTransactionChain");
                          Lib_OVMCodec.QueueElement memory element = ICanonicalTransactionChain(
                              canonicalTransactionChain
                          ).getQueueElement(_queueIndex);
                          // Compute the calldata that was originally used to send the message.
                          bytes memory xDomainCalldata = Lib_CrossDomainUtils.encodeXDomainCalldata(
                              _target,
                              _sender,
                              _message,
                              _queueIndex
                          );
                          // Compute the transactionHash
                          bytes32 transactionHash = keccak256(
                              abi.encode(
                                  AddressAliasHelper.applyL1ToL2Alias(address(this)),
                                  Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER,
                                  _oldGasLimit,
                                  xDomainCalldata
                              )
                          );
                          // Now check that the provided message data matches the one in the queue element.
                          require(
                              transactionHash == element.transactionHash,
                              "Provided message has not been enqueued."
                          );
                          // Send the same message but with the new gas limit.
                          _sendXDomainMessage(canonicalTransactionChain, xDomainCalldata, _newGasLimit);
                      }
                      /**********************
                       * Internal Functions *
                       **********************/
                      /**
                       * Verifies that the given message is valid.
                       * @param _xDomainCalldata Calldata to verify.
                       * @param _proof Inclusion proof for the message.
                       * @return Whether or not the provided message is valid.
                       */
                      function _verifyXDomainMessage(
                          bytes memory _xDomainCalldata,
                          L2MessageInclusionProof memory _proof
                      ) internal view returns (bool) {
                          return (_verifyStateRootProof(_proof) && _verifyStorageProof(_xDomainCalldata, _proof));
                      }
                      /**
                       * Verifies that the state root within an inclusion proof is valid.
                       * @param _proof Message inclusion proof.
                       * @return Whether or not the provided proof is valid.
                       */
                      function _verifyStateRootProof(L2MessageInclusionProof memory _proof)
                          internal
                          view
                          returns (bool)
                      {
                          IStateCommitmentChain ovmStateCommitmentChain = IStateCommitmentChain(
                              resolve("StateCommitmentChain")
                          );
                          return (ovmStateCommitmentChain.insideFraudProofWindow(_proof.stateRootBatchHeader) ==
                              false &&
                              ovmStateCommitmentChain.verifyStateCommitment(
                                  _proof.stateRoot,
                                  _proof.stateRootBatchHeader,
                                  _proof.stateRootProof
                              ));
                      }
                      /**
                       * Verifies that the storage proof within an inclusion proof is valid.
                       * @param _xDomainCalldata Encoded message calldata.
                       * @param _proof Message inclusion proof.
                       * @return Whether or not the provided proof is valid.
                       */
                      function _verifyStorageProof(
                          bytes memory _xDomainCalldata,
                          L2MessageInclusionProof memory _proof
                      ) internal view returns (bool) {
                          bytes32 storageKey = keccak256(
                              abi.encodePacked(
                                  keccak256(
                                      abi.encodePacked(
                                          _xDomainCalldata,
                                          Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER
                                      )
                                  ),
                                  uint256(0)
                              )
                          );
                          (bool exists, bytes memory encodedMessagePassingAccount) = Lib_SecureMerkleTrie.get(
                              abi.encodePacked(Lib_PredeployAddresses.L2_TO_L1_MESSAGE_PASSER),
                              _proof.stateTrieWitness,
                              _proof.stateRoot
                          );
                          require(
                              exists == true,
                              "Message passing predeploy has not been initialized or invalid proof provided."
                          );
                          Lib_OVMCodec.EVMAccount memory account = Lib_OVMCodec.decodeEVMAccount(
                              encodedMessagePassingAccount
                          );
                          return
                              Lib_SecureMerkleTrie.verifyInclusionProof(
                                  abi.encodePacked(storageKey),
                                  abi.encodePacked(uint8(1)),
                                  _proof.storageTrieWitness,
                                  account.storageRoot
                              );
                      }
                      /**
                       * Sends a cross domain message.
                       * @param _canonicalTransactionChain Address of the CanonicalTransactionChain instance.
                       * @param _message Message to send.
                       * @param _gasLimit OVM gas limit for the message.
                       */
                      function _sendXDomainMessage(
                          address _canonicalTransactionChain,
                          bytes memory _message,
                          uint256 _gasLimit
                      ) internal {
                          ICanonicalTransactionChain(_canonicalTransactionChain).enqueue(
                              Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER,
                              _gasLimit,
                              _message
                          );
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >0.5.0 <0.9.0;
                  /* Library Imports */
                  import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
                  /* Interface Imports */
                  import { IChainStorageContainer } from "./IChainStorageContainer.sol";
                  /**
                   * @title ICanonicalTransactionChain
                   */
                  interface ICanonicalTransactionChain {
                      /**********
                       * Events *
                       **********/
                      event L2GasParamsUpdated(
                          uint256 l2GasDiscountDivisor,
                          uint256 enqueueGasCost,
                          uint256 enqueueL2GasPrepaid
                      );
                      event TransactionEnqueued(
                          address indexed _l1TxOrigin,
                          address indexed _target,
                          uint256 _gasLimit,
                          bytes _data,
                          uint256 indexed _queueIndex,
                          uint256 _timestamp
                      );
                      event QueueBatchAppended(
                          uint256 _startingQueueIndex,
                          uint256 _numQueueElements,
                          uint256 _totalElements
                      );
                      event SequencerBatchAppended(
                          uint256 _startingQueueIndex,
                          uint256 _numQueueElements,
                          uint256 _totalElements
                      );
                      event TransactionBatchAppended(
                          uint256 indexed _batchIndex,
                          bytes32 _batchRoot,
                          uint256 _batchSize,
                          uint256 _prevTotalElements,
                          bytes _extraData
                      );
                      /***********
                       * Structs *
                       ***********/
                      struct BatchContext {
                          uint256 numSequencedTransactions;
                          uint256 numSubsequentQueueTransactions;
                          uint256 timestamp;
                          uint256 blockNumber;
                      }
                      /*******************************
                       * Authorized Setter Functions *
                       *******************************/
                      /**
                       * Allows the Burn Admin to update the parameters which determine the amount of gas to burn.
                       * The value of enqueueL2GasPrepaid is immediately updated as well.
                       */
                      function setGasParams(uint256 _l2GasDiscountDivisor, uint256 _enqueueGasCost) external;
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * Accesses the batch storage container.
                       * @return Reference to the batch storage container.
                       */
                      function batches() external view returns (IChainStorageContainer);
                      /**
                       * Retrieves the total number of elements submitted.
                       * @return _totalElements Total submitted elements.
                       */
                      function getTotalElements() external view returns (uint256 _totalElements);
                      /**
                       * Retrieves the total number of batches submitted.
                       * @return _totalBatches Total submitted batches.
                       */
                      function getTotalBatches() external view returns (uint256 _totalBatches);
                      /**
                       * Returns the index of the next element to be enqueued.
                       * @return Index for the next queue element.
                       */
                      function getNextQueueIndex() external view returns (uint40);
                      /**
                       * Gets the queue element at a particular index.
                       * @param _index Index of the queue element to access.
                       * @return _element Queue element at the given index.
                       */
                      function getQueueElement(uint256 _index)
                          external
                          view
                          returns (Lib_OVMCodec.QueueElement memory _element);
                      /**
                       * Returns the timestamp of the last transaction.
                       * @return Timestamp for the last transaction.
                       */
                      function getLastTimestamp() external view returns (uint40);
                      /**
                       * Returns the blocknumber of the last transaction.
                       * @return Blocknumber for the last transaction.
                       */
                      function getLastBlockNumber() external view returns (uint40);
                      /**
                       * Get the number of queue elements which have not yet been included.
                       * @return Number of pending queue elements.
                       */
                      function getNumPendingQueueElements() external view returns (uint40);
                      /**
                       * Retrieves the length of the queue, including
                       * both pending and canonical transactions.
                       * @return Length of the queue.
                       */
                      function getQueueLength() external view returns (uint40);
                      /**
                       * Adds a transaction to the queue.
                       * @param _target Target contract to send the transaction to.
                       * @param _gasLimit Gas limit for the given transaction.
                       * @param _data Transaction data.
                       */
                      function enqueue(
                          address _target,
                          uint256 _gasLimit,
                          bytes memory _data
                      ) external;
                      /**
                       * Allows the sequencer to append a batch of transactions.
                       * @dev This function uses a custom encoding scheme for efficiency reasons.
                       * .param _shouldStartAtElement Specific batch we expect to start appending to.
                       * .param _totalElementsToAppend Total number of batch elements we expect to append.
                       * .param _contexts Array of batch contexts.
                       * .param _transactionDataFields Array of raw transaction data.
                       */
                      function appendSequencerBatch(
                          // uint40 _shouldStartAtElement,
                          // uint24 _totalElementsToAppend,
                          // BatchContext[] _contexts,
                          // bytes[] _transactionDataFields
                      ) external;
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >0.5.0 <0.9.0;
                  /**
                   * @title IChainStorageContainer
                   */
                  interface IChainStorageContainer {
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * Sets the container's global metadata field. We're using `bytes27` here because we use five
                       * bytes to maintain the length of the underlying data structure, meaning we have an extra
                       * 27 bytes to store arbitrary data.
                       * @param _globalMetadata New global metadata to set.
                       */
                      function setGlobalMetadata(bytes27 _globalMetadata) external;
                      /**
                       * Retrieves the container's global metadata field.
                       * @return Container global metadata field.
                       */
                      function getGlobalMetadata() external view returns (bytes27);
                      /**
                       * Retrieves the number of objects stored in the container.
                       * @return Number of objects in the container.
                       */
                      function length() external view returns (uint256);
                      /**
                       * Pushes an object into the container.
                       * @param _object A 32 byte value to insert into the container.
                       */
                      function push(bytes32 _object) external;
                      /**
                       * Pushes an object into the container. Function allows setting the global metadata since
                       * we'll need to touch the "length" storage slot anyway, which also contains the global
                       * metadata (it's an optimization).
                       * @param _object A 32 byte value to insert into the container.
                       * @param _globalMetadata New global metadata for the container.
                       */
                      function push(bytes32 _object, bytes27 _globalMetadata) external;
                      /**
                       * Retrieves an object from the container.
                       * @param _index Index of the particular object to access.
                       * @return 32 byte object value.
                       */
                      function get(uint256 _index) external view returns (bytes32);
                      /**
                       * Removes all objects after and including a given index.
                       * @param _index Object index to delete from.
                       */
                      function deleteElementsAfterInclusive(uint256 _index) external;
                      /**
                       * Removes all objects after and including a given index. Also allows setting the global
                       * metadata field.
                       * @param _index Object index to delete from.
                       * @param _globalMetadata New global metadata for the container.
                       */
                      function deleteElementsAfterInclusive(uint256 _index, bytes27 _globalMetadata) external;
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >0.5.0 <0.9.0;
                  /* Library Imports */
                  import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
                  /**
                   * @title IStateCommitmentChain
                   */
                  interface IStateCommitmentChain {
                      /**********
                       * Events *
                       **********/
                      event StateBatchAppended(
                          uint256 indexed _batchIndex,
                          bytes32 _batchRoot,
                          uint256 _batchSize,
                          uint256 _prevTotalElements,
                          bytes _extraData
                      );
                      event StateBatchDeleted(uint256 indexed _batchIndex, bytes32 _batchRoot);
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * Retrieves the total number of elements submitted.
                       * @return _totalElements Total submitted elements.
                       */
                      function getTotalElements() external view returns (uint256 _totalElements);
                      /**
                       * Retrieves the total number of batches submitted.
                       * @return _totalBatches Total submitted batches.
                       */
                      function getTotalBatches() external view returns (uint256 _totalBatches);
                      /**
                       * Retrieves the timestamp of the last batch submitted by the sequencer.
                       * @return _lastSequencerTimestamp Last sequencer batch timestamp.
                       */
                      function getLastSequencerTimestamp() external view returns (uint256 _lastSequencerTimestamp);
                      /**
                       * Appends a batch of state roots to the chain.
                       * @param _batch Batch of state roots.
                       * @param _shouldStartAtElement Index of the element at which this batch should start.
                       */
                      function appendStateBatch(bytes32[] calldata _batch, uint256 _shouldStartAtElement) external;
                      /**
                       * Deletes all state roots after (and including) a given batch.
                       * @param _batchHeader Header of the batch to start deleting from.
                       */
                      function deleteStateBatch(Lib_OVMCodec.ChainBatchHeader memory _batchHeader) external;
                      /**
                       * Verifies a batch inclusion proof.
                       * @param _element Hash of the element to verify a proof for.
                       * @param _batchHeader Header of the batch in which the element was included.
                       * @param _proof Merkle inclusion proof for the element.
                       */
                      function verifyStateCommitment(
                          bytes32 _element,
                          Lib_OVMCodec.ChainBatchHeader memory _batchHeader,
                          Lib_OVMCodec.ChainInclusionProof memory _proof
                      ) external view returns (bool _verified);
                      /**
                       * Checks whether a given batch is still inside its fraud proof window.
                       * @param _batchHeader Header of the batch to check.
                       * @return _inside Whether or not the batch is inside the fraud proof window.
                       */
                      function insideFraudProofWindow(Lib_OVMCodec.ChainBatchHeader memory _batchHeader)
                          external
                          view
                          returns (bool _inside);
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >0.5.0 <0.9.0;
                  /**
                   * @title ICrossDomainMessenger
                   */
                  interface ICrossDomainMessenger {
                      /**********
                       * Events *
                       **********/
                      event SentMessage(
                          address indexed target,
                          address sender,
                          bytes message,
                          uint256 messageNonce,
                          uint256 gasLimit
                      );
                      event RelayedMessage(bytes32 indexed msgHash);
                      event FailedRelayedMessage(bytes32 indexed msgHash);
                      /*************
                       * Variables *
                       *************/
                      function xDomainMessageSender() external view returns (address);
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * Sends a cross domain message to the target messenger.
                       * @param _target Target contract address.
                       * @param _message Message to send to the target.
                       * @param _gasLimit Gas limit for the provided message.
                       */
                      function sendMessage(
                          address _target,
                          bytes calldata _message,
                          uint32 _gasLimit
                      ) external;
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /* Library Imports */
                  import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol";
                  /**
                   * @title Lib_CrossDomainUtils
                   */
                  library Lib_CrossDomainUtils {
                      /**
                       * Generates the correct cross domain calldata for a message.
                       * @param _target Target contract address.
                       * @param _sender Message sender address.
                       * @param _message Message to send to the target.
                       * @param _messageNonce Nonce for the provided message.
                       * @return ABI encoded cross domain calldata.
                       */
                      function encodeXDomainCalldata(
                          address _target,
                          address _sender,
                          bytes memory _message,
                          uint256 _messageNonce
                      ) internal pure returns (bytes memory) {
                          return
                              abi.encodeWithSignature(
                                  "relayMessage(address,address,bytes,uint256)",
                                  _target,
                                  _sender,
                                  _message,
                                  _messageNonce
                              );
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /* Library Imports */
                  import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol";
                  import { Lib_RLPWriter } from "../rlp/Lib_RLPWriter.sol";
                  import { Lib_BytesUtils } from "../utils/Lib_BytesUtils.sol";
                  import { Lib_Bytes32Utils } from "../utils/Lib_Bytes32Utils.sol";
                  /**
                   * @title Lib_OVMCodec
                   */
                  library Lib_OVMCodec {
                      /*********
                       * Enums *
                       *********/
                      enum QueueOrigin {
                          SEQUENCER_QUEUE,
                          L1TOL2_QUEUE
                      }
                      /***********
                       * Structs *
                       ***********/
                      struct EVMAccount {
                          uint256 nonce;
                          uint256 balance;
                          bytes32 storageRoot;
                          bytes32 codeHash;
                      }
                      struct ChainBatchHeader {
                          uint256 batchIndex;
                          bytes32 batchRoot;
                          uint256 batchSize;
                          uint256 prevTotalElements;
                          bytes extraData;
                      }
                      struct ChainInclusionProof {
                          uint256 index;
                          bytes32[] siblings;
                      }
                      struct Transaction {
                          uint256 timestamp;
                          uint256 blockNumber;
                          QueueOrigin l1QueueOrigin;
                          address l1TxOrigin;
                          address entrypoint;
                          uint256 gasLimit;
                          bytes data;
                      }
                      struct TransactionChainElement {
                          bool isSequenced;
                          uint256 queueIndex; // QUEUED TX ONLY
                          uint256 timestamp; // SEQUENCER TX ONLY
                          uint256 blockNumber; // SEQUENCER TX ONLY
                          bytes txData; // SEQUENCER TX ONLY
                      }
                      struct QueueElement {
                          bytes32 transactionHash;
                          uint40 timestamp;
                          uint40 blockNumber;
                      }
                      /**********************
                       * Internal Functions *
                       **********************/
                      /**
                       * Encodes a standard OVM transaction.
                       * @param _transaction OVM transaction to encode.
                       * @return Encoded transaction bytes.
                       */
                      function encodeTransaction(Transaction memory _transaction)
                          internal
                          pure
                          returns (bytes memory)
                      {
                          return
                              abi.encodePacked(
                                  _transaction.timestamp,
                                  _transaction.blockNumber,
                                  _transaction.l1QueueOrigin,
                                  _transaction.l1TxOrigin,
                                  _transaction.entrypoint,
                                  _transaction.gasLimit,
                                  _transaction.data
                              );
                      }
                      /**
                       * Hashes a standard OVM transaction.
                       * @param _transaction OVM transaction to encode.
                       * @return Hashed transaction
                       */
                      function hashTransaction(Transaction memory _transaction) internal pure returns (bytes32) {
                          return keccak256(encodeTransaction(_transaction));
                      }
                      /**
                       * @notice Decodes an RLP-encoded account state into a useful struct.
                       * @param _encoded RLP-encoded account state.
                       * @return Account state struct.
                       */
                      function decodeEVMAccount(bytes memory _encoded) internal pure returns (EVMAccount memory) {
                          Lib_RLPReader.RLPItem[] memory accountState = Lib_RLPReader.readList(_encoded);
                          return
                              EVMAccount({
                                  nonce: Lib_RLPReader.readUint256(accountState[0]),
                                  balance: Lib_RLPReader.readUint256(accountState[1]),
                                  storageRoot: Lib_RLPReader.readBytes32(accountState[2]),
                                  codeHash: Lib_RLPReader.readBytes32(accountState[3])
                              });
                      }
                      /**
                       * Calculates a hash for a given batch header.
                       * @param _batchHeader Header to hash.
                       * @return Hash of the header.
                       */
                      function hashBatchHeader(Lib_OVMCodec.ChainBatchHeader memory _batchHeader)
                          internal
                          pure
                          returns (bytes32)
                      {
                          return
                              keccak256(
                                  abi.encode(
                                      _batchHeader.batchRoot,
                                      _batchHeader.batchSize,
                                      _batchHeader.prevTotalElements,
                                      _batchHeader.extraData
                                  )
                              );
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /**
                   * @title Lib_DefaultValues
                   */
                  library Lib_DefaultValues {
                      // The default x-domain message sender being set to a non-zero value makes
                      // deployment a bit more expensive, but in exchange the refund on every call to
                      // `relayMessage` by the L1 and L2 messengers will be higher.
                      address internal constant DEFAULT_XDOMAIN_SENDER = 0x000000000000000000000000000000000000dEaD;
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /**
                   * @title Lib_PredeployAddresses
                   */
                  library Lib_PredeployAddresses {
                      address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000;
                      address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001;
                      address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002;
                      address payable internal constant OVM_ETH = payable(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000);
                      address internal constant L2_CROSS_DOMAIN_MESSENGER =
                          0x4200000000000000000000000000000000000007;
                      address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008;
                      address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009;
                      address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;
                      address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;
                      address internal constant L2_STANDARD_TOKEN_FACTORY =
                          0x4200000000000000000000000000000000000012;
                      address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013;
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /* External Imports */
                  import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
                  /**
                   * @title Lib_AddressManager
                   */
                  contract Lib_AddressManager is Ownable {
                      /**********
                       * Events *
                       **********/
                      event AddressSet(string indexed _name, address _newAddress, address _oldAddress);
                      /*************
                       * Variables *
                       *************/
                      mapping(bytes32 => address) private addresses;
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * Changes the address associated with a particular name.
                       * @param _name String name to associate an address with.
                       * @param _address Address to associate with the name.
                       */
                      function setAddress(string memory _name, address _address) external onlyOwner {
                          bytes32 nameHash = _getNameHash(_name);
                          address oldAddress = addresses[nameHash];
                          addresses[nameHash] = _address;
                          emit AddressSet(_name, _address, oldAddress);
                      }
                      /**
                       * Retrieves the address associated with a given name.
                       * @param _name Name to retrieve an address for.
                       * @return Address associated with the given name.
                       */
                      function getAddress(string memory _name) external view returns (address) {
                          return addresses[_getNameHash(_name)];
                      }
                      /**********************
                       * Internal Functions *
                       **********************/
                      /**
                       * Computes the hash of a name.
                       * @param _name Name to compute a hash for.
                       * @return Hash of the given name.
                       */
                      function _getNameHash(string memory _name) internal pure returns (bytes32) {
                          return keccak256(abi.encodePacked(_name));
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /* Library Imports */
                  import { Lib_AddressManager } from "./Lib_AddressManager.sol";
                  /**
                   * @title Lib_AddressResolver
                   */
                  abstract contract Lib_AddressResolver {
                      /*************
                       * Variables *
                       *************/
                      Lib_AddressManager public libAddressManager;
                      /***************
                       * Constructor *
                       ***************/
                      /**
                       * @param _libAddressManager Address of the Lib_AddressManager.
                       */
                      constructor(address _libAddressManager) {
                          libAddressManager = Lib_AddressManager(_libAddressManager);
                      }
                      /********************
                       * Public Functions *
                       ********************/
                      /**
                       * Resolves the address associated with a given name.
                       * @param _name Name to resolve an address for.
                       * @return Address associated with the given name.
                       */
                      function resolve(string memory _name) public view returns (address) {
                          return libAddressManager.getAddress(_name);
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /**
                   * @title Lib_RLPReader
                   * @dev Adapted from "RLPReader" by Hamdi Allam ([email protected]).
                   */
                  library Lib_RLPReader {
                      /*************
                       * Constants *
                       *************/
                      uint256 internal constant MAX_LIST_LENGTH = 32;
                      /*********
                       * Enums *
                       *********/
                      enum RLPItemType {
                          DATA_ITEM,
                          LIST_ITEM
                      }
                      /***********
                       * Structs *
                       ***********/
                      struct RLPItem {
                          uint256 length;
                          uint256 ptr;
                      }
                      /**********************
                       * Internal Functions *
                       **********************/
                      /**
                       * Converts bytes to a reference to memory position and length.
                       * @param _in Input bytes to convert.
                       * @return Output memory reference.
                       */
                      function toRLPItem(bytes memory _in) internal pure returns (RLPItem memory) {
                          uint256 ptr;
                          assembly {
                              ptr := add(_in, 32)
                          }
                          return RLPItem({ length: _in.length, ptr: ptr });
                      }
                      /**
                       * Reads an RLP list value into a list of RLP items.
                       * @param _in RLP list value.
                       * @return Decoded RLP list items.
                       */
                      function readList(RLPItem memory _in) internal pure returns (RLPItem[] memory) {
                          (uint256 listOffset, , RLPItemType itemType) = _decodeLength(_in);
                          require(itemType == RLPItemType.LIST_ITEM, "Invalid RLP list value.");
                          // Solidity in-memory arrays can't be increased in size, but *can* be decreased in size by
                          // writing to the length. Since we can't know the number of RLP items without looping over
                          // the entire input, we'd have to loop twice to accurately size this array. It's easier to
                          // simply set a reasonable maximum list length and decrease the size before we finish.
                          RLPItem[] memory out = new RLPItem[](MAX_LIST_LENGTH);
                          uint256 itemCount = 0;
                          uint256 offset = listOffset;
                          while (offset < _in.length) {
                              require(itemCount < MAX_LIST_LENGTH, "Provided RLP list exceeds max list length.");
                              (uint256 itemOffset, uint256 itemLength, ) = _decodeLength(
                                  RLPItem({ length: _in.length - offset, ptr: _in.ptr + offset })
                              );
                              out[itemCount] = RLPItem({ length: itemLength + itemOffset, ptr: _in.ptr + offset });
                              itemCount += 1;
                              offset += itemOffset + itemLength;
                          }
                          // Decrease the array size to match the actual item count.
                          assembly {
                              mstore(out, itemCount)
                          }
                          return out;
                      }
                      /**
                       * Reads an RLP list value into a list of RLP items.
                       * @param _in RLP list value.
                       * @return Decoded RLP list items.
                       */
                      function readList(bytes memory _in) internal pure returns (RLPItem[] memory) {
                          return readList(toRLPItem(_in));
                      }
                      /**
                       * Reads an RLP bytes value into bytes.
                       * @param _in RLP bytes value.
                       * @return Decoded bytes.
                       */
                      function readBytes(RLPItem memory _in) internal pure returns (bytes memory) {
                          (uint256 itemOffset, uint256 itemLength, RLPItemType itemType) = _decodeLength(_in);
                          require(itemType == RLPItemType.DATA_ITEM, "Invalid RLP bytes value.");
                          return _copy(_in.ptr, itemOffset, itemLength);
                      }
                      /**
                       * Reads an RLP bytes value into bytes.
                       * @param _in RLP bytes value.
                       * @return Decoded bytes.
                       */
                      function readBytes(bytes memory _in) internal pure returns (bytes memory) {
                          return readBytes(toRLPItem(_in));
                      }
                      /**
                       * Reads an RLP string value into a string.
                       * @param _in RLP string value.
                       * @return Decoded string.
                       */
                      function readString(RLPItem memory _in) internal pure returns (string memory) {
                          return string(readBytes(_in));
                      }
                      /**
                       * Reads an RLP string value into a string.
                       * @param _in RLP string value.
                       * @return Decoded string.
                       */
                      function readString(bytes memory _in) internal pure returns (string memory) {
                          return readString(toRLPItem(_in));
                      }
                      /**
                       * Reads an RLP bytes32 value into a bytes32.
                       * @param _in RLP bytes32 value.
                       * @return Decoded bytes32.
                       */
                      function readBytes32(RLPItem memory _in) internal pure returns (bytes32) {
                          require(_in.length <= 33, "Invalid RLP bytes32 value.");
                          (uint256 itemOffset, uint256 itemLength, RLPItemType itemType) = _decodeLength(_in);
                          require(itemType == RLPItemType.DATA_ITEM, "Invalid RLP bytes32 value.");
                          uint256 ptr = _in.ptr + itemOffset;
                          bytes32 out;
                          assembly {
                              out := mload(ptr)
                              // Shift the bytes over to match the item size.
                              if lt(itemLength, 32) {
                                  out := div(out, exp(256, sub(32, itemLength)))
                              }
                          }
                          return out;
                      }
                      /**
                       * Reads an RLP bytes32 value into a bytes32.
                       * @param _in RLP bytes32 value.
                       * @return Decoded bytes32.
                       */
                      function readBytes32(bytes memory _in) internal pure returns (bytes32) {
                          return readBytes32(toRLPItem(_in));
                      }
                      /**
                       * Reads an RLP uint256 value into a uint256.
                       * @param _in RLP uint256 value.
                       * @return Decoded uint256.
                       */
                      function readUint256(RLPItem memory _in) internal pure returns (uint256) {
                          return uint256(readBytes32(_in));
                      }
                      /**
                       * Reads an RLP uint256 value into a uint256.
                       * @param _in RLP uint256 value.
                       * @return Decoded uint256.
                       */
                      function readUint256(bytes memory _in) internal pure returns (uint256) {
                          return readUint256(toRLPItem(_in));
                      }
                      /**
                       * Reads an RLP bool value into a bool.
                       * @param _in RLP bool value.
                       * @return Decoded bool.
                       */
                      function readBool(RLPItem memory _in) internal pure returns (bool) {
                          require(_in.length == 1, "Invalid RLP boolean value.");
                          uint256 ptr = _in.ptr;
                          uint256 out;
                          assembly {
                              out := byte(0, mload(ptr))
                          }
                          require(out == 0 || out == 1, "Lib_RLPReader: Invalid RLP boolean value, must be 0 or 1");
                          return out != 0;
                      }
                      /**
                       * Reads an RLP bool value into a bool.
                       * @param _in RLP bool value.
                       * @return Decoded bool.
                       */
                      function readBool(bytes memory _in) internal pure returns (bool) {
                          return readBool(toRLPItem(_in));
                      }
                      /**
                       * Reads an RLP address value into a address.
                       * @param _in RLP address value.
                       * @return Decoded address.
                       */
                      function readAddress(RLPItem memory _in) internal pure returns (address) {
                          if (_in.length == 1) {
                              return address(0);
                          }
                          require(_in.length == 21, "Invalid RLP address value.");
                          return address(uint160(readUint256(_in)));
                      }
                      /**
                       * Reads an RLP address value into a address.
                       * @param _in RLP address value.
                       * @return Decoded address.
                       */
                      function readAddress(bytes memory _in) internal pure returns (address) {
                          return readAddress(toRLPItem(_in));
                      }
                      /**
                       * Reads the raw bytes of an RLP item.
                       * @param _in RLP item to read.
                       * @return Raw RLP bytes.
                       */
                      function readRawBytes(RLPItem memory _in) internal pure returns (bytes memory) {
                          return _copy(_in);
                      }
                      /*********************
                       * Private Functions *
                       *********************/
                      /**
                       * Decodes the length of an RLP item.
                       * @param _in RLP item to decode.
                       * @return Offset of the encoded data.
                       * @return Length of the encoded data.
                       * @return RLP item type (LIST_ITEM or DATA_ITEM).
                       */
                      function _decodeLength(RLPItem memory _in)
                          private
                          pure
                          returns (
                              uint256,
                              uint256,
                              RLPItemType
                          )
                      {
                          require(_in.length > 0, "RLP item cannot be null.");
                          uint256 ptr = _in.ptr;
                          uint256 prefix;
                          assembly {
                              prefix := byte(0, mload(ptr))
                          }
                          if (prefix <= 0x7f) {
                              // Single byte.
                              return (0, 1, RLPItemType.DATA_ITEM);
                          } else if (prefix <= 0xb7) {
                              // Short string.
                              uint256 strLen = prefix - 0x80;
                              require(_in.length > strLen, "Invalid RLP short string.");
                              return (1, strLen, RLPItemType.DATA_ITEM);
                          } else if (prefix <= 0xbf) {
                              // Long string.
                              uint256 lenOfStrLen = prefix - 0xb7;
                              require(_in.length > lenOfStrLen, "Invalid RLP long string length.");
                              uint256 strLen;
                              assembly {
                                  // Pick out the string length.
                                  strLen := div(mload(add(ptr, 1)), exp(256, sub(32, lenOfStrLen)))
                              }
                              require(_in.length > lenOfStrLen + strLen, "Invalid RLP long string.");
                              return (1 + lenOfStrLen, strLen, RLPItemType.DATA_ITEM);
                          } else if (prefix <= 0xf7) {
                              // Short list.
                              uint256 listLen = prefix - 0xc0;
                              require(_in.length > listLen, "Invalid RLP short list.");
                              return (1, listLen, RLPItemType.LIST_ITEM);
                          } else {
                              // Long list.
                              uint256 lenOfListLen = prefix - 0xf7;
                              require(_in.length > lenOfListLen, "Invalid RLP long list length.");
                              uint256 listLen;
                              assembly {
                                  // Pick out the list length.
                                  listLen := div(mload(add(ptr, 1)), exp(256, sub(32, lenOfListLen)))
                              }
                              require(_in.length > lenOfListLen + listLen, "Invalid RLP long list.");
                              return (1 + lenOfListLen, listLen, RLPItemType.LIST_ITEM);
                          }
                      }
                      /**
                       * Copies the bytes from a memory location.
                       * @param _src Pointer to the location to read from.
                       * @param _offset Offset to start reading from.
                       * @param _length Number of bytes to read.
                       * @return Copied bytes.
                       */
                      function _copy(
                          uint256 _src,
                          uint256 _offset,
                          uint256 _length
                      ) private pure returns (bytes memory) {
                          bytes memory out = new bytes(_length);
                          if (out.length == 0) {
                              return out;
                          }
                          uint256 src = _src + _offset;
                          uint256 dest;
                          assembly {
                              dest := add(out, 32)
                          }
                          // Copy over as many complete words as we can.
                          for (uint256 i = 0; i < _length / 32; i++) {
                              assembly {
                                  mstore(dest, mload(src))
                              }
                              src += 32;
                              dest += 32;
                          }
                          // Pick out the remaining bytes.
                          uint256 mask;
                          unchecked {
                              mask = 256**(32 - (_length % 32)) - 1;
                          }
                          assembly {
                              mstore(dest, or(and(mload(src), not(mask)), and(mload(dest), mask)))
                          }
                          return out;
                      }
                      /**
                       * Copies an RLP item into bytes.
                       * @param _in RLP item to copy.
                       * @return Copied bytes.
                       */
                      function _copy(RLPItem memory _in) private pure returns (bytes memory) {
                          return _copy(_in.ptr, 0, _in.length);
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /**
                   * @title Lib_RLPWriter
                   * @author Bakaoh (with modifications)
                   */
                  library Lib_RLPWriter {
                      /**********************
                       * Internal Functions *
                       **********************/
                      /**
                       * RLP encodes a byte string.
                       * @param _in The byte string to encode.
                       * @return The RLP encoded string in bytes.
                       */
                      function writeBytes(bytes memory _in) internal pure returns (bytes memory) {
                          bytes memory encoded;
                          if (_in.length == 1 && uint8(_in[0]) < 128) {
                              encoded = _in;
                          } else {
                              encoded = abi.encodePacked(_writeLength(_in.length, 128), _in);
                          }
                          return encoded;
                      }
                      /**
                       * RLP encodes a list of RLP encoded byte byte strings.
                       * @param _in The list of RLP encoded byte strings.
                       * @return The RLP encoded list of items in bytes.
                       */
                      function writeList(bytes[] memory _in) internal pure returns (bytes memory) {
                          bytes memory list = _flatten(_in);
                          return abi.encodePacked(_writeLength(list.length, 192), list);
                      }
                      /**
                       * RLP encodes a string.
                       * @param _in The string to encode.
                       * @return The RLP encoded string in bytes.
                       */
                      function writeString(string memory _in) internal pure returns (bytes memory) {
                          return writeBytes(bytes(_in));
                      }
                      /**
                       * RLP encodes an address.
                       * @param _in The address to encode.
                       * @return The RLP encoded address in bytes.
                       */
                      function writeAddress(address _in) internal pure returns (bytes memory) {
                          return writeBytes(abi.encodePacked(_in));
                      }
                      /**
                       * RLP encodes a uint.
                       * @param _in The uint256 to encode.
                       * @return The RLP encoded uint256 in bytes.
                       */
                      function writeUint(uint256 _in) internal pure returns (bytes memory) {
                          return writeBytes(_toBinary(_in));
                      }
                      /**
                       * RLP encodes a bool.
                       * @param _in The bool to encode.
                       * @return The RLP encoded bool in bytes.
                       */
                      function writeBool(bool _in) internal pure returns (bytes memory) {
                          bytes memory encoded = new bytes(1);
                          encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80));
                          return encoded;
                      }
                      /*********************
                       * Private Functions *
                       *********************/
                      /**
                       * Encode the first byte, followed by the `len` in binary form if `length` is more than 55.
                       * @param _len The length of the string or the payload.
                       * @param _offset 128 if item is string, 192 if item is list.
                       * @return RLP encoded bytes.
                       */
                      function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) {
                          bytes memory encoded;
                          if (_len < 56) {
                              encoded = new bytes(1);
                              encoded[0] = bytes1(uint8(_len) + uint8(_offset));
                          } else {
                              uint256 lenLen;
                              uint256 i = 1;
                              while (_len / i != 0) {
                                  lenLen++;
                                  i *= 256;
                              }
                              encoded = new bytes(lenLen + 1);
                              encoded[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55);
                              for (i = 1; i <= lenLen; i++) {
                                  encoded[i] = bytes1(uint8((_len / (256**(lenLen - i))) % 256));
                              }
                          }
                          return encoded;
                      }
                      /**
                       * Encode integer in big endian binary form with no leading zeroes.
                       * @notice TODO: This should be optimized with assembly to save gas costs.
                       * @param _x The integer to encode.
                       * @return RLP encoded bytes.
                       */
                      function _toBinary(uint256 _x) private pure returns (bytes memory) {
                          bytes memory b = abi.encodePacked(_x);
                          uint256 i = 0;
                          for (; i < 32; i++) {
                              if (b[i] != 0) {
                                  break;
                              }
                          }
                          bytes memory res = new bytes(32 - i);
                          for (uint256 j = 0; j < res.length; j++) {
                              res[j] = b[i++];
                          }
                          return res;
                      }
                      /**
                       * Copies a piece of memory to another location.
                       * @notice From: https://github.com/Arachnid/solidity-stringutils/blob/master/src/strings.sol.
                       * @param _dest Destination location.
                       * @param _src Source location.
                       * @param _len Length of memory to copy.
                       */
                      function _memcpy(
                          uint256 _dest,
                          uint256 _src,
                          uint256 _len
                      ) private pure {
                          uint256 dest = _dest;
                          uint256 src = _src;
                          uint256 len = _len;
                          for (; len >= 32; len -= 32) {
                              assembly {
                                  mstore(dest, mload(src))
                              }
                              dest += 32;
                              src += 32;
                          }
                          uint256 mask;
                          unchecked {
                              mask = 256**(32 - len) - 1;
                          }
                          assembly {
                              let srcpart := and(mload(src), not(mask))
                              let destpart := and(mload(dest), mask)
                              mstore(dest, or(destpart, srcpart))
                          }
                      }
                      /**
                       * Flattens a list of byte strings into one byte string.
                       * @notice From: https://github.com/sammayo/solidity-rlp-encoder/blob/master/RLPEncode.sol.
                       * @param _list List of byte strings to flatten.
                       * @return The flattened byte string.
                       */
                      function _flatten(bytes[] memory _list) private pure returns (bytes memory) {
                          if (_list.length == 0) {
                              return new bytes(0);
                          }
                          uint256 len;
                          uint256 i = 0;
                          for (; i < _list.length; i++) {
                              len += _list[i].length;
                          }
                          bytes memory flattened = new bytes(len);
                          uint256 flattenedPtr;
                          assembly {
                              flattenedPtr := add(flattened, 0x20)
                          }
                          for (i = 0; i < _list.length; i++) {
                              bytes memory item = _list[i];
                              uint256 listPtr;
                              assembly {
                                  listPtr := add(item, 0x20)
                              }
                              _memcpy(flattenedPtr, listPtr, item.length);
                              flattenedPtr += _list[i].length;
                          }
                          return flattened;
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /* Library Imports */
                  import { Lib_BytesUtils } from "../utils/Lib_BytesUtils.sol";
                  import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol";
                  import { Lib_RLPWriter } from "../rlp/Lib_RLPWriter.sol";
                  /**
                   * @title Lib_MerkleTrie
                   */
                  library Lib_MerkleTrie {
                      /*******************
                       * Data Structures *
                       *******************/
                      enum NodeType {
                          BranchNode,
                          ExtensionNode,
                          LeafNode
                      }
                      struct TrieNode {
                          bytes encoded;
                          Lib_RLPReader.RLPItem[] decoded;
                      }
                      /**********************
                       * Contract Constants *
                       **********************/
                      // TREE_RADIX determines the number of elements per branch node.
                      uint256 constant TREE_RADIX = 16;
                      // Branch nodes have TREE_RADIX elements plus an additional `value` slot.
                      uint256 constant BRANCH_NODE_LENGTH = TREE_RADIX + 1;
                      // Leaf nodes and extension nodes always have two elements, a `path` and a `value`.
                      uint256 constant LEAF_OR_EXTENSION_NODE_LENGTH = 2;
                      // Prefixes are prepended to the `path` within a leaf or extension node and
                      // allow us to differentiate between the two node types. `ODD` or `EVEN` is
                      // determined by the number of nibbles within the unprefixed `path`. If the
                      // number of nibbles if even, we need to insert an extra padding nibble so
                      // the resulting prefixed `path` has an even number of nibbles.
                      uint8 constant PREFIX_EXTENSION_EVEN = 0;
                      uint8 constant PREFIX_EXTENSION_ODD = 1;
                      uint8 constant PREFIX_LEAF_EVEN = 2;
                      uint8 constant PREFIX_LEAF_ODD = 3;
                      // Just a utility constant. RLP represents `NULL` as 0x80.
                      bytes1 constant RLP_NULL = bytes1(0x80);
                      bytes constant RLP_NULL_BYTES = hex"80";
                      bytes32 internal constant KECCAK256_RLP_NULL_BYTES = keccak256(RLP_NULL_BYTES);
                      /**********************
                       * Internal Functions *
                       **********************/
                      /**
                       * @notice Verifies a proof that a given key/value pair is present in the
                       * Merkle trie.
                       * @param _key Key of the node to search for, as a hex string.
                       * @param _value Value of the node to search for, as a hex string.
                       * @param _proof Merkle trie inclusion proof for the desired node. Unlike
                       * traditional Merkle trees, this proof is executed top-down and consists
                       * of a list of RLP-encoded nodes that make a path down to the target node.
                       * @param _root Known root of the Merkle trie. Used to verify that the
                       * included proof is correctly constructed.
                       * @return _verified `true` if the k/v pair exists in the trie, `false` otherwise.
                       */
                      function verifyInclusionProof(
                          bytes memory _key,
                          bytes memory _value,
                          bytes memory _proof,
                          bytes32 _root
                      ) internal pure returns (bool _verified) {
                          (bool exists, bytes memory value) = get(_key, _proof, _root);
                          return (exists && Lib_BytesUtils.equal(_value, value));
                      }
                      /**
                       * @notice Updates a Merkle trie and returns a new root hash.
                       * @param _key Key of the node to update, as a hex string.
                       * @param _value Value of the node to update, as a hex string.
                       * @param _proof Merkle trie inclusion proof for the node *nearest* the
                       * target node. If the key exists, we can simply update the value.
                       * Otherwise, we need to modify the trie to handle the new k/v pair.
                       * @param _root Known root of the Merkle trie. Used to verify that the
                       * included proof is correctly constructed.
                       * @return _updatedRoot Root hash of the newly constructed trie.
                       */
                      function update(
                          bytes memory _key,
                          bytes memory _value,
                          bytes memory _proof,
                          bytes32 _root
                      ) internal pure returns (bytes32 _updatedRoot) {
                          // Special case when inserting the very first node.
                          if (_root == KECCAK256_RLP_NULL_BYTES) {
                              return getSingleNodeRootHash(_key, _value);
                          }
                          TrieNode[] memory proof = _parseProof(_proof);
                          (uint256 pathLength, bytes memory keyRemainder, ) = _walkNodePath(proof, _key, _root);
                          TrieNode[] memory newPath = _getNewPath(proof, pathLength, _key, keyRemainder, _value);
                          return _getUpdatedTrieRoot(newPath, _key);
                      }
                      /**
                       * @notice Retrieves the value associated with a given key.
                       * @param _key Key to search for, as hex bytes.
                       * @param _proof Merkle trie inclusion proof for the key.
                       * @param _root Known root of the Merkle trie.
                       * @return _exists Whether or not the key exists.
                       * @return _value Value of the key if it exists.
                       */
                      function get(
                          bytes memory _key,
                          bytes memory _proof,
                          bytes32 _root
                      ) internal pure returns (bool _exists, bytes memory _value) {
                          TrieNode[] memory proof = _parseProof(_proof);
                          (uint256 pathLength, bytes memory keyRemainder, bool isFinalNode) = _walkNodePath(
                              proof,
                              _key,
                              _root
                          );
                          bool exists = keyRemainder.length == 0;
                          require(exists || isFinalNode, "Provided proof is invalid.");
                          bytes memory value = exists ? _getNodeValue(proof[pathLength - 1]) : bytes("");
                          return (exists, value);
                      }
                      /**
                       * Computes the root hash for a trie with a single node.
                       * @param _key Key for the single node.
                       * @param _value Value for the single node.
                       * @return _updatedRoot Hash of the trie.
                       */
                      function getSingleNodeRootHash(bytes memory _key, bytes memory _value)
                          internal
                          pure
                          returns (bytes32 _updatedRoot)
                      {
                          return keccak256(_makeLeafNode(Lib_BytesUtils.toNibbles(_key), _value).encoded);
                      }
                      /*********************
                       * Private Functions *
                       *********************/
                      /**
                       * @notice Walks through a proof using a provided key.
                       * @param _proof Inclusion proof to walk through.
                       * @param _key Key to use for the walk.
                       * @param _root Known root of the trie.
                       * @return _pathLength Length of the final path
                       * @return _keyRemainder Portion of the key remaining after the walk.
                       * @return _isFinalNode Whether or not we've hit a dead end.
                       */
                      function _walkNodePath(
                          TrieNode[] memory _proof,
                          bytes memory _key,
                          bytes32 _root
                      )
                          private
                          pure
                          returns (
                              uint256 _pathLength,
                              bytes memory _keyRemainder,
                              bool _isFinalNode
                          )
                      {
                          uint256 pathLength = 0;
                          bytes memory key = Lib_BytesUtils.toNibbles(_key);
                          bytes32 currentNodeID = _root;
                          uint256 currentKeyIndex = 0;
                          uint256 currentKeyIncrement = 0;
                          TrieNode memory currentNode;
                          // Proof is top-down, so we start at the first element (root).
                          for (uint256 i = 0; i < _proof.length; i++) {
                              currentNode = _proof[i];
                              currentKeyIndex += currentKeyIncrement;
                              // Keep track of the proof elements we actually need.
                              // It's expensive to resize arrays, so this simply reduces gas costs.
                              pathLength += 1;
                              if (currentKeyIndex == 0) {
                                  // First proof element is always the root node.
                                  require(keccak256(currentNode.encoded) == currentNodeID, "Invalid root hash");
                              } else if (currentNode.encoded.length >= 32) {
                                  // Nodes 32 bytes or larger are hashed inside branch nodes.
                                  require(
                                      keccak256(currentNode.encoded) == currentNodeID,
                                      "Invalid large internal hash"
                                  );
                              } else {
                                  // Nodes smaller than 31 bytes aren't hashed.
                                  require(
                                      Lib_BytesUtils.toBytes32(currentNode.encoded) == currentNodeID,
                                      "Invalid internal node hash"
                                  );
                              }
                              if (currentNode.decoded.length == BRANCH_NODE_LENGTH) {
                                  if (currentKeyIndex == key.length) {
                                      // We've hit the end of the key
                                      // meaning the value should be within this branch node.
                                      break;
                                  } else {
                                      // We're not at the end of the key yet.
                                      // Figure out what the next node ID should be and continue.
                                      uint8 branchKey = uint8(key[currentKeyIndex]);
                                      Lib_RLPReader.RLPItem memory nextNode = currentNode.decoded[branchKey];
                                      currentNodeID = _getNodeID(nextNode);
                                      currentKeyIncrement = 1;
                                      continue;
                                  }
                              } else if (currentNode.decoded.length == LEAF_OR_EXTENSION_NODE_LENGTH) {
                                  bytes memory path = _getNodePath(currentNode);
                                  uint8 prefix = uint8(path[0]);
                                  uint8 offset = 2 - (prefix % 2);
                                  bytes memory pathRemainder = Lib_BytesUtils.slice(path, offset);
                                  bytes memory keyRemainder = Lib_BytesUtils.slice(key, currentKeyIndex);
                                  uint256 sharedNibbleLength = _getSharedNibbleLength(pathRemainder, keyRemainder);
                                  if (prefix == PREFIX_LEAF_EVEN || prefix == PREFIX_LEAF_ODD) {
                                      if (
                                          pathRemainder.length == sharedNibbleLength &&
                                          keyRemainder.length == sharedNibbleLength
                                      ) {
                                          // The key within this leaf matches our key exactly.
                                          // Increment the key index to reflect that we have no remainder.
                                          currentKeyIndex += sharedNibbleLength;
                                      }
                                      // We've hit a leaf node, so our next node should be NULL.
                                      currentNodeID = bytes32(RLP_NULL);
                                      break;
                                  } else if (prefix == PREFIX_EXTENSION_EVEN || prefix == PREFIX_EXTENSION_ODD) {
                                      if (sharedNibbleLength != pathRemainder.length) {
                                          // Our extension node is not identical to the remainder.
                                          // We've hit the end of this path
                                          // updates will need to modify this extension.
                                          currentNodeID = bytes32(RLP_NULL);
                                          break;
                                      } else {
                                          // Our extension shares some nibbles.
                                          // Carry on to the next node.
                                          currentNodeID = _getNodeID(currentNode.decoded[1]);
                                          currentKeyIncrement = sharedNibbleLength;
                                          continue;
                                      }
                                  } else {
                                      revert("Received a node with an unknown prefix");
                                  }
                              } else {
                                  revert("Received an unparseable node.");
                              }
                          }
                          // If our node ID is NULL, then we're at a dead end.
                          bool isFinalNode = currentNodeID == bytes32(RLP_NULL);
                          return (pathLength, Lib_BytesUtils.slice(key, currentKeyIndex), isFinalNode);
                      }
                      /**
                       * @notice Creates new nodes to support a k/v pair insertion into a given Merkle trie path.
                       * @param _path Path to the node nearest the k/v pair.
                       * @param _pathLength Length of the path. Necessary because the provided path may include
                       *  additional nodes (e.g., it comes directly from a proof) and we can't resize in-memory
                       *  arrays without costly duplication.
                       * @param _key Full original key.
                       * @param _keyRemainder Portion of the initial key that must be inserted into the trie.
                       * @param _value Value to insert at the given key.
                       * @return _newPath A new path with the inserted k/v pair and extra supporting nodes.
                       */
                      function _getNewPath(
                          TrieNode[] memory _path,
                          uint256 _pathLength,
                          bytes memory _key,
                          bytes memory _keyRemainder,
                          bytes memory _value
                      ) private pure returns (TrieNode[] memory _newPath) {
                          bytes memory keyRemainder = _keyRemainder;
                          // Most of our logic depends on the status of the last node in the path.
                          TrieNode memory lastNode = _path[_pathLength - 1];
                          NodeType lastNodeType = _getNodeType(lastNode);
                          // Create an array for newly created nodes.
                          // We need up to three new nodes, depending on the contents of the last node.
                          // Since array resizing is expensive, we'll keep track of the size manually.
                          // We're using an explicit `totalNewNodes += 1` after insertions for clarity.
                          TrieNode[] memory newNodes = new TrieNode[](3);
                          uint256 totalNewNodes = 0;
                          // solhint-disable-next-line max-line-length
                          // Reference: https://github.com/ethereumjs/merkle-patricia-tree/blob/c0a10395aab37d42c175a47114ebfcbd7efcf059/src/baseTrie.ts#L294-L313
                          bool matchLeaf = false;
                          if (lastNodeType == NodeType.LeafNode) {
                              uint256 l = 0;
                              if (_path.length > 0) {
                                  for (uint256 i = 0; i < _path.length - 1; i++) {
                                      if (_getNodeType(_path[i]) == NodeType.BranchNode) {
                                          l++;
                                      } else {
                                          l += _getNodeKey(_path[i]).length;
                                      }
                                  }
                              }
                              if (
                                  _getSharedNibbleLength(
                                      _getNodeKey(lastNode),
                                      Lib_BytesUtils.slice(Lib_BytesUtils.toNibbles(_key), l)
                                  ) ==
                                  _getNodeKey(lastNode).length &&
                                  keyRemainder.length == 0
                              ) {
                                  matchLeaf = true;
                              }
                          }
                          if (matchLeaf) {
                              // We've found a leaf node with the given key.
                              // Simply need to update the value of the node to match.
                              newNodes[totalNewNodes] = _makeLeafNode(_getNodeKey(lastNode), _value);
                              totalNewNodes += 1;
                          } else if (lastNodeType == NodeType.BranchNode) {
                              if (keyRemainder.length == 0) {
                                  // We've found a branch node with the given key.
                                  // Simply need to update the value of the node to match.
                                  newNodes[totalNewNodes] = _editBranchValue(lastNode, _value);
                                  totalNewNodes += 1;
                              } else {
                                  // We've found a branch node, but it doesn't contain our key.
                                  // Reinsert the old branch for now.
                                  newNodes[totalNewNodes] = lastNode;
                                  totalNewNodes += 1;
                                  // Create a new leaf node, slicing our remainder since the first byte points
                                  // to our branch node.
                                  newNodes[totalNewNodes] = _makeLeafNode(
                                      Lib_BytesUtils.slice(keyRemainder, 1),
                                      _value
                                  );
                                  totalNewNodes += 1;
                              }
                          } else {
                              // Our last node is either an extension node or a leaf node with a different key.
                              bytes memory lastNodeKey = _getNodeKey(lastNode);
                              uint256 sharedNibbleLength = _getSharedNibbleLength(lastNodeKey, keyRemainder);
                              if (sharedNibbleLength != 0) {
                                  // We've got some shared nibbles between the last node and our key remainder.
                                  // We'll need to insert an extension node that covers these shared nibbles.
                                  bytes memory nextNodeKey = Lib_BytesUtils.slice(lastNodeKey, 0, sharedNibbleLength);
                                  newNodes[totalNewNodes] = _makeExtensionNode(nextNodeKey, _getNodeHash(_value));
                                  totalNewNodes += 1;
                                  // Cut down the keys since we've just covered these shared nibbles.
                                  lastNodeKey = Lib_BytesUtils.slice(lastNodeKey, sharedNibbleLength);
                                  keyRemainder = Lib_BytesUtils.slice(keyRemainder, sharedNibbleLength);
                              }
                              // Create an empty branch to fill in.
                              TrieNode memory newBranch = _makeEmptyBranchNode();
                              if (lastNodeKey.length == 0) {
                                  // Key remainder was larger than the key for our last node.
                                  // The value within our last node is therefore going to be shifted into
                                  // a branch value slot.
                                  newBranch = _editBranchValue(newBranch, _getNodeValue(lastNode));
                              } else {
                                  // Last node key was larger than the key remainder.
                                  // We're going to modify some index of our branch.
                                  uint8 branchKey = uint8(lastNodeKey[0]);
                                  // Move on to the next nibble.
                                  lastNodeKey = Lib_BytesUtils.slice(lastNodeKey, 1);
                                  if (lastNodeType == NodeType.LeafNode) {
                                      // We're dealing with a leaf node.
                                      // We'll modify the key and insert the old leaf node into the branch index.
                                      TrieNode memory modifiedLastNode = _makeLeafNode(
                                          lastNodeKey,
                                          _getNodeValue(lastNode)
                                      );
                                      newBranch = _editBranchIndex(
                                          newBranch,
                                          branchKey,
                                          _getNodeHash(modifiedLastNode.encoded)
                                      );
                                  } else if (lastNodeKey.length != 0) {
                                      // We're dealing with a shrinking extension node.
                                      // We need to modify the node to decrease the size of the key.
                                      TrieNode memory modifiedLastNode = _makeExtensionNode(
                                          lastNodeKey,
                                          _getNodeValue(lastNode)
                                      );
                                      newBranch = _editBranchIndex(
                                          newBranch,
                                          branchKey,
                                          _getNodeHash(modifiedLastNode.encoded)
                                      );
                                  } else {
                                      // We're dealing with an unnecessary extension node.
                                      // We're going to delete the node entirely.
                                      // Simply insert its current value into the branch index.
                                      newBranch = _editBranchIndex(newBranch, branchKey, _getNodeValue(lastNode));
                                  }
                              }
                              if (keyRemainder.length == 0) {
                                  // We've got nothing left in the key remainder.
                                  // Simply insert the value into the branch value slot.
                                  newBranch = _editBranchValue(newBranch, _value);
                                  // Push the branch into the list of new nodes.
                                  newNodes[totalNewNodes] = newBranch;
                                  totalNewNodes += 1;
                              } else {
                                  // We've got some key remainder to work with.
                                  // We'll be inserting a leaf node into the trie.
                                  // First, move on to the next nibble.
                                  keyRemainder = Lib_BytesUtils.slice(keyRemainder, 1);
                                  // Push the branch into the list of new nodes.
                                  newNodes[totalNewNodes] = newBranch;
                                  totalNewNodes += 1;
                                  // Push a new leaf node for our k/v pair.
                                  newNodes[totalNewNodes] = _makeLeafNode(keyRemainder, _value);
                                  totalNewNodes += 1;
                              }
                          }
                          // Finally, join the old path with our newly created nodes.
                          // Since we're overwriting the last node in the path, we use `_pathLength - 1`.
                          return _joinNodeArrays(_path, _pathLength - 1, newNodes, totalNewNodes);
                      }
                      /**
                       * @notice Computes the trie root from a given path.
                       * @param _nodes Path to some k/v pair.
                       * @param _key Key for the k/v pair.
                       * @return _updatedRoot Root hash for the updated trie.
                       */
                      function _getUpdatedTrieRoot(TrieNode[] memory _nodes, bytes memory _key)
                          private
                          pure
                          returns (bytes32 _updatedRoot)
                      {
                          bytes memory key = Lib_BytesUtils.toNibbles(_key);
                          // Some variables to keep track of during iteration.
                          TrieNode memory currentNode;
                          NodeType currentNodeType;
                          bytes memory previousNodeHash;
                          // Run through the path backwards to rebuild our root hash.
                          for (uint256 i = _nodes.length; i > 0; i--) {
                              // Pick out the current node.
                              currentNode = _nodes[i - 1];
                              currentNodeType = _getNodeType(currentNode);
                              if (currentNodeType == NodeType.LeafNode) {
                                  // Leaf nodes are already correctly encoded.
                                  // Shift the key over to account for the nodes key.
                                  bytes memory nodeKey = _getNodeKey(currentNode);
                                  key = Lib_BytesUtils.slice(key, 0, key.length - nodeKey.length);
                              } else if (currentNodeType == NodeType.ExtensionNode) {
                                  // Shift the key over to account for the nodes key.
                                  bytes memory nodeKey = _getNodeKey(currentNode);
                                  key = Lib_BytesUtils.slice(key, 0, key.length - nodeKey.length);
                                  // If this node is the last element in the path, it'll be correctly encoded
                                  // and we can skip this part.
                                  if (previousNodeHash.length > 0) {
                                      // Re-encode the node based on the previous node.
                                      currentNode = _editExtensionNodeValue(currentNode, previousNodeHash);
                                  }
                              } else if (currentNodeType == NodeType.BranchNode) {
                                  // If this node is the last element in the path, it'll be correctly encoded
                                  // and we can skip this part.
                                  if (previousNodeHash.length > 0) {
                                      // Re-encode the node based on the previous node.
                                      uint8 branchKey = uint8(key[key.length - 1]);
                                      key = Lib_BytesUtils.slice(key, 0, key.length - 1);
                                      currentNode = _editBranchIndex(currentNode, branchKey, previousNodeHash);
                                  }
                              }
                              // Compute the node hash for the next iteration.
                              previousNodeHash = _getNodeHash(currentNode.encoded);
                          }
                          // Current node should be the root at this point.
                          // Simply return the hash of its encoding.
                          return keccak256(currentNode.encoded);
                      }
                      /**
                       * @notice Parses an RLP-encoded proof into something more useful.
                       * @param _proof RLP-encoded proof to parse.
                       * @return _parsed Proof parsed into easily accessible structs.
                       */
                      function _parseProof(bytes memory _proof) private pure returns (TrieNode[] memory _parsed) {
                          Lib_RLPReader.RLPItem[] memory nodes = Lib_RLPReader.readList(_proof);
                          TrieNode[] memory proof = new TrieNode[](nodes.length);
                          for (uint256 i = 0; i < nodes.length; i++) {
                              bytes memory encoded = Lib_RLPReader.readBytes(nodes[i]);
                              proof[i] = TrieNode({ encoded: encoded, decoded: Lib_RLPReader.readList(encoded) });
                          }
                          return proof;
                      }
                      /**
                       * @notice Picks out the ID for a node. Node ID is referred to as the
                       * "hash" within the specification, but nodes < 32 bytes are not actually
                       * hashed.
                       * @param _node Node to pull an ID for.
                       * @return _nodeID ID for the node, depending on the size of its contents.
                       */
                      function _getNodeID(Lib_RLPReader.RLPItem memory _node) private pure returns (bytes32 _nodeID) {
                          bytes memory nodeID;
                          if (_node.length < 32) {
                              // Nodes smaller than 32 bytes are RLP encoded.
                              nodeID = Lib_RLPReader.readRawBytes(_node);
                          } else {
                              // Nodes 32 bytes or larger are hashed.
                              nodeID = Lib_RLPReader.readBytes(_node);
                          }
                          return Lib_BytesUtils.toBytes32(nodeID);
                      }
                      /**
                       * @notice Gets the path for a leaf or extension node.
                       * @param _node Node to get a path for.
                       * @return _path Node path, converted to an array of nibbles.
                       */
                      function _getNodePath(TrieNode memory _node) private pure returns (bytes memory _path) {
                          return Lib_BytesUtils.toNibbles(Lib_RLPReader.readBytes(_node.decoded[0]));
                      }
                      /**
                       * @notice Gets the key for a leaf or extension node. Keys are essentially
                       * just paths without any prefix.
                       * @param _node Node to get a key for.
                       * @return _key Node key, converted to an array of nibbles.
                       */
                      function _getNodeKey(TrieNode memory _node) private pure returns (bytes memory _key) {
                          return _removeHexPrefix(_getNodePath(_node));
                      }
                      /**
                       * @notice Gets the path for a node.
                       * @param _node Node to get a value for.
                       * @return _value Node value, as hex bytes.
                       */
                      function _getNodeValue(TrieNode memory _node) private pure returns (bytes memory _value) {
                          return Lib_RLPReader.readBytes(_node.decoded[_node.decoded.length - 1]);
                      }
                      /**
                       * @notice Computes the node hash for an encoded node. Nodes < 32 bytes
                       * are not hashed, all others are keccak256 hashed.
                       * @param _encoded Encoded node to hash.
                       * @return _hash Hash of the encoded node. Simply the input if < 32 bytes.
                       */
                      function _getNodeHash(bytes memory _encoded) private pure returns (bytes memory _hash) {
                          if (_encoded.length < 32) {
                              return _encoded;
                          } else {
                              return abi.encodePacked(keccak256(_encoded));
                          }
                      }
                      /**
                       * @notice Determines the type for a given node.
                       * @param _node Node to determine a type for.
                       * @return _type Type of the node; BranchNode/ExtensionNode/LeafNode.
                       */
                      function _getNodeType(TrieNode memory _node) private pure returns (NodeType _type) {
                          if (_node.decoded.length == BRANCH_NODE_LENGTH) {
                              return NodeType.BranchNode;
                          } else if (_node.decoded.length == LEAF_OR_EXTENSION_NODE_LENGTH) {
                              bytes memory path = _getNodePath(_node);
                              uint8 prefix = uint8(path[0]);
                              if (prefix == PREFIX_LEAF_EVEN || prefix == PREFIX_LEAF_ODD) {
                                  return NodeType.LeafNode;
                              } else if (prefix == PREFIX_EXTENSION_EVEN || prefix == PREFIX_EXTENSION_ODD) {
                                  return NodeType.ExtensionNode;
                              }
                          }
                          revert("Invalid node type");
                      }
                      /**
                       * @notice Utility; determines the number of nibbles shared between two
                       * nibble arrays.
                       * @param _a First nibble array.
                       * @param _b Second nibble array.
                       * @return _shared Number of shared nibbles.
                       */
                      function _getSharedNibbleLength(bytes memory _a, bytes memory _b)
                          private
                          pure
                          returns (uint256 _shared)
                      {
                          uint256 i = 0;
                          while (_a.length > i && _b.length > i && _a[i] == _b[i]) {
                              i++;
                          }
                          return i;
                      }
                      /**
                       * @notice Utility; converts an RLP-encoded node into our nice struct.
                       * @param _raw RLP-encoded node to convert.
                       * @return _node Node as a TrieNode struct.
                       */
                      function _makeNode(bytes[] memory _raw) private pure returns (TrieNode memory _node) {
                          bytes memory encoded = Lib_RLPWriter.writeList(_raw);
                          return TrieNode({ encoded: encoded, decoded: Lib_RLPReader.readList(encoded) });
                      }
                      /**
                       * @notice Utility; converts an RLP-decoded node into our nice struct.
                       * @param _items RLP-decoded node to convert.
                       * @return _node Node as a TrieNode struct.
                       */
                      function _makeNode(Lib_RLPReader.RLPItem[] memory _items)
                          private
                          pure
                          returns (TrieNode memory _node)
                      {
                          bytes[] memory raw = new bytes[](_items.length);
                          for (uint256 i = 0; i < _items.length; i++) {
                              raw[i] = Lib_RLPReader.readRawBytes(_items[i]);
                          }
                          return _makeNode(raw);
                      }
                      /**
                       * @notice Creates a new extension node.
                       * @param _key Key for the extension node, unprefixed.
                       * @param _value Value for the extension node.
                       * @return _node New extension node with the given k/v pair.
                       */
                      function _makeExtensionNode(bytes memory _key, bytes memory _value)
                          private
                          pure
                          returns (TrieNode memory _node)
                      {
                          bytes[] memory raw = new bytes[](2);
                          bytes memory key = _addHexPrefix(_key, false);
                          raw[0] = Lib_RLPWriter.writeBytes(Lib_BytesUtils.fromNibbles(key));
                          raw[1] = Lib_RLPWriter.writeBytes(_value);
                          return _makeNode(raw);
                      }
                      /**
                       * Creates a new extension node with the same key but a different value.
                       * @param _node Extension node to copy and modify.
                       * @param _value New value for the extension node.
                       * @return New node with the same key and different value.
                       */
                      function _editExtensionNodeValue(TrieNode memory _node, bytes memory _value)
                          private
                          pure
                          returns (TrieNode memory)
                      {
                          bytes[] memory raw = new bytes[](2);
                          bytes memory key = _addHexPrefix(_getNodeKey(_node), false);
                          raw[0] = Lib_RLPWriter.writeBytes(Lib_BytesUtils.fromNibbles(key));
                          if (_value.length < 32) {
                              raw[1] = _value;
                          } else {
                              raw[1] = Lib_RLPWriter.writeBytes(_value);
                          }
                          return _makeNode(raw);
                      }
                      /**
                       * @notice Creates a new leaf node.
                       * @dev This function is essentially identical to `_makeExtensionNode`.
                       * Although we could route both to a single method with a flag, it's
                       * more gas efficient to keep them separate and duplicate the logic.
                       * @param _key Key for the leaf node, unprefixed.
                       * @param _value Value for the leaf node.
                       * @return _node New leaf node with the given k/v pair.
                       */
                      function _makeLeafNode(bytes memory _key, bytes memory _value)
                          private
                          pure
                          returns (TrieNode memory _node)
                      {
                          bytes[] memory raw = new bytes[](2);
                          bytes memory key = _addHexPrefix(_key, true);
                          raw[0] = Lib_RLPWriter.writeBytes(Lib_BytesUtils.fromNibbles(key));
                          raw[1] = Lib_RLPWriter.writeBytes(_value);
                          return _makeNode(raw);
                      }
                      /**
                       * @notice Creates an empty branch node.
                       * @return _node Empty branch node as a TrieNode struct.
                       */
                      function _makeEmptyBranchNode() private pure returns (TrieNode memory _node) {
                          bytes[] memory raw = new bytes[](BRANCH_NODE_LENGTH);
                          for (uint256 i = 0; i < raw.length; i++) {
                              raw[i] = RLP_NULL_BYTES;
                          }
                          return _makeNode(raw);
                      }
                      /**
                       * @notice Modifies the value slot for a given branch.
                       * @param _branch Branch node to modify.
                       * @param _value Value to insert into the branch.
                       * @return _updatedNode Modified branch node.
                       */
                      function _editBranchValue(TrieNode memory _branch, bytes memory _value)
                          private
                          pure
                          returns (TrieNode memory _updatedNode)
                      {
                          bytes memory encoded = Lib_RLPWriter.writeBytes(_value);
                          _branch.decoded[_branch.decoded.length - 1] = Lib_RLPReader.toRLPItem(encoded);
                          return _makeNode(_branch.decoded);
                      }
                      /**
                       * @notice Modifies a slot at an index for a given branch.
                       * @param _branch Branch node to modify.
                       * @param _index Slot index to modify.
                       * @param _value Value to insert into the slot.
                       * @return _updatedNode Modified branch node.
                       */
                      function _editBranchIndex(
                          TrieNode memory _branch,
                          uint8 _index,
                          bytes memory _value
                      ) private pure returns (TrieNode memory _updatedNode) {
                          bytes memory encoded = _value.length < 32 ? _value : Lib_RLPWriter.writeBytes(_value);
                          _branch.decoded[_index] = Lib_RLPReader.toRLPItem(encoded);
                          return _makeNode(_branch.decoded);
                      }
                      /**
                       * @notice Utility; adds a prefix to a key.
                       * @param _key Key to prefix.
                       * @param _isLeaf Whether or not the key belongs to a leaf.
                       * @return _prefixedKey Prefixed key.
                       */
                      function _addHexPrefix(bytes memory _key, bool _isLeaf)
                          private
                          pure
                          returns (bytes memory _prefixedKey)
                      {
                          uint8 prefix = _isLeaf ? uint8(0x02) : uint8(0x00);
                          uint8 offset = uint8(_key.length % 2);
                          bytes memory prefixed = new bytes(2 - offset);
                          prefixed[0] = bytes1(prefix + offset);
                          return abi.encodePacked(prefixed, _key);
                      }
                      /**
                       * @notice Utility; removes a prefix from a path.
                       * @param _path Path to remove the prefix from.
                       * @return _unprefixedKey Unprefixed key.
                       */
                      function _removeHexPrefix(bytes memory _path)
                          private
                          pure
                          returns (bytes memory _unprefixedKey)
                      {
                          if (uint8(_path[0]) % 2 == 0) {
                              return Lib_BytesUtils.slice(_path, 2);
                          } else {
                              return Lib_BytesUtils.slice(_path, 1);
                          }
                      }
                      /**
                       * @notice Utility; combines two node arrays. Array lengths are required
                       * because the actual lengths may be longer than the filled lengths.
                       * Array resizing is extremely costly and should be avoided.
                       * @param _a First array to join.
                       * @param _aLength Length of the first array.
                       * @param _b Second array to join.
                       * @param _bLength Length of the second array.
                       * @return _joined Combined node array.
                       */
                      function _joinNodeArrays(
                          TrieNode[] memory _a,
                          uint256 _aLength,
                          TrieNode[] memory _b,
                          uint256 _bLength
                      ) private pure returns (TrieNode[] memory _joined) {
                          TrieNode[] memory ret = new TrieNode[](_aLength + _bLength);
                          // Copy elements from the first array.
                          for (uint256 i = 0; i < _aLength; i++) {
                              ret[i] = _a[i];
                          }
                          // Copy elements from the second array.
                          for (uint256 i = 0; i < _bLength; i++) {
                              ret[i + _aLength] = _b[i];
                          }
                          return ret;
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /* Library Imports */
                  import { Lib_MerkleTrie } from "./Lib_MerkleTrie.sol";
                  /**
                   * @title Lib_SecureMerkleTrie
                   */
                  library Lib_SecureMerkleTrie {
                      /**********************
                       * Internal Functions *
                       **********************/
                      /**
                       * @notice Verifies a proof that a given key/value pair is present in the
                       * Merkle trie.
                       * @param _key Key of the node to search for, as a hex string.
                       * @param _value Value of the node to search for, as a hex string.
                       * @param _proof Merkle trie inclusion proof for the desired node. Unlike
                       * traditional Merkle trees, this proof is executed top-down and consists
                       * of a list of RLP-encoded nodes that make a path down to the target node.
                       * @param _root Known root of the Merkle trie. Used to verify that the
                       * included proof is correctly constructed.
                       * @return _verified `true` if the k/v pair exists in the trie, `false` otherwise.
                       */
                      function verifyInclusionProof(
                          bytes memory _key,
                          bytes memory _value,
                          bytes memory _proof,
                          bytes32 _root
                      ) internal pure returns (bool _verified) {
                          bytes memory key = _getSecureKey(_key);
                          return Lib_MerkleTrie.verifyInclusionProof(key, _value, _proof, _root);
                      }
                      /**
                       * @notice Updates a Merkle trie and returns a new root hash.
                       * @param _key Key of the node to update, as a hex string.
                       * @param _value Value of the node to update, as a hex string.
                       * @param _proof Merkle trie inclusion proof for the node *nearest* the
                       * target node. If the key exists, we can simply update the value.
                       * Otherwise, we need to modify the trie to handle the new k/v pair.
                       * @param _root Known root of the Merkle trie. Used to verify that the
                       * included proof is correctly constructed.
                       * @return _updatedRoot Root hash of the newly constructed trie.
                       */
                      function update(
                          bytes memory _key,
                          bytes memory _value,
                          bytes memory _proof,
                          bytes32 _root
                      ) internal pure returns (bytes32 _updatedRoot) {
                          bytes memory key = _getSecureKey(_key);
                          return Lib_MerkleTrie.update(key, _value, _proof, _root);
                      }
                      /**
                       * @notice Retrieves the value associated with a given key.
                       * @param _key Key to search for, as hex bytes.
                       * @param _proof Merkle trie inclusion proof for the key.
                       * @param _root Known root of the Merkle trie.
                       * @return _exists Whether or not the key exists.
                       * @return _value Value of the key if it exists.
                       */
                      function get(
                          bytes memory _key,
                          bytes memory _proof,
                          bytes32 _root
                      ) internal pure returns (bool _exists, bytes memory _value) {
                          bytes memory key = _getSecureKey(_key);
                          return Lib_MerkleTrie.get(key, _proof, _root);
                      }
                      /**
                       * Computes the root hash for a trie with a single node.
                       * @param _key Key for the single node.
                       * @param _value Value for the single node.
                       * @return _updatedRoot Hash of the trie.
                       */
                      function getSingleNodeRootHash(bytes memory _key, bytes memory _value)
                          internal
                          pure
                          returns (bytes32 _updatedRoot)
                      {
                          bytes memory key = _getSecureKey(_key);
                          return Lib_MerkleTrie.getSingleNodeRootHash(key, _value);
                      }
                      /*********************
                       * Private Functions *
                       *********************/
                      /**
                       * Computes the secure counterpart to a key.
                       * @param _key Key to get a secure key from.
                       * @return _secureKey Secure version of the key.
                       */
                      function _getSecureKey(bytes memory _key) private pure returns (bytes memory _secureKey) {
                          return abi.encodePacked(keccak256(_key));
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /**
                   * @title Lib_Byte32Utils
                   */
                  library Lib_Bytes32Utils {
                      /**********************
                       * Internal Functions *
                       **********************/
                      /**
                       * Converts a bytes32 value to a boolean. Anything non-zero will be converted to "true."
                       * @param _in Input bytes32 value.
                       * @return Bytes32 as a boolean.
                       */
                      function toBool(bytes32 _in) internal pure returns (bool) {
                          return _in != 0;
                      }
                      /**
                       * Converts a boolean to a bytes32 value.
                       * @param _in Input boolean value.
                       * @return Boolean as a bytes32.
                       */
                      function fromBool(bool _in) internal pure returns (bytes32) {
                          return bytes32(uint256(_in ? 1 : 0));
                      }
                      /**
                       * Converts a bytes32 value to an address. Takes the *last* 20 bytes.
                       * @param _in Input bytes32 value.
                       * @return Bytes32 as an address.
                       */
                      function toAddress(bytes32 _in) internal pure returns (address) {
                          return address(uint160(uint256(_in)));
                      }
                      /**
                       * Converts an address to a bytes32.
                       * @param _in Input address value.
                       * @return Address as a bytes32.
                       */
                      function fromAddress(address _in) internal pure returns (bytes32) {
                          return bytes32(uint256(uint160(_in)));
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.8.9;
                  /**
                   * @title Lib_BytesUtils
                   */
                  library Lib_BytesUtils {
                      /**********************
                       * Internal Functions *
                       **********************/
                      function slice(
                          bytes memory _bytes,
                          uint256 _start,
                          uint256 _length
                      ) internal pure returns (bytes memory) {
                          require(_length + 31 >= _length, "slice_overflow");
                          require(_start + _length >= _start, "slice_overflow");
                          require(_bytes.length >= _start + _length, "slice_outOfBounds");
                          bytes memory tempBytes;
                          assembly {
                              switch iszero(_length)
                              case 0 {
                                  // Get a location of some free memory and store it in tempBytes as
                                  // Solidity does for memory variables.
                                  tempBytes := mload(0x40)
                                  // The first word of the slice result is potentially a partial
                                  // word read from the original array. To read it, we calculate
                                  // the length of that partial word and start copying that many
                                  // bytes into the array. The first word we copy will start with
                                  // data we don't care about, but the last `lengthmod` bytes will
                                  // land at the beginning of the contents of the new array. When
                                  // we're done copying, we overwrite the full first word with
                                  // the actual length of the slice.
                                  let lengthmod := and(_length, 31)
                                  // The multiplication in the next line is necessary
                                  // because when slicing multiples of 32 bytes (lengthmod == 0)
                                  // the following copy loop was copying the origin's length
                                  // and then ending prematurely not copying everything it should.
                                  let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                                  let end := add(mc, _length)
                                  for {
                                      // The multiplication in the next line has the same exact purpose
                                      // as the one above.
                                      let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                                  } lt(mc, end) {
                                      mc := add(mc, 0x20)
                                      cc := add(cc, 0x20)
                                  } {
                                      mstore(mc, mload(cc))
                                  }
                                  mstore(tempBytes, _length)
                                  //update free-memory pointer
                                  //allocating the array padded to 32 bytes like the compiler does now
                                  mstore(0x40, and(add(mc, 31), not(31)))
                              }
                              //if we want a zero-length slice let's just return a zero-length array
                              default {
                                  tempBytes := mload(0x40)
                                  //zero out the 32 bytes slice we are about to return
                                  //we need to do it because Solidity does not garbage collect
                                  mstore(tempBytes, 0)
                                  mstore(0x40, add(tempBytes, 0x20))
                              }
                          }
                          return tempBytes;
                      }
                      function slice(bytes memory _bytes, uint256 _start) internal pure returns (bytes memory) {
                          if (_start >= _bytes.length) {
                              return bytes("");
                          }
                          return slice(_bytes, _start, _bytes.length - _start);
                      }
                      function toBytes32(bytes memory _bytes) internal pure returns (bytes32) {
                          if (_bytes.length < 32) {
                              bytes32 ret;
                              assembly {
                                  ret := mload(add(_bytes, 32))
                              }
                              return ret;
                          }
                          return abi.decode(_bytes, (bytes32)); // will truncate if input length > 32 bytes
                      }
                      function toUint256(bytes memory _bytes) internal pure returns (uint256) {
                          return uint256(toBytes32(_bytes));
                      }
                      function toNibbles(bytes memory _bytes) internal pure returns (bytes memory) {
                          bytes memory nibbles = new bytes(_bytes.length * 2);
                          for (uint256 i = 0; i < _bytes.length; i++) {
                              nibbles[i * 2] = _bytes[i] >> 4;
                              nibbles[i * 2 + 1] = bytes1(uint8(_bytes[i]) % 16);
                          }
                          return nibbles;
                      }
                      function fromNibbles(bytes memory _bytes) internal pure returns (bytes memory) {
                          bytes memory ret = new bytes(_bytes.length / 2);
                          for (uint256 i = 0; i < ret.length; i++) {
                              ret[i] = (_bytes[i * 2] << 4) | (_bytes[i * 2 + 1]);
                          }
                          return ret;
                      }
                      function equal(bytes memory _bytes, bytes memory _other) internal pure returns (bool) {
                          return keccak256(_bytes) == keccak256(_other);
                      }
                  }
                  // SPDX-License-Identifier: Apache-2.0
                  /*
                   * Copyright 2019-2021, Offchain Labs, Inc.
                   *
                   * 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
                   *
                   *    http://www.apache.org/licenses/LICENSE-2.0
                   *
                   * 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.8.7;
                  library AddressAliasHelper {
                      uint160 constant offset = uint160(0x1111000000000000000000000000000000001111);
                      /// @notice Utility function that converts the address in the L1 that submitted a tx to
                      /// the inbox to the msg.sender viewed in the L2
                      /// @param l1Address the address in the L1 that triggered the tx to L2
                      /// @return l2Address L2 address as viewed in msg.sender
                      function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {
                          unchecked {
                              l2Address = address(uint160(l1Address) + offset);
                          }
                      }
                      /// @notice Utility function that converts the msg.sender viewed in the L2 to the
                      /// address in the L1 that submitted a tx to the inbox
                      /// @param l2Address L2 address as viewed in msg.sender
                      /// @return l1Address the address in the L1 that triggered the tx to L2
                      function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) {
                          unchecked {
                              l1Address = address(uint160(l2Address) - offset);
                          }
                      }
                  }