APE Price: $0.65 (-5.98%)

Contract

0x6000030000842044000077551D00cfc6b4005900

Overview

APE Balance

Apechain LogoApechain LogoApechain Logo0 APE

APE Value

$0.00
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Parent Transaction Hash Block From To
29892872024-10-31 17:53:5097 days ago1730397230  Contract Creation0 APE

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
WrappedNative

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
cancun EvmVersion, MIT license
File 1 of 9 : WrappedNative.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "./Constants.sol";
import "./utils/EIP712.sol";
import "./utils/Math.sol";

/**
 * @title  WrappedNative
 * @author Limit Break, Inc.
 * @notice A contract that wraps native tokens (e.g. Ether) into an ERC-20 token.  Designed as a
 *         canonical replacement for WETH9 that can be deployed to a consistent, deterministic address on all chains.
 *
 * @notice WrappedNative features the following improvements over WETH9:
 *
 * @notice - **Deterministically Deployable By Anyone To A Consistent Address On Any Chain!**
 * @notice - **More Gas Efficient Operations Than WETH9!**
 * @notice - **`approve` and `transfer` functions are payable** - will auto-deposit when `msg.value > 0`.  This feature
 *           will allow a user to wrap and approve a protocol in a single action instead of two, improving UX and saving gas.
 * @notice - **`depositTo`** - allows a depositor to specify the address to give WNATIVE to.  
 *           Much more gas efficient for operations such as native refunds from protocols compared to `deposit + transfer`.
 * @notice - **`withdrawToAccount`** - allows a withdrawer to withdraw to a different address.
 * @notice - **`withdrawSplit`** - allows a withdrawer to withdraw and send native tokens to several addresses at once.
 * @notice - **Permit Functions** - allows for transfers and withdrawals to be approved to spenders/operators gaslessly using EIP-712 signatures.
 *           Permitted withdrawals allow gas sponsorship to unwrap wrapped native tokens on the user's behalf, for a small convenience fee specified by the app.
 *           This is useful when user has no native tokens on a new chain but they have received wrapped native tokens.
 */

contract WrappedNative is EIP712 {

    /// @dev Storage of user master nonces for permit processing.
    mapping (address => uint256) private _masterNonces;

    /// @dev Storage of permit nonces for permit processing.  Uses bitmaps for gas-efficient storage.
    mapping (address => mapping (uint256 => uint256)) private _permitNonces;

    /// @notice Stores the wrapped native token balance of each user.
    mapping (address => uint256) public balanceOf;

    /// @notice Stores the wrapped native token allowance for each user/spender pair.
    mapping (address => mapping (address => uint)) public allowance;

    /// @notice Address that will receive infrastructure fee taxes on permit transfers.
    address immutable ADDRESS_INFRASTRUCTURE_TAX;

    constructor(address infrastructureTaxRecipient) EIP712(NAME, VERSION) {
        ADDRESS_INFRASTRUCTURE_TAX = infrastructureTaxRecipient;
    }

    //=================================================
    //== Deposit / Fallback Function Implementations ==
    //=================================================

    /**
     * @notice Fallback function to deposit funds into the contract, or to call various view functions.
     *         If the `msg.value` is greater than zero, the function will deposit the funds into the
     *         `msg.sender` account. If the `msg.value` is zero, the function will check the `msg.sig`
     *         to determine which view function is being called.  If a matching function selector is found
     *         the function will execute and return the appropriate value. If no matching function selector is found,
     *         the function will revert.
     *         
     * @notice The reason seldom-used view functions have been implemented via fallback is to save gas costs
     *         elsewhere in the contract in common operations that have a runtime gas cost.
     *
     * @notice The following function selectors are implemented via fallback:
     * 
     * @notice - **function isNonceUsed(address account, uint256 nonce) external view returns (bool)**
     * @notice - **function masterNonces(address account) external view returns (uint256)**
     * @notice - **function totalSupply() external view returns (uint256)**
     * @notice - **function domainSeparatorV4() external view returns (bytes32)**
     * @notice - **function name() external view returns (string)**
     * @notice - **function symbol() external view returns (string)**
     * @notice - **function decimals() external view returns (uint8)**
     *
     * @dev     Throws when `msg.value` == 0 and the `msg.sig` does not match any of the implemented view functions.
     */
    fallback() external payable {
        if (msg.value > 0) {
            deposit();
        } else {
            if (msg.sig == SELECTOR_IS_NONCE_USED) { // isNonceUsed(address account, uint256 nonce)
                (address account, uint256 nonce) = abi.decode(msg.data[4:], (address,uint256));
                bool isUsed = ((_permitNonces[account][uint248(nonce >> 8)] >> uint8(nonce)) & ONE) == ONE;
                assembly {
                    mstore(0x00, isUsed)
                    return(0x00, 0x20)
                }
            } else if (msg.sig == SELECTOR_MASTER_NONCES) { // masterNonces(address account)
                assembly {
                    if lt(calldatasize(), 0x24) {
                        revert(0,0)
                    }
                    mstore(0x00, shr(0x60, shl(0x60, calldataload(0x04))))
                    mstore(0x20, _masterNonces.slot)
                    mstore(0x00, sload(keccak256(0x00, 0x40)))
                    return(0x00, 0x20)
                }
            } else if (msg.sig == SELECTOR_TOTAL_SUPPLY) { // totalSupply()
                assembly {
                    mstore(0x00, selfbalance())
                    return(0x00, 0x20)
                }
            } else if (msg.sig == SELECTOR_DOMAIN_SEPARATOR_V4) { // domainSeparatorV4()
                bytes32 domainSeparator = _domainSeparatorV4();
                assembly {
                    mstore(0x00, domainSeparator)
                    return(0x00, 0x20)
                }
            } else if (msg.sig == SELECTOR_NAME) { // name()
                bytes memory nameReturnValue = abi.encode(NAME);
                assembly {
                    return(add(nameReturnValue, 0x20), mload(nameReturnValue))
                }
            } else if (msg.sig == SELECTOR_SYMBOL) { // symbol()
                bytes memory symbolReturnValue = abi.encode(SYMBOL);
                assembly {
                    return(add(symbolReturnValue, 0x20), mload(symbolReturnValue))
                }
            } else if (msg.sig == SELECTOR_DECIMALS) { // decimals()
                assembly {
                    mstore(0x00, 0x12) // 18
                    return(0x00, 0x20)
                }
            } else {
                revert();
            }
        }
    }

    /**
     * @notice Deposits `msg.value` funds into the `msg.sender` account, increasing their wrapped native token balance.
     * @notice This function is triggered when native funds are sent to this contract with no calldata.
     */
    receive() external payable {
        deposit();
    }

    //=================================================
    //========== Basic Deposits / Withdrawals =========
    //=================================================

    /**
     * @notice Deposits `msg.value` funds into the `msg.sender` account, increasing their wrapped native token balance.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. This contract's native token balance has increased by `msg.value`.
     * @dev    2. The `msg.sender`'s native token balance has decreased by `msg.value`.
     * @dev    3. The `msg.sender`'s wrapped native token balance has increased by `msg.value`.
     * @dev    4. A `Deposit` event has been emitted.  The `msg.sender` address is logged in the event.
     */
    function deposit() public payable {
        depositTo(msg.sender);
    }

    /**
     * @notice Deposits `msg.value` funds into specified user's account, increasing their wrapped native token balance.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. This contract's native token balance has increased by `msg.value`.
     * @dev    2. The `msg.sender`'s native token balance has decreased by `msg.value`.
     * @dev    3. The `to` account's wrapped native token balance has increased by `msg.value`.
     * @dev    4. A `Deposit` event has been emitted.  Caveat: The `to` address is logged in the event, not `msg.sender`.
     *
     * @param to  The address that receives wrapped native tokens.
     */
    function depositTo(address to) public payable {
        assembly {
            mstore(0x00, to)
            mstore(0x20, balanceOf.slot)
            let balanceSlot := keccak256(0x00, 0x40)

            sstore(balanceSlot, add(sload(balanceSlot), callvalue()))

            mstore(0x00, callvalue())
            log2(0x00, 0x20, DEPOSIT_EVENT_TOPIC_0, to)
        }
    }

    /**
     * @notice Withdraws `amount` funds from the `msg.sender` account, decreasing their wrapped native token balance.
     *
     * @dev    Throws when the `msg.sender`'s wrapped native token balance is less than `amount` to withdraw.
     * @dev    Throws when the unwrapped native funds cannot be transferred to the `msg.sender` account.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. This contract's native token balance has decreased by `amount`.
     * @dev    2. The `msg.sender`'s wrapped native token balance has decreased by `amount`.
     * @dev    3. The `msg.sender`'s native token balance has increased by `amount`.
     * @dev    4. A `Withdrawal` event has been emitted.  The `msg.sender` address is logged in the event.
     *
     * @param amount  The amount of wrapped native tokens to withdraw.
     */
    function withdraw(uint256 amount) public {
        withdrawToAccount(msg.sender, amount);
    }

    /**
     * @notice Withdraws `amount` funds from the `msg.sender` account, decreasing their wrapped native token balance.
     *
     * @dev    Throws when the `msg.sender`'s wrapped native token balance is less than `amount` to withdraw.
     * @dev    Throws when the unwrapped native funds cannot be transferred to the `to` account.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. This contract's native token balance has decreased by `amount`.
     * @dev    2. The `msg.sender`'s wrapped native token balance has decreased by `amount`.
     * @dev    3. The `to` account's native token balance has increased by `amount`.
     * @dev    4. A `Withdrawal` event has been emitted.  Caveat: The `msg.sender` address is logged in the event, not `to`.
     *
     * @param to  The address that receives the unwrapped native tokens.
     * @param amount  The amount of wrapped native tokens to withdraw.
     */
    function withdrawToAccount(address to, uint256 amount) public {
        _withdrawFromAccount(msg.sender, to, amount);
    }

    /**
     * @notice Withdraws funds from the `msg.sender` and splits the funds between multiple receiver addresses.
     *
     * @dev    Throws when the `msg.sender`'s wrapped native token balance is less than the sum of `amounts` to withdraw.
     * @dev    Throws when the unwrapped native funds cannot be transferred to one or more of the receiver addresses.
     * @dev    Throws when the `toAddresses` and `amounts` arrays are not the same length.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. This contract's native token balance has decreased by the sum of `amounts`.
     * @dev    2. The `msg.sender`'s wrapped native token balance has decreased by the sum of `amounts`.
     * @dev    3. The receiver addresses' native token balances have increased by the corresponding amounts in `amounts`.
     * @dev    4. A `Withdrawal` event has been emitted for each receiver address.  Caveat: The `msg.sender` address is 
     *            logged in the events, not the receiver address.
     *
     * @param toAddresses  The addresses that receive the unwrapped native tokens.
     * @param amounts  The amounts of wrapped native tokens to withdraw for each receiver address.
     */
    function withdrawSplit(address[] calldata toAddresses, uint256[] calldata amounts) external {
        if (toAddresses.length != amounts.length) {
            revert();
        }

        for (uint256 i = 0; i < toAddresses.length;) {
            withdrawToAccount(toAddresses[i], amounts[i]);
            unchecked {
                ++i;
            }
        }
    }

    //=================================================
    //========== ERC-20 Approvals & Transfers =========
    //=================================================

    /**
     * @notice Approves `spender` to spend/transfer `amount` of the `msg.sender`'s wrapped native tokens.
     *         When `amount` is set to `type(uint256).max`, the approval is unlimited.
     *
     * @notice Unlike a typical ERC-20 token, this function is payable, allowing for a `deposit` and approval to be
     *         executed simultaneously.  If `msg.value` is greater than zero, the function will deposit the funds
     *         into the `msg.sender` account before approving the `spender` to spend/transfer the funds.
     *         If `msg.value` is zero, the function will only approve the `spender` to spend/transfer the funds.
     *         This feature is intended to improve the UX of users using wrapped native tokens so that users don't have
     *         to perform two transactions to first deposit, then approve the spending of their tokens, saving gas in
     *         the process.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The `spender` is approved to spend/transfer `amount` of the `msg.sender`'s wrapped native tokens.
     * @dev    2. A `Approval` event has been emitted.  The `msg.sender` address, `spender` address, and `amount` of the 
     *            updated approval are logged in the event.
     * @dev    3. If `msg.value` is greater than zero, the `msg.sender`'s wrapped native token balance has increased by 
     *            `msg.value`.
     * @dev    4. If `msg.value` is greater than zero, a `Deposit` event has been emitted.  The `msg.sender` address is 
     *            logged in the event.
     *
     * @param spender  The address that is approved to spend/transfer the `msg.sender`'s wrapped native tokens.
     * @param amount   The amount of wrapped native tokens that the `spender` is approved to spend/transfer. Approved
     *                 spending is unlimited when this values is set to `type(uint256).max`.
     *
     * @return Always returns `true`.
     */
    function approve(address spender, uint256 amount) public payable returns (bool) {
        if (msg.value > 0) {
            deposit();
        }

        assembly {
            mstore(0x00, caller())
            mstore(0x20, allowance.slot)
            mstore(0x20, keccak256(0x00, 0x40))
            mstore(0x00, spender)
            let allowanceSlot := keccak256(0x00, 0x40)

            sstore(allowanceSlot, amount)

            mstore(0x00, amount)
            log3(0x00, 0x20, APPROVAL_EVENT_TOPIC_0, caller(), spender)

            mstore(0x00, 0x01)
            return(0x00, 0x20)
        }
    }

    /**
     * @notice Transfers an `amount` of wrapped native tokens from the `msg.sender` to the `to` address.
     *
     * @notice If the `msg.value` is greater than zero, the function will deposit the funds into the `msg.sender` account
     *         before transferring the wrapped funds.  Otherwise, the function will only transfer the funds.
     *
     * @dev    Throws when the `msg.sender` has an insufficient balance to transfer `amount` of wrapped native tokens.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. When `msg.value` is greater than zero, this contract's native token balance has increased by `msg.value`.
     * @dev    2. When `msg.value` is greater than zero, the `msg.sender`'s native token balance has decreased by `msg.value`.
     * @dev    3. When `msg.value` is greater than zero, the `msg.sender`'s wrapped native token balance has increased by `msg.value`.
     * @dev    4. When `msg.value` is greater than zero, a `Deposit` event has been emitted.  The `msg.sender` address is logged in the event.
     * @dev    5. The `amount` of wrapped native tokens has been transferred from the `msg.sender` account to the `to` account.
     * @dev    6. A `Transfer` event has been emitted.  The `msg.sender` address, `to` address, and `amount` are logged in the event.
     *
     * @param to  The address that receives the wrapped native tokens.
     * @param amount  The amount of wrapped native tokens to transfer.
     *
     * @return Always returns `true`.
     */
    function transfer(address to, uint256 amount) public payable returns (bool) {
        return transferFrom(msg.sender, to, amount);
    }

    /**
     * @notice Transfers an `amount` of wrapped native tokens from the `from` to the `to` address.
     *
     * @notice If the `msg.value` is greater than zero, the function will deposit the funds into the `from` account
     *         before transferring the wrapped funds.  Otherwise, the function will only transfer the funds.
     * @notice **As a reminder, the `msg.sender`'s native tokens will be deposited and the `from` (not the `msg.sender`) 
     *         address will be credited before the transfer.  Integrating spender/operator protocols MUST be aware that 
     *         deposits made during transfers will not credit their own account.**
     *
     * @dev    Throws when the `from` account has an insufficient balance to transfer `amount` of wrapped native tokens.
     * @dev    Throws when the `msg.sender` is not the `from` address, and the `msg.sender` has not been approved
     *         by `from` for an allowance greater than or equal to `amount`.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. When `msg.value` is greater than zero, this contract's native token balance has increased by `msg.value`.
     * @dev    2. When `msg.value` is greater than zero, the `msg.sender`'s native token balance has decreased by `msg.value`.
     * @dev    3. When `msg.value` is greater than zero, the `from` account's wrapped native token balance has increased by `msg.value`.
     * @dev    4. When `msg.value` is greater than zero, a `Deposit` event has been emitted.  The `from` address is logged in the event.
     * @dev    5. The `amount` of wrapped native tokens has been transferred from the `from` account to the `to` account.
     * @dev    6. A `Transfer` event has been emitted.  The `from` address, `to` address, and `amount` are logged in the event.
     *
     * @param from  The address that transfers the wrapped native tokens.
     * @param to    The address that receives the wrapped native tokens.
     * @param amount  The amount of wrapped native tokens to transfer.
     *
     * @return Always returns `true`.
     */
    function transferFrom(address from, address to, uint256 amount) public payable returns (bool) {
        if (msg.value > 0) {
            depositTo(from);
        }

        assembly {
            mstore(0x00, from)
            mstore(0x20, balanceOf.slot)
            let balanceSlotFrom := keccak256(0x00, 0x40)
            let balanceValFrom := sload(balanceSlotFrom)
            if lt(balanceValFrom, amount) {
                revert(0,0)
            }
            sstore(balanceSlotFrom, sub(balanceValFrom, amount))

            mstore(0x00, to)
            let balanceSlotTo := keccak256(0x00, 0x40)
            sstore(balanceSlotTo, add(sload(balanceSlotTo), amount))

            if iszero(eq(from, caller())) {
                mstore(0x00, from)
                mstore(0x20, allowance.slot)
                mstore(0x20, keccak256(0x00, 0x40))
                mstore(0x00, caller())
                let allowanceSlot := keccak256(0x00, 0x40)
                let allowanceVal := sload(allowanceSlot)

                if iszero(eq(allowanceVal, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)) {
                    if lt(allowanceVal, amount) {
                        revert(0,0)
                    }
                    sstore(allowanceSlot, sub(allowanceVal, amount))
                }
            }

            mstore(0x00, amount)
            log3(0x00, 0x20, TRANSFER_EVENT_TOPIC_0, from, to)

            mstore(0x00, 0x01)
            return(0x00, 0x20)
        }
    }

    //=================================================
    //======= Permitted Transfers / Withdrawals =======
    //=================================================

    /**
     * @notice Allows the `msg.sender` to revoke/cancel all prior permitted transfer and withdrawal signatures.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The `msg.sender`'s master nonce has been incremented by `1` in contract storage, rendering all signed
     *            permits using the prior master nonce unusable.
     * @dev    2. A `MasterNonceInvalidated` event has been emitted.
     */
    function revokeMyOutstandingPermits() external {
        assembly {
            mstore(0x00, caller())
            mstore(0x20, _masterNonces.slot)
            let masterNonceSlot := keccak256(0x00, 0x40)
            let invalidatedNonce := sload(masterNonceSlot)
            sstore(masterNonceSlot, add(0x01, invalidatedNonce))
            log3(0x00, 0x00, MASTER_NONCE_INVALIDATED_EVENT_TOPIC_0, caller(), invalidatedNonce)
        }
    }

    /**
     * @notice Allows the `msg.sender` to revoke/cancel a single, previously signed permitted transfer or withdrawal 
     *         signature by specifying the nonce of the individual permit.
     *
     * @dev    Throws when the `msg.sender` has already revoked the permit nonce.
     * @dev    Throws when the permit nonce was already used successfully.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The specified `nonce` for the `msg.sender` has been revoked and can
     *            no longer be used to execute a permitted transfer or withdrawal.
     * @dev    2. A `PermitNonceInvalidated` event has been emitted.
     *
     * @param  nonce The nonce that was signed in the permitted transfer or withdrawal.
     */
    function revokeMyNonce(uint256 nonce) external {
        _checkAndInvalidateNonce(msg.sender, nonce);
    }

    /**
     * @notice Allows a spender/operator to transfer wrapped native tokens from the `from` account to the `to` account
     *         using a gasless signature from the `from` account so that the `from` account does not need to pay gas
     *         to set an on-chain allowance.
     *
     * @notice If the `msg.value` is greater than zero, the function will deposit the funds into the `from` account
     *         before transferring the wrapped funds.  Otherwise, the function will only transfer the funds.
     * @notice **As a reminder, the `msg.sender`'s native tokens will be deposited and the `from` (not the `msg.sender`) 
     *         address will be credited before the transfer.  Integrating spender/operator protocols MUST be aware that 
     *         deposits made during transfers will not credit their own account.**
     *
     * @dev    Throws when the `from` account is the zero address.
     * @dev    Throws when the `msg.sender` does not match the operator/spender from the signed transfer permit.
     * @dev    Throws when the permitAmount does not match the signed transfer permit. 
     * @dev    Throws when the nonce does not match the signed transfer permit.
     * @dev    Throws when the expiration does not match the signed transfer permit.
     * @dev    Throws when the permit has expired.
     * @dev    Throws when the requested transfer amount exceeds the maximum permitted transfer amount. 
     * @dev    Throws when the permit nonce has already been used or revoked/cancelled.
     * @dev    Throws when the master nonce has been revoked/cancelled since the permit was signed.
     * @dev    Throws when the permit signature is invalid, or was not signed by the `from` account.
     * @dev    Throws when the `from` account has an insufficient balance to transfer `transferAmount` of wrapped native tokens.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. When `msg.value` is greater than zero, this contract's native token balance has increased by `msg.value`.
     * @dev    2. When `msg.value` is greater than zero, the `msg.sender`'s native token balance has decreased by `msg.value`.
     * @dev    3. When `msg.value` is greater than zero, the `from` account's wrapped native token balance has increased by `msg.value`.
     * @dev    4. When `msg.value` is greater than zero, a `Deposit` event has been emitted.  The `from` address is logged in the event.
     * @dev    5. `nonce` for `from` account is invalidated.
     * @dev    6. A `PermitNonceInvalidated` event has been emitted.
     * @dev    7. The `transferAmount` of wrapped native tokens has been transferred from the `from` account to the `to` account.
     * @dev    8. A `Transfer` event has been emitted.  The `from` address, `to` address, and `transferAmount` are logged in the event.
     *
     * @param from  The address that transfers the wrapped native tokens.
     * @param to    The address that receives the wrapped native tokens.
     * @param transferAmount  The amount of wrapped native tokens to transfer.
     * @param permitAmount  The maximum amount of wrapped native tokens that can be transferred, signed in permit.
     * @param nonce  The nonce, signed in permit.
     * @param expiration  The expiration timestamp, signed in permit.
     * @param signedPermit  The signature of the permit.
     */
    function permitTransfer(
        address from,
        address to,
        uint256 transferAmount,
        uint256 permitAmount,
        uint256 nonce,
        uint256 expiration,
        bytes calldata signedPermit
    ) external payable {
        if (msg.value > 0) {
            depositTo(from);
        }

        if (block.timestamp > expiration ||
            transferAmount > permitAmount ||
            from == address(0)) {
            revert();
        }

        _checkAndInvalidateNonce(from, nonce);
        
        _verifyPermitSignature(
            from,
            _hashTypedDataV4(
                keccak256(
                    abi.encode(
                        PERMIT_TRANSFER_TYPEHASH,
                        msg.sender,
                        permitAmount,
                        nonce,
                        expiration,
                        _masterNonces[from]
                    )
                )
            ), 
            signedPermit
        );

        _balanceTransfer(from, to, transferAmount);
    }

    /**
     * @notice Allows a spender/operator to withdraw wrapped native tokens from the `from` account to the `to` account
     *         using a gasless signature signed by the `from` account to prove authorization of the withdrawal.
     *
     * @dev    Throws when the `from` account is the zero address.
     * @dev    Throws when the `msg.sender` does not match the operator/spender from the signed withdrawal permit.
     * @dev    Throws when the permit has expired.
     * @dev    Throws when the amount does not match the signed withdrawal permit. 
     * @dev    Throws when the nonce does not match the signed withdrawal permit.
     * @dev    Throws when the expiration does not match the signed withdrawal permit.
     * @dev    Throws when the convenience fee reciever and fee does not match the signed withdrawal permit.
     * @dev    Throws when the `to` address does not match the signed withdrawal permit.
     * @dev    Throws when the permit nonce has already been used or revoked/cancelled.
     * @dev    Throws when the master nonce has been revoked/cancelled since the permit was signed.
     * @dev    Throws when the permit signature is invalid, or was not signed by the `from` account.
     * @dev    Throws when the `from` account has an insufficient balance to transfer `transferAmount` of wrapped native tokens.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. This contract's native token balance has decreased by `amount`, less convenience and infrastructure
     *            fees that remain wrapped.
     * @dev    2. The `from` account's wrapped native token balance has decreased by `amount`.
     * @dev    3. The `to` account's native token balance has increased by `amount`, less convenience and/or infrastructure fees.
     * @dev    4. The `convenienceFeeReceiver` account's wrapped native token balance has increased by the convenience fee.
     * @dev    5. The infrastructure tax account's wrapped native token balance has increased by the infrastructure fee.
     * @dev    6. `nonce` for `from` account is invalidated.
     * @dev    7. A `PermitNonceInvalidated` event has been emitted.
     * @dev    8. A `Withdrawal` event has been emitted.  Caveat: The `from` address is logged in the event, not `to` or `msg.sender`.
     *
     * @param from  The address that from which funds are withdrawn.
     * @param to  The address that receives the withdrawn funds.
     * @param amount  The amount of wrapped native tokens to withdraw.
     * @param nonce  The nonce, signed in permit.
     * @param expiration  The expiration timestamp, signed in permit.
     * @param convenienceFeeReceiver  The address that receives the convenience fee.
     * @param convenienceFeeBps  The basis points of the convenience fee.
     * @param signedPermit  The signature of the permit.
     */
    function doPermittedWithdraw(
        address from,
        address to,
        uint256 amount,
        uint256 nonce,
        uint256 expiration,
        address convenienceFeeReceiver,
        uint256 convenienceFeeBps,
        bytes calldata signedPermit
    ) external {
        if (block.timestamp > expiration ||
            from == address(0)) {
            revert();
        }

        _checkAndInvalidateNonce(from, nonce);

        _verifyPermitSignature(
            from,
            _hashTypedDataV4(
                keccak256(
                    abi.encode(
                        PERMIT_WITHDRAWAL_TYPEHASH,
                        msg.sender,
                        amount,
                        nonce,
                        expiration,
                        _masterNonces[from],
                        to,
                        convenienceFeeReceiver,
                        convenienceFeeBps
                    )
                )
            ), 
            signedPermit
        );

        (
            uint256 userAmount, 
            uint256 convenienceFee, 
            uint256 infrastructureFee
        ) = _computeWithdrawalSplits(amount, convenienceFeeReceiver, convenienceFeeBps);

        if (convenienceFee > 0) {
            _balanceTransfer(from, convenienceFeeReceiver, convenienceFee);
        }

        if (infrastructureFee > 0) {
            _balanceTransfer(from, ADDRESS_INFRASTRUCTURE_TAX, infrastructureFee);
        }

        _withdrawFromAccount(from, to, userAmount);
    }

    //=================================================
    //========= Miscellaneous Helper Functions ========
    //=================================================

    /**
     * @dev Helper function that transfers wrapped native token balance between accounts.
     *
     * @dev Throws when the `from` account has an insufficient balance to transfer `amount` of wrapped native tokens.
     *
     * @param from  The address from which the wrapped native tokens is transferred.
     * @param to  The address to which the wrapped native tokens are transferred.
     * @param amount  The amount of wrapped native tokens to transfer.
     */
    function _balanceTransfer(address from, address to, uint256 amount) private {
        assembly {
            mstore(0x00, from)
            mstore(0x20, balanceOf.slot)
            let balanceSlotFrom := keccak256(0x00, 0x40)
            let balanceValFrom := sload(balanceSlotFrom)
            if lt(balanceValFrom, amount) {
                revert(0,0)
            }
            sstore(balanceSlotFrom, sub(balanceValFrom, amount))

            mstore(0x00, to)
            let balanceSlotTo := keccak256(0x00, 0x40)
            sstore(balanceSlotTo, add(sload(balanceSlotTo), amount))

            mstore(0x00, amount)
            log3(0x00, 0x20, TRANSFER_EVENT_TOPIC_0, from, to)
        }
    }

    /**
     * @dev Helper function that withdraws wrapped native tokens from an account to another account.
     *
     * @dev Throws when the `from` account has an insufficient balance to transfer `amount` of wrapped native tokens.
     * @dev Throws when the unwrapped native funds cannot be transferred to the `to` account.
     *
     * @param from  The address from which the wrapped native tokens are withdrawn.
     * @param to  The address to which the native tokens are transferred.
     * @param amount  The amount of wrapped native tokens to withdraw.
     */
    function _withdrawFromAccount(address from, address to, uint256 amount) private {
        assembly {
            mstore(0x00, from)
            mstore(0x20, balanceOf.slot)
            let balanceSlot := keccak256(0x00, 0x40)

            let balanceVal := sload(balanceSlot)
            let updatedBalance := sub(balanceVal, amount)
            sstore(balanceSlot, updatedBalance)

            mstore(0x00, amount)
            log2(0x00, 0x20, WITHDRAWAL_EVENT_TOPIC_0, from)

            if or(gt(updatedBalance, balanceVal), iszero(call(gas(), to, amount, 0, 0, 0, 0))) {
                revert(0,0)
            }
        }
    }

    /**
     * @dev Helper function that checks and invalidates a permit nonce.
     * 
     * @dev Throws when the permit nonce has already been used or revoked/cancelled.
     * 
     * @param account  The account that signed the permit.
     * @param nonce  The nonce that was signed in the permit.
     */
    function _checkAndInvalidateNonce(address account, uint256 nonce) private {
        unchecked {
            if (uint256(_permitNonces[account][uint248(nonce >> 8)] ^= (ONE << uint8(nonce))) & 
                (ONE << uint8(nonce)) == ZERO) {
                revert();
            }
        }

        assembly {
            log3(0x00, 0x00, PERMIT_NONCE_INVALIDATED_EVENT_TOPIC_0, account, nonce)
        }
    }

    //=================================================
    //============= Fee Split Calculations ============
    //=================================================

    /**
     * @dev Helper function that computes the withdrawal fee split amounts.
     *
     * @param amount  The amount of wrapped native tokens to split.
     * @param convenienceFeeReceiver  The address that receives the convenience fee.
     * @param convenienceFeeBps  The basis points of the convenience fee.
     */
    function _computeWithdrawalSplits(
        uint256 amount,
        address convenienceFeeReceiver,
        uint256 convenienceFeeBps
    ) private pure returns (uint256 userAmount, uint256 convenienceFee, uint256 convenienceFeeInfrastructure) {
        if (convenienceFeeBps > FEE_DENOMINATOR) {
            revert();
        }

        if (amount > type(uint240).max) {
            revert();
        }

        if (convenienceFeeReceiver == address(0)) {
            convenienceFeeBps = 0;
        }

        unchecked {
            if (convenienceFeeBps > INFRASTRUCTURE_TAX_THRESHOLD) {
                convenienceFee = amount * convenienceFeeBps / FEE_DENOMINATOR;
                convenienceFeeInfrastructure = convenienceFee * INFRASTRUCTURE_TAX_BPS / FEE_DENOMINATOR;
                convenienceFee -= convenienceFeeInfrastructure;
                userAmount = amount - convenienceFee - convenienceFeeInfrastructure;
            } else if (convenienceFeeBps > 0) {
                convenienceFeeInfrastructure = amount / FEE_DENOMINATOR;
                convenienceFee = amount * (convenienceFeeBps - ONE) / FEE_DENOMINATOR;
                userAmount = amount - convenienceFee - convenienceFeeInfrastructure;
            } else {
                convenienceFeeInfrastructure = amount / FEE_DENOMINATOR;
                userAmount = amount - convenienceFeeInfrastructure;
            }
        }
    }

    //=================================================
    //============ Signature Verification =============
    //=================================================

    /**
     * @notice  Verifies a permit signature based on the bytes length of the signature provided.
     * 
     * @dev     Throws when -
     * @dev         The bytes signature length is 64 or 65 bytes AND
     * @dev         The ECDSA recovered signer is not the expectedSigner AND
     * @dev         The expectedSigner's code length is zero OR the expectedSigner does not return a valid EIP-1271 response
     * @dev 
     * @dev         OR
     * @dev
     * @dev         The bytes signature length is not 64 or 65 bytes AND
     * @dev         The expectedSigner's code length is zero OR the expectedSigner does not return a valid EIP-1271 response
     */
    function _verifyPermitSignature(
        address expectedSigner, 
        bytes32 digest, 
        bytes calldata signature
    ) private view {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // Divide the signature in r, s and v variables
            /// @solidity memory-safe-assembly
            assembly {
                r := calldataload(signature.offset)
                s := calldataload(add(signature.offset, 32))
                v := byte(0, calldataload(add(signature.offset, 64)))
            }
            (bool isError, address signer) = _ecdsaRecover(digest, v, r, s);
            if (expectedSigner != signer || isError) {
                _verifyEIP1271Signature(expectedSigner, digest, signature);
            }
        } else if (signature.length == 64) {
            bytes32 r;
            bytes32 vs;
            // Divide the signature in r and vs variables
            /// @solidity memory-safe-assembly
            assembly {
                r := calldataload(signature.offset)
                vs := calldataload(add(signature.offset, 32))
            }
            (bool isError, address signer) = _ecdsaRecover(digest, r, vs);
            if (expectedSigner != signer || isError) {
                _verifyEIP1271Signature(expectedSigner, digest, signature);
            }
        } else {
            _verifyEIP1271Signature(expectedSigner, digest, signature);
        }
    }

    /**
     * @notice Verifies an EIP-1271 signature.
     * 
     * @dev    Throws when `signer` code length is zero OR the EIP-1271 call does not
     * @dev    return the correct magic value.
     * 
     * @param signer     The signer address to verify a signature with
     * @param hash       The hash digest to verify with the signer
     * @param signature  The signature to verify
     */
    function _verifyEIP1271Signature(address signer, bytes32 hash, bytes calldata signature) private view {
        if(signer.code.length == 0) {
            revert();
        }

        if (!_safeIsValidSignature(signer, hash, signature)) {
            revert();
        }
    }

    /**
     * @notice  Overload of the `_ecdsaRecover` function to unpack the `v` and `s` values
     * 
     * @param digest    The hash digest that was signed
     * @param r         The `r` value of the signature
     * @param vs        The packed `v` and `s` values of the signature
     * 
     * @return isError  True if the ECDSA function is provided invalid inputs
     * @return signer   The recovered address from ECDSA
     */
    function _ecdsaRecover(bytes32 digest, bytes32 r, bytes32 vs) private pure returns (bool isError, address signer) {
        unchecked {
            bytes32 s = vs & UPPER_BIT_MASK;
            uint8 v = uint8(uint256(vs >> 255)) + 27;

            (isError, signer) = _ecdsaRecover(digest, v, r, s);
        }
    }

    /**
     * @notice  Recovers the signer address using ECDSA
     * 
     * @dev     Does **NOT** revert if invalid input values are provided or `signer` is recovered as address(0)
     * @dev     Returns an `isError` value in those conditions that is handled upstream
     * 
     * @param digest    The hash digest that was signed
     * @param v         The `v` value of the signature
     * @param r         The `r` value of the signature
     * @param s         The `s` value of the signature
     * 
     * @return isError  True if the ECDSA function is provided invalid inputs
     * @return signer   The recovered address from ECDSA
     */
    function _ecdsaRecover(bytes32 digest, uint8 v, bytes32 r, bytes32 s) private pure returns (bool isError, address signer) {
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            // Invalid signature `s` value - return isError = true and signer = address(0) to check EIP-1271
            return (true, address(0));
        }

        signer = ecrecover(digest, v, r, s);
        isError = (signer == address(0));
    }

    /**
     * @notice A gas efficient, and fallback-safe way to call the isValidSignature function for EIP-1271.
     *
     * @param signer     The EIP-1271 signer to call to check for a valid signature.
     * @param hash       The hash digest to verify with the EIP-1271 signer.
     * @param signature  The supplied signature to verify.
     * 
     * @return isValid   True if the EIP-1271 signer returns the EIP-1271 magic value.
     */
    function _safeIsValidSignature(
        address signer,
        bytes32 hash,
        bytes calldata signature
    ) private view returns(bool isValid) {
        assembly {
            function _callIsValidSignature(_signer, _hash, _signatureOffset, _signatureLength) -> _isValid {
                let ptr := mload(0x40)
                // store isValidSignature(bytes32,bytes) selector
                mstore(ptr, hex"1626ba7e")
                // store bytes32 hash value in abi encoded location
                mstore(add(ptr, 0x04), _hash)
                // store abi encoded location of the bytes signature data
                mstore(add(ptr, 0x24), 0x40)
                // store bytes signature length
                mstore(add(ptr, 0x44), _signatureLength)
                // copy calldata bytes signature to memory
                calldatacopy(add(ptr, 0x64), _signatureOffset, _signatureLength)
                // calculate data length based on abi encoded data with rounded up signature length
                let dataLength := add(0x64, and(add(_signatureLength, 0x1F), not(0x1F)))
                // update free memory pointer
                mstore(0x40, add(ptr, dataLength))

                // static call _signer with abi encoded data
                // skip return data check if call failed or return data size is not at least 32 bytes
                if and(iszero(lt(returndatasize(), 0x20)), staticcall(gas(), _signer, ptr, dataLength, 0x00, 0x20)) {
                    // check if return data is equal to isValidSignature magic value
                    _isValid := eq(mload(0x00), hex"1626ba7e")
                    leave
                }
            }
            isValid := _callIsValidSignature(signer, hash, signature.offset, signature.length)
        }
    }
}

File 2 of 9 : Constants.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "./interfaces/IWrappedNative.sol";
import "./interfaces/IWrappedNativeExtended.sol";

string constant VERSION = "1";
string constant NAME = "Wrapped Native";
string constant SYMBOL = "WNATIVE";
uint8 constant DECIMALS = 18;

bytes32 constant UPPER_BIT_MASK = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
uint256 constant ZERO = 0;
uint256 constant ONE = 1;
uint256 constant INFRASTRUCTURE_TAX_THRESHOLD = 9; // When convenienceFeeBps is greater than 9, we apply infrastructure tax to convenience fee.
uint256 constant INFRASTRUCTURE_TAX_BPS = 10_00;
uint256 constant FEE_DENOMINATOR = 100_00;

uint256 constant WITHDRAWAL_EVENT_TOPIC_0 = 0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65;
uint256 constant DEPOSIT_EVENT_TOPIC_0 = 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c;
uint256 constant APPROVAL_EVENT_TOPIC_0 = 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;
uint256 constant TRANSFER_EVENT_TOPIC_0 = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
uint256 constant PERMIT_NONCE_INVALIDATED_EVENT_TOPIC_0 = 0x8dc5a0b2e80f26187d38744e9559150e3bd6e06fccefbe737fd33411cfb15151;
uint256 constant MASTER_NONCE_INVALIDATED_EVENT_TOPIC_0 = 0x9614574d6542397172c19ba2bf4588434feeb977576e92b7b59b38242ab59609;

bytes32 constant PERMIT_TRANSFER_TYPEHASH =
    keccak256("PermitTransfer(address operator,uint256 amount,uint256 nonce,uint256 expiration,uint256 masterNonce)");

bytes32 constant PERMIT_WITHDRAWAL_TYPEHASH =
    keccak256("PermitWithdrawal(address operator,uint256 amount,uint256 nonce,uint256 expiration,uint256 masterNonce,address to,address convenienceFeeReceiver,uint256 convenienceFeeBps)");

bytes4 constant SELECTOR_IS_NONCE_USED = IWrappedNativeExtended.isNonceUsed.selector;
bytes4 constant SELECTOR_MASTER_NONCES = IWrappedNativeExtended.masterNonces.selector;
bytes4 constant SELECTOR_TOTAL_SUPPLY = IWrappedNative.totalSupply.selector;
bytes4 constant SELECTOR_DOMAIN_SEPARATOR_V4 = IWrappedNativeExtended.domainSeparatorV4.selector;
bytes4 constant SELECTOR_NAME = IWrappedNative.name.selector;
bytes4 constant SELECTOR_SYMBOL = IWrappedNative.symbol.selector;
bytes4 constant SELECTOR_DECIMALS = IWrappedNative.decimals.selector;

File 3 of 9 : IWrappedNative.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

interface IWrappedNative {
    // ERC20 Specific
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);

    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, uint256 value) external payable returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 value) external payable returns (bool);
    function transferFrom(address from, address to, uint256 value) external payable returns (bool);

    // ERC20 Metadata Specific
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);

    // Wrapped Native Specific
    event Deposit(address indexed to, uint256 amount);
    event Withdrawal(address indexed from, uint256 amount);

    function deposit() external payable;
    function withdraw(uint256 amount) external;
}

File 4 of 9 : IWrappedNativeExtended.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "./IWrappedNative.sol";

interface IWrappedNativeExtended is IWrappedNative {
    // Wrapped Native Permit Specific
    event PermitNonceInvalidated(address indexed account,uint256 indexed nonce);
    event MasterNonceInvalidated(address indexed account, uint256 indexed nonce);

    // Enhancements for Deposits and Withdrawals
    function depositTo(address to) external payable;
    function withdrawToAccount(address to, uint256 amount) external;
    function withdrawSplit(address[] calldata toAddresses, uint256[] calldata amounts) external;

    // Permit Processing
    function domainSeparatorV4() external view returns (bytes32);

    function isNonceUsed(address account, uint256 nonce) external view returns (bool);
    function masterNonces(address account) external view returns (uint256);

    function revokeMyOutstandingPermits() external;
    function revokeMyNonce(uint256 nonce) external;

    function permitTransfer(
        address from,
        address to,
        uint256 transferAmount,
        uint256 permitAmount,
        uint256 nonce,
        uint256 expiration,
        bytes calldata signedPermit
    ) external payable;

    function doPermittedWithdraw(
        address from,
        address to,
        uint256 amount,
        uint256 nonce,
        uint256 expiration,
        address convenienceFeeReceiver,
        uint256 convenienceFeeBps,
        bytes calldata signedPermit
    ) external;
}

File 5 of 9 : EIP712.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol)

pragma solidity ^0.8.20;

import "./MessageHashUtils.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
 * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
 * they need in their contracts using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
 * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the
 * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
 *
 * _Available since v3.4._
 *
 * @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
 */
abstract contract EIP712 {
    bytes32 private constant _TYPE_HASH =
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
    // invalidate the cached domain separator if the chain id changes.
    bytes32 private immutable _cachedDomainSeparator;
    uint256 private immutable _cachedChainId;

    bytes32 private immutable _hashedName;
    bytes32 private immutable _hashedVersion;

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    constructor(string memory name, string memory version) {
        _hashedName = keccak256(bytes(name));
        _hashedVersion = keccak256(bytes(version));

        _cachedChainId = block.chainid;
        _cachedDomainSeparator = _buildDomainSeparator();
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        if (block.chainid == _cachedChainId) {
            return _cachedDomainSeparator;
        } else {
            return _buildDomainSeparator();
        }
    }

    function _buildDomainSeparator() private view returns (bytes32) {
        return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
    }
}

File 6 of 9 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

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

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

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

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

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

File 7 of 9 : MessageHashUtils.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)

pragma solidity ^0.8.20;

import {Strings} from "./Strings.sol";

/**
 * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
 *
 * The library provides methods for generating a hash of a message that conforms to the
 * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
 * specifications.
 */
library MessageHashUtils {
    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing a bytes32 `messageHash` with
     * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
     * keccak256, although any bytes32 value can be safely used because the final digest will
     * be re-hashed.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
            mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
            digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
        }
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing an arbitrary `message` with
     * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
        return
            keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x00` (data with intended validator).
     *
     * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
     * `validator` address. Then hashing the result.
     *
     * See {ECDSA-recover}.
     */
    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(hex"19_00", validator, data));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
     *
     * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
     * `\x19\x01` and hashing the result. It corresponds to the hash signed by the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
     *
     * See {ECDSA-recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, hex"19_01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            digest := keccak256(ptr, 0x42)
        }
    }
}

File 8 of 9 : SignedMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

File 9 of 9 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

pragma solidity ^0.8.20;

import {Math} from "./Math.sol";
import {SignedMath} from "./SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        uint256 localValue = value;
        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_DIGITS[localValue & 0xf];
            localValue >>= 4;
        }
        if (localValue != 0) {
            revert StringsInsufficientHexLength(value, length);
        }
        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);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "@limitbreak/creator-token-transfer-validator/=lib/creator-token-transfer-validator/",
    "@limitbreak/tm-cloner/=lib/tm-cloner/",
    "@limitbreak/tm-core-lib/=lib/tm-core-lib/",
    "@limitbreak/tm-extension-registry/=lib/tm-extension-registry/",
    "@limitbreak/tm-role-server/=lib/tm-role-server/",
    "@limitbreak/tm-template-factory/=lib/tm-template-factory/",
    "@limitbreak/tm-web2-gateway/=lib/tm-web2-gateway/",
    "@limitbreak/wrapped-native/=lib/wrapped-native/",
    "@limitbreak/permit-c/=lib/payment-processor-v2/lib/PermitC/src/",
    "@limitbreak/trusted-forwarder/=lib/payment-processor-v2/lib/TrustedForwarder/src/",
    "@opensea/tstorish/=lib/creator-token-standards/lib/tstorish/src/",
    "@openzeppelin/=lib/payment-processor-v2/lib/openzeppelin-contracts/",
    "@rari-capital/solmate/=lib/payment-processor-v2/lib/solmate/",
    "ERC721A/=lib/creator-token-standards/lib/ERC721A/contracts/",
    "PermitC/=lib/payment-processor-v2/lib/PermitC/",
    "TrustedForwarder/=lib/TrustedForwarder/",
    "creator-token-standards/=lib/creator-token-standards/",
    "creator-token-transfer-validator/=lib/creator-token-transfer-validator/src/",
    "erc4626-tests/=lib/payment-processor-v2/lib/openzeppelin-contracts/lib/erc4626-tests/",
    "erc721a/=lib/creator-token-standards/lib/ERC721A/",
    "fake-contracts/=lib/fake-contracts/src/",
    "forge-gas-metering/=lib/payment-processor-v2/lib/PermitC/lib/forge-gas-metering/",
    "multisig/=lib/multisig/",
    "murky/=lib/payment-processor-v2/lib/murky/",
    "openzeppelin-contracts/=lib/payment-processor-v2/lib/openzeppelin-contracts/",
    "openzeppelin/=lib/payment-processor-v2/lib/openzeppelin-contracts/contracts/",
    "payment-processor-v2/=lib/payment-processor-v2/",
    "solady/=lib/payment-processor-v2/lib/PermitC/lib/forge-gas-metering/lib/solady/",
    "solmate/=lib/payment-processor-v2/lib/solmate/src/",
    "tm-cloner/=lib/tm-cloner/src/",
    "tm-core-lib/=lib/tm-core-lib/src/",
    "tm-extension-registry/=lib/tm-extension-registry/src/",
    "tm-role-server/=lib/tm-role-server/src/",
    "tm-template-factory/=lib/tm-template-factory/src/",
    "tm-web2-gateway/=lib/tm-web2-gateway/src/",
    "tstorish/=lib/creator-token-standards/lib/tstorish/src/",
    "wrapped-native/=lib/wrapped-native/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"infrastructureTaxRecipient","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"depositTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"address","name":"convenienceFeeReceiver","type":"address"},{"internalType":"uint256","name":"convenienceFeeBps","type":"uint256"},{"internalType":"bytes","name":"signedPermit","type":"bytes"}],"name":"doPermittedWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"transferAmount","type":"uint256"},{"internalType":"uint256","name":"permitAmount","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"bytes","name":"signedPermit","type":"bytes"}],"name":"permitTransfer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"revokeMyNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revokeMyOutstandingPermits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"toAddresses","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"withdrawSplit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawToAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

6101203461015e57601f61160238819003918201601f19168301926001600160401b039290918385118386101761014a57816020928492604097885283398101031261015e5751916001600160a01b038316830361015e5780519061006382610162565b600e825260208201916d57726170706564204e617469766560901b835281519261008c84610162565b600184526020840191603160f81b8352519020928360c052519020908160e0524660a05280519160208301937f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f85528284015260608301524660808301523060a083015260a0825260c08201938285109085111761014a57839052519020608052610100918252611484918261017e833960805182611218015260a051826111f2015260c05182611267015260e0518261128d015251816108bd0152f35b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b604081019081106001600160401b0382111761014a5760405256fe60806040526004361015610026575b361561001e5761001c610cd9565b005b61001c610ad9565b5f3560e01c8063095ea7b31461010557806323b872dd146101005780632e1a7d4d146100fb57806370a08231146100f6578063a9059cbb146100f1578063b760faf9146100ec578063c2b1a472146100e7578063d0e30db0146100e2578063d4229c24146100dd578063dd62ed3e146100d8578063e06cbc62146100d3578063e5fe69fe146100ce578063f38e809d146100c95763facb18e30361000e576109ec565b610952565b610917565b610730565b6106af565b610503565b6104a3565b61045b565b61041d565b610378565b610311565b6102d5565b6101c2565b61012c565b73ffffffffffffffffffffffffffffffffffffffff81160361012857565b5f80fd5b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610128576004356101628161010a565b602435346101b4575b335f52600360205260405f20602052815f528060405f20555f52337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560205fa360015f5260205ff35b6101bd33610a9d565b61016b565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610128576004356101f88161010a565b602435906102058261010a565b604435346102c7575b815f52600260205260405f208054828110610128578290039055825f5260405f2081815401905533820361026d575b5f527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60205fa360015f5260205ff35b815f52600360205260405f20602052335f5260405f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81036102b4575b505061023d565b8281106101285782900390555f806102ad565b6102d082610a9d565b61020e565b346101285760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101285761001c6004353333610f30565b346101285760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101285773ffffffffffffffffffffffffffffffffffffffff6004356103618161010a565b165f526002602052602060405f2054604051908152f35b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610128576004356103ae8161010a565b6024353461040f575b335f52600260205260405f208054828110610128578290039055815f5260405f208181540190555f52337fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60205fa360015f5260205ff35b61041833610a9d565b6103b7565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101285761001c6004356104568161010a565b610a9d565b346101285760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101285761001c6004356104998161010a565b6024359033610f30565b5f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101285761001c33610a9d565b9181601f840112156101285782359167ffffffffffffffff8311610128576020838186019501011161012857565b60e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610128576004356105398161010a565b6024356105458161010a565b604435906064359260843560a4359060c43567ffffffffffffffff8111610128576105749036906004016104d5565b91346106a1575b8342118015610698575b801561067a575b6101285761001c9761067594610667836105a961066f958a610f81565b73ffffffffffffffffffffffffffffffffffffffff89165f525f60205261063b60405f205460405194859360208501973389919260a093969594919673ffffffffffffffffffffffffffffffffffffffff60c08501987f3c038916d033a3e04838da5aca7b9a42656eeae3b520daf7ed52ec02fd37fb9486521660208501526040840152606083015260808201520152565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610b2d565b519020611011565b84611052565b6110df565b5073ffffffffffffffffffffffffffffffffffffffff85161561058c565b50878711610585565b6106aa85610a9d565b61057b565b346101285760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610128576004356106ea8161010a565b602435906106f78261010a565b73ffffffffffffffffffffffffffffffffffffffff8091165f52600360205260405f2091165f52602052602060405f2054604051908152f35b34610128576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101285760043561076c8161010a565b602435906107798261010a565b6044359160a435916064356084356107908561010a565b60c4359060e43567ffffffffffffffff8111610128576107b49036906004016104d5565b97909382421180156108f9575b6101285761001c986108a095610895848b966106678661063b8b8f8f9073ffffffffffffffffffffffffffffffffffffffff828f9361089b9e61080391610f81565b165f525f60205260405f2054604051978896602088019a338c9461010096919294999897939961012087019a7fe55aaa79350b0eb9ee70c987c9b0603c46531ab71d2b7c5404835db2f60e220c885273ffffffffffffffffffffffffffffffffffffffff968780961660208a015260408901526060880152608087015260a08601521660c08401521660e08201520152565b88611052565b611131565b919490806108e8575b5050806108b7575b50610f30565b6108e2907f0000000000000000000000000000000000000000000000000000000000000000836110df565b5f6108b1565b6108f291846110df565b5f806108a9565b5073ffffffffffffffffffffffffffffffffffffffff8616156107c1565b346101285760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101285761001c60043533610f81565b34610128575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261012857335f525f60205260405f20805490816001019055337f9614574d6542397172c19ba2bf4588434feeb977576e92b7b59b38242ab596095f80a3005b9181601f840112156101285782359167ffffffffffffffff8311610128576020808501948460051b01011161012857565b346101285760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101285767ffffffffffffffff60043581811161012857610a3c9036906004016109bb565b909160243590811161012857610a569036906004016109bb565b90818303610128575f5b838110610a6957005b80610a97610a7a6001938789610b6e565b35610a848161010a565b610a8f838787610b6e565b359033610f30565b01610a60565b805f52600260205260405f20348154019055345f527fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c60205fa2565b610ae233610a9d565b565b6040810190811067ffffffffffffffff821117610b0057604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610b0057604052565b9190811015610b7e5760051b0190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b60405190610bb882610ae4565b600782527f574e4154495645000000000000000000000000000000000000000000000000006020830152565b6020808252825181830181905293925f5b858110610c34575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6040809697860101520116010190565b818101830151848201604001528201610bf5565b60405190610c5582610ae4565b600e82527f57726170706564204e61746976650000000000000000000000000000000000006020830152565b91909182600411610128578211610128577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6004920190565b91908260409103126101285760208235610cd38161010a565b92013590565b3415610ce757610ae2610ad9565b5f357fffffffff00000000000000000000000000000000000000000000000000000000167fcab7e8eb000000000000000000000000000000000000000000000000000000008103610dcb5760018073ffffffffffffffffffffffffffffffffffffffff60ff610dbe610d8d610d67610d5f3636610c81565b810190610cba565b941673ffffffffffffffffffffffffffffffffffffffff165f52600160205260405f2090565b8360081c7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b5491161c16145f5260205ff35b7f45253c53000000000000000000000000000000000000000000000000000000008103610e2557602436106101285773ffffffffffffffffffffffffffffffffffffffff600435165f525f60205260405f20545f5260205ff35b7f18160ddd000000000000000000000000000000000000000000000000000000008103610e5457475f5260205ff35b7f78e890ba000000000000000000000000000000000000000000000000000000008103610e8a57610e836111ef565b5f5260205ff35b7f06fdde03000000000000000000000000000000000000000000000000000000008103610ed257610eb9610c48565b604051610ece8161063b602082019485610be4565b5190f35b7f95d89b41000000000000000000000000000000000000000000000000000000008103610f0157610eb9610bab565b7f313ce56700000000000000000000000000000000000000000000000000000000036101285760125f5260205ff35b90915f80808093858252600260205260408220968754968288038099558284527f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65602085a25af11591111761012857565b600160ff83161b73ffffffffffffffffffffffffffffffffffffffff82165f526001602052610fde60405f208460081c7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b818154188091551615610128577f8dc5a0b2e80f26187d38744e9559150e3bd6e06fccefbe737fd33411cfb151515f80a3565b60429061101c6111ef565b90604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b929190604183036110be576110746020830135833560408501355f1a84611337565b73ffffffffffffffffffffffffffffffffffffffff868116911614801591906110b6575b506110a4575b50505050565b6110ad936112e1565b5f80808061109e565b90505f611098565b604083036110d65761107460208301358335836112fb565b610ae2936112e1565b9091815f52600260205260405f208054828110610128578290039055825f5260405f208181540190555f527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60205fa3565b915f61271092838311610128577dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85116101285773ffffffffffffffffffffffffffffffffffffffff16156111e7575b60098211156111a057508190830204906103e8820204808092038093030392565b929181156111dd57829350807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9304928392018402048093030392565b9050810480910392565b5f915061117f565b467f00000000000000000000000000000000000000000000000000000000000000000361123a577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f000000000000000000000000000000000000000000000000000000000000000060408201527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260a0815260c0810181811067ffffffffffffffff821117610b005760405251902090565b929190833b15610128576112f4936113bc565b1561012857565b90611333929160ff601b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff851694821c011690611337565b9091565b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084116113b1576020935f9360ff60809460405194855216868401526040830152606082015282805260015afa156113a6575f5173ffffffffffffffffffffffffffffffffffffffff81161591565b6040513d5f823e3d90fd5b505050506001905f90565b5f90602092937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f5f989780604051947f1626ba7e00000000000000000000000000000000000000000000000000000000998a875260048701526040602487015281604487015260648601370116606481830101604052606401915afa60203d1015166114475750565b5f5114915056fea26469706673582212202bc2e977d4326194251bed68a13b88aa97f9f60de0fe047b4a249863c5cc5c6664736f6c634300081800330000000000000000000000004e3c052b97f27156f785c578b99346947e1bb4b3

Deployed Bytecode

0x60806040526004361015610026575b361561001e5761001c610cd9565b005b61001c610ad9565b5f3560e01c8063095ea7b31461010557806323b872dd146101005780632e1a7d4d146100fb57806370a08231146100f6578063a9059cbb146100f1578063b760faf9146100ec578063c2b1a472146100e7578063d0e30db0146100e2578063d4229c24146100dd578063dd62ed3e146100d8578063e06cbc62146100d3578063e5fe69fe146100ce578063f38e809d146100c95763facb18e30361000e576109ec565b610952565b610917565b610730565b6106af565b610503565b6104a3565b61045b565b61041d565b610378565b610311565b6102d5565b6101c2565b61012c565b73ffffffffffffffffffffffffffffffffffffffff81160361012857565b5f80fd5b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610128576004356101628161010a565b602435346101b4575b335f52600360205260405f20602052815f528060405f20555f52337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560205fa360015f5260205ff35b6101bd33610a9d565b61016b565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610128576004356101f88161010a565b602435906102058261010a565b604435346102c7575b815f52600260205260405f208054828110610128578290039055825f5260405f2081815401905533820361026d575b5f527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60205fa360015f5260205ff35b815f52600360205260405f20602052335f5260405f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81036102b4575b505061023d565b8281106101285782900390555f806102ad565b6102d082610a9d565b61020e565b346101285760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101285761001c6004353333610f30565b346101285760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101285773ffffffffffffffffffffffffffffffffffffffff6004356103618161010a565b165f526002602052602060405f2054604051908152f35b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610128576004356103ae8161010a565b6024353461040f575b335f52600260205260405f208054828110610128578290039055815f5260405f208181540190555f52337fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60205fa360015f5260205ff35b61041833610a9d565b6103b7565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101285761001c6004356104568161010a565b610a9d565b346101285760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101285761001c6004356104998161010a565b6024359033610f30565b5f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101285761001c33610a9d565b9181601f840112156101285782359167ffffffffffffffff8311610128576020838186019501011161012857565b60e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610128576004356105398161010a565b6024356105458161010a565b604435906064359260843560a4359060c43567ffffffffffffffff8111610128576105749036906004016104d5565b91346106a1575b8342118015610698575b801561067a575b6101285761001c9761067594610667836105a961066f958a610f81565b73ffffffffffffffffffffffffffffffffffffffff89165f525f60205261063b60405f205460405194859360208501973389919260a093969594919673ffffffffffffffffffffffffffffffffffffffff60c08501987f3c038916d033a3e04838da5aca7b9a42656eeae3b520daf7ed52ec02fd37fb9486521660208501526040840152606083015260808201520152565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610b2d565b519020611011565b84611052565b6110df565b5073ffffffffffffffffffffffffffffffffffffffff85161561058c565b50878711610585565b6106aa85610a9d565b61057b565b346101285760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610128576004356106ea8161010a565b602435906106f78261010a565b73ffffffffffffffffffffffffffffffffffffffff8091165f52600360205260405f2091165f52602052602060405f2054604051908152f35b34610128576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101285760043561076c8161010a565b602435906107798261010a565b6044359160a435916064356084356107908561010a565b60c4359060e43567ffffffffffffffff8111610128576107b49036906004016104d5565b97909382421180156108f9575b6101285761001c986108a095610895848b966106678661063b8b8f8f9073ffffffffffffffffffffffffffffffffffffffff828f9361089b9e61080391610f81565b165f525f60205260405f2054604051978896602088019a338c9461010096919294999897939961012087019a7fe55aaa79350b0eb9ee70c987c9b0603c46531ab71d2b7c5404835db2f60e220c885273ffffffffffffffffffffffffffffffffffffffff968780961660208a015260408901526060880152608087015260a08601521660c08401521660e08201520152565b88611052565b611131565b919490806108e8575b5050806108b7575b50610f30565b6108e2907f0000000000000000000000004e3c052b97f27156f785c578b99346947e1bb4b3836110df565b5f6108b1565b6108f291846110df565b5f806108a9565b5073ffffffffffffffffffffffffffffffffffffffff8616156107c1565b346101285760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101285761001c60043533610f81565b34610128575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261012857335f525f60205260405f20805490816001019055337f9614574d6542397172c19ba2bf4588434feeb977576e92b7b59b38242ab596095f80a3005b9181601f840112156101285782359167ffffffffffffffff8311610128576020808501948460051b01011161012857565b346101285760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101285767ffffffffffffffff60043581811161012857610a3c9036906004016109bb565b909160243590811161012857610a569036906004016109bb565b90818303610128575f5b838110610a6957005b80610a97610a7a6001938789610b6e565b35610a848161010a565b610a8f838787610b6e565b359033610f30565b01610a60565b805f52600260205260405f20348154019055345f527fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c60205fa2565b610ae233610a9d565b565b6040810190811067ffffffffffffffff821117610b0057604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610b0057604052565b9190811015610b7e5760051b0190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b60405190610bb882610ae4565b600782527f574e4154495645000000000000000000000000000000000000000000000000006020830152565b6020808252825181830181905293925f5b858110610c34575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6040809697860101520116010190565b818101830151848201604001528201610bf5565b60405190610c5582610ae4565b600e82527f57726170706564204e61746976650000000000000000000000000000000000006020830152565b91909182600411610128578211610128577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6004920190565b91908260409103126101285760208235610cd38161010a565b92013590565b3415610ce757610ae2610ad9565b5f357fffffffff00000000000000000000000000000000000000000000000000000000167fcab7e8eb000000000000000000000000000000000000000000000000000000008103610dcb5760018073ffffffffffffffffffffffffffffffffffffffff60ff610dbe610d8d610d67610d5f3636610c81565b810190610cba565b941673ffffffffffffffffffffffffffffffffffffffff165f52600160205260405f2090565b8360081c7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b5491161c16145f5260205ff35b7f45253c53000000000000000000000000000000000000000000000000000000008103610e2557602436106101285773ffffffffffffffffffffffffffffffffffffffff600435165f525f60205260405f20545f5260205ff35b7f18160ddd000000000000000000000000000000000000000000000000000000008103610e5457475f5260205ff35b7f78e890ba000000000000000000000000000000000000000000000000000000008103610e8a57610e836111ef565b5f5260205ff35b7f06fdde03000000000000000000000000000000000000000000000000000000008103610ed257610eb9610c48565b604051610ece8161063b602082019485610be4565b5190f35b7f95d89b41000000000000000000000000000000000000000000000000000000008103610f0157610eb9610bab565b7f313ce56700000000000000000000000000000000000000000000000000000000036101285760125f5260205ff35b90915f80808093858252600260205260408220968754968288038099558284527f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65602085a25af11591111761012857565b600160ff83161b73ffffffffffffffffffffffffffffffffffffffff82165f526001602052610fde60405f208460081c7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b818154188091551615610128577f8dc5a0b2e80f26187d38744e9559150e3bd6e06fccefbe737fd33411cfb151515f80a3565b60429061101c6111ef565b90604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b929190604183036110be576110746020830135833560408501355f1a84611337565b73ffffffffffffffffffffffffffffffffffffffff868116911614801591906110b6575b506110a4575b50505050565b6110ad936112e1565b5f80808061109e565b90505f611098565b604083036110d65761107460208301358335836112fb565b610ae2936112e1565b9091815f52600260205260405f208054828110610128578290039055825f5260405f208181540190555f527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60205fa3565b915f61271092838311610128577dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85116101285773ffffffffffffffffffffffffffffffffffffffff16156111e7575b60098211156111a057508190830204906103e8820204808092038093030392565b929181156111dd57829350807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9304928392018402048093030392565b9050810480910392565b5f915061117f565b467f00000000000000000000000000000000000000000000000000000000000081730361123a577f203501403e693081e811072f909cd2bf162eb3828ff7c30c608384818f01a72190565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f10e20441b5a92700455eb9fe1bd4e33f98bd0733d6a532f2eec1ab8c30caf5d260408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c0810181811067ffffffffffffffff821117610b005760405251902090565b929190833b15610128576112f4936113bc565b1561012857565b90611333929160ff601b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff851694821c011690611337565b9091565b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084116113b1576020935f9360ff60809460405194855216868401526040830152606082015282805260015afa156113a6575f5173ffffffffffffffffffffffffffffffffffffffff81161591565b6040513d5f823e3d90fd5b505050506001905f90565b5f90602092937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f5f989780604051947f1626ba7e00000000000000000000000000000000000000000000000000000000998a875260048701526040602487015281604487015260648601370116606481830101604052606401915afa60203d1015166114475750565b5f5114915056fea26469706673582212202bc2e977d4326194251bed68a13b88aa97f9f60de0fe047b4a249863c5cc5c6664736f6c63430008180033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000004e3c052b97f27156f785c578b99346947e1bb4b3

-----Decoded View---------------
Arg [0] : infrastructureTaxRecipient (address): 0x4E3c052b97F27156f785c578B99346947e1bb4b3

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000004e3c052b97f27156f785c578b99346947e1bb4b3


Deployed Bytecode Sourcemap

1757:41700:1:-:0;;;;;;;;;-1:-1:-1;1757:41700:1;;;;;;:::i;:::-;;;6951:53;;:::i;1757:41700::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;14654:9;14650:53;;1757:41700;14713:445;-1:-1:-1;14713:445:1;;1757:41700;14713:445;1757:41700;-1:-1:-1;14713:445:1;1757:41700;14713:445;;-1:-1:-1;14713:445:1;;1757:41700;-1:-1:-1;14713:445:1;;-1:-1:-1;14713:445:1;;;1757:41700;-1:-1:-1;14713:445:1;;-1:-1:-1;14713:445:1;1757:41700;-1:-1:-1;14713:445:1;14650:53;7789:10;;;:::i;:::-;14650:53;;1757:41700;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;19021:9;19017:59;;1757:41700;19086:1327;-1:-1:-1;19086:1327:1;;1757:41700;19086:1327;1757:41700;-1:-1:-1;19086:1327:1;;;;;;;;;;;;;;-1:-1:-1;19086:1327:1;1757:41700;-1:-1:-1;19086:1327:1;;;;;;;;;;;;1757:41700;-1:-1:-1;19086:1327:1;;1757:41700;-1:-1:-1;19086:1327:1;;-1:-1:-1;19086:1327:1;1757:41700;-1:-1:-1;19086:1327:1;;;-1:-1:-1;19086:1327:1;;1757:41700;19086:1327;1757:41700;-1:-1:-1;19086:1327:1;1757:41700;19086:1327;;-1:-1:-1;19086:1327:1;1757:41700;-1:-1:-1;19086:1327:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;19017:59;19060:4;;;:::i;:::-;19017:59;;1757:41700;;;;;;;;;;;10827:6;1757:41700;;9755:10;;10827:6;:::i;1757:41700::-;;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;1757:41700:1;2170:45;1757:41700;;;;-1:-1:-1;1757:41700:1;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;19021:9;19017:59;;1757:41700;16793:10;-1:-1:-1;19086:1327:1;;1757:41700;19086:1327;1757:41700;-1:-1:-1;19086:1327:1;;;;;;;;;;;;;;-1:-1:-1;19086:1327:1;1757:41700;-1:-1:-1;19086:1327:1;;;;;;;-1:-1:-1;19086:1327:1;16793:10;19086:1327;1757:41700;-1:-1:-1;19086:1327:1;;-1:-1:-1;19086:1327:1;1757:41700;-1:-1:-1;19086:1327:1;19017:59;19060:4;16793:10;19060:4;:::i;:::-;19017:59;;1757:41700;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;;10827:6;1757:41700;;;;;:::i;:::-;;;10811:10;;10827:6;:::i;1757:41700::-;;;;;;;;7789:10;;;:::i;1757:41700::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;25952:9;;25948:59;;1757:41700;26021:15;;:28;:73;;;;1757:41700;26021:107;;;;1757:41700;26017:146;;26723:14;26204:5;26663:12;26204:5;26348:268;26204:5;;26283:365;26204:5;;;:::i;:::-;1757:41700;;;-1:-1:-1;1757:41700:1;-1:-1:-1;1757:41700:1;;26348:268;1757:41700;-1:-1:-1;1757:41700:1;1423:113:0;1757:41700:1;;26348:268;;;1757:41700;26348:268;;26434:10;;26348:268;1423:113:0;;;;;;;;;1757:41700:1;1423:113:0;;;1757:41700:1;1423:113:0;1757:41700:1;;;1423:113:0;;;;;;;1757:41700:1;1423:113:0;;;1757:41700:1;1423:113:0;;;1757:41700:1;1423:113:0;1757:41700:1;1423:113:0;26348:268:1;;;;;;;;;:::i;:::-;1423:113:0;26317:317:1;;26283:365;:::i;:::-;26663:12;;:::i;:::-;26723:14;:::i;26021:107::-;1757:41700;;;;26110:18;26021:107;;:73;26065:29;;;;26021:73;;25948:59;25991:4;;;:::i;:::-;25948:59;;1757:41700;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;-1:-1:-1;1757:41700:1;2308:63;1757:41700;;;-1:-1:-1;1757:41700:1;;;-1:-1:-1;1757:41700:1;;;;;-1:-1:-1;1757:41700:1;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;29886:15;;;;;:28;:62;;;;1757:41700;29882:101;;31114:10;30024:5;30745:75;30024:5;30095:480;30024:5;;;30160:383;30024:5;30160:383;30024:5;;;;1757:41700;30024:5;;;30590:12;30024:5;;;;:::i;:::-;1757:41700;30383:13;1757:41700;30383:13;1757:41700;;;30383:13;1757:41700;1423:113:0;1757:41700:1;;30160:383;;;1757:41700;30160:383;;30248:10;;30160:383;1589:183:0;;;;;;;;;;;;;;1757:41700:1;1589:183:0;1757:41700:1;;;;;;;;1589:183:0;;;1423:113;1589:183;;;1757:41700:1;1589:183:0;;;1757:41700:1;1589:183:0;;;1757:41700:1;1589:183:0;;;1757:41700:1;;1589:183:0;;;1423:113;1757:41700:1;1589:183:0;;;1423:113;1589:183;1757:41700:1;1589:183:0;30095:480:1;30590:12;;:::i;:::-;30745:75;:::i;:::-;30835:18;;;;30831:111;;1757:41700;30956:21;;;30952:121;;1757:41700;31114:10;;:::i;30952:121::-;31044:17;31016:26;;31044:17;;:::i;:::-;30952:121;;;30831:111;30916:14;;;;:::i;:::-;30831:111;;;;29886:62;1757:41700;;;;29930:18;29886:62;;1757:41700;;;;;;;;;;;22317:5;1757:41700;;22305:10;22317:5;:::i;1757:41700::-;;;;;;;;;;;21080:378;1757:41700;21080:378;1757:41700;21080:378;;;1757:41700;21080:378;;;;;;;;;;;1757:41700;21080:378;;1757:41700;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;12162:36;;;;12158:75;;-1:-1:-1;12263:22:1;;;;;;1757:41700;12248:13;12320:14;10827:6;12320:14;1757:41700;12320:14;;;;:::i;:::-;1757:41700;;;;:::i;:::-;12336:10;;;;;:::i;:::-;1757:41700;10811:10;;10827:6;:::i;:::-;1757:41700;12248:13;;8461:371;8517:309;;;;;;;;;;;;;;;;;;;;;;8461:371::o;7735:72::-;7789:10;;;:::i;:::-;7735:72::o;1423:113:0:-;2287:32;1423:113;;;;;;;;;;;2287:32;1423:113;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;1757:41700:1:-;;;;;;;;;;;;:::o;:::-;;;;;;;;;;2287:32:0;;1757:41700:1;2287:32:0;;;;:::i;:::-;;;;;;;;;:::o;247:9::-;;;;;1423:113;;247:9;;;;;;1423:113;247:9;-1:-1:-1;247:9:0;;;;;;;;;1423:113;;247:9;;;;;;;;;;1423:113;;247:9;;;:::o;:::-;;;;;;;;;;;;;;;;;;2287:32;1757:41700:1;2287:32:0;;;;:::i;:::-;247:9;2287:32;;247:9;;;;;:::o;204:16::-;;;;;4690:1:1;204:16:0;;;;;;;;4690:1:1;204:16:0;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;1757:41700:1;204:16:0;:::o;4420:2285:1:-;4462:9;:13;:9;;4458:2241;;:::i;:::-;4474:1;4535:7;;;1816:43:0;4535:33:1;;1816:43:0;;4747:13:1;4681:8;1757:41700;204:16:0;4747:43:1;:22;4670:43;4681:12;:8;;:12;:::i;:::-;4670:43;;;;:::i;:::-;1757:41700;;;;;;4747:13;1757:41700;;;;;;;4747:22;1757:41700;204:16:0;1757:41700:1;204:16:0;;;;;;;;;;;4747:43:1;1423:113:0;204:16;;1757:41700:1;4746:67;4745:76;4474:1;4839:108;;4474:1;4839:108;4531:2158;1902:44:0;4971:33:1;;1902:44:0;;5057:366:1;;;;;;;;;4474:1;5057:366;4474:1;5057:366;;;4474:1;5057:366;;4474:1;5057:366;;4474:1;5057:366;4967:1722;1988:35:0;5447:32:1;;1988:35:0;;5516:115:1;4474:1;5516:115;;4474:1;5516:115;5443:1246;2072:49:0;5655:39:1;;2072:49:0;;5763:20:1;;:::i;:::-;4474:1;5801:117;;4474:1;5801:117;5651:1038;2155:28:0;5942:24:1;;2155:28:0;;247:9;;:::i;:::-;1757:41700:1;;6027:16;;;;;;;;;:::i;:::-;6061:107;;;5938:751;2219:30:0;6192:26:1;;2219:30:0;;2287:32;;:::i;6188:501:1:-;2287:32:0;6454:28:1;2287:32:0;;6516:112:1;4474:1;6516:112;;4474:1;6516:112;33061:632;;;33151:536;33061:632;;;;33151:536;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;33061:632::o;34009:412::-;441:1:0;204:16;;;1757:41700:1;;;;-1:-1:-1;1757:41700:1;441:1:0;1757:41700:1;;34129:43;1757:41700;-1:-1:-1;1757:41700:1;;34169:1;1757:41700;204:16:0;;;;;;;;;;;34129:43:1;1423:113:0;;;34129:68:1;1757:41700;;;34121:118;:126;34117:173;;34310:105;-1:-1:-1;34310:105:1;;34009:412::o;4263:176:4:-;3514:233:6;4263:176:4;4399:20;;:::i;:::-;3514:233:6;;;;;;;;;;;;;;;;4263:176:4;:::o;37173:1471:1:-;;;;37350:2;37330:22;;37350:2;;37795:30;37542:207;;;;;;;;;;-1:-1:-1;37542:207:1;37795:30;;:::i;:::-;1757:41700;;;;;;37843:24;;;;;:35;;37326:1312;37839:132;;;37326:1312;;;;;37173:1471::o;37839:132::-;37946:9;;;:::i;:::-;37839:132;;;;;;37843:35;;;;;;37326:1312;38011:2;37991:22;;38011:2;;38365:28;38181:138;;;;;;38365:28;;:::i;37987:651::-;38617:9;;;:::i;31783:700::-;;;31869:608;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;31783:700::o;34922:1408::-;;1757:41700;672:6:0;35179:35:1;;;;35175:74;;672:6:0;35263:26:1;;35259:65;;1757:41700;;35338:36;35334:88;;34922:1408;492:1:0;35460:48:1;;492:1:0;;;;;;;;;;630:5;492:1;;;;;;;;;;;35456:858:1;34922:1408::o;35456:858::-;35869:21;;;;;;492:1:0;;;;;;;;;;;;;;;;;;35865:449:1;34922:1408::o;35865:449::-;492:1:0;;;;;;;35865:449:1;7735:72::o;35334:88::-;1757:41700;;-1:-1:-1;35334:88:1;;3222:230:4;3298:13;3315:14;3298:31;3315:14;;3352:22;3345:29;:::o;3294:152::-;1757:41700:1;;3549:81:4;;;1757:41700:1;1828:95:4;1757:41700:1;;3572:11:4;1757:41700:1;1828:95:4;;1757:41700:1;3585:14:4;1828:95;;;1757:41700:1;3298:13:4;1828:95;;;1757:41700:1;3624:4:4;1828:95;;;1423:113:0;1828:95:4;3549:81;;1828:95;1423:113:0;;;;;;;;;;;1757:41700:1;1423:113:0;;3539:92:4;;3405:30;:::o;39049:275:1:-;;;;39164:18;;:23;39161:61;;41825:1624;;;:::i;:::-;39236:47;39232:86;;39049:275::o;39769:315::-;;40037:30;39769:315;;204:16:0;40000:2:1;323:66:0;39929:19:1;;1757:41700;;;323:66:0;204:16;40037:30:1;;:::i;:::-;40017:50;39769:315;:::o;40742:470::-;40891:66;40878:79;;40874:244;;1757:41700;;-1:-1:-1;1757:41700:1;204:16:0;1757:41700:1;;;;;;;204:16:0;1757:41700:1;;;;;;;;;;;;41137:26;;;;;;;;;-1:-1:-1;41137:26:1;1757:41700;;;41184:20;40742:470;:::o;41137:26::-;1757:41700;;;-1:-1:-1;1757:41700:1;;;;;40874:244;41082:25;;;;41090:4;41082:25;41104:1;41082:25;:::o;41825:1624::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;-1:-1:-1;41825:1624:1:o

Swarm Source

ipfs://2bc2e977d4326194251bed68a13b88aa97f9f60de0fe047b4a249863c5cc5c66

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.