ETH Price: $2,572.41 (+0.23%)

Transaction Decoder

Block:
18934335 at Jan-04-2024 01:41:47 PM +UTC
Transaction Fee:
0.003110801012074652 ETH $8.00
Gas Used:
139,204 Gas / 22.347066263 Gwei

Emitted Events:

256 E4CRanger.Transfer( from=0x00000000...000000000, to=[Sender] 0xf10abf668ae17738f418c2613972bdb6c1731a2a, tokenId=8167 )
257 E4CRanger.AssetMinted( to=[Sender] 0xf10abf668ae17738f418c2613972bdb6c1731a2a, id=8167, blueprint=0x6D65746164617461 )
258 DOOR.0x7e6e15df814c1a309a57686de672b2bedd128eacde35c5370c36d6840d4e9a92( 0x7e6e15df814c1a309a57686de672b2bedd128eacde35c5370c36d6840d4e9a92, 0511bf148b5d3723236313683686c9a3aceb0bb880ed876150d1cff2f56bd3f8, 003202d0e3faa167cb88b065ca78ae22462ccda95e83f43bdba34b7dc694af2c, 0000000000000000000000000000000000000000000000000000000000000001, 0000000000000000000000000000000000000000000000000000000000000001, 04005542d5b026af244923fcc570d0ee51c378491e5582eb84eaf935fa905c53 )

Account State Difference:

  Address   Before After State Difference Code
6.909588546657824421 Eth6.909602467057824421 Eth0.0000139204
0x5FDCCA53...1058e27e9
(Immutable X: Bridge)
0x82dcc794...7aBe8ed89
0xF10abf66...6C1731A2a
0.005345098083228618 Eth
Nonce: 792
0.002234297071153966 Eth
Nonce: 793
0.003110801012074652

Execution Trace

DOOR.d91443b7( )
  • StarkExchange.d91443b7( )
    • TokensAndRamping.withdrawAndMint( starkKey=2292919430445489941211581844758683465638535732417146618020464195588810593272, assetType=88361788409513177092115962627678782169564144164395173926740080068926943020, mintingBlob=0x7B383136377D3A7B6D657461646174617D )
      • E4CRanger.mintFor( user=0xF10abf668Ae17738f418C2613972bdb6C1731A2a, quantity=1, mintingBlob=0x7B383136377D3A7B6D657461646174617D )
        File 1 of 4: DOOR
        // File: node_modules\@openzeppelin\contracts\token\ERC20\IERC20.sol
        
        // 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);
        }
        
        /**
         * @dev Interface for the optional metadata functions from the ERC20 standard.
         *
         * _Available since v4.1._
         */
        interface IERC20Metadata is IERC20 {
            /**
             * @dev Returns the name of the token.
             */
            function name() external view returns (string memory);
        
            /**
             * @dev Returns the symbol of the token.
             */
            function symbol() external view returns (string memory);
        
            /**
             * @dev Returns the decimals places of the token.
             */
            function decimals() external view returns (uint8);
        }
        
        /*
         * @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) {
                this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                return msg.data;
            }
        }
        
        
        /**
         * @dev Implementation of the {IERC20} interface.
         *
         * This implementation is agnostic to the way tokens are created. This means
         * that a supply mechanism has to be added in a derived contract using {_mint}.
         * For a generic mechanism see {ERC20PresetMinterPauser}.
         *
         * TIP: For a detailed writeup see our guide
         * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
         * to implement supply mechanisms].
         *
         * We have followed general OpenZeppelin guidelines: functions revert instead
         * of returning `false` on failure. This behavior is nonetheless conventional
         * and does not conflict with the expectations of ERC20 applications.
         *
         * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
         * This allows applications to reconstruct the allowance for all accounts just
         * by listening to said events. Other implementations of the EIP may not emit
         * these events, as it isn't required by the specification.
         *
         * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
         * functions have been added to mitigate the well-known issues around setting
         * allowances. See {IERC20-approve}.
         */
        contract ERC20 is Context, IERC20, IERC20Metadata {
            mapping (address => uint256) private _balances;
        
            mapping (address => mapping (address => uint256)) private _allowances;
        
            uint256 private _totalSupply;
        
            string private _name;
            string private _symbol;
        
            /**
             * @dev Sets the values for {name} and {symbol}.
             *
             * The defaut value of {decimals} is 18. To select a different value for
             * {decimals} you should overload it.
             *
             * All two of these values are immutable: they can only be set once during
             * construction.
             */
            constructor (string memory name_, string memory symbol_) {
                _name = name_;
                _symbol = symbol_;
            }
        
            /**
             * @dev Returns the name of the token.
             */
            function name() public view virtual override returns (string memory) {
                return _name;
            }
        
            /**
             * @dev Returns the symbol of the token, usually a shorter version of the
             * name.
             */
            function symbol() public view virtual override returns (string memory) {
                return _symbol;
            }
        
            /**
             * @dev Returns the number of decimals used to get its user representation.
             * For example, if `decimals` equals `2`, a balance of `505` tokens should
             * be displayed to a user as `5,05` (`505 / 10 ** 2`).
             *
             * Tokens usually opt for a value of 18, imitating the relationship between
             * Ether and Wei. This is the value {ERC20} uses, unless this function is
             * overridden;
             *
             * NOTE: This information is only used for _display_ purposes: it in
             * no way affects any of the arithmetic of the contract, including
             * {IERC20-balanceOf} and {IERC20-transfer}.
             */
            function decimals() public view virtual override returns (uint8) {
                return 18;
            }
        
            /**
             * @dev See {IERC20-totalSupply}.
             */
            function totalSupply() public view virtual override returns (uint256) {
                return _totalSupply;
            }
        
            /**
             * @dev See {IERC20-balanceOf}.
             */
            function balanceOf(address account) public view virtual override returns (uint256) {
                return _balances[account];
            }
        
            /**
             * @dev See {IERC20-transfer}.
             *
             * Requirements:
             *
             * - `recipient` cannot be the zero address.
             * - the caller must have a balance of at least `amount`.
             */
            function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
                _transfer(_msgSender(), recipient, amount);
                return true;
            }
        
            /**
             * @dev See {IERC20-allowance}.
             */
            function allowance(address owner, address spender) public view virtual override returns (uint256) {
                return _allowances[owner][spender];
            }
        
            /**
             * @dev See {IERC20-approve}.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             */
            function approve(address spender, uint256 amount) public virtual override returns (bool) {
                _approve(_msgSender(), spender, amount);
                return true;
            }
        
            /**
             * @dev See {IERC20-transferFrom}.
             *
             * Emits an {Approval} event indicating the updated allowance. This is not
             * required by the EIP. See the note at the beginning of {ERC20}.
             *
             * Requirements:
             *
             * - `sender` and `recipient` cannot be the zero address.
             * - `sender` must have a balance of at least `amount`.
             * - the caller must have allowance for ``sender``'s tokens of at least
             * `amount`.
             */
            function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
                _transfer(sender, recipient, amount);
        
                uint256 currentAllowance = _allowances[sender][_msgSender()];
                require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
                _approve(sender, _msgSender(), currentAllowance - amount);
        
                return true;
            }
        
            /**
             * @dev Atomically increases the allowance granted to `spender` by the caller.
             *
             * This is an alternative to {approve} that can be used as a mitigation for
             * problems described in {IERC20-approve}.
             *
             * Emits an {Approval} event indicating the updated allowance.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             */
            function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
                _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
                return true;
            }
        
            /**
             * @dev Atomically decreases the allowance granted to `spender` by the caller.
             *
             * This is an alternative to {approve} that can be used as a mitigation for
             * problems described in {IERC20-approve}.
             *
             * Emits an {Approval} event indicating the updated allowance.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             * - `spender` must have allowance for the caller of at least
             * `subtractedValue`.
             */
            function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
                uint256 currentAllowance = _allowances[_msgSender()][spender];
                require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
                _approve(_msgSender(), spender, currentAllowance - subtractedValue);
        
                return true;
            }
        
            /**
             * @dev Moves tokens `amount` from `sender` to `recipient`.
             *
             * This is internal function is equivalent to {transfer}, and can be used to
             * e.g. implement automatic token fees, slashing mechanisms, etc.
             *
             * Emits a {Transfer} event.
             *
             * Requirements:
             *
             * - `sender` cannot be the zero address.
             * - `recipient` cannot be the zero address.
             * - `sender` must have a balance of at least `amount`.
             */
            function _transfer(address sender, address recipient, uint256 amount) internal virtual {
                require(sender != address(0), "ERC20: transfer from the zero address");
                require(recipient != address(0), "ERC20: transfer to the zero address");
        
                _beforeTokenTransfer(sender, recipient, amount);
        
                uint256 senderBalance = _balances[sender];
                require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
                _balances[sender] = senderBalance - amount;
                _balances[recipient] += amount;
        
                emit Transfer(sender, recipient, amount);
            }
        
            /** @dev Creates `amount` tokens and assigns them to `account`, increasing
             * the total supply.
             *
             * Emits a {Transfer} event with `from` set to the zero address.
             *
             * Requirements:
             *
             * - `to` cannot be the zero address.
             */
            function _mint(address account, uint256 amount) internal virtual {
                require(account != address(0), "ERC20: mint to the zero address");
        
                _beforeTokenTransfer(address(0), account, amount);
        
                _totalSupply += amount;
                _balances[account] += amount;
                emit Transfer(address(0), account, amount);
            }
        
            /**
             * @dev Destroys `amount` tokens from `account`, reducing the
             * total supply.
             *
             * Emits a {Transfer} event with `to` set to the zero address.
             *
             * Requirements:
             *
             * - `account` cannot be the zero address.
             * - `account` must have at least `amount` tokens.
             */
            function _burn(address account, uint256 amount) internal virtual {
                require(account != address(0), "ERC20: burn from the zero address");
        
                _beforeTokenTransfer(account, address(0), amount);
        
                uint256 accountBalance = _balances[account];
                require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
                _balances[account] = accountBalance - amount;
                _totalSupply -= amount;
        
                emit Transfer(account, address(0), amount);
            }
        
            /**
             * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
             *
             * This internal function is equivalent to `approve`, and can be used to
             * e.g. set automatic allowances for certain subsystems, etc.
             *
             * Emits an {Approval} event.
             *
             * Requirements:
             *
             * - `owner` cannot be the zero address.
             * - `spender` cannot be the zero address.
             */
            function _approve(address owner, address spender, uint256 amount) internal virtual {
                require(owner != address(0), "ERC20: approve from the zero address");
                require(spender != address(0), "ERC20: approve to the zero address");
        
                _allowances[owner][spender] = amount;
                emit Approval(owner, spender, amount);
            }
        
            /**
             * @dev Hook that is called before any transfer of tokens. This includes
             * minting and burning.
             *
             * Calling conditions:
             *
             * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
             * will be to transferred to `to`.
             * - when `from` is zero, `amount` tokens will be minted for `to`.
             * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
             * - `from` and `to` are never both zero.
             *
             * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
             */
            function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
        }
        
        contract DOOR is ERC20 {
            constructor() ERC20("DOOR", "DOOR") {
                uint256 initialSupply = 4000000000 * (10 ** 18);
                _mint(msg.sender, initialSupply);
            }
        }

        File 2 of 4: E4CRanger
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
        import "@openzeppelin/contracts/access/Ownable.sol";
        import "./Mintable.sol";
        contract E4CRanger is ERC721, Mintable {
            string public baseURI;
            constructor(address imx, string memory name, string memory symbol) ERC721(name, symbol) Mintable(msg.sender, imx) { }
            function _baseURI() internal view override returns (string memory) {
                return baseURI;
            }
            function setBaseURI(string memory baseURI_) external onlyOwner {
                baseURI = baseURI_;
            }
            function _mintFor(
                address to,
                uint256 id,
                bytes memory
            ) internal override {
                _safeMint(to, id);
            }
            function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                return super.supportsInterface(interfaceId);
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.4;
        import "@openzeppelin/contracts/access/Ownable.sol";
        import "./IMintable.sol";
        import "./utils/Minting.sol";
        abstract contract Mintable is Ownable, IMintable {
            address public imx;
            mapping(uint256 => bytes) public blueprints;
            event AssetMinted(address to, uint256 id, bytes blueprint);
            address public saler;
            constructor(address _owner, address _imx) {
                imx = _imx;
                require(_owner != address(0), "Owner must not be empty");
                transferOwnership(_owner);
            }
            modifier onlyOwnerOrIMXOrSaler() {
                require(msg.sender == imx || msg.sender == saler || msg.sender == owner(), "Function can only be called by owner or IMX");
                _;
            }
            function mintFor(
                address user,
                uint256 quantity,
                bytes calldata mintingBlob
            ) external override onlyOwnerOrIMXOrSaler {
                require(quantity == 1, "Mintable: invalid quantity");
                (uint256 id, bytes memory blueprint) = Minting.split(mintingBlob);
                _mintFor(user, id, blueprint);
                blueprints[id] = blueprint;
                emit AssetMinted(user, id, blueprint);
            }
            function _mintFor(
                address to,
                uint256 id,
                bytes memory blueprint
            ) internal virtual;
            function setSaler(address _saler) external onlyOwner {
                saler = _saler;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/ERC721.sol)
        pragma solidity ^0.8.0;
        import "./IERC721.sol";
        import "./IERC721Receiver.sol";
        import "./extensions/IERC721Metadata.sol";
        import "../../utils/Address.sol";
        import "../../utils/Context.sol";
        import "../../utils/Strings.sol";
        import "../../utils/introspection/ERC165.sol";
        /**
         * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
         * the Metadata extension, but not including the Enumerable extension, which is available separately as
         * {ERC721Enumerable}.
         */
        contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
            using Address for address;
            using Strings for uint256;
            // Token name
            string private _name;
            // Token symbol
            string private _symbol;
            // Mapping from token ID to owner address
            mapping(uint256 => address) private _owners;
            // Mapping owner address to token count
            mapping(address => uint256) private _balances;
            // Mapping from token ID to approved address
            mapping(uint256 => address) private _tokenApprovals;
            // Mapping from owner to operator approvals
            mapping(address => mapping(address => bool)) private _operatorApprovals;
            /**
             * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
             */
            constructor(string memory name_, string memory symbol_) {
                _name = name_;
                _symbol = symbol_;
            }
            /**
             * @dev See {IERC165-supportsInterface}.
             */
            function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
                return
                    interfaceId == type(IERC721).interfaceId ||
                    interfaceId == type(IERC721Metadata).interfaceId ||
                    super.supportsInterface(interfaceId);
            }
            /**
             * @dev See {IERC721-balanceOf}.
             */
            function balanceOf(address owner) public view virtual override returns (uint256) {
                require(owner != address(0), "ERC721: address zero is not a valid owner");
                return _balances[owner];
            }
            /**
             * @dev See {IERC721-ownerOf}.
             */
            function ownerOf(uint256 tokenId) public view virtual override returns (address) {
                address owner = _owners[tokenId];
                require(owner != address(0), "ERC721: invalid token ID");
                return owner;
            }
            /**
             * @dev See {IERC721Metadata-name}.
             */
            function name() public view virtual override returns (string memory) {
                return _name;
            }
            /**
             * @dev See {IERC721Metadata-symbol}.
             */
            function symbol() public view virtual override returns (string memory) {
                return _symbol;
            }
            /**
             * @dev See {IERC721Metadata-tokenURI}.
             */
            function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
                _requireMinted(tokenId);
                string memory baseURI = _baseURI();
                return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
            }
            /**
             * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
             * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
             * by default, can be overridden in child contracts.
             */
            function _baseURI() internal view virtual returns (string memory) {
                return "";
            }
            /**
             * @dev See {IERC721-approve}.
             */
            function approve(address to, uint256 tokenId) public virtual override {
                address owner = ERC721.ownerOf(tokenId);
                require(to != owner, "ERC721: approval to current owner");
                require(
                    _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
                    "ERC721: approve caller is not token owner nor approved for all"
                );
                _approve(to, tokenId);
            }
            /**
             * @dev See {IERC721-getApproved}.
             */
            function getApproved(uint256 tokenId) public view virtual override returns (address) {
                _requireMinted(tokenId);
                return _tokenApprovals[tokenId];
            }
            /**
             * @dev See {IERC721-setApprovalForAll}.
             */
            function setApprovalForAll(address operator, bool approved) public virtual override {
                _setApprovalForAll(_msgSender(), operator, approved);
            }
            /**
             * @dev See {IERC721-isApprovedForAll}.
             */
            function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
                return _operatorApprovals[owner][operator];
            }
            /**
             * @dev See {IERC721-transferFrom}.
             */
            function transferFrom(
                address from,
                address to,
                uint256 tokenId
            ) public virtual override {
                //solhint-disable-next-line max-line-length
                require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner nor approved");
                _transfer(from, to, tokenId);
            }
            /**
             * @dev See {IERC721-safeTransferFrom}.
             */
            function safeTransferFrom(
                address from,
                address to,
                uint256 tokenId
            ) public virtual override {
                safeTransferFrom(from, to, tokenId, "");
            }
            /**
             * @dev See {IERC721-safeTransferFrom}.
             */
            function safeTransferFrom(
                address from,
                address to,
                uint256 tokenId,
                bytes memory data
            ) public virtual override {
                require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner nor approved");
                _safeTransfer(from, to, tokenId, data);
            }
            /**
             * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
             * are aware of the ERC721 protocol to prevent tokens from being forever locked.
             *
             * `data` is additional data, it has no specified format and it is sent in call to `to`.
             *
             * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
             * implement alternative mechanisms to perform token transfer, such as signature-based.
             *
             * Requirements:
             *
             * - `from` cannot be the zero address.
             * - `to` cannot be the zero address.
             * - `tokenId` token must exist and be owned by `from`.
             * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
             *
             * Emits a {Transfer} event.
             */
            function _safeTransfer(
                address from,
                address to,
                uint256 tokenId,
                bytes memory data
            ) internal virtual {
                _transfer(from, to, tokenId);
                require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer");
            }
            /**
             * @dev Returns whether `tokenId` exists.
             *
             * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
             *
             * Tokens start existing when they are minted (`_mint`),
             * and stop existing when they are burned (`_burn`).
             */
            function _exists(uint256 tokenId) internal view virtual returns (bool) {
                return _owners[tokenId] != address(0);
            }
            /**
             * @dev Returns whether `spender` is allowed to manage `tokenId`.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             */
            function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
                address owner = ERC721.ownerOf(tokenId);
                return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
            }
            /**
             * @dev Safely mints `tokenId` and transfers it to `to`.
             *
             * Requirements:
             *
             * - `tokenId` must not exist.
             * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
             *
             * Emits a {Transfer} event.
             */
            function _safeMint(address to, uint256 tokenId) internal virtual {
                _safeMint(to, tokenId, "");
            }
            /**
             * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
             * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
             */
            function _safeMint(
                address to,
                uint256 tokenId,
                bytes memory data
            ) internal virtual {
                _mint(to, tokenId);
                require(
                    _checkOnERC721Received(address(0), to, tokenId, data),
                    "ERC721: transfer to non ERC721Receiver implementer"
                );
            }
            /**
             * @dev Mints `tokenId` and transfers it to `to`.
             *
             * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
             *
             * Requirements:
             *
             * - `tokenId` must not exist.
             * - `to` cannot be the zero address.
             *
             * Emits a {Transfer} event.
             */
            function _mint(address to, uint256 tokenId) internal virtual {
                require(to != address(0), "ERC721: mint to the zero address");
                require(!_exists(tokenId), "ERC721: token already minted");
                _beforeTokenTransfer(address(0), to, tokenId);
                _balances[to] += 1;
                _owners[tokenId] = to;
                emit Transfer(address(0), to, tokenId);
                _afterTokenTransfer(address(0), to, tokenId);
            }
            /**
             * @dev Destroys `tokenId`.
             * The approval is cleared when the token is burned.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             *
             * Emits a {Transfer} event.
             */
            function _burn(uint256 tokenId) internal virtual {
                address owner = ERC721.ownerOf(tokenId);
                _beforeTokenTransfer(owner, address(0), tokenId);
                // Clear approvals
                _approve(address(0), tokenId);
                _balances[owner] -= 1;
                delete _owners[tokenId];
                emit Transfer(owner, address(0), tokenId);
                _afterTokenTransfer(owner, address(0), tokenId);
            }
            /**
             * @dev Transfers `tokenId` from `from` to `to`.
             *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
             *
             * Requirements:
             *
             * - `to` cannot be the zero address.
             * - `tokenId` token must be owned by `from`.
             *
             * Emits a {Transfer} event.
             */
            function _transfer(
                address from,
                address to,
                uint256 tokenId
            ) internal virtual {
                require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
                require(to != address(0), "ERC721: transfer to the zero address");
                _beforeTokenTransfer(from, to, tokenId);
                // Clear approvals from the previous owner
                _approve(address(0), tokenId);
                _balances[from] -= 1;
                _balances[to] += 1;
                _owners[tokenId] = to;
                emit Transfer(from, to, tokenId);
                _afterTokenTransfer(from, to, tokenId);
            }
            /**
             * @dev Approve `to` to operate on `tokenId`
             *
             * Emits an {Approval} event.
             */
            function _approve(address to, uint256 tokenId) internal virtual {
                _tokenApprovals[tokenId] = to;
                emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
            }
            /**
             * @dev Approve `operator` to operate on all of `owner` tokens
             *
             * Emits an {ApprovalForAll} event.
             */
            function _setApprovalForAll(
                address owner,
                address operator,
                bool approved
            ) internal virtual {
                require(owner != operator, "ERC721: approve to caller");
                _operatorApprovals[owner][operator] = approved;
                emit ApprovalForAll(owner, operator, approved);
            }
            /**
             * @dev Reverts if the `tokenId` has not been minted yet.
             */
            function _requireMinted(uint256 tokenId) internal view virtual {
                require(_exists(tokenId), "ERC721: invalid token ID");
            }
            /**
             * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
             * The call is not executed if the target address is not a contract.
             *
             * @param from address representing the previous owner of the given token ID
             * @param to target address that will receive the tokens
             * @param tokenId uint256 ID of the token to be transferred
             * @param data bytes optional data to send along with the call
             * @return bool whether the call correctly returned the expected magic value
             */
            function _checkOnERC721Received(
                address from,
                address to,
                uint256 tokenId,
                bytes memory data
            ) private returns (bool) {
                if (to.isContract()) {
                    try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
                        return retval == IERC721Receiver.onERC721Received.selector;
                    } catch (bytes memory reason) {
                        if (reason.length == 0) {
                            revert("ERC721: transfer to non ERC721Receiver implementer");
                        } else {
                            /// @solidity memory-safe-assembly
                            assembly {
                                revert(add(32, reason), mload(reason))
                            }
                        }
                    }
                } else {
                    return true;
                }
            }
            /**
             * @dev Hook that is called before any token transfer. This includes minting
             * and burning.
             *
             * Calling conditions:
             *
             * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
             * transferred to `to`.
             * - When `from` is zero, `tokenId` will be minted for `to`.
             * - When `to` is zero, ``from``'s `tokenId` will be burned.
             * - `from` and `to` are never both zero.
             *
             * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
             */
            function _beforeTokenTransfer(
                address from,
                address to,
                uint256 tokenId
            ) internal virtual {}
            /**
             * @dev Hook that is called after any transfer of tokens. This includes
             * minting and burning.
             *
             * Calling conditions:
             *
             * - when `from` and `to` are both non-zero.
             * - `from` and `to` are never both zero.
             *
             * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
             */
            function _afterTokenTransfer(
                address from,
                address to,
                uint256 tokenId
            ) internal virtual {}
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
        pragma solidity ^0.8.0;
        import "../utils/Context.sol";
        /**
         * @dev Contract module which provides a basic access control mechanism, where
         * there is an account (an owner) that can be granted exclusive access to
         * specific functions.
         *
         * By default, the owner account will be the one that deploys the contract. This
         * can later be changed with {transferOwnership}.
         *
         * This module is used through inheritance. It will make available the modifier
         * `onlyOwner`, which can be applied to your functions to restrict their use to
         * the owner.
         */
        abstract contract Ownable is Context {
            address private _owner;
            event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            /**
             * @dev Initializes the contract setting the deployer as the initial owner.
             */
            constructor() {
                _transferOwnership(_msgSender());
            }
            /**
             * @dev Throws if called by any account other than the owner.
             */
            modifier onlyOwner() {
                _checkOwner();
                _;
            }
            /**
             * @dev Returns the address of the current owner.
             */
            function owner() public view virtual returns (address) {
                return _owner;
            }
            /**
             * @dev Throws if the sender is not the owner.
             */
            function _checkOwner() internal view virtual {
                require(owner() == _msgSender(), "Ownable: caller is not the owner");
            }
            /**
             * @dev Leaves the contract without owner. It will not be possible to call
             * `onlyOwner` functions anymore. Can only be called by the current owner.
             *
             * NOTE: Renouncing ownership will leave the contract without an owner,
             * thereby removing any functionality that is only available to the owner.
             */
            function renounceOwnership() public virtual onlyOwner {
                _transferOwnership(address(0));
            }
            /**
             * @dev Transfers ownership of the contract to a new account (`newOwner`).
             * Can only be called by the current owner.
             */
            function transferOwnership(address newOwner) public virtual onlyOwner {
                require(newOwner != address(0), "Ownable: new owner is the zero address");
                _transferOwnership(newOwner);
            }
            /**
             * @dev Transfers ownership of the contract to a new account (`newOwner`).
             * Internal function without access restriction.
             */
            function _transferOwnership(address newOwner) internal virtual {
                address oldOwner = _owner;
                _owner = newOwner;
                emit OwnershipTransferred(oldOwner, newOwner);
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.4;
        interface IMintable {
            function mintFor(
                address to,
                uint256 quantity,
                bytes calldata mintingBlob
            ) external;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.4;
        import "./Bytes.sol";
        library Minting {
            // Split the minting blob into token_id and blueprint portions
            // {token_id}:{blueprint}
            function split(bytes calldata blob)
                internal
                pure
                returns (uint256, bytes memory)
            {
                int256 index = Bytes.indexOf(blob, ":", 0);
                require(index >= 0, "Separator must exist");
                // Trim the { and } from the parameters
                uint256 tokenID = Bytes.toUint(blob[1:uint256(index) - 1]);
                uint256 blueprintLength = blob.length - uint256(index) - 3;
                if (blueprintLength == 0) {
                    return (tokenID, bytes(""));
                }
                bytes calldata blueprint = blob[uint256(index) + 2:blob.length - 1];
                return (tokenID, blueprint);
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.4;
        library Bytes {
            /**
             * @dev Converts a `uint256` to a `string`.
             * via OraclizeAPI - MIT licence
             * https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
             */
            function fromUint(uint256 value) internal pure returns (string memory) {
                if (value == 0) {
                    return "0";
                }
                uint256 temp = value;
                uint256 digits;
                while (temp != 0) {
                    digits++;
                    temp /= 10;
                }
                bytes memory buffer = new bytes(digits);
                uint256 index = digits - 1;
                temp = value;
                while (temp != 0) {
                    buffer[index--] = bytes1(uint8(48 + (temp % 10)));
                    temp /= 10;
                }
                return string(buffer);
            }
            bytes constant alphabet = "0123456789abcdef";
            /**
             * Index Of
             *
             * Locates and returns the position of a character within a string starting
             * from a defined offset
             *
             * @param _base When being used for a data type this is the extended object
             *              otherwise this is the string acting as the haystack to be
             *              searched
             * @param _value The needle to search for, at present this is currently
             *               limited to one character
             * @param _offset The starting point to start searching from which can start
             *                from 0, but must not exceed the length of the string
             * @return int The position of the needle starting from 0 and returning -1
             *             in the case of no matches found
             */
            function indexOf(
                bytes memory _base,
                string memory _value,
                uint256 _offset
            ) internal pure returns (int256) {
                bytes memory _valueBytes = bytes(_value);
                assert(_valueBytes.length == 1);
                for (uint256 i = _offset; i < _base.length; i++) {
                    if (_base[i] == _valueBytes[0]) {
                        return int256(i);
                    }
                }
                return -1;
            }
            function substring(
                bytes memory strBytes,
                uint256 startIndex,
                uint256 endIndex
            ) internal pure returns (string memory) {
                bytes memory result = new bytes(endIndex - startIndex);
                for (uint256 i = startIndex; i < endIndex; i++) {
                    result[i - startIndex] = strBytes[i];
                }
                return string(result);
            }
            function toUint(bytes memory b) internal pure returns (uint256) {
                uint256 result = 0;
                for (uint256 i = 0; i < b.length; i++) {
                    uint256 val = uint256(uint8(b[i]));
                    if (val >= 48 && val <= 57) {
                        // input is 0-9
                        result = result * 10 + (val - 48);
                    } else {
                        // invalid character, expecting integer input
                        revert("invalid input, only numbers allowed");
                    }
                }
                return result;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
        pragma solidity ^0.8.0;
        /**
         * @dev Provides information about the current execution context, including the
         * sender of the transaction and its data. While these are generally available
         * via msg.sender and msg.data, they should not be accessed in such a direct
         * manner, since when dealing with meta-transactions the account sending and
         * paying for execution may not be the actual sender (as far as an application
         * is concerned).
         *
         * This contract is only required for intermediate, library-like contracts.
         */
        abstract contract Context {
            function _msgSender() internal view virtual returns (address) {
                return msg.sender;
            }
            function _msgData() internal view virtual returns (bytes calldata) {
                return msg.data;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)
        pragma solidity ^0.8.0;
        /**
         * @dev String operations.
         */
        library Strings {
            bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
            uint8 private constant _ADDRESS_LENGTH = 20;
            /**
             * @dev Converts a `uint256` to its ASCII `string` decimal representation.
             */
            function toString(uint256 value) internal pure returns (string memory) {
                // Inspired by OraclizeAPI's implementation - MIT licence
                // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
                if (value == 0) {
                    return "0";
                }
                uint256 temp = value;
                uint256 digits;
                while (temp != 0) {
                    digits++;
                    temp /= 10;
                }
                bytes memory buffer = new bytes(digits);
                while (value != 0) {
                    digits -= 1;
                    buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                    value /= 10;
                }
                return string(buffer);
            }
            /**
             * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
             */
            function toHexString(uint256 value) internal pure returns (string memory) {
                if (value == 0) {
                    return "0x00";
                }
                uint256 temp = value;
                uint256 length = 0;
                while (temp != 0) {
                    length++;
                    temp >>= 8;
                }
                return toHexString(value, length);
            }
            /**
             * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
             */
            function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                bytes memory buffer = new bytes(2 * length + 2);
                buffer[0] = "0";
                buffer[1] = "x";
                for (uint256 i = 2 * length + 1; i > 1; --i) {
                    buffer[i] = _HEX_SYMBOLS[value & 0xf];
                    value >>= 4;
                }
                require(value == 0, "Strings: hex length insufficient");
                return string(buffer);
            }
            /**
             * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
             */
            function toHexString(address addr) internal pure returns (string memory) {
                return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
        pragma solidity ^0.8.1;
        /**
         * @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
             * ====
             *
             * [IMPORTANT]
             * ====
             * You shouldn't rely on `isContract` to protect against flash loan attacks!
             *
             * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
             * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
             * constructor.
             * ====
             */
            function isContract(address account) internal view returns (bool) {
                // This method relies on extcodesize/address.code.length, which returns 0
                // for contracts in construction, since the code is only stored at the end
                // of the constructor execution.
                return account.code.length > 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
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert(errorMessage);
                    }
                }
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)
        pragma solidity ^0.8.0;
        import "../../utils/introspection/IERC165.sol";
        /**
         * @dev Required interface of an ERC721 compliant contract.
         */
        interface IERC721 is IERC165 {
            /**
             * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
             */
            event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
            /**
             * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
             */
            event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
            /**
             * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
             */
            event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
            /**
             * @dev Returns the number of tokens in ``owner``'s account.
             */
            function balanceOf(address owner) external view returns (uint256 balance);
            /**
             * @dev Returns the owner of the `tokenId` token.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             */
            function ownerOf(uint256 tokenId) external view returns (address owner);
            /**
             * @dev Safely transfers `tokenId` token from `from` to `to`.
             *
             * Requirements:
             *
             * - `from` cannot be the zero address.
             * - `to` cannot be the zero address.
             * - `tokenId` token must exist and be owned by `from`.
             * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
             * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
             *
             * Emits a {Transfer} event.
             */
            function safeTransferFrom(
                address from,
                address to,
                uint256 tokenId,
                bytes calldata data
            ) external;
            /**
             * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
             * are aware of the ERC721 protocol to prevent tokens from being forever locked.
             *
             * Requirements:
             *
             * - `from` cannot be the zero address.
             * - `to` cannot be the zero address.
             * - `tokenId` token must exist and be owned by `from`.
             * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
             * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
             *
             * Emits a {Transfer} event.
             */
            function safeTransferFrom(
                address from,
                address to,
                uint256 tokenId
            ) external;
            /**
             * @dev Transfers `tokenId` token from `from` to `to`.
             *
             * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
             *
             * Requirements:
             *
             * - `from` cannot be the zero address.
             * - `to` cannot be the zero address.
             * - `tokenId` token must be owned by `from`.
             * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
             *
             * Emits a {Transfer} event.
             */
            function transferFrom(
                address from,
                address to,
                uint256 tokenId
            ) external;
            /**
             * @dev Gives permission to `to` to transfer `tokenId` token to another account.
             * The approval is cleared when the token is transferred.
             *
             * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
             *
             * Requirements:
             *
             * - The caller must own the token or be an approved operator.
             * - `tokenId` must exist.
             *
             * Emits an {Approval} event.
             */
            function approve(address to, uint256 tokenId) external;
            /**
             * @dev Approve or remove `operator` as an operator for the caller.
             * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
             *
             * Requirements:
             *
             * - The `operator` cannot be the caller.
             *
             * Emits an {ApprovalForAll} event.
             */
            function setApprovalForAll(address operator, bool _approved) external;
            /**
             * @dev Returns the account approved for `tokenId` token.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             */
            function getApproved(uint256 tokenId) external view returns (address operator);
            /**
             * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
             *
             * See {setApprovalForAll}
             */
            function isApprovedForAll(address owner, address operator) external view returns (bool);
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
        pragma solidity ^0.8.0;
        /**
         * @title ERC721 token receiver interface
         * @dev Interface for any contract that wants to support safeTransfers
         * from ERC721 asset contracts.
         */
        interface IERC721Receiver {
            /**
             * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
             * by `operator` from `from`, this function is called.
             *
             * It must return its Solidity selector to confirm the token transfer.
             * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
             *
             * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
             */
            function onERC721Received(
                address operator,
                address from,
                uint256 tokenId,
                bytes calldata data
            ) external returns (bytes4);
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
        pragma solidity ^0.8.0;
        import "./IERC165.sol";
        /**
         * @dev Implementation of the {IERC165} interface.
         *
         * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
         * for the additional interface id that will be supported. For example:
         *
         * ```solidity
         * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
         *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
         * }
         * ```
         *
         * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
         */
        abstract contract ERC165 is IERC165 {
            /**
             * @dev See {IERC165-supportsInterface}.
             */
            function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                return interfaceId == type(IERC165).interfaceId;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)
        pragma solidity ^0.8.0;
        import "../IERC721.sol";
        /**
         * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
         * @dev See https://eips.ethereum.org/EIPS/eip-721
         */
        interface IERC721Metadata is IERC721 {
            /**
             * @dev Returns the token collection name.
             */
            function name() external view returns (string memory);
            /**
             * @dev Returns the token collection symbol.
             */
            function symbol() external view returns (string memory);
            /**
             * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
             */
            function tokenURI(uint256 tokenId) external view returns (string memory);
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
        pragma solidity ^0.8.0;
        /**
         * @dev Interface of the ERC165 standard, as defined in the
         * https://eips.ethereum.org/EIPS/eip-165[EIP].
         *
         * Implementers can declare support of contract interfaces, which can then be
         * queried by others ({ERC165Checker}).
         *
         * For an implementation, see {ERC165}.
         */
        interface IERC165 {
            /**
             * @dev Returns true if this contract implements the interface defined by
             * `interfaceId`. See the corresponding
             * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
             * to learn more about how these ids are created.
             *
             * This function call must use less than 30 000 gas.
             */
            function supportsInterface(bytes4 interfaceId) external view returns (bool);
        }
        

        File 3 of 4: StarkExchange
        {"BlockDirectCall.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\n/*\n  This contract provides means to block direct call of an external function.\n  A derived contract (e.g. MainDispatcherBase) should decorate sensitive functions with the\n  notCalledDirectly modifier, thereby preventing it from being called directly, and allowing only calling\n  using delegate_call.\n\n  This Guard contract uses pseudo-random slot, So each deployed contract would have its own guard.\n*/\nabstract contract BlockDirectCall {\n    bytes32 immutable UNIQUE_SAFEGUARD_SLOT; // NOLINT naming-convention.\n    constructor( ) internal {\n        // The slot is pseudo-random to allow hierarchy of contracts with guarded functions.\n        bytes32 slot = keccak256(abi.encode(this, block.timestamp, gasleft()));\n        UNIQUE_SAFEGUARD_SLOT = slot;\n        assembly {\n            sstore(slot, 42)\n        }\n    }\n\n    modifier notCalledDirectly() {\n        { // Prevent too many local variables in stack.\n            uint256 safeGuardValue;\n            bytes32 slot = UNIQUE_SAFEGUARD_SLOT;\n            assembly {\n                safeGuardValue := sload(slot)\n            }\n            require(safeGuardValue == 0, \"DIRECT_CALL_DISALLOWED\");\n        }\n        _;\n    }\n}\n"},"Common.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\n/*\n  Common Utility librarries.\n  I. Addresses (extending address).\n*/\nlibrary Addresses {\n    function isContract(address account) internal view returns (bool) {\n        uint256 size;\n        assembly {\n            size := extcodesize(account)\n        }\n        return size \u003e 0;\n    }\n\n    function performEthTransfer(address recipient, uint256 amount) internal {\n        (bool success, ) = recipient.call{value: amount}(\"\"); // NOLINT: low-level-calls.\n        require(success, \"ETH_TRANSFER_FAILED\");\n    }\n\n    /*\n      Safe wrapper around ERC20/ERC721 calls.\n      This is required because many deployed ERC20 contracts don\u0027t return a value.\n      See https://github.com/ethereum/solidity/issues/4116.\n    */\n    function safeTokenContractCall(address tokenAddress, bytes memory callData) internal {\n        require(isContract(tokenAddress), \"BAD_TOKEN_ADDRESS\");\n        // NOLINTNEXTLINE: low-level-calls.\n        (bool success, bytes memory returndata) = tokenAddress.call(callData);\n        require(success, string(returndata));\n\n        if (returndata.length \u003e 0) {\n            require(abi.decode(returndata, (bool)), \"TOKEN_OPERATION_FAILED\");\n        }\n    }\n\n    /*\n      Validates that the passed contract address is of a real contract,\n      and that its id hash (as infered fromn identify()) matched the expected one.\n    */\n    function validateContractId(address contractAddress, bytes32 expectedIdHash)\n        internal\n    {\n        require(isContract(contractAddress), \"ADDRESS_NOT_CONTRACT\");\n        (bool success, bytes memory returndata) = contractAddress.call( // NOLINT: low-level-calls.\n            abi.encodeWithSignature(\"identify()\"));\n        require(success, \"FAILED_TO_IDENTIFY_CONTRACT\");\n        string memory realContractId = abi.decode(returndata, (string));\n        require(\n            keccak256(abi.encodePacked(realContractId)) == expectedIdHash,\n            \"UNEXPECTED_CONTRACT_IDENTIFIER\");\n    }\n\n    /*\n      Similar to safeTokenContractCall, but always ignores the return value.\n\n      Assumes some other method is used to detect the failures\n      (e.g. balance is checked before and after the call).\n    */\n    function uncheckedTokenContractCall(address tokenAddress, bytes memory callData) internal {\n        // NOLINTNEXTLINE: low-level-calls.\n        (bool success, bytes memory returndata) = tokenAddress.call(callData);\n        require(success, string(returndata));\n    }\n\n}\n\nlibrary UintArray {\n    function hashSubArray(uint256[] memory array, uint256 subArrayStart, uint256 subArraySize)\n        internal pure\n        returns(bytes32 subArrayHash)\n    {\n        require(array.length \u003e= subArrayStart + subArraySize, \"ILLEGAL_SUBARRAY_DIMENSIONS\");\n        uint256 startOffsetBytes = 0x20 * (1 + subArrayStart);\n        uint256 dataSizeBytes = 0x20 * subArraySize;\n        assembly {\n            subArrayHash := keccak256(add(array, startOffsetBytes), dataSizeBytes)\n        }\n    }\n\n    /*\n      Returns the address of a cell in offset within a uint256[] array.\n      This allows assigning new variable of dynamic unit256[] pointing to a sub_array\n      with a layout of serialied uint256[] (i.e. length+content).\n    */\n    function extractSerializedUintArray(uint256[] memory programOutput, uint256 offset)\n        internal pure\n        returns (uint256[] memory addr)\n    {\n        uint256 memOffset = 0x20 * (offset + 1);\n        assembly {\n            addr := add(programOutput, memOffset)\n        }\n    }\n\n}\n\n/*\n  II. StarkExTypes - Common data types.\n*/\nlibrary StarkExTypes {\n\n    // Structure representing a list of verifiers (validity/availability).\n    // A statement is valid only if all the verifiers in the list agree on it.\n    // Adding a verifier to the list is immediate - this is used for fast resolution of\n    // any soundness issues.\n    // Removing from the list is time-locked, to ensure that any user of the system\n    // not content with the announced removal has ample time to leave the system before it is\n    // removed.\n    struct ApprovalChainData {\n        address[] list;\n        // Represents the time after which the verifier with the given address can be removed.\n        // Removal of the verifier with address A is allowed only in the case the value\n        // of unlockedForRemovalTime[A] != 0 and unlockedForRemovalTime[A] \u003c (current time).\n        mapping (address =\u003e uint256) unlockedForRemovalTime;\n    }\n}\n"},"GovernanceStorage.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\n/*\n  Holds the governance slots for ALL entities, including proxy and the main contract.\n*/\ncontract GovernanceStorage {\n\n    struct GovernanceInfoStruct {\n        mapping (address =\u003e bool) effectiveGovernors;\n        address candidateGovernor;\n        bool initialized;\n    }\n\n    // A map from a Governor tag to its own GovernanceInfoStruct.\n    mapping (string =\u003e GovernanceInfoStruct) internal governanceInfo;\n}\n"},"Identity.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\ninterface Identity {\n\n    /*\n      Allows a caller, typically another contract,\n      to ensure that the provided address is of the expected type and version.\n    */\n    function identify()\n        external pure\n        returns(string memory);\n}\n"},"IDispatcherBase.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\n/*\n  Interface for generic dispatcher to use,\n  which the concrete dispatcher must implement.\n\n  I contains the functions that are specific to the concrete dispatcher instance.\n\n  The interface is implemented as contract, because interface implies all methods external.\n*/\nabstract contract IDispatcherBase {\n\n    function getSubContract(bytes4 selector) internal view virtual returns (address);\n\n    function setSubContractAddress(uint256 index, address subContract) internal virtual;\n\n    function getNumSubcontracts() internal pure virtual returns (uint256);\n\n    function validateSubContractIndex(uint256 index, address subContract) internal pure virtual;\n\n    /*\n      Ensures initializer can be called. Reverts otherwise.\n    */\n    function initializationSentinel() internal view virtual;\n}\n"},"MainDispatcher.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"MainStorage.sol\";\nimport \"MainDispatcherBase.sol\";\n\nabstract contract MainDispatcher is MainStorage, MainDispatcherBase {\n\n    uint256 constant SUBCONTRACT_BITS = 4;\n\n    function magicSalt() internal pure virtual returns(uint256);\n    function handlerMapSection(uint256 section) internal view virtual returns(uint256);\n    function expectedIdByIndex(uint256 index) internal pure virtual returns (string memory id);\n\n    function validateSubContractIndex(uint256 index, address subContract) internal pure override {\n        string memory id = SubContractor(subContract).identify();\n        bytes32 hashed_expected_id = keccak256(abi.encodePacked(expectedIdByIndex(index)));\n        require(\n            hashed_expected_id == keccak256(abi.encodePacked(id)),\n            \"MISPLACED_INDEX_OR_BAD_CONTRACT_ID\"\n        );\n    }\n\n    function getSubContract(bytes4 selector) internal view override returns (address) {\n        uint256 location = 0xFF \u0026 uint256(keccak256(abi.encodePacked(selector, magicSalt())));\n        uint256 subContractIdx;\n        uint256 offset = (SUBCONTRACT_BITS * location) % 256;\n\n        // We have 64 locations in each register, hence the \u003e\u003e6 (i.e. location // 64).\n        subContractIdx = (handlerMapSection(location \u003e\u003e 6) \u003e\u003e offset) \u0026 0xF;\n        return subContracts[subContractIdx];\n    }\n\n    function setSubContractAddress(uint256 index, address subContractAddress) internal override {\n        subContracts[index] = subContractAddress;\n    }\n}\n"},"MainDispatcherBase.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"SubContractor.sol\";\nimport \"IDispatcherBase.sol\";\nimport \"BlockDirectCall.sol\";\nimport \"Common.sol\";\n\nabstract contract MainDispatcherBase is IDispatcherBase, BlockDirectCall {\n\n    using Addresses for address;\n\n    /*\n      This entry point serves only transactions with empty calldata. (i.e. pure value transfer tx).\n      We don\u0027t expect to receive such, thus block them.\n    */\n    receive() external payable {\n        revert(\"CONTRACT_NOT_EXPECTED_TO_RECEIVE\");\n    }\n\n    fallback() external payable {\n        address subContractAddress = getSubContract(msg.sig);\n        require(subContractAddress != address(0x0), \"NO_CONTRACT_FOR_FUNCTION\");\n\n        assembly {\n            // Copy msg.data. We take full control of memory in this inline assembly\n            // block because it will not return to Solidity code. We overwrite the\n            // Solidity scratch pad at memory position 0.\n            calldatacopy(0, 0, calldatasize())\n\n            // Call the implementation.\n            // out and outsize are 0 for now, as we don\"t know the out size yet.\n            let result := delegatecall(gas(), subContractAddress, 0, calldatasize(), 0, 0)\n\n            // Copy the returned data.\n            returndatacopy(0, 0, returndatasize())\n\n            switch result\n                // delegatecall returns 0 on error.\n                case 0 {\n                    revert(0, returndatasize())\n                }\n                default {\n                    return(0, returndatasize())\n                }\n        }\n    }\n\n    /*\n      1. Extract subcontracts.\n      2. Verify correct sub-contract initializer size.\n      3. Extract sub-contract initializer data.\n      4. Call sub-contract initializer.\n\n      The init data bytes passed to initialize are structed as following:\n      I. N slots (uin256 size) addresses of the deployed sub-contracts.\n      II. An address of an external initialization contract (optional, or ZERO_ADDRESS).\n      III. (Up to) N bytes sections of the sub-contracts initializers.\n\n      If already initialized (i.e. upgrade) we expect the init data to be consistent with this.\n      and if a different size of init data is expected when upgrading, the initializerSize should\n      reflect this.\n\n      If an external initializer contract is not used, ZERO_ADDRESS is passed in its slot.\n      If the external initializer contract is used, all the remaining init data is passed to it,\n      and internal initialization will not occur.\n\n      External Initialization Contract\n      --------------------------------\n      External Initialization Contract (EIC) is a hook for custom initialization.\n      Typically in an upgrade flow, the expected initialization contains only the addresses of\n      the sub-contracts. Normal initialization of the sub-contracts is such that is not needed\n      in an upgrade, and actually may be very dangerous, as changing of state on a working system\n      may corrupt it.\n\n      In the event that some state initialization is required, the EIC is a hook that allows this.\n      It may be deployed and called specifically for this purpose.\n\n      The address of the EIC must be provided (if at all) when a new implementation is added to\n      a Proxy contract (as part of the initialization vector).\n      Hence, it is considered part of the code open to reviewers prior to a time-locked upgrade.\n\n      When a custom initialization is performed using an EIC,\n      the main dispatcher initialize extracts and stores the sub-contracts addresses, and then\n      yields to the EIC, skipping the rest of its initialization code.\n\n\n      Flow of MainDispatcher initialize\n      ---------------------------------\n      1. Extraction and assignment of subcontracts addresses\n         Main dispatcher expects a valid and consistent set of addresses in the passed data.\n         It validates that, extracts the addresses from the data, and validates that the addresses\n         are of the expected type and order. Then those addresses are stored.\n\n      2. Extraction of EIC address\n         The address of the EIC is extracted from the data.\n         External Initializer Contract is optional. ZERO_ADDRESS indicates it is not used.\n\n      3a. EIC is used\n          Dispatcher calls the EIC initialize function with the remaining data.\n          Note - In this option 3b is not performed.\n\n      3b. EIC is not used\n          If there is additional initialization data then:\n          I. Sentitenl function is called to permit subcontracts initialization.\n          II. Dispatcher loops through the subcontracts and for each one it extracts the\n              initializing data and passes it to the subcontract\u0027s initialize function.\n\n    */\n    // NOLINTNEXTLINE: external-function.\n    function initialize(bytes memory data) public virtual\n        notCalledDirectly\n    {\n        // Number of sub-contracts.\n        uint256 nSubContracts = getNumSubcontracts();\n\n        // We support currently 4 bits per contract, i.e. 16, reserving 00 leads to 15.\n        require(nSubContracts \u003c= 15, \"TOO_MANY_SUB_CONTRACTS\");\n\n        // Init data MUST include addresses for all sub-contracts + EIC.\n        require(data.length \u003e= 32 * (nSubContracts + 1), \"SUB_CONTRACTS_NOT_PROVIDED\");\n\n        // Size of passed data, excluding sub-contract addresses.\n        uint256 additionalDataSize = data.length - 32 * (nSubContracts + 1);\n\n        // Sum of subcontract initializers. Aggregated for verification near the end.\n        uint256 totalInitSizes = 0;\n\n        // Offset (within data) of sub-contract initializer vector.\n        // Just past the sub-contract addresses.\n        uint256 initDataContractsOffset = 32 * (nSubContracts + 1);\n\n        // Extract \u0026 update contract addresses.\n        for (uint256 nContract = 1; nContract \u003c= nSubContracts; nContract++) {\n            address contractAddress;\n\n            // Extract sub-contract address.\n            assembly {\n                contractAddress := mload(add(data, mul(32, nContract)))\n            }\n\n            validateSubContractIndex(nContract, contractAddress);\n\n            // Contracts are indexed from 1 and 0 is not in use here.\n            setSubContractAddress(nContract, contractAddress);\n        }\n\n        // Check if we have an external initializer contract.\n        address externalInitializerAddr;\n\n        // 2. Extract sub-contract address, again. It\u0027s cheaper than reading from storage.\n        assembly {\n            externalInitializerAddr := mload(add(data, mul(32, add(nSubContracts, 1))))\n        }\n\n        // 3(a). Yield to EIC initialization.\n        if (externalInitializerAddr != address(0x0)) {\n            callExternalInitializer(data, externalInitializerAddr, additionalDataSize);\n            return;\n        }\n\n        // 3(b). Subcontracts initialization.\n        // I. If no init data passed besides sub-contracts, return.\n        if (additionalDataSize == 0) {\n            return;\n        }\n\n        // Just to be on the safe side.\n        assert(externalInitializerAddr == address(0x0));\n\n        // II. Gate further initialization.\n        initializationSentinel();\n\n        // III. Loops through the subcontracts, extracts their data and calls their initializer.\n        for (uint256 nContract = 1; nContract \u003c= nSubContracts; nContract++) {\n            address contractAddress;\n\n            // Extract sub-contract address, again. It\u0027s cheaper than reading from storage.\n            assembly {\n                contractAddress := mload(add(data, mul(32, nContract)))\n            }\n            // The initializerSize returns the expected size, with respect also to the state status.\n            // i.e. different size if it\u0027s a first init (clean state) or upgrade init (alive state).\n            // NOLINTNEXTLINE: calls-loop.\n\n            // The initializerSize is called via delegatecall, so that it can relate to the state,\n            // and not only to the new contract code. (e.g. return 0 if state-intialized else 192).\n            // NOLINTNEXTLINE: reentrancy-events low-level-calls calls-loop.\n            (bool success, bytes memory returndata) = contractAddress.delegatecall(\n                abi.encodeWithSelector(SubContractor(contractAddress).initializerSize.selector));\n            require(success, string(returndata));\n            uint256 initSize = abi.decode(returndata, (uint256));\n            require(initSize \u003c= additionalDataSize, \"INVALID_INITIALIZER_SIZE\");\n            require(totalInitSizes + initSize \u003c= additionalDataSize, \"INVALID_INITIALIZER_SIZE\");\n\n            if (initSize == 0) {\n                continue;\n            }\n\n            // Extract sub-contract init vector.\n            bytes memory subContractInitData = new bytes(initSize);\n            for (uint256 trgOffset = 32; trgOffset \u003c= initSize; trgOffset += 32) {\n                assembly {\n                    mstore(\n                        add(subContractInitData, trgOffset),\n                        mload(add(add(data, trgOffset), initDataContractsOffset))\n                    )\n                }\n            }\n\n            // Call sub-contract initializer.\n            // NOLINTNEXTLINE: low-level-calls.\n            (success, returndata) = contractAddress.delegatecall(\n                abi.encodeWithSelector(this.initialize.selector, subContractInitData)\n            );\n            require(success, string(returndata));\n            totalInitSizes += initSize;\n            initDataContractsOffset += initSize;\n        }\n        require(\n            additionalDataSize == totalInitSizes,\n            \"MISMATCHING_INIT_DATA_SIZE\");\n    }\n\n    function callExternalInitializer(\n        bytes memory data,\n        address externalInitializerAddr,\n        uint256 dataSize)\n        private {\n        require(externalInitializerAddr.isContract(), \"NOT_A_CONTRACT\");\n        require(dataSize \u003c= data.length, \"INVALID_DATA_SIZE\");\n        bytes memory extInitData = new bytes(dataSize);\n\n        // Prepare memcpy pointers.\n        uint256 srcDataOffset = 32 + data.length - dataSize;\n        uint256 srcData;\n        uint256 trgData;\n\n        assembly {\n            srcData := add(data, srcDataOffset)\n            trgData := add(extInitData, 32)\n        }\n\n        // Copy initializer data to be passed to the EIC.\n        for (uint256 seek = 0; seek \u003c dataSize; seek += 32) {\n            assembly {\n                mstore(\n                    add(trgData, seek),\n                    mload(add(srcData, seek))\n                )\n            }\n        }\n\n        // NOLINTNEXTLINE: low-level-calls.\n        (bool success, bytes memory returndata) = externalInitializerAddr.delegatecall(\n            abi.encodeWithSelector(this.initialize.selector, extInitData)\n        );\n        require(success, string(returndata));\n        require(returndata.length == 0, string(returndata));\n    }\n}\n"},"MainStorage.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"ProxyStorage.sol\";\nimport \"Common.sol\";\n/*\n  Holds ALL the main contract state (storage) variables.\n*/\ncontract MainStorage is ProxyStorage {\n\n    uint256 constant internal LAYOUT_LENGTH = 2**64;\n\n    address escapeVerifierAddress;                  // NOLINT: constable-states.\n\n    // Global dex-frozen flag.\n    bool stateFrozen;                               // NOLINT: constable-states.\n\n    // Time when unFreeze can be successfully called (UNFREEZE_DELAY after freeze).\n    uint256 unFreezeTime;                           // NOLINT: constable-states.\n\n    // Pending deposits.\n    // A map STARK key =\u003e asset id =\u003e vault id =\u003e quantized amount.\n    mapping (uint256 =\u003e mapping (uint256 =\u003e mapping (uint256 =\u003e uint256))) pendingDeposits;\n\n    // Cancellation requests.\n    // A map STARK key =\u003e asset id =\u003e vault id =\u003e request timestamp.\n    mapping (uint256 =\u003e mapping (uint256 =\u003e mapping (uint256 =\u003e uint256))) cancellationRequests;\n\n    // Pending withdrawals.\n    // A map STARK key =\u003e asset id =\u003e quantized amount.\n    mapping (uint256 =\u003e mapping (uint256 =\u003e uint256)) pendingWithdrawals;\n\n    // vault_id =\u003e escape used boolean.\n    mapping (uint256 =\u003e bool) escapesUsed;\n\n    // Number of escapes that were performed when frozen.\n    uint256 escapesUsedCount;                       // NOLINT: constable-states.\n\n    // NOTE: fullWithdrawalRequests is deprecated, and replaced by forcedActionRequests.\n    // NOLINTNEXTLINE naming-convention.\n    mapping (uint256 =\u003e mapping (uint256 =\u003e uint256)) fullWithdrawalRequests_DEPRECATED;\n\n    // State sequence number.\n    uint256 sequenceNumber;                         // NOLINT: constable-states uninitialized-state.\n\n    // Vaults Tree Root \u0026 Height.\n    uint256 vaultRoot;                              // NOLINT: constable-states uninitialized-state.\n    uint256 vaultTreeHeight;                        // NOLINT: constable-states uninitialized-state.\n\n    // Order Tree Root \u0026 Height.\n    uint256 orderRoot;                              // NOLINT: constable-states uninitialized-state.\n    uint256 orderTreeHeight;                        // NOLINT: constable-states uninitialized-state.\n\n    // True if and only if the address is allowed to add tokens.\n    mapping (address =\u003e bool) tokenAdmins;\n\n    // True if and only if the address is allowed to register users.\n    mapping (address =\u003e bool) userAdmins;\n\n    // True if and only if the address is an operator (allowed to update state).\n    mapping (address =\u003e bool) operators;\n\n    // Mapping of contract ID to asset data.\n    mapping (uint256 =\u003e bytes) assetTypeToAssetInfo;    // NOLINT: uninitialized-state.\n\n    // Mapping of registered contract IDs.\n    mapping (uint256 =\u003e bool) registeredAssetType;      // NOLINT: uninitialized-state.\n\n    // Mapping from contract ID to quantum.\n    mapping (uint256 =\u003e uint256) assetTypeToQuantum;    // NOLINT: uninitialized-state.\n\n    // This mapping is no longer in use, remains for backwards compatibility.\n    mapping (address =\u003e uint256) starkKeys_DEPRECATED;  // NOLINT: naming-convention.\n\n    // Mapping from STARK public key to the Ethereum public key of its owner.\n    mapping (uint256 =\u003e address) ethKeys;               // NOLINT: uninitialized-state.\n\n    // Timelocked state transition and availability verification chain.\n    StarkExTypes.ApprovalChainData verifiersChain;\n    StarkExTypes.ApprovalChainData availabilityVerifiersChain;\n\n    // Batch id of last accepted proof.\n    uint256 lastBatchId;                            // NOLINT: constable-states uninitialized-state.\n\n    // Mapping between sub-contract index to sub-contract address.\n    mapping(uint256 =\u003e address) subContracts;       // NOLINT: uninitialized-state.\n\n    mapping (uint256 =\u003e bool) permissiveAssetType_DEPRECATED; // NOLINT: naming-convention.\n    // ---- END OF MAIN STORAGE AS DEPLOYED IN STARKEX2.0 ----\n\n    // Onchain-data version configured for the system.\n    uint256 onchainDataVersion;                     // NOLINT: constable-states uninitialized-state.\n\n    // Counter of forced action request in block. The key is the block number.\n    mapping(uint256 =\u003e uint256) forcedRequestsInBlock;\n\n    // ForcedAction requests: actionHash =\u003e requestTime.\n    mapping(bytes32 =\u003e uint256) forcedActionRequests;\n\n    // Mapping for timelocked actions.\n    // A actionKey =\u003e activation time.\n    mapping (bytes32 =\u003e uint256) actionsTimeLock;\n\n    // Append only list of requested forced action hashes.\n    bytes32[] actionHashList;\n\n    // Reserved storage space for Extensibility.\n    // Every added MUST be added above the end gap, and the __endGap size must be reduced\n    // accordingly.\n    // NOLINTNEXTLINE: naming-convention.\n    uint256[LAYOUT_LENGTH - 37] private __endGap;  // __endGap complements layout to LAYOUT_LENGTH.\n}\n"},"ProxyStorage.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"GovernanceStorage.sol\";\n\n/*\n  Holds the Proxy-specific state variables.\n  This contract is inherited by the GovernanceStorage (and indirectly by MainStorage)\n  to prevent collision hazard.\n*/\ncontract ProxyStorage is GovernanceStorage {\n\n    // NOLINTNEXTLINE: naming-convention uninitialized-state.\n    mapping (address =\u003e bytes32) internal initializationHash_DEPRECATED;\n\n    // The time after which we can switch to the implementation.\n    // Hash(implementation, data, finalize) =\u003e time.\n    mapping (bytes32 =\u003e uint256) internal enabledTime;\n\n    // A central storage of the flags whether implementation has been initialized.\n    // Note - it can be used flexibly enough to accommodate multiple levels of initialization\n    // (i.e. using different key salting schemes for different initialization levels).\n    mapping (bytes32 =\u003e bool) internal initialized;\n}\n"},"StarkExchange.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"MainDispatcher.sol\";\n\ncontract StarkExchange is MainDispatcher {\n    string public constant VERSION = \"3.0.3\";\n\n    // Salt for a 8 bit unique spread of all relevant selectors. Pre-caclulated.\n    // ---------- The following code was auto-generated. PLEASE DO NOT EDIT. ----------\n    uint256 constant MAGIC_SALT = 20188;\n    uint256 constant IDX_MAP_0 = 0x110200000021000030000005000020015200500020500200002020220000;\n    uint256 constant IDX_MAP_1 = 0x200200032001330010000101000203000003120201405000200010000;\n    uint256 constant IDX_MAP_2 = 0x100230002000000020032200261550025010000100102002003020010000030;\n    uint256 constant IDX_MAP_3 = 0x2001022000000001031050500102200001020200300004010100002002;\n    // ---------- End of auto-generated code. ----------\n\n    function getNumSubcontracts() internal pure override returns (uint256) {\n        return 6;\n    }\n\n    function magicSalt() internal pure override returns(uint256) {\n        return MAGIC_SALT;\n    }\n\n    function handlerMapSection(uint256 section) internal view override returns(uint256) {\n        if(section == 0) {\n            return IDX_MAP_0;\n        }\n        else if(section == 1) {\n            return IDX_MAP_1;\n        }\n        else if(section == 2) {\n            return IDX_MAP_2;\n        }\n        else if(section == 3) {\n            return IDX_MAP_3;\n        }\n        revert(\"BAD_IDX_MAP_SECTION\");\n    }\n\n    function expectedIdByIndex(uint256 index)\n        internal pure override returns (string memory id) {\n        if (index == 1) {\n            id = \"StarkWare_AllVerifiers_2020_1\";\n        } else if (index == 2) {\n            id = \"StarkWare_TokensAndRamping_2020_1\";\n        } else if (index == 3) {\n            id = \"StarkWare_StarkExState_2021_1\";\n        } else if (index == 4) {\n            id = \"StarkWare_ForcedActions_2020_1\";\n        } else if (index == 5) {\n            id = \"StarkWare_OnchainVaults_2021_1\";\n        } else if (index == 6) {\n            id = \"StarkWare_ProxyUtils_2021_1\";\n        } else {\n            revert(\"UNEXPECTED_INDEX\");\n        }\n    }\n\n    function initializationSentinel() internal view override {\n        string memory REVERT_MSG = \"INITIALIZATION_BLOCKED\";\n        // This initializer sets roots etc. It must not be applied twice.\n        // I.e. it can run only when the state is still empty.\n        require(vaultRoot == 0, REVERT_MSG);\n        require(vaultTreeHeight == 0, REVERT_MSG);\n        require(orderRoot == 0, REVERT_MSG);\n        require(orderTreeHeight == 0, REVERT_MSG);\n    }\n}\n"},"SubContractor.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"Identity.sol\";\n\ninterface SubContractor is Identity {\n\n    function initialize(bytes calldata data)\n        external;\n\n    function initializerSize()\n        external view\n        returns(uint256);\n}\n"}}

        File 4 of 4: TokensAndRamping
        {"AcceptModifications.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"LibConstants.sol\";\nimport \"MAcceptModifications.sol\";\nimport \"MTokenQuantization.sol\";\nimport \"MainStorage.sol\";\n\n/*\n  Interface containing actions a verifier can invoke on the state.\n  The contract containing the state should implement these and verify correctness.\n*/\nabstract contract AcceptModifications is\n    MainStorage,\n    LibConstants,\n    MAcceptModifications,\n    MTokenQuantization\n{\n    event LogWithdrawalAllowed(\n        uint256 starkKey,\n        uint256 assetType,\n        uint256 nonQuantizedAmount,\n        uint256 quantizedAmount\n    );\n\n    event LogNftWithdrawalAllowed(uint256 starkKey, uint256 assetId);\n\n    event LogMintableWithdrawalAllowed(\n        uint256 starkKey,\n        uint256 assetId,\n        uint256 quantizedAmount\n    );\n\n    /*\n      Transfers funds from the on-chain deposit area to the off-chain area.\n      Implemented in the Deposits contracts.\n    */\n    function acceptDeposit(\n        uint256 starkKey,\n        uint256 vaultId,\n        uint256 assetId,\n        uint256 quantizedAmount\n    ) internal virtual override {\n        // Fetch deposit.\n        require(\n            pendingDeposits[starkKey][assetId][vaultId] \u003e= quantizedAmount,\n            \"DEPOSIT_INSUFFICIENT\"\n        );\n\n        // Subtract accepted quantized amount.\n        pendingDeposits[starkKey][assetId][vaultId] -= quantizedAmount;\n    }\n\n    /*\n      Transfers funds from the off-chain area to the on-chain withdrawal area.\n    */\n    function allowWithdrawal(\n        uint256 starkKey,\n        uint256 assetId,\n        uint256 quantizedAmount\n    )\n        internal\n        override\n    {\n        // Fetch withdrawal.\n        uint256 withdrawal = pendingWithdrawals[starkKey][assetId];\n\n        // Add accepted quantized amount.\n        withdrawal += quantizedAmount;\n        require(withdrawal \u003e= quantizedAmount, \"WITHDRAWAL_OVERFLOW\");\n\n        // Store withdrawal.\n        pendingWithdrawals[starkKey][assetId] = withdrawal;\n\n        // Log event.\n        uint256 presumedAssetType = assetId;\n        if (registeredAssetType[presumedAssetType]) {\n            emit LogWithdrawalAllowed(\n                starkKey,\n                presumedAssetType,\n                fromQuantized(presumedAssetType, quantizedAmount),\n                quantizedAmount\n            );\n        } else if(assetId == ((assetId \u0026 MASK_240) | MINTABLE_ASSET_ID_FLAG)) {\n            emit LogMintableWithdrawalAllowed(\n                starkKey,\n                assetId,\n                quantizedAmount\n            );\n        } else {\n            // Default case is Non-Mintable ERC721 asset id.\n            require(assetId == assetId \u0026 MASK_250, \"INVALID_NFT_ASSET_ID\");\n            // In ERC721 case, assetId is not the assetType.\n            require(withdrawal \u003c= 1, \"INVALID_NFT_AMOUNT\");\n            emit LogNftWithdrawalAllowed(starkKey, assetId);\n        }\n    }\n\n    // Verifier authorizes withdrawal.\n    function acceptWithdrawal(\n        uint256 starkKey,\n        uint256 assetId,\n        uint256 quantizedAmount\n    ) internal virtual override {\n        allowWithdrawal(starkKey, assetId, quantizedAmount);\n    }\n}\n"},"ActionHash.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"MainStorage.sol\";\nimport \"LibConstants.sol\";\n\n/*\n  Calculation action hash for the various forced actions in a generic manner.\n*/\ncontract ActionHash is MainStorage , LibConstants{\n\n    function getActionHash(string memory actionName, bytes memory packedActionParameters)\n        internal\n        pure\n        returns(bytes32 actionHash)\n    {\n        actionHash = keccak256(abi.encodePacked(actionName, packedActionParameters));\n    }\n\n    function setActionHash(bytes32 actionHash, bool premiumCost) internal\n    {\n        // The rate of forced trade requests is restricted.\n        // First restriction is by capping the number of requests in a block.\n        // User can override this cap by requesting with a permium flag set,\n        // in this case, the gas cost is high (~1M) but no \"technical\" limit is set.\n        // However, the high gas cost creates an obvious limitation due to the block gas limit.\n        if (premiumCost) {\n            for (uint256 i = 0; i \u003c 21129; i++) {}\n        } else {\n            require(\n                forcedRequestsInBlock[block.number] \u003c MAX_FORCED_ACTIONS_REQS_PER_BLOCK,\n                \"MAX_REQUESTS_PER_BLOCK_REACHED\");\n            forcedRequestsInBlock[block.number] += 1;\n        }\n        forcedActionRequests[actionHash] = block.timestamp;\n        actionHashList.push(actionHash);\n    }\n\n    function getActionCount() external view returns(uint256)\n    {\n        return actionHashList.length;\n    }\n\n    function getActionHashByIndex(uint256 actionIndex) external view returns(bytes32)\n    {\n        require(actionIndex \u003c actionHashList.length, \"ACTION_INDEX_TOO_HIGH\");\n        return actionHashList[actionIndex];\n    }\n}\n"},"Common.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\n/*\n  Common Utility librarries.\n  I. Addresses (extending address).\n*/\nlibrary Addresses {\n    function isContract(address account) internal view returns (bool) {\n        uint256 size;\n        assembly {\n            size := extcodesize(account)\n        }\n        return size \u003e 0;\n    }\n\n    function performEthTransfer(address recipient, uint256 amount) internal {\n        (bool success, ) = recipient.call{value: amount}(\"\"); // NOLINT: low-level-calls.\n        require(success, \"ETH_TRANSFER_FAILED\");\n    }\n\n    /*\n      Safe wrapper around ERC20/ERC721 calls.\n      This is required because many deployed ERC20 contracts don\u0027t return a value.\n      See https://github.com/ethereum/solidity/issues/4116.\n    */\n    function safeTokenContractCall(address tokenAddress, bytes memory callData) internal {\n        require(isContract(tokenAddress), \"BAD_TOKEN_ADDRESS\");\n        // NOLINTNEXTLINE: low-level-calls.\n        (bool success, bytes memory returndata) = tokenAddress.call(callData);\n        require(success, string(returndata));\n\n        if (returndata.length \u003e 0) {\n            require(abi.decode(returndata, (bool)), \"TOKEN_OPERATION_FAILED\");\n        }\n    }\n\n    /*\n      Validates that the passed contract address is of a real contract,\n      and that its id hash (as infered fromn identify()) matched the expected one.\n    */\n    function validateContractId(address contractAddress, bytes32 expectedIdHash)\n        internal\n    {\n        require(isContract(contractAddress), \"ADDRESS_NOT_CONTRACT\");\n        (bool success, bytes memory returndata) = contractAddress.call( // NOLINT: low-level-calls.\n            abi.encodeWithSignature(\"identify()\"));\n        require(success, \"FAILED_TO_IDENTIFY_CONTRACT\");\n        string memory realContractId = abi.decode(returndata, (string));\n        require(\n            keccak256(abi.encodePacked(realContractId)) == expectedIdHash,\n            \"UNEXPECTED_CONTRACT_IDENTIFIER\");\n    }\n\n    /*\n      Similar to safeTokenContractCall, but always ignores the return value.\n\n      Assumes some other method is used to detect the failures\n      (e.g. balance is checked before and after the call).\n    */\n    function uncheckedTokenContractCall(address tokenAddress, bytes memory callData) internal {\n        // NOLINTNEXTLINE: low-level-calls.\n        (bool success, bytes memory returndata) = tokenAddress.call(callData);\n        require(success, string(returndata));\n    }\n\n}\n\nlibrary UintArray {\n    function hashSubArray(uint256[] memory array, uint256 subArrayStart, uint256 subArraySize)\n        internal pure\n        returns(bytes32 subArrayHash)\n    {\n        require(array.length \u003e= subArrayStart + subArraySize, \"ILLEGAL_SUBARRAY_DIMENSIONS\");\n        uint256 startOffsetBytes = 0x20 * (1 + subArrayStart);\n        uint256 dataSizeBytes = 0x20 * subArraySize;\n        assembly {\n            subArrayHash := keccak256(add(array, startOffsetBytes), dataSizeBytes)\n        }\n    }\n\n    /*\n      Returns the address of a cell in offset within a uint256[] array.\n      This allows assigning new variable of dynamic unit256[] pointing to a sub_array\n      with a layout of serialied uint256[] (i.e. length+content).\n    */\n    function extractSerializedUintArray(uint256[] memory programOutput, uint256 offset)\n        internal pure\n        returns (uint256[] memory addr)\n    {\n        uint256 memOffset = 0x20 * (offset + 1);\n        assembly {\n            addr := add(programOutput, memOffset)\n        }\n    }\n\n}\n\n/*\n  II. StarkExTypes - Common data types.\n*/\nlibrary StarkExTypes {\n\n    // Structure representing a list of verifiers (validity/availability).\n    // A statement is valid only if all the verifiers in the list agree on it.\n    // Adding a verifier to the list is immediate - this is used for fast resolution of\n    // any soundness issues.\n    // Removing from the list is time-locked, to ensure that any user of the system\n    // not content with the announced removal has ample time to leave the system before it is\n    // removed.\n    struct ApprovalChainData {\n        address[] list;\n        // Represents the time after which the verifier with the given address can be removed.\n        // Removal of the verifier with address A is allowed only in the case the value\n        // of unlockedForRemovalTime[A] != 0 and unlockedForRemovalTime[A] \u003c (current time).\n        mapping (address =\u003e uint256) unlockedForRemovalTime;\n    }\n}\n"},"CompositeActions.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"MDeposits.sol\";\nimport \"MUsers.sol\";\n\nabstract contract CompositeActions is\n    MDeposits,\n    MUsers\n{\n    function registerAndDepositERC20(\n        address ethKey,\n        uint256 starkKey,\n        bytes calldata signature,\n        uint256 assetType,\n        uint256 vaultId,\n        uint256 quantizedAmount)\n        external {\n        registerUser(ethKey, starkKey, signature);\n        depositERC20(starkKey, assetType, vaultId, quantizedAmount);\n    }\n\n    function registerAndDepositEth( // NOLINT: locked-ether.\n        address ethKey,\n        uint256 starkKey,\n        bytes calldata signature,\n        uint256 assetType,\n        uint256 vaultId)\n        external payable {\n        registerUser(ethKey, starkKey, signature);\n        depositEth(starkKey, assetType, vaultId);\n    }\n}\n"},"Deposits.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"LibConstants.sol\";\nimport \"MAcceptModifications.sol\";\nimport \"MDeposits.sol\";\nimport \"MTokenQuantization.sol\";\nimport \"MTokenAssetData.sol\";\nimport \"MFreezable.sol\";\nimport \"MKeyGetters.sol\";\nimport \"MTokenTransfers.sol\";\nimport \"MainStorage.sol\";\n\n/**\n  For a user to perform a deposit to the contract two calls need to take place:\n\n  1. A call to an ERC20 contract, authorizing this contract to transfer funds on behalf of the user.\n  2. A call to :sol:func:`deposit` indicating the starkKey, amount, asset type and target vault ID to which to send the deposit.\n\n  The amount should be quantized, according to the specific quantization defined for the asset type.\n\n  The result of the operation, assuming all requirements are met, is that an amount of ERC20 tokens\n  equaling the amount specified in the :sol:func:`deposit` call times the quantization factor is\n  transferred on behalf of the user to the contract. In addition, the contract adds the funds to an\n  accumulator of pending deposits for the provided user, asset ID and vault ID.\n\n  Once a deposit is made, the exchange may include it in a proof which will result in addition\n  of the amount(s) deposited to the off-chain vault with the specified ID. When the contract\n  receives such valid proof, it deducts the transfered funds from the pending deposits for the\n  specified Stark key, asset ID and vault ID.\n\n  The exchange will not be able to move the deposited funds to the off-chain vault if the Stark key\n  is not registered in the system.\n\n  Until that point, the user may cancel the deposit by performing a time-locked cancel-deposit\n  operation consisting of two calls:\n\n  1. A call to :sol:func:`depositCancel`, setting a timer to enable reclaiming the deposit. Until this timer expires the user cannot reclaim funds as the exchange may still be processing the deposit for inclusion in the off chain vault.\n  2. A call to :sol:func:`depositReclaim`, to perform the actual transfer of funds from the contract back to the ERC20 contract. This will only succeed if the timer set in the previous call has expired. The result should be the transfer of all funds not accounted for in proofs for off-chain inclusion, back to the user account on the ERC20 contract.\n\n  Calling depositCancel and depositReclaim can only be done via an ethKey that is associated with\n  that vault\u0027s starkKey. This is enforced by the contract.\n\n*/\nabstract contract Deposits is\n    MainStorage,\n    LibConstants,\n    MAcceptModifications,\n    MDeposits,\n    MTokenQuantization,\n    MTokenAssetData,\n    MFreezable,\n    MKeyGetters,\n    MTokenTransfers\n{\n    event LogDeposit(\n        address depositorEthKey,\n        uint256 starkKey,\n        uint256 vaultId,\n        uint256 assetType,\n        uint256 nonQuantizedAmount,\n        uint256 quantizedAmount\n    );\n\n    event LogNftDeposit(\n        address depositorEthKey,\n        uint256 starkKey,\n        uint256 vaultId,\n        uint256 assetType,\n        uint256 tokenId,\n        uint256 assetId\n    );\n\n    event LogDepositCancel(uint256 starkKey, uint256 vaultId, uint256 assetId);\n\n    event LogDepositCancelReclaimed(\n        uint256 starkKey,\n        uint256 vaultId,\n        uint256 assetType,\n        uint256 nonQuantizedAmount,\n        uint256 quantizedAmount\n    );\n\n    event LogDepositNftCancelReclaimed(\n        uint256 starkKey,\n        uint256 vaultId,\n        uint256 assetType,\n        uint256 tokenId,\n        uint256 assetId\n    );\n\n    function getDepositBalance(\n        uint256 starkKey,\n        uint256 assetId,\n        uint256 vaultId\n    ) external view returns (uint256 balance) {\n        uint256 presumedAssetType = assetId;\n        balance = fromQuantized(presumedAssetType, pendingDeposits[starkKey][assetId][vaultId]);\n    }\n\n    function getQuantizedDepositBalance(\n        uint256 starkKey,\n        uint256 assetId,\n        uint256 vaultId\n    ) external view returns (uint256 balance) {\n        balance = pendingDeposits[starkKey][assetId][vaultId];\n    }\n\n    function depositNft(\n        uint256 starkKey,\n        uint256 assetType,\n        uint256 vaultId,\n        uint256 tokenId\n    ) external notFrozen()\n    {\n        // The vaultId is not validated but should be in the allowed range supported by the\n        // exchange. If not, it will be ignored by the exchange and the starkKey owner may reclaim\n        // the funds by using depositCancel + depositReclaim.\n\n        // starkKey must be registered.\n        require(ethKeys[starkKey] != ZERO_ADDRESS, \"INVALID_STARK_KEY\");\n        require(!isMintableAssetType(assetType), \"MINTABLE_ASSET_TYPE\");\n        require(!isFungibleAssetType(assetType), \"FUNGIBLE_ASSET_TYPE\");\n        uint256 assetId = calculateNftAssetId(assetType, tokenId);\n\n        // Update the balance.\n        pendingDeposits[starkKey][assetId][vaultId] = 1;\n\n        // Disable the cancellationRequest timeout when users deposit into their own account.\n        if (isMsgSenderStarkKeyOwner(starkKey) \u0026\u0026\n                cancellationRequests[starkKey][assetId][vaultId] != 0) {\n            delete cancellationRequests[starkKey][assetId][vaultId];\n        }\n\n        // Transfer the tokens to the Deposit contract.\n        transferInNft(assetType, tokenId);\n\n        // Log event.\n        emit LogNftDeposit(msg.sender, starkKey, vaultId, assetType, tokenId, assetId);\n    }\n\n    function getCancellationRequest(\n        uint256 starkKey,\n        uint256 assetId,\n        uint256 vaultId\n    ) external view returns (uint256 request) {\n        request = cancellationRequests[starkKey][assetId][vaultId];\n    }\n\n    function depositERC20(\n        uint256 starkKey,\n        uint256 assetType,\n        uint256 vaultId,\n        uint256 quantizedAmount\n    ) public override\n    {\n        deposit(starkKey, assetType, vaultId, quantizedAmount);\n    }\n\n    function depositEth( // NOLINT: locked-ether.\n        uint256 starkKey,\n        uint256 assetType,\n        uint256 vaultId\n    ) public payable override {\n        require(isEther(assetType), \"INVALID_ASSET_TYPE\");\n        deposit(starkKey, assetType, vaultId, toQuantized(assetType, msg.value));\n    }\n\n    function deposit(\n        uint256 starkKey,\n        uint256 assetType,\n        uint256 vaultId,\n        uint256 quantizedAmount\n    ) public notFrozen()\n    {\n        // The vaultId is not validated but should be in the allowed range supported by the\n        // exchange. If not, it will be ignored by the exchange and the starkKey owner may reclaim\n        // the funds by using depositCancel + depositReclaim.\n\n        // No need to verify amount \u003e 0, a deposit with amount = 0 can be used to undo cancellation.\n        // starkKey must be registered.\n        require(ethKeys[starkKey] != ZERO_ADDRESS, \"INVALID_STARK_KEY\");\n        require(!isMintableAssetType(assetType), \"MINTABLE_ASSET_TYPE\");\n        require(isFungibleAssetType(assetType), \"NON_FUNGIBLE_ASSET_TYPE\");\n        uint256 assetId = assetType;\n\n        // Update the balance.\n        pendingDeposits[starkKey][assetId][vaultId] += quantizedAmount;\n        require(\n            pendingDeposits[starkKey][assetId][vaultId] \u003e= quantizedAmount,\n            \"DEPOSIT_OVERFLOW\"\n        );\n\n        // Disable the cancellationRequest timeout when users deposit into their own account.\n        if (isMsgSenderStarkKeyOwner(starkKey) \u0026\u0026\n                cancellationRequests[starkKey][assetId][vaultId] != 0) {\n            delete cancellationRequests[starkKey][assetId][vaultId];\n        }\n\n        // Transfer the tokens to the Deposit contract.\n        transferIn(assetType, quantizedAmount);\n\n        // Log event.\n        emit LogDeposit(\n            msg.sender,\n            starkKey,\n            vaultId,\n            assetType,\n            fromQuantized(assetType, quantizedAmount),\n            quantizedAmount\n        );\n    }\n\n    function deposit( // NOLINT: locked-ether.\n        uint256 starkKey,\n        uint256 assetType,\n        uint256 vaultId\n    ) external payable {\n        require(isEther(assetType), \"INVALID_ASSET_TYPE\");\n        deposit(starkKey, assetType, vaultId, toQuantized(assetType, msg.value));\n    }\n\n    function depositCancel(\n        uint256 starkKey,\n        uint256 assetId,\n        uint256 vaultId\n    )\n        external\n        onlyStarkKeyOwner(starkKey)\n    // No notFrozen modifier: This function can always be used, even when frozen.\n    {\n        // Start the timeout.\n        cancellationRequests[starkKey][assetId][vaultId] = block.timestamp;\n\n        // Log event.\n        emit LogDepositCancel(starkKey, vaultId, assetId);\n    }\n\n    function depositReclaim(\n        uint256 starkKey,\n        uint256 assetId,\n        uint256 vaultId\n    )\n        external\n        onlyStarkKeyOwner(starkKey)\n    // No notFrozen modifier: This function can always be used, even when frozen.\n    {\n        uint256 assetType = assetId;\n\n        // Make sure enough time has passed.\n        uint256 requestTime = cancellationRequests[starkKey][assetId][vaultId];\n        require(requestTime != 0, \"DEPOSIT_NOT_CANCELED\");\n        uint256 freeTime = requestTime + DEPOSIT_CANCEL_DELAY;\n        assert(freeTime \u003e= DEPOSIT_CANCEL_DELAY);\n        require(block.timestamp \u003e= freeTime, \"DEPOSIT_LOCKED\"); // NOLINT: timestamp.\n\n        // Clear deposit.\n        uint256 quantizedAmount = pendingDeposits[starkKey][assetId][vaultId];\n        delete pendingDeposits[starkKey][assetId][vaultId];\n        delete cancellationRequests[starkKey][assetId][vaultId];\n\n        // Refund deposit.\n        transferOut(msg.sender, assetType, quantizedAmount);\n\n        // Log event.\n        emit LogDepositCancelReclaimed(\n            starkKey,\n            vaultId,\n            assetType,\n            fromQuantized(assetType, quantizedAmount),\n            quantizedAmount\n        );\n    }\n\n    function depositNftReclaim(\n        uint256 starkKey,\n        uint256 assetType,\n        uint256 vaultId,\n        uint256 tokenId\n    )\n        external\n        onlyStarkKeyOwner(starkKey)\n    // No notFrozen modifier: This function can always be used, even when frozen.\n    {\n        // assetId is the id for the deposits/withdrawals.\n        // equivalent for the usage of assetType for ERC20.\n        uint256 assetId = calculateNftAssetId(assetType, tokenId);\n\n        // Make sure enough time has passed.\n        uint256 requestTime = cancellationRequests[starkKey][assetId][vaultId];\n        require(requestTime != 0, \"DEPOSIT_NOT_CANCELED\");\n        uint256 freeTime = requestTime + DEPOSIT_CANCEL_DELAY;\n        assert(freeTime \u003e= DEPOSIT_CANCEL_DELAY);\n        require(block.timestamp \u003e= freeTime, \"DEPOSIT_LOCKED\");\n\n        // Clear deposit.\n        uint256 amount = pendingDeposits[starkKey][assetId][vaultId];\n        delete pendingDeposits[starkKey][assetId][vaultId];\n        delete cancellationRequests[starkKey][assetId][vaultId];\n\n        if (amount \u003e 0) {\n            // Refund deposit.\n            transferOutNft(msg.sender, assetType, tokenId);\n\n            // Log event.\n            emit LogDepositNftCancelReclaimed(starkKey, vaultId, assetType, tokenId, assetId);\n        }\n    }\n}\n"},"ERC721Receiver.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"IERC721Receiver.sol\";\n\n/*\n  ERC721 token receiver interface\n  EIP-721 requires any contract receiving ERC721 tokens to implement IERC721Receiver interface.\n  By EIP, safeTransferFrom API of ERC721 shall call onERC721Received on the receiving contract.\n\n  Have the receiving contract failed to respond as expected, the safeTransferFrom shall be reverted.\n\n  Params:\n  `operator` The address which called `safeTransferFrom` function\n  `from` The address which previously owned the token\n  `tokenId` The NFT identifier which is being transferred\n  `data` Additional data with no specified format\n\n  Returns: fixed value:`bytes4(keccak256(\"onERC721Received(address,address,uint256,bytes)\"))`.\n*/\ncontract ERC721Receiver is IERC721Receiver {\n    // NOLINTNEXTLINE: external-function.\n    function onERC721Received(\n        address /*operator*/,  // The address which called `safeTransferFrom` function.\n        address /*from*/,  // The address which previously owned the token.\n        uint256 /*tokenId*/,  // The NFT identifier which is being transferred.\n        bytes memory /*data*/)  // Additional data with no specified format.\n        external override returns (bytes4)\n    {\n        return this.onERC721Received.selector;\n    }\n}\n"},"Freezable.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"LibConstants.sol\";\nimport \"MFreezable.sol\";\nimport \"MGovernance.sol\";\nimport \"MainStorage.sol\";\n\n/*\n  Implements MFreezable.\n*/\nabstract contract Freezable is MainStorage, LibConstants, MGovernance, MFreezable {\n    event LogFrozen();\n    event LogUnFrozen();\n\n    function isFrozen() public view override returns (bool) {\n        return stateFrozen;\n    }\n\n    function validateFreezeRequest(uint256 requestTime) internal override {\n        require(requestTime != 0, \"FORCED_ACTION_UNREQUESTED\");\n        // Verify timer on escape request.\n        uint256 freezeTime = requestTime + FREEZE_GRACE_PERIOD;\n\n        // Prevent wraparound.\n        assert(freezeTime \u003e= FREEZE_GRACE_PERIOD);\n        require(block.timestamp \u003e= freezeTime, \"FORCED_ACTION_PENDING\"); // NOLINT: timestamp.\n\n        // Forced action requests placed before freeze, are no longer valid after the un-freeze.\n        require(freezeTime \u003e unFreezeTime, \"REFREEZE_ATTEMPT\");\n    }\n\n    function freeze()\n        internal\n        override\n        notFrozen()\n    {\n        unFreezeTime = block.timestamp + UNFREEZE_DELAY;\n\n        // Update state.\n        stateFrozen = true;\n\n        // Log event.\n        emit LogFrozen();\n    }\n\n    function unFreeze()\n        external\n        onlyFrozen()\n        onlyGovernance()\n    {\n        require(block.timestamp \u003e= unFreezeTime, \"UNFREEZE_NOT_ALLOWED_YET\");\n\n        // Update state.\n        stateFrozen = false;\n\n        // Increment roots to invalidate them, w/o losing information.\n        vaultRoot += 1;\n        orderRoot += 1;\n\n        // Log event.\n        emit LogUnFrozen();\n    }\n\n}\n"},"Governance.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"GovernanceStorage.sol\";\nimport \"MGovernance.sol\";\n\n/*\n  Implements Generic Governance, applicable for both proxy and main contract, and possibly others.\n  Notes:\n  1. This class is virtual (getGovernanceTag is not implemented).\n  2. The use of the same function names by both the Proxy and a delegated implementation\n     is not possible since calling the implementation functions is done via the default function\n     of the Proxy. For this reason, for example, the implementation of MainContract (MainGovernance)\n     exposes mainIsGovernor, which calls the internal isGovernor method.\n*/\nabstract contract Governance is GovernanceStorage, MGovernance {\n    event LogNominatedGovernor(address nominatedGovernor);\n    event LogNewGovernorAccepted(address acceptedGovernor);\n    event LogRemovedGovernor(address removedGovernor);\n    event LogNominationCancelled();\n\n    /*\n      Returns a string which uniquely identifies the type of the governance mechanism.\n    */\n    function getGovernanceTag()\n        virtual\n        internal\n        pure\n        returns (string memory);\n\n    /*\n      Returns the GovernanceInfoStruct associated with the governance tag.\n    */\n    function contractGovernanceInfo()\n        internal\n        view\n        returns (GovernanceInfoStruct storage) {\n        string memory tag = getGovernanceTag();\n        GovernanceInfoStruct storage gub = governanceInfo[tag];\n        require(gub.initialized, \"NOT_INITIALIZED\");\n        return gub;\n    }\n\n    /*\n      Current code intentionally prevents governance re-initialization.\n      This may be a problem in an upgrade situation, in a case that the upgrade-to implementation\n      performs an initialization (for real) and within that calls initGovernance().\n\n      Possible workarounds:\n      1. Clearing the governance info altogether by changing the MAIN_GOVERNANCE_INFO_TAG.\n         This will remove existing main governance information.\n      2. Modify the require part in this function, so that it will exit quietly\n         when trying to re-initialize (uncomment the lines below).\n    */\n    function initGovernance()\n        internal\n    {\n        string memory tag = getGovernanceTag();\n        GovernanceInfoStruct storage gub = governanceInfo[tag];\n        require(!gub.initialized, \"ALREADY_INITIALIZED\");\n        gub.initialized = true;  // to ensure addGovernor() won\u0027t fail.\n        // Add the initial governer.\n        addGovernor(msg.sender);\n    }\n\n    function isGovernor(address testGovernor)\n        internal view override\n        returns (bool){\n        GovernanceInfoStruct storage gub = contractGovernanceInfo();\n        return gub.effectiveGovernors[testGovernor];\n    }\n\n    /*\n      Cancels the nomination of a governor candidate.\n    */\n    function cancelNomination() internal onlyGovernance() {\n        GovernanceInfoStruct storage gub = contractGovernanceInfo();\n        gub.candidateGovernor = address(0x0);\n        emit LogNominationCancelled();\n    }\n\n    function nominateNewGovernor(address newGovernor) internal onlyGovernance() {\n        GovernanceInfoStruct storage gub = contractGovernanceInfo();\n        require(!isGovernor(newGovernor), \"ALREADY_GOVERNOR\");\n        gub.candidateGovernor = newGovernor;\n        emit LogNominatedGovernor(newGovernor);\n    }\n\n    /*\n      The addGovernor is called in two cases:\n      1. by acceptGovernance when a new governor accepts its role.\n      2. by initGovernance to add the initial governor.\n      The difference is that the init path skips the nominate step\n      that would fail because of the onlyGovernance modifier.\n    */\n    function addGovernor(address newGovernor) private {\n        require(!isGovernor(newGovernor), \"ALREADY_GOVERNOR\");\n        GovernanceInfoStruct storage gub = contractGovernanceInfo();\n        gub.effectiveGovernors[newGovernor] = true;\n    }\n\n    function acceptGovernance()\n        internal\n    {\n        // The new governor was proposed as a candidate by the current governor.\n        GovernanceInfoStruct storage gub = contractGovernanceInfo();\n        require(msg.sender == gub.candidateGovernor, \"ONLY_CANDIDATE_GOVERNOR\");\n\n        // Update state.\n        addGovernor(gub.candidateGovernor);\n        gub.candidateGovernor = address(0x0);\n\n        // Send a notification about the change of governor.\n        emit LogNewGovernorAccepted(msg.sender);\n    }\n\n    /*\n      Remove a governor from office.\n    */\n    function removeGovernor(address governorForRemoval) internal onlyGovernance() {\n        require(msg.sender != governorForRemoval, \"GOVERNOR_SELF_REMOVE\");\n        GovernanceInfoStruct storage gub = contractGovernanceInfo();\n        require (isGovernor(governorForRemoval), \"NOT_GOVERNOR\");\n        gub.effectiveGovernors[governorForRemoval] = false;\n        emit LogRemovedGovernor(governorForRemoval);\n    }\n}\n"},"GovernanceStorage.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\n/*\n  Holds the governance slots for ALL entities, including proxy and the main contract.\n*/\ncontract GovernanceStorage {\n\n    struct GovernanceInfoStruct {\n        mapping (address =\u003e bool) effectiveGovernors;\n        address candidateGovernor;\n        bool initialized;\n    }\n\n    // A map from a Governor tag to its own GovernanceInfoStruct.\n    mapping (string =\u003e GovernanceInfoStruct) internal governanceInfo;\n}\n"},"Identity.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\ninterface Identity {\n\n    /*\n      Allows a caller, typically another contract,\n      to ensure that the provided address is of the expected type and version.\n    */\n    function identify()\n        external pure\n        returns(string memory);\n}\n"},"IERC20.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\n/*\n  Interface of the ERC20 standard as defined in the EIP. Does not include\n  the optional functions; to access them see {ERC20Detailed}.\n*/\ninterface IERC20 {\n\n    function totalSupply() external view returns (uint256);\n\n    function balanceOf(address account) external view returns (uint256);\n\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    function transferFrom(address sender, address recipient, uint256 amount)\n     external returns (bool);\n\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"},"IERC721Receiver.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\ninterface IERC721Receiver {\n    function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)\n        external returns (bytes4);\n}\n"},"KeyGetters.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"MainStorage.sol\";\nimport \"MKeyGetters.sol\";\n\n/*\n  Implements MKeyGetters.\n*/\ncontract KeyGetters is MainStorage, MKeyGetters {\n    function getEthKey(uint256 starkKey) public view\n        override returns (address ethKey) {\n        // Fetch the user\u0027s Ethereum key.\n        ethKey = ethKeys[starkKey];\n        require(ethKey != address(0x0), \"USER_UNREGISTERED\");\n    }\n\n    function isMsgSenderStarkKeyOwner(uint256 starkKey) internal view\n        override returns (bool) {\n        return msg.sender == getEthKey(starkKey);\n    }\n}\n"},"LibConstants.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\ncontract LibConstants {\n    // Durations for time locked mechanisms (in seconds).\n    // Note that it is known that miners can manipulate block timestamps\n    // up to a deviation of a few seconds.\n    // This mechanism should not be used for fine grained timing.\n\n    // The time required to cancel a deposit, in the case the operator does not move the funds\n    // to the off-chain storage.\n    uint256 public constant DEPOSIT_CANCEL_DELAY = 3 days;\n\n    // The time required to freeze the exchange, in the case the operator does not execute a\n    // requested full withdrawal.\n    uint256 public constant FREEZE_GRACE_PERIOD = 7 days;\n\n    // The time after which the exchange may be unfrozen after it froze. This should be enough time\n    // for users to perform escape hatches to get back their funds.\n    uint256 public constant UNFREEZE_DELAY = 365 days;\n\n    // Maximal number of verifiers which may co-exist.\n    uint256 public constant MAX_VERIFIER_COUNT = uint256(64);\n\n    // The time required to remove a verifier in case of a verifier upgrade.\n    uint256 public constant VERIFIER_REMOVAL_DELAY = FREEZE_GRACE_PERIOD + (21 days);\n\n    address constant ZERO_ADDRESS = address(0x0);\n\n    uint256 constant K_MODULUS =\n    0x800000000000011000000000000000000000000000000000000000000000001;\n\n    uint256 constant K_BETA =\n    0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89;\n\n    uint256 internal constant MASK_250 =\n    0x03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;\n    uint256 internal constant MASK_240 =\n    0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;\n\n    uint256 public constant MAX_FORCED_ACTIONS_REQS_PER_BLOCK = 10;\n\n    uint256 constant QUANTUM_UPPER_BOUND = 2**128;\n    uint256 internal constant MINTABLE_ASSET_ID_FLAG = 1\u003c\u003c250;\n\n}\n"},"MAcceptModifications.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\n/*\n  Interface containing actions a verifier can invoke on the state.\n  The contract containing the state should implement these and verify correctness.\n*/\nabstract contract MAcceptModifications {\n\n    function acceptDeposit(\n        uint256 starkKey,\n        uint256 vaultId,\n        uint256 assetId,\n        uint256 quantizedAmount\n    )\n        internal virtual;\n\n    function allowWithdrawal(\n        uint256 starkKey,\n        uint256 assetId,\n        uint256 quantizedAmount\n    )\n        internal virtual;\n\n    function acceptWithdrawal(\n        uint256 starkKey,\n        uint256 assetId,\n        uint256 quantizedAmount\n    )\n    internal virtual;\n\n}\n"},"MainGovernance.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"Governance.sol\";\n\n/**\n  The StarkEx contract is governed by one or more Governors of which the initial one is the\n  deployer of the contract.\n\n  A governor has the sole authority to perform the following operations:\n\n  1. Nominate additional governors (:sol:func:`mainNominateNewGovernor`)\n  2. Remove other governors (:sol:func:`mainRemoveGovernor`)\n  3. Add new :sol:mod:`Verifiers` and :sol:mod:`AvailabilityVerifiers`\n  4. Remove :sol:mod:`Verifiers` and :sol:mod:`AvailabilityVerifiers` after a timelock allows it\n  5. Nominate Operators (see :sol:mod:`Operator`) and Token Administrators (see :sol:mod:`TokenRegister`)\n\n  Adding governors is performed in a two step procedure:\n\n  1. First, an existing governor nominates a new governor (:sol:func:`mainNominateNewGovernor`)\n  2. Then, the new governor must accept governance to become a governor (:sol:func:`mainAcceptGovernance`)\n\n  This two step procedure ensures that a governor public key cannot be nominated unless there is an\n  entity that has the corresponding private key. This is intended to prevent errors in the addition\n  process.\n\n  The governor private key should typically be held in a secure cold wallet.\n*/\n/*\n  Implements Governance for the StarkDex main contract.\n  The wrapper methods (e.g. mainIsGovernor wrapping isGovernor) are needed to give\n  the method unique names.\n  Both Proxy and StarkExchange inherit from Governance. Thus, the logical contract method names\n  must have unique names in order for the proxy to successfully delegate to them.\n*/\ncontract MainGovernance is Governance {\n\n    // The tag is the sting key that is used in the Governance storage mapping.\n    string public constant MAIN_GOVERNANCE_INFO_TAG = \"StarkEx.Main.2019.GovernorsInformation\";\n\n    function getGovernanceTag()\n        internal\n        pure\n        override\n        returns (string memory tag) {\n        tag = MAIN_GOVERNANCE_INFO_TAG;\n    }\n\n    function mainIsGovernor(address testGovernor) external view returns (bool) {\n        return isGovernor(testGovernor);\n    }\n\n    function mainNominateNewGovernor(address newGovernor) external {\n        nominateNewGovernor(newGovernor);\n    }\n\n    function mainRemoveGovernor(address governorForRemoval) external {\n        removeGovernor(governorForRemoval);\n    }\n\n    function mainAcceptGovernance()\n        external\n    {\n        acceptGovernance();\n    }\n\n    function mainCancelNomination() external {\n        cancelNomination();\n    }\n\n}\n"},"MainStorage.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"ProxyStorage.sol\";\nimport \"Common.sol\";\n/*\n  Holds ALL the main contract state (storage) variables.\n*/\ncontract MainStorage is ProxyStorage {\n\n    uint256 constant internal LAYOUT_LENGTH = 2**64;\n\n    address escapeVerifierAddress;                  // NOLINT: constable-states.\n\n    // Global dex-frozen flag.\n    bool stateFrozen;                               // NOLINT: constable-states.\n\n    // Time when unFreeze can be successfully called (UNFREEZE_DELAY after freeze).\n    uint256 unFreezeTime;                           // NOLINT: constable-states.\n\n    // Pending deposits.\n    // A map STARK key =\u003e asset id =\u003e vault id =\u003e quantized amount.\n    mapping (uint256 =\u003e mapping (uint256 =\u003e mapping (uint256 =\u003e uint256))) pendingDeposits;\n\n    // Cancellation requests.\n    // A map STARK key =\u003e asset id =\u003e vault id =\u003e request timestamp.\n    mapping (uint256 =\u003e mapping (uint256 =\u003e mapping (uint256 =\u003e uint256))) cancellationRequests;\n\n    // Pending withdrawals.\n    // A map STARK key =\u003e asset id =\u003e quantized amount.\n    mapping (uint256 =\u003e mapping (uint256 =\u003e uint256)) pendingWithdrawals;\n\n    // vault_id =\u003e escape used boolean.\n    mapping (uint256 =\u003e bool) escapesUsed;\n\n    // Number of escapes that were performed when frozen.\n    uint256 escapesUsedCount;                       // NOLINT: constable-states.\n\n    // NOTE: fullWithdrawalRequests is deprecated, and replaced by forcedActionRequests.\n    // NOLINTNEXTLINE naming-convention.\n    mapping (uint256 =\u003e mapping (uint256 =\u003e uint256)) fullWithdrawalRequests_DEPRECATED;\n\n    // State sequence number.\n    uint256 sequenceNumber;                         // NOLINT: constable-states uninitialized-state.\n\n    // Vaults Tree Root \u0026 Height.\n    uint256 vaultRoot;                              // NOLINT: constable-states uninitialized-state.\n    uint256 vaultTreeHeight;                        // NOLINT: constable-states uninitialized-state.\n\n    // Order Tree Root \u0026 Height.\n    uint256 orderRoot;                              // NOLINT: constable-states uninitialized-state.\n    uint256 orderTreeHeight;                        // NOLINT: constable-states uninitialized-state.\n\n    // True if and only if the address is allowed to add tokens.\n    mapping (address =\u003e bool) tokenAdmins;\n\n    // True if and only if the address is allowed to register users.\n    mapping (address =\u003e bool) userAdmins;\n\n    // True if and only if the address is an operator (allowed to update state).\n    mapping (address =\u003e bool) operators;\n\n    // Mapping of contract ID to asset data.\n    mapping (uint256 =\u003e bytes) assetTypeToAssetInfo;    // NOLINT: uninitialized-state.\n\n    // Mapping of registered contract IDs.\n    mapping (uint256 =\u003e bool) registeredAssetType;      // NOLINT: uninitialized-state.\n\n    // Mapping from contract ID to quantum.\n    mapping (uint256 =\u003e uint256) assetTypeToQuantum;    // NOLINT: uninitialized-state.\n\n    // This mapping is no longer in use, remains for backwards compatibility.\n    mapping (address =\u003e uint256) starkKeys_DEPRECATED;  // NOLINT: naming-convention.\n\n    // Mapping from STARK public key to the Ethereum public key of its owner.\n    mapping (uint256 =\u003e address) ethKeys;               // NOLINT: uninitialized-state.\n\n    // Timelocked state transition and availability verification chain.\n    StarkExTypes.ApprovalChainData verifiersChain;\n    StarkExTypes.ApprovalChainData availabilityVerifiersChain;\n\n    // Batch id of last accepted proof.\n    uint256 lastBatchId;                            // NOLINT: constable-states uninitialized-state.\n\n    // Mapping between sub-contract index to sub-contract address.\n    mapping(uint256 =\u003e address) subContracts;       // NOLINT: uninitialized-state.\n\n    mapping (uint256 =\u003e bool) permissiveAssetType_DEPRECATED; // NOLINT: naming-convention.\n    // ---- END OF MAIN STORAGE AS DEPLOYED IN STARKEX2.0 ----\n\n    // Onchain-data version configured for the system.\n    uint256 onchainDataVersion;                     // NOLINT: constable-states uninitialized-state.\n\n    // Counter of forced action request in block. The key is the block number.\n    mapping(uint256 =\u003e uint256) forcedRequestsInBlock;\n\n    // ForcedAction requests: actionHash =\u003e requestTime.\n    mapping(bytes32 =\u003e uint256) forcedActionRequests;\n\n    // Mapping for timelocked actions.\n    // A actionKey =\u003e activation time.\n    mapping (bytes32 =\u003e uint256) actionsTimeLock;\n\n    // Append only list of requested forced action hashes.\n    bytes32[] actionHashList;\n\n    // Reserved storage space for Extensibility.\n    // Every added MUST be added above the end gap, and the __endGap size must be reduced\n    // accordingly.\n    // NOLINTNEXTLINE: naming-convention.\n    uint256[LAYOUT_LENGTH - 37] private __endGap;  // __endGap complements layout to LAYOUT_LENGTH.\n}\n"},"MDeposits.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nabstract contract MDeposits {\n    function depositERC20( // NOLINT external-function.\n        uint256 starkKey,\n        uint256 assetType,\n        uint256 vaultId,\n        uint256 quantizedAmount\n    ) public virtual;\n\n    function depositEth( // NOLINT external-function.\n        uint256 starkKey,\n        uint256 assetType,\n        uint256 vaultId\n    ) public payable virtual;\n}\n"},"MFreezable.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nabstract contract MFreezable {\n    /*\n      Returns true if the exchange is frozen.\n    */\n    function isFrozen() public view virtual returns (bool); // NOLINT: external-function.\n\n    /*\n      Forbids calling the function if the exchange is frozen.\n    */\n    modifier notFrozen()\n    {\n        require(!isFrozen(), \"STATE_IS_FROZEN\");\n        _;\n    }\n\n    function validateFreezeRequest(uint256 requestTime) internal virtual;\n\n    /*\n      Allows calling the function only if the exchange is frozen.\n    */\n    modifier onlyFrozen()\n    {\n        require(isFrozen(), \"STATE_NOT_FROZEN\");\n        _;\n    }\n\n    /*\n      Freezes the exchange.\n    */\n    function freeze() internal virtual;\n}\n"},"MGovernance.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nabstract contract MGovernance {\n\n    function isGovernor(address testGovernor)\n        internal\n        view\n        virtual\n        returns (bool);\n\n    /*\n      Allows calling the function only by a Governor.\n    */\n    modifier onlyGovernance ()\n    {\n        require(isGovernor(msg.sender), \"ONLY_GOVERNANCE\");\n        _;\n    }\n}\n"},"MKeyGetters.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nabstract contract MKeyGetters {\n    // NOLINTNEXTLINE: external-function.\n    function getEthKey(uint256 starkKey) public view virtual returns (address ethKey);\n\n    function isMsgSenderStarkKeyOwner(uint256 starkKey) internal view virtual returns (bool);\n\n    /*\n      Allows calling the function only if starkKey is registered to msg.sender.\n    */\n    modifier onlyStarkKeyOwner(uint256 starkKey) {\n        // Require the calling user to own the stark key.\n        require(isMsgSenderStarkKeyOwner(starkKey), \"MISMATCHING_STARK_ETH_KEYS\");\n        _;\n    }\n}\n"},"MStarkExForcedActionState.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nabstract contract MStarkExForcedActionState {\n    function fullWithdrawActionHash(uint256 starkKey, uint256 vaultId)\n        internal\n        pure\n        virtual\n        returns(bytes32);\n\n    function clearFullWithdrawalRequest(uint256 starkKey, uint256 vaultId)\n        internal\n        virtual;\n\n    // NOLINTNEXTLINE: external-function.\n    function getFullWithdrawalRequest(uint256 starkKey, uint256 vaultId)\n        public\n        view\n        virtual\n        returns (uint256 res);\n\n    function setFullWithdrawalRequest(uint256 starkKey, uint256 vaultId)\n        internal\n        virtual;\n}\n"},"MTokenAssetData.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nabstract contract MTokenAssetData {\n\n    // NOLINTNEXTLINE: external-function.\n    function getAssetInfo(uint256 assetType)\n        public\n        view\n        virtual\n        returns (bytes memory assetInfo);\n\n    function extractTokenSelector(bytes memory assetInfo)\n        internal\n        pure\n        virtual\n        returns (bytes4 selector);\n\n    function isEther(uint256 assetType)\n        internal\n        view\n        virtual\n        returns (bool);\n\n    function isERC20(uint256 assetType)\n        internal\n        view\n        virtual\n        returns (bool);\n\n    function isERC721(uint256 assetType)\n        internal\n        view\n        virtual\n        returns (bool);\n\n    function isFungibleAssetType(uint256 assetType)\n        internal\n        view\n        virtual\n        returns (bool);\n\n    function isMintableAssetType(uint256 assetType)\n        internal\n        view\n        virtual\n        returns (bool);\n\n    function extractContractAddress(uint256 assetType)\n        internal\n        view\n        virtual\n        returns (address);\n\n    function verifyAssetInfo(bytes memory assetInfo)\n        internal\n        view\n        virtual;\n\n    function isNonFungibleAssetInfo(bytes memory assetInfo)\n        internal\n        pure\n        virtual\n        returns (bool);\n\n    function calculateNftAssetId(uint256 assetType, uint256 tokenId)\n        internal\n        pure\n        virtual\n        returns(uint256 assetId);\n\n    function calculateMintableAssetId(uint256 assetType, bytes memory mintingBlob)\n        internal\n        pure\n        virtual\n        returns(uint256 assetId);\n}\n"},"MTokenQuantization.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nabstract contract MTokenQuantization {\n    function fromQuantized(uint256 presumedAssetType, uint256 quantizedAmount)\n        internal\n        view\n        virtual\n        returns (uint256 amount);\n\n    // NOLINTNEXTLINE: external-function.\n    function getQuantum(uint256 presumedAssetType)\n        public\n        view\n        virtual\n        returns (uint256 quantum);\n\n    function toQuantized(uint256 presumedAssetType, uint256 amount)\n        internal\n        view\n        virtual\n        returns (uint256 quantizedAmount);\n}\n"},"MTokenTransfers.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nabstract contract MTokenTransfers {\n    function transferIn(uint256 assetType, uint256 quantizedAmount) internal virtual;\n\n    function transferInNft(uint256 assetType, uint256 tokenId) internal virtual;\n\n    function transferOut(\n        address payable recipient, uint256 assetType, uint256 quantizedAmount) internal virtual;\n\n    function transferOutNft(address recipient, uint256 assetType, uint256 tokenId) internal virtual;\n\n    function transferOutMint(\n        uint256 assetType, uint256 quantizedAmount, bytes memory mintingBlob) internal virtual;\n}\n"},"MUsers.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nabstract contract MUsers {\n    function registerUser( // NOLINT external-function.\n        address ethKey,\n        uint256 starkKey,\n        bytes calldata signature)\n        public virtual;\n}\n"},"ProxyStorage.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"GovernanceStorage.sol\";\n\n/*\n  Holds the Proxy-specific state variables.\n  This contract is inherited by the GovernanceStorage (and indirectly by MainStorage)\n  to prevent collision hazard.\n*/\ncontract ProxyStorage is GovernanceStorage {\n\n    // NOLINTNEXTLINE: naming-convention uninitialized-state.\n    mapping (address =\u003e bytes32) internal initializationHash_DEPRECATED;\n\n    // The time after which we can switch to the implementation.\n    // Hash(implementation, data, finalize) =\u003e time.\n    mapping (bytes32 =\u003e uint256) internal enabledTime;\n\n    // A central storage of the flags whether implementation has been initialized.\n    // Note - it can be used flexibly enough to accommodate multiple levels of initialization\n    // (i.e. using different key salting schemes for different initialization levels).\n    mapping (bytes32 =\u003e bool) internal initialized;\n}\n"},"StarkExForcedActionState.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"StarkExStorage.sol\";\nimport \"MStarkExForcedActionState.sol\";\nimport \"ActionHash.sol\";\n\n/*\n  StarkExchange specific action hashses.\n*/\ncontract StarkExForcedActionState is\n    StarkExStorage,\n    ActionHash,\n    MStarkExForcedActionState\n{\n\n    function fullWithdrawActionHash(uint256 starkKey, uint256 vaultId)\n        internal\n        pure\n        override\n        returns(bytes32)\n    {\n        return getActionHash(\"FULL_WITHDRAWAL\", abi.encode(starkKey, vaultId));\n    }\n\n    /*\n      Implemented in the FullWithdrawal contracts.\n    */\n    function clearFullWithdrawalRequest(\n        uint256 starkKey,\n        uint256 vaultId\n    )\n        internal\n        virtual\n        override\n    {\n        // Reset escape request.\n        delete forcedActionRequests[fullWithdrawActionHash(starkKey, vaultId)];\n    }\n\n    function getFullWithdrawalRequest(uint256 starkKey, uint256 vaultId)\n        public\n        view\n        override\n        returns (uint256 res)\n    {\n        // Return request value. Expect zero if the request doesn\u0027t exist or has been serviced, and\n        // a non-zero value otherwise.\n        res = forcedActionRequests[fullWithdrawActionHash(starkKey, vaultId)];\n    }\n\n    function setFullWithdrawalRequest(uint256 starkKey, uint256 vaultId)\n        internal\n        override\n    {\n        // FullWithdrawal is always at premium cost, hence the `true`.\n        setActionHash(fullWithdrawActionHash(starkKey, vaultId), true);\n    }\n}\n"},"StarkExStorage.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"MainStorage.sol\";\n\n/*\n  Extends MainStorage, holds StarkEx App specific state (storage) variables.\n\n  ALL State variables that are common to all applications, reside in MainStorage,\n  whereas ALL the StarkEx app specific ones reside here.\n*/\ncontract StarkExStorage is MainStorage {\n    // Onchain vaults balances.\n    // A map eth_address =\u003e asset_id =\u003e vault_id =\u003e quantized amount.\n    mapping(address =\u003e mapping(uint256 =\u003e mapping(uint256 =\u003e uint256))) vaultsBalances;\n\n    // Onchain vaults withdrawal lock time.\n    // A map eth_address =\u003e asset_id =\u003e vault_id =\u003e lock expiration timestamp.\n    mapping(address =\u003e mapping(uint256 =\u003e mapping(uint256 =\u003e uint256))) vaultsWithdrawalLocks;\n\n    // Enforces the minimal balance requirement (as output by Cairo) on onchain vault updates.\n    // When disabled, flash loans are enabled.\n    bool strictVaultBalancePolicy;\n\n    // The default time, in seconds, that an onchain vault is locked for withdrawal after a deposit.\n    uint256 public defaultVaultWithdrawalLock;\n\n    // Address of the message registry contract that is used to sign and verify L1 orders.\n    address public orderRegistryAddress;\n\n    // Reserved storage space for Extensibility.\n    // Every added MUST be added above the end gap, and the __endGap size must be reduced\n    // accordingly.\n    // NOLINTNEXTLINE: naming-convention shadowing-abstract.\n    uint256[LAYOUT_LENGTH - 5] private __endGap; // __endGap complements layout to LAYOUT_LENGTH.\n}\n"},"SubContractor.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"Identity.sol\";\n\ninterface SubContractor is Identity {\n\n    function initialize(bytes calldata data)\n        external;\n\n    function initializerSize()\n        external view\n        returns(uint256);\n}\n"},"TokenAssetData.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"MainStorage.sol\";\nimport \"MTokenAssetData.sol\";\nimport \"Common.sol\";\nimport \"LibConstants.sol\";\n\ncontract TokenAssetData is MainStorage, LibConstants, MTokenAssetData {\n    bytes4 internal constant ERC20_SELECTOR = bytes4(keccak256(\"ERC20Token(address)\"));\n    bytes4 internal constant ETH_SELECTOR = bytes4(keccak256(\"ETH()\"));\n    bytes4 internal constant ERC721_SELECTOR = bytes4(keccak256(\"ERC721Token(address,uint256)\"));\n    bytes4 internal constant MINTABLE_ERC20_SELECTOR =\n    bytes4(keccak256(\"MintableERC20Token(address)\"));\n    bytes4 internal constant MINTABLE_ERC721_SELECTOR =\n    bytes4(keccak256(\"MintableERC721Token(address,uint256)\"));\n\n    // The selector follows the 0x20 bytes assetInfo.length field.\n    uint256 internal constant SELECTOR_OFFSET = 0x20;\n    uint256 internal constant SELECTOR_SIZE = 4;\n    uint256 internal constant TOKEN_CONTRACT_ADDRESS_OFFSET = SELECTOR_OFFSET + SELECTOR_SIZE;\n    string internal constant NFT_ASSET_ID_PREFIX = \"NFT:\";\n    string internal constant MINTABLE_PREFIX = \"MINTABLE:\";\n\n    using Addresses for address;\n\n    /*\n      Extract the tokenSelector from assetInfo.\n\n      Works like bytes4 tokenSelector = abi.decode(assetInfo, (bytes4))\n      but does not revert when assetInfo.length \u003c SELECTOR_OFFSET.\n    */\n    function extractTokenSelector(bytes memory assetInfo) internal pure override\n        returns (bytes4 selector) {\n        assembly {\n            selector := and(\n                0xffffffff00000000000000000000000000000000000000000000000000000000,\n                mload(add(assetInfo, SELECTOR_OFFSET))\n            )\n        }\n    }\n\n    function getAssetInfo(uint256 assetType) public view override\n        returns (bytes memory assetInfo) {\n        // Verify that the registration is set and valid.\n        require(registeredAssetType[assetType], \"ASSET_TYPE_NOT_REGISTERED\");\n\n        // Retrieve registration.\n        assetInfo = assetTypeToAssetInfo[assetType];\n    }\n\n    function isEther(uint256 assetType) internal view override returns (bool) {\n        return extractTokenSelector(getAssetInfo(assetType)) == ETH_SELECTOR;\n    }\n\n    function isERC20(uint256 assetType) internal view override returns (bool) {\n        return extractTokenSelector(getAssetInfo(assetType)) == ERC20_SELECTOR;\n    }\n\n    function isERC721(uint256 assetType) internal view override returns (bool) {\n        return extractTokenSelector(getAssetInfo(assetType)) == ERC721_SELECTOR;\n    }\n\n    function isFungibleAssetType(uint256 assetType) internal view override returns (bool) {\n        bytes4 tokenSelector = extractTokenSelector(getAssetInfo(assetType));\n        return\n            tokenSelector == ETH_SELECTOR ||\n            tokenSelector == ERC20_SELECTOR ||\n            tokenSelector == MINTABLE_ERC20_SELECTOR;\n    }\n\n    function isMintableAssetType(uint256 assetType) internal view override returns (bool) {\n        bytes4 tokenSelector = extractTokenSelector(getAssetInfo(assetType));\n        return\n            tokenSelector == MINTABLE_ERC20_SELECTOR ||\n            tokenSelector == MINTABLE_ERC721_SELECTOR;\n    }\n\n    function isTokenSupported(bytes4 tokenSelector) private pure returns (bool) {\n        return\n            tokenSelector == ETH_SELECTOR ||\n            tokenSelector == ERC20_SELECTOR ||\n            tokenSelector == ERC721_SELECTOR ||\n            tokenSelector == MINTABLE_ERC20_SELECTOR ||\n            tokenSelector == MINTABLE_ERC721_SELECTOR;\n    }\n\n    function extractContractAddressFromAssetInfo(bytes memory assetInfo)\n        private pure returns (address) {\n        uint256 offset = TOKEN_CONTRACT_ADDRESS_OFFSET;\n        uint256 res;\n        assembly {\n            res := mload(add(assetInfo, offset))\n        }\n        return address(res);\n    }\n\n    function extractContractAddress(uint256 assetType) internal view override returns (address) {\n        return extractContractAddressFromAssetInfo(getAssetInfo(assetType));\n    }\n\n    function verifyAssetInfo(bytes memory assetInfo) internal view override {\n        bytes4 tokenSelector = extractTokenSelector(assetInfo);\n\n        // Ensure the selector is of an asset type we know.\n        require(isTokenSupported(tokenSelector), \"UNSUPPORTED_TOKEN_TYPE\");\n\n        if (tokenSelector == ETH_SELECTOR) {\n            // Assset info for ETH assetType is only a selector, i.e. 4 bytes length.\n            require(assetInfo.length == 4, \"INVALID_ASSET_STRING\");\n        } else {\n            // Assset info for other asset types are a selector + uint256 concatanation.\n            // We pass the address as a uint256 (zero padded),\n            // thus its length is 0x04 + 0x20 = 0x24.\n            require(assetInfo.length == 0x24, \"INVALID_ASSET_STRING\");\n            address tokenAddress = extractContractAddressFromAssetInfo(assetInfo);\n            require(tokenAddress.isContract(), \"BAD_TOKEN_ADDRESS\");\n        }\n    }\n\n    function isNonFungibleAssetInfo(bytes memory assetInfo) internal pure override returns (bool) {\n        bytes4 tokenSelector = extractTokenSelector(assetInfo);\n        return\n            tokenSelector == ERC721_SELECTOR ||\n            tokenSelector == MINTABLE_ERC721_SELECTOR;\n    }\n\n    function calculateNftAssetId(uint256 assetType, uint256 tokenId)\n        internal\n        pure\n        override\n        returns(uint256 assetId) {\n        assetId = uint256(keccak256(abi.encodePacked(NFT_ASSET_ID_PREFIX, assetType, tokenId))) \u0026\n            MASK_250;\n    }\n\n    function calculateMintableAssetId(uint256 assetType, bytes memory mintingBlob)\n        internal\n        pure\n        override\n        returns(uint256 assetId) {\n        uint256 blobHash = uint256(keccak256(mintingBlob));\n        assetId = (uint256(keccak256(abi.encodePacked(MINTABLE_PREFIX ,assetType, blobHash))) \u0026\n            MASK_240) | MINTABLE_ASSET_ID_FLAG;\n    }\n\n}\n"},"TokenQuantization.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"MainStorage.sol\";\nimport \"MTokenQuantization.sol\";\n\n\ncontract TokenQuantization is MainStorage, MTokenQuantization {\n\n    function fromQuantized(uint256 presumedAssetType, uint256 quantizedAmount)\n        internal view override returns (uint256 amount) {\n        uint256 quantum = getQuantum(presumedAssetType);\n        amount = quantizedAmount * quantum;\n        require(amount / quantum == quantizedAmount, \"DEQUANTIZATION_OVERFLOW\");\n    }\n\n    function getQuantum(uint256 presumedAssetType) public view override returns (uint256 quantum) {\n        if (!registeredAssetType[presumedAssetType]) {\n            // Default quantization, for NFTs etc.\n            quantum = 1;\n        } else {\n            // Retrieve registration.\n            quantum = assetTypeToQuantum[presumedAssetType];\n        }\n    }\n\n    function toQuantized(uint256 presumedAssetType, uint256 amount)\n        internal view override returns (uint256 quantizedAmount) {\n        uint256 quantum = getQuantum(presumedAssetType);\n        require(amount % quantum == 0, \"INVALID_AMOUNT\");\n        quantizedAmount = amount / quantum;\n    }\n}\n"},"TokenRegister.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"LibConstants.sol\";\nimport \"MGovernance.sol\";\nimport \"MTokenAssetData.sol\";\nimport \"IERC20.sol\";\nimport \"MainStorage.sol\";\n\n/**\n  Registration of a new token (:sol:func:`registerToken`) entails defining a new asset type within\n  the system, and associating it with an `assetInfo` array of\n  bytes and a quantization factor (`quantum`).\n\n  The `assetInfo` is a byte array, with a size depending on the token.\n  For ETH, assetInfo is 4 bytes long. For ERC20 tokens, it is 36 bytes long.\n\n  For each token type, the following constant 4-byte hash is defined, called the `selector`:\n\n   | `ETH_SELECTOR = bytes4(keccak256(\"ETH()\"));`\n   | `ERC20_SELECTOR = bytes4(keccak256(\"ERC20Token(address)\"));`\n   | `ERC721_SELECTOR = bytes4(keccak256(\"ERC721Token(address,uint256)\"));`\n   | `MINTABLE_ERC20_SELECTOR = bytes4(keccak256(\"MintableERC20Token(address)\"));`\n   | `MINTABLE_ERC721_SELECTOR = bytes4(keccak256(\"MintableERC721Token(address,uint256)\"));`\n\n  For each token type, `assetInfo` is defined as follows:\n\n\n  The `quantum` quantization factor defines the multiplicative transformation from the native token\n  denomination as a 256b unsigned integer to a 63b unsigned integer representation as used by the\n  Stark exchange. Only amounts in the native representation that represent an integer number of\n  quanta are allowed in the system.\n\n  The asset type is restricted to be the result of a hash of the `assetInfo` and the\n  `quantum` masked to 250 bits (to be less than the prime used) according to the following formula:\n\n  | ``uint256 assetType = uint256(keccak256(abi.encodePacked(assetInfo, quantum))) \u0026``\n  | ``0x03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;``\n\n  Once registered, tokens cannot be removed from the system, as their IDs may be used by off-chain\n  accounts.\n\n  New tokens may only be registered by a Token Administrator. A Token Administrator may be instantly\n  appointed or removed by the contract Governor (see :sol:mod:`MainGovernance`). Typically, the\n  Token Administrator\u0027s private key should be kept in a cold wallet.\n*/\nabstract contract TokenRegister is MainStorage, LibConstants, MGovernance, MTokenAssetData {\n    event LogTokenRegistered(uint256 assetType, bytes assetInfo);\n    event LogTokenAdminAdded(address tokenAdmin);\n    event LogTokenAdminRemoved(address tokenAdmin);\n\n    modifier onlyTokensAdmin() {\n        require(isTokenAdmin(msg.sender), \"ONLY_TOKENS_ADMIN\");\n        _;\n    }\n\n    function isTokenAdmin(address testedAdmin) public view returns (bool) {\n        return tokenAdmins[testedAdmin];\n    }\n\n    function registerTokenAdmin(address newAdmin) external onlyGovernance() {\n        tokenAdmins[newAdmin] = true;\n        emit LogTokenAdminAdded(newAdmin);\n    }\n\n    function unregisterTokenAdmin(address oldAdmin) external onlyGovernance() {\n        tokenAdmins[oldAdmin] = false;\n        emit LogTokenAdminRemoved(oldAdmin);\n    }\n\n    function isAssetRegistered(uint256 assetType) public view returns (bool) {\n        return registeredAssetType[assetType];\n    }\n\n    /*\n      Registers a new asset to the system.\n      Once added, it can not be removed and there is a limited number\n      of slots available.\n    */\n    function registerToken(\n        uint256 assetType,\n        bytes memory assetInfo,\n        uint256 quantum\n    ) public virtual onlyTokensAdmin() {\n        // Make sure it is not invalid or already registered.\n        require(!isAssetRegistered(assetType), \"ASSET_ALREADY_REGISTERED\");\n        require(assetType \u003c K_MODULUS, \"INVALID_ASSET_TYPE\");\n        require(quantum \u003e 0, \"INVALID_QUANTUM\");\n        require(quantum \u003c QUANTUM_UPPER_BOUND, \"INVALID_QUANTUM\");\n\n        // Require that the assetType is the hash of the assetInfo and quantum truncated to 250 bits.\n        uint256 enforcedId = uint256(keccak256(abi.encodePacked(assetInfo, quantum))) \u0026 MASK_250;\n        require(assetType == enforcedId, \"INVALID_ASSET_TYPE\");\n\n        verifyAssetInfo(assetInfo);\n        // NFTs quantum must equal one.\n        if (isNonFungibleAssetInfo(assetInfo)) {\n            require(quantum == 1, \"INVALID_NFT_QUANTUM\");\n        }\n\n        // Add token to the in-storage structures.\n        registeredAssetType[assetType] = true;\n        assetTypeToAssetInfo[assetType] = assetInfo;\n        assetTypeToQuantum[assetType] = quantum;\n\n        // Log the registration of a new token.\n        emit LogTokenRegistered(assetType, assetInfo);\n    }\n\n    function registerToken(uint256 assetType, bytes calldata assetInfo) external virtual {\n        registerToken(assetType, assetInfo, 1);\n    }\n}\n"},"TokensAndRamping.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"StarkExForcedActionState.sol\";\nimport \"ERC721Receiver.sol\";\nimport \"Freezable.sol\";\nimport \"KeyGetters.sol\";\nimport \"TokenRegister.sol\";\nimport \"TokenTransfers.sol\";\nimport \"Users.sol\";\nimport \"MainGovernance.sol\";\nimport \"AcceptModifications.sol\";\nimport \"CompositeActions.sol\";\nimport \"Deposits.sol\";\nimport \"TokenAssetData.sol\";\nimport \"TokenQuantization.sol\";\nimport \"Withdrawals.sol\";\nimport \"SubContractor.sol\";\n\ncontract TokensAndRamping is\n    ERC721Receiver,\n    SubContractor,\n    Freezable,\n    MainGovernance,\n    AcceptModifications,\n    StarkExForcedActionState,\n    TokenAssetData,\n    TokenQuantization,\n    TokenRegister,\n    TokenTransfers,\n    KeyGetters,\n    Users,\n    Deposits,\n    CompositeActions,\n    Withdrawals\n{\n    function initialize(bytes calldata /* data */)\n        external override {\n        revert(\"NOT_IMPLEMENTED\");\n    }\n\n    function initializerSize()\n        external view override\n        returns(uint256){\n        return 0;\n    }\n\n    function identify()\n        external pure override\n        returns(string memory){\n        return \"StarkWare_TokensAndRamping_2020_1\";\n    }\n}\n"},"TokenTransfers.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"Common.sol\";\nimport \"MTokenTransfers.sol\";\nimport \"MTokenAssetData.sol\";\nimport \"MTokenQuantization.sol\";\nimport \"IERC20.sol\";\n\n/*\n  Implements various transferIn and transferOut functionalities.\n*/\nabstract contract TokenTransfers is MTokenQuantization, MTokenAssetData, MTokenTransfers {\n    using Addresses for address;\n    using Addresses for address payable;\n\n    /*\n      Transfers funds from msg.sender to the exchange.\n    */\n    function transferIn(uint256 assetType, uint256 quantizedAmount) internal override {\n        uint256 amount = fromQuantized(assetType, quantizedAmount);\n        if (isERC20(assetType)) {\n            address tokenAddress = extractContractAddress(assetType);\n            IERC20 token = IERC20(tokenAddress);\n            uint256 exchangeBalanceBefore = token.balanceOf(address(this));\n            bytes memory callData = abi.encodeWithSelector(\n                token.transferFrom.selector,\n                msg.sender,\n                address(this),\n                amount\n            );\n            tokenAddress.safeTokenContractCall(callData);\n            uint256 exchangeBalanceAfter = token.balanceOf(address(this));\n            require(exchangeBalanceAfter \u003e= exchangeBalanceBefore, \"OVERFLOW\");\n            // NOLINTNEXTLINE(incorrect-equality): strict equality needed.\n            require(\n                exchangeBalanceAfter == exchangeBalanceBefore + amount,\n                \"INCORRECT_AMOUNT_TRANSFERRED\"\n            );\n        } else if (isEther(assetType)) {\n            require(msg.value == amount, \"INCORRECT_DEPOSIT_AMOUNT\");\n        } else {\n            revert(\"UNSUPPORTED_TOKEN_TYPE\");\n        }\n    }\n\n    function transferInNft(uint256 assetType, uint256 tokenId) internal override {\n        require(isERC721(assetType), \"NOT_ERC721_TOKEN\");\n        address tokenAddress = extractContractAddress(assetType);\n        tokenAddress.safeTokenContractCall(\n            abi.encodeWithSignature(\n                \"safeTransferFrom(address,address,uint256)\",\n                msg.sender,\n                address(this),\n                tokenId\n            )\n        );\n    }\n\n    /*\n      Transfers funds from the exchange to recipient.\n    */\n    function transferOut(\n        address payable recipient,\n        uint256 assetType,\n        uint256 quantizedAmount\n    ) internal override {\n        uint256 amount = fromQuantized(assetType, quantizedAmount);\n        if (isERC20(assetType)) {\n            address tokenAddress = extractContractAddress(assetType);\n            IERC20 token = IERC20(tokenAddress);\n            uint256 exchangeBalanceBefore = token.balanceOf(address(this));\n            bytes memory callData = abi.encodeWithSelector(\n                token.transfer.selector,\n                recipient,\n                amount\n            );\n            tokenAddress.safeTokenContractCall(callData);\n            uint256 exchangeBalanceAfter = token.balanceOf(address(this));\n            require(exchangeBalanceAfter \u003c= exchangeBalanceBefore, \"UNDERFLOW\");\n            // NOLINTNEXTLINE(incorrect-equality): strict equality needed.\n            require(\n                exchangeBalanceAfter == exchangeBalanceBefore - amount,\n                \"INCORRECT_AMOUNT_TRANSFERRED\"\n            );\n        } else if (isEther(assetType)) {\n            recipient.performEthTransfer(amount);\n        } else {\n            revert(\"UNSUPPORTED_TOKEN_TYPE\");\n        }\n    }\n\n    /*\n      Transfers NFT from the exchange to recipient.\n    */\n    function transferOutNft(\n        address recipient,\n        uint256 assetType,\n        uint256 tokenId\n    ) internal override {\n        require(isERC721(assetType), \"NOT_ERC721_TOKEN\");\n        address tokenAddress = extractContractAddress(assetType);\n        tokenAddress.safeTokenContractCall(\n            abi.encodeWithSignature(\n                \"safeTransferFrom(address,address,uint256)\",\n                address(this),\n                recipient,\n                tokenId\n            )\n        );\n    }\n\n    function transferOutMint(\n        uint256 assetType,\n        uint256 quantizedAmount,\n        bytes memory mintingBlob\n    ) internal override {\n        require(isMintableAssetType(assetType), \"NON_MINTABLE_ASSET_TYPE\");\n        uint256 amount = fromQuantized(assetType, quantizedAmount);\n        address tokenAddress = extractContractAddress(assetType);\n        tokenAddress.safeTokenContractCall(\n            abi.encodeWithSignature(\n                \"mintFor(address,uint256,bytes)\",\n                msg.sender,\n                amount,\n                mintingBlob\n            )\n        );\n    }\n}\n"},"Users.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"MainStorage.sol\";\nimport \"LibConstants.sol\";\nimport \"MGovernance.sol\";\nimport \"MKeyGetters.sol\";\nimport \"MUsers.sol\";\n\n/**\n  Users of the Stark Exchange are identified within the exchange by their Stark Key which is a\n  public key defined over a Stark-friendly elliptic curve that is different from the standard\n  Ethereum elliptic curve. These keys may be generated using the same private key used by the user\n  on Ethereum.\n\n  The Stark-friendly elliptic curve used is defined as follows:\n\n  .. math:: y^2 = (x^3 + \\alpha \\cdot x + \\beta) \\% p\n\n  where:\n\n  .. math:: \\alpha = 1\n  .. math:: \\beta = 3141592653589793238462643383279502884197169399375105820974944592307816406665\n  .. math:: p = 3618502788666131213697322783095070105623107215331596699973092056135872020481\n\n  In order to associate exchange users with Ethereum account addresses, an Ethereum address must be\n  registered with the Stark Key on the exchange contract before any other user operation can take\n  place.\n  User registration is performed by calling :sol:func:`registerUser` with the selected Stark Key,\n  representing an `x` coordinate on the Stark-friendly elliptic curve, and the `y` coordinate of\n  the key on the curve (due to the nature of the curve, only two such possible `y` coordinates\n  exist).\n\n  The registration is accepted if the following holds:\n\n  1. The key registered is not zero and has not been registered in the past by the user or anyone else.\n  2. The key provided represents a valid point on the Stark-friendly elliptic curve.\n  3. The linkage between the provided Ethereum key and the selected Stark Key is signed by the User Admin (typically the exchange operator).\n\n  If the above holds, the Stark Key is registered by the contract, mapping it to the Ethereum key.\n  This mapping is later used to ensure that withdrawals from accounts mapped to the Stark Keys can\n  only be performed by users authenticated with the associated Ethereum public keys (see :sol:mod:`Withdrawals`).\n*/\nabstract contract Users is MainStorage, LibConstants, MGovernance, MUsers, MKeyGetters {\n    event LogUserRegistered(address ethKey, uint256 starkKey, address sender);\n    event LogUserAdminAdded(address userAdmin);\n    event LogUserAdminRemoved(address userAdmin);\n\n    function isOnCurve(uint256 starkKey) private view returns (bool) {\n        uint256 xCubed = mulmod(mulmod(starkKey, starkKey, K_MODULUS), starkKey, K_MODULUS);\n        return isQuadraticResidue(addmod(addmod(xCubed, starkKey, K_MODULUS), K_BETA, K_MODULUS));\n    }\n\n    function registerUserAdmin(address newAdmin) external onlyGovernance() {\n        userAdmins[newAdmin] = true;\n        emit LogUserAdminAdded(newAdmin);\n    }\n\n    function unregisterUserAdmin(address oldAdmin) external onlyGovernance() {\n        userAdmins[oldAdmin] = false;\n        emit LogUserAdminRemoved(oldAdmin);\n    }\n\n    function isUserAdmin(address testedAdmin) public view returns (bool) {\n        return userAdmins[testedAdmin];\n    }\n\n    function registerUser(address ethKey, uint256 starkKey, bytes calldata signature) public override {\n        // Validate keys and availability.\n        require(starkKey != 0, \"INVALID_STARK_KEY\");\n        require(starkKey \u003c K_MODULUS, \"INVALID_STARK_KEY\");\n        require(ethKey != ZERO_ADDRESS, \"INVALID_ETH_ADDRESS\");\n        require(ethKeys[starkKey] == ZERO_ADDRESS, \"STARK_KEY_UNAVAILABLE\");\n        require(isOnCurve(starkKey), \"INVALID_STARK_KEY\");\n        require(signature.length == 65, \"INVALID_SIGNATURE\");\n\n        bytes32 signedData = keccak256(abi.encodePacked(\"UserRegistration:\", ethKey, starkKey));\n\n        bytes memory sig = signature;\n        uint8 v = uint8(sig[64]);\n        bytes32 r;\n        bytes32 s;\n\n        assembly {\n            r := mload(add(sig, 32))\n            s := mload(add(sig, 64))\n        }\n\n        address signer = ecrecover(signedData, v, r, s);\n        require(signer != ZERO_ADDRESS \u0026\u0026 isUserAdmin(signer), \"INVALID_SIGNATURE\");\n\n        // Update state.\n        ethKeys[starkKey] = ethKey;\n\n        // Log new user.\n        emit LogUserRegistered(ethKey, starkKey, msg.sender);\n    }\n\n    function fieldPow(uint256 base, uint256 exponent) internal view returns (uint256) {\n        // NOLINTNEXTLINE: low-level-calls reentrancy-events reentrancy-no-eth.\n        (bool success, bytes memory returndata) = address(5).staticcall(\n            abi.encode(0x20, 0x20, 0x20, base, exponent, K_MODULUS)\n        );\n        require(success, string(returndata));\n        return abi.decode(returndata, (uint256));\n    }\n\n    function isQuadraticResidue(uint256 fieldElement) private view returns (bool) {\n        return 1 == fieldPow(fieldElement, ((K_MODULUS - 1) / 2));\n    }\n}\n"},"Withdrawals.sol":{"content":"/*\n  Copyright 2019-2021 StarkWare Industries Ltd.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\").\n  You may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  https://www.starkware.co/open-source-license/\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions\n  and limitations under the License.\n*/\n// SPDX-License-Identifier: Apache-2.0.\npragma solidity ^0.6.11;\n\nimport \"MAcceptModifications.sol\";\nimport \"MTokenQuantization.sol\";\nimport \"MTokenAssetData.sol\";\nimport \"MFreezable.sol\";\nimport \"MKeyGetters.sol\";\nimport \"MTokenTransfers.sol\";\nimport \"MainStorage.sol\";\n\n/**\n  For a user to perform a withdrawal operation from the Stark Exchange during normal operation\n  two calls are required:\n\n  1. A call to an offchain exchange API, requesting a withdrawal from a user account (vault).\n  2. A call to the on-chain :sol:func:`withdraw` function to perform the actual withdrawal of funds transferring them to the users Eth or ERC20 account (depending on the token type).\n\n  For simplicity, hereafter it is assumed that all tokens are ERC20 tokens but the text below\n  applies to Eth in the same manner.\n\n  In the first call mentioned above, anyone can call the API to request the withdrawal of an\n  amount from a given vault. Following the request, the exchange may include the withdrawal in a\n  STARK proof. The submission of a proof then results in the addition of the amount(s) withdrawn to\n  an on-chain pending withdrawals account under the stark key of the vault owner and the appropriate\n  asset ID. At the same time, this also implies that this amount is deducted from the off-chain\n  vault.\n\n  Once the amount to be withdrawn has been transfered to the on-chain pending withdrawals account,\n  the user may perform the second call mentioned above to complete the transfer of funds from the\n  Stark Exchange contract to the appropriate ERC20 account. Only a user holding the Eth key\n  corresponding to the Stark Key of a pending withdrawals account may perform this operation.\n\n  It is possible that for multiple withdrawal calls to the API, a single withdrawal call to the\n  contract may retrieve all funds, as long as they are all for the same asset ID.\n\n  The result of the operation, assuming all requirements are met, is that an amount of ERC20 tokens\n  in the pending withdrawal account times the quantization factor is transferred to the ERC20\n  account of the user.\n\n  A withdrawal request cannot be cancelled. Once funds reach the pending withdrawals account\n  on-chain, they cannot be moved back into an off-chain vault before completion of the withdrawal\n  to the ERC20 account of the user.\n\n  In the event that the exchange reaches a frozen state the user may perform a withdrawal operation\n  via an alternative flow, known as the \"Escape\" flow. In this flow, the API call above is replaced\n  with an :sol:func:`escape` call to the on-chain contract (see :sol:mod:`Escapes`) proving the\n  ownership of off-chain funds. If such proof is accepted, the user may proceed as above with\n  the :sol:func:`withdraw` call to the contract to complete the operation.\n*/\nabstract contract Withdrawals is\n    MainStorage,\n    MAcceptModifications,\n    MTokenQuantization,\n    MTokenAssetData,\n    MFreezable,\n    MKeyGetters,\n    MTokenTransfers  {\n    event LogWithdrawalPerformed(\n        uint256 starkKey,\n        uint256 assetType,\n        uint256 nonQuantizedAmount,\n        uint256 quantizedAmount,\n        address recipient\n    );\n\n    event LogNftWithdrawalPerformed(\n        uint256 starkKey,\n        uint256 assetType,\n        uint256 tokenId,\n        uint256 assetId,\n        address recipient\n    );\n\n    event LogMintWithdrawalPerformed(\n        uint256 starkKey,\n        uint256 tokenId,\n        uint256 nonQuantizedAmount,\n        uint256 quantizedAmount,\n        uint256 assetId\n    );\n\n    function getWithdrawalBalance(\n        uint256 starkKey,\n        uint256 assetId\n    )\n        external\n        view\n        returns (uint256 balance)\n    {\n        uint256 presumedAssetType = assetId;\n        balance = fromQuantized(presumedAssetType, pendingWithdrawals[starkKey][assetId]);\n    }\n\n    /*\n      Allows a user to withdraw accepted funds to a recipient\u0027s account.\n      This function can be called normally while frozen.\n    */\n    function withdrawTo(\n        uint256 starkKey,\n        uint256 assetType,\n        address payable recipient)\n        external\n        onlyStarkKeyOwner(starkKey)\n    {\n        internalWithdrawTo(starkKey, assetType, recipient);\n    }\n\n    /*\n      Underlying implementation of withdraw \u0026 withdrawTo.\n      Checking that the address of the recipient preserves self-custody is the responsibility of the\n      calling function. (i.e. that the recipient is either the owner of the assets or that the owner\n      has authorized the withdrawal).\n    */\n    function internalWithdrawTo(\n        uint256 starkKey,\n        uint256 assetType,\n        address payable recipient) internal\n    {\n        require(!isMintableAssetType(assetType), \"MINTABLE_ASSET_TYPE\");\n        require(isFungibleAssetType(assetType), \"NON_FUNGIBLE_ASSET_TYPE\");\n        uint256 assetId = assetType;\n        // Fetch and clear quantized amount.\n        uint256 quantizedAmount = pendingWithdrawals[starkKey][assetId];\n        pendingWithdrawals[starkKey][assetId] = 0;\n\n        // Transfer funds.\n        transferOut(recipient, assetType, quantizedAmount);\n        emit LogWithdrawalPerformed(\n            starkKey,\n            assetType,\n            fromQuantized(assetType, quantizedAmount),\n            quantizedAmount,\n            recipient\n        );\n    }\n\n    /*\n      Moves funds from the pending withdrawal account to the owner address.\n      Note: this function can be called by anyone.\n      Can be called normally while frozen.\n    */\n    function withdraw(uint256 starkKey, uint256 assetType)\n        external\n    {\n        internalWithdrawTo(starkKey, assetType, address(uint160(getEthKey(starkKey))));\n    }\n\n    /*\n      Allows a user to withdraw an accepted NFT to a recipient\u0027s account.\n      This function can be called normally while frozen.\n    */\n    function withdrawNftTo(\n        uint256 starkKey,\n        uint256 assetType,\n        uint256 tokenId,\n        address recipient\n    )\n        public\n        onlyStarkKeyOwner(starkKey)\n    // No notFrozen modifier: This function can always be used, even when frozen.\n    {\n        // Calculate assetId.\n        uint256 assetId = calculateNftAssetId(assetType, tokenId);\n        require(!isMintableAssetType(assetType), \"MINTABLE_ASSET_TYPE\");\n        require(!isFungibleAssetType(assetType), \"FUNGIBLE_ASSET_TYPE\");\n        require(pendingWithdrawals[starkKey][assetId] == 1, \"ILLEGAL_NFT_BALANCE\");\n        pendingWithdrawals[starkKey][assetId] = 0;\n\n        // Transfer funds.\n        transferOutNft(recipient, assetType, tokenId);\n        emit LogNftWithdrawalPerformed(starkKey, assetType, tokenId, assetId, recipient);\n    }\n\n    /*\n      Allows a user to withdraw an accepted NFT to its own account.\n      This function can be called normally while frozen.\n    */\n    function withdrawNft(\n        uint256 starkKey,\n        uint256 assetType,\n        uint256 tokenId\n    )\n        external\n    // No notFrozen modifier: This function can always be used, even when frozen.\n    {\n        withdrawNftTo(starkKey, assetType, tokenId, msg.sender);\n    }\n\n    function withdrawAndMint(\n        uint256 starkKey,\n        uint256 assetType,\n        bytes calldata mintingBlob\n    ) external onlyStarkKeyOwner(starkKey) {\n        require(registeredAssetType[assetType], \"INVALID_ASSET_TYPE\");\n        require(isMintableAssetType(assetType), \"NON_MINTABLE_ASSET_TYPE\");\n        uint256 assetId = calculateMintableAssetId(assetType, mintingBlob);\n        require(pendingWithdrawals[starkKey][assetId] \u003e 0, \"NO_PENDING_WITHDRAWAL_BALANCE\");\n        uint256 quantizedAmount = pendingWithdrawals[starkKey][assetId];\n        pendingWithdrawals[starkKey][assetId] = 0;\n        // Transfer funds.\n        transferOutMint(assetType, quantizedAmount, mintingBlob);\n        emit LogMintWithdrawalPerformed(\n            starkKey, assetType, fromQuantized(assetType, quantizedAmount), quantizedAmount,\n            assetId);\n    }\n}\n"}}