ETH Price: $2,690.37 (+2.61%)

Contract

0xf2f92d78FB4721B2A1E265bfe31bCc03818F0Cb1
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Deposit Native184708212023-10-31 14:51:47470 days ago1698763907IN
0xf2f92d78...3818F0Cb1
0.00001 ETH0.0034335223.41622458

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block
From
To
184708212023-10-31 14:51:47470 days ago1698763907
0xf2f92d78...3818F0Cb1
0.00001 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
WrappedTokenGateway

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 5 : WrappedTokenGateway.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;

import {IWrappedToken} from "./interfaces/IWrappedToken.sol";
import {IMaxApyVault} from "./interfaces/IMaxApyVault.sol";

import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol";

/*KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
KKKKK0OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO0KKKKKKK
KK0dcclllllllllllllllllllllllllllllccccccccccccccccccclx0KKK
KOc,dKNWWWWWWWWWWWWWWWWWWWWWWWWWWWWNNNNNNNNNNNNNNNNNXOl';xKK
Kd'oWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMX; ,kK
Ko'xMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNc .dK
Ko'dMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNc .oK
Kd'oWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNc .oK
KO:,xXWWWWWWWWWWWWWWWWWWWWMMMMMMMMMMMMMMMMMMMMMMMMMMMMNc .oK
KKOl,',;;,,,,,,;;,,,,,,,;;cxXMMMMMMMMMMMMMMMMMMMMMMMMMNc .oK
KKKKOoc;;;;;;;;;;;;;;;;;;;,.cXMMMMMMMMMMMMMMMMMMMMMMMMNc .oK
KKKKKKKKKKKKKKKKKKKK00O00K0:,0MMMMMMMMMMMMMMMMMMMMMMMMNc .oK
KKKKKKKKKKKKKKKKKKklcccccld;,0MMMMMMMMMMMMMMMMMMMMMMMMNc .oK
KKKKKKKKKKKKKKKKkl;ckXNXOc. '0MMMMMMMMMMMMMMMMMMMMMMMMNc .oK
KKKKKKKKKKKKKKkc;l0WMMMMMX; .oKNMMMMMMMMMMMMMMMMMMMMMMNc .oK
KKKKKKKKKKKKkc;l0WMMMMMMMWd.  .,lddddddxONMMMMMMMMMMMMNc .oK
KKKKKKKKKKkc;l0WMMMMMMMMMMWOl::;'.  .....:0WMMMMMMMMMMNc .oK
KKKKKKK0xc;o0WMMMMMMMMMMMMMMMMMWNk'.;xkko'lNMMMMMMMMMMNc .oK
KKKKK0x:;oKWMMMMMMMMMMMMMMMMMMMMMWd..lKKk,lNMMMMMMMMMMNc .oK
KKK0x:;oKWMMMMMMMMMMMMMMMMMMMMMMWO,  c0Kk,lNMMMMMMMMMMNc .oK
KKx:;dKWMMMMMMMMMMMMMMMMMMMMMWN0c.  ;kKKk,lNMMMMMMMMMMNc .oK
Kx,:KWMMMMMMMMMMMMMMMMMMMMMW0c,.  'oOKKKk,lNMMMMMMMMMMNc .oK
Ko'xMMMMMMMMMMMMMMMMMMMMMW0c.   'oOKKKKKk,lNMMMMMMMMMMNc .oK
Ko'xMMMMMMMMMMMMMMMMMMMW0c.  ':oOKKKKKKKk,lNMMMMMMMMMMNc .oK
Ko'xMMMMMMMMMMMMMMMMMW0l.  'oOKKKKKKKKKKk,cNMMMMMMMMMMNc .oK
Ko'xMMMMMMMMMMMMMMMW0l.  'oOKKKKKKKKKKKKk,lNMMMMMMMMMMNc .oK
Ko'dWMMMMMMMMMMMMW0l.  'oOKKKKKKKKKKKKKKk,cNMMMMMMMMMMX: .oK
KO:,xXNWWWWWWWWNOl.  'oOKKKKKKKKKKKKKKKK0c,xNMMMMMMMMNd. .dK
KKOl''',,,,,,,,..  'oOKKKKKKKKKKKKKKKKKKKOl,,ccccccc:'  .c0K
KKKKOoc:;;;;;;;;:ldOKKKKKKKKKKKKKKKKKKKKKKKkl;'......',cx0KK
KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK0OOOOOOO0KKK*/

/// @notice Helper contract to interact with a MaxApy Vault utilizing the chain's native token the protocol
/// has been deployed to
/// @author MaxApy
contract WrappedTokenGateway {
    using SafeTransferLib for address;

    ////////////////////////////////////////////////////////////////
    ///                       CONSTANTS                          ///
    ////////////////////////////////////////////////////////////////

    /// @notice The chain's wrapped native token
    IWrappedToken public immutable wrappedToken;
    /// @notice The MaxApy vault linked to this Gateway contract
    IMaxApyVault public immutable vault;

    ////////////////////////////////////////////////////////////////
    ///                        ERRORS                            ///
    ////////////////////////////////////////////////////////////////
    error InvalidZeroValue();
    error FailedNativeTransfer();
    error ReceiveNotAllowed();

    ////////////////////////////////////////////////////////////////
    ///                        EVENTS                            ///
    ////////////////////////////////////////////////////////////////

    /// @notice Emitted on native vault deposits
    event DepositNative(address indexed recipient, uint256 shares, uint256 amount);

    /// @notice Emitted on native vault withdrawals
    event WithdrawNative(address indexed recipient, uint256 shares, uint256 amount);

    /// @dev `keccak256(bytes("DepositNative(address,uint256,uint256)"))`.
    uint256 internal constant _DEPOSIT_NATIVE_EVENT_SIGNATURE =
        0x6bb902f8baf2580ae3dae24e58f4b874ecca85152076af921bfd172dce1c7e28;

    /// @dev `keccak256(bytes("WithdrawNative(address,uint256,uint256)"))`.
    uint256 internal constant _WITHDRAW_NATIVE_EVENT_SIGNATURE =
        0x5cb35f4e7dbc40dd34f0d58cec4f5548fc47638cb46d7964e4f07c48e97e4c7d;

    ////////////////////////////////////////////////////////////////
    ///                      CONSTRUCTOR                         ///
    ////////////////////////////////////////////////////////////////

    /// @notice Create the WrappedToken Gateway
    /// @param _wrappedToken The wrapped token of the chain the contract will be deployed to
    /// @param _vault The MaxApy vault linked to this Gateway contract
    constructor(IWrappedToken _wrappedToken, IMaxApyVault _vault) {
        wrappedToken = _wrappedToken;
        vault = _vault;
        address(_wrappedToken).safeApprove(address(_vault), type(uint256).max);
    }

    ////////////////////////////////////////////////////////////////
    ///                 GATEWAY CORE LOGIC                       ///
    ////////////////////////////////////////////////////////////////

    /// @notice  Deposits `msg.value` of `_wrappedToken`, issuing shares to `recipient`
    /// @param recipient The address to issue the shares from MaxApy's Vault to
    function depositNative(address recipient) external payable returns (uint256) {
        // Cache `wrappedToken` and `vault` due to assembly's immutable access restrictions
        address cachedWrappedToken = address(wrappedToken);
        address cachedVault = address(vault);

        assembly ("memory-safe") {
            // Check if `msg.value` is 0
            if iszero(callvalue()) {
                // Throw the `InvalidZeroValue()` error
                mstore(0x00, 0xef7a63d0)
                revert(0x1c, 0x04)
            }

            // Cache the free memory pointer
            let m := mload(0x40)

            // Store Wrapped Token's `deposit()` function selector:
            // `bytes4(keccak256("deposit()"))`
            mstore(0x00, 0xd0e30db0)

            // Deposit native token in exchange for wrapped native token
            // Note: using some wrapped tokens' fallback function for deposit allows saving the previous
            // selector loading into memory to call wrappedToken's `deposit()`.
            // This is avoided due to some chain's wrapped native versions not allowing such behaviour
            if iszero(
                call(
                    gas(), // Remaining amount of gas
                    cachedWrappedToken, // Address of `wrappedToken`
                    callvalue(), // `msg.value`
                    0x1c, // byte offset in memory where calldata starts
                    0x24, // size of the calldata to copy
                    0x00, // byte offset in memory to store the return data
                    0x00 // size of the return data
                )
            ) {
                // Throw the `WrappedTokenDepositFailed()` error
                mstore(0x00, 0x22cd2378)
                revert(0x1c, 0x04)
            }

            // Store MaxApy vault's `deposit()` function selector:
            // `bytes4(keccak256("deposit(uint256,address)"))`
            mstore(0x00, 0x6e553f65)
            mstore(0x20, callvalue()) // Append the `amount` argument
            mstore(0x40, recipient) // Append the `recipient` argument

            // Deposit into MaxApy vault
            if iszero(
                call(
                    gas(), // Remaining amount of gas
                    cachedVault, // Address of `vault`
                    0, // `msg.value`
                    0x1c, // byte offset in memory where calldata starts
                    0x44, // size of the calldata to copy
                    0x00, // byte offset in memory to store the return data
                    0x20 // size of the return data
                )
            ) {
                // If call failed, throw the error thrown in the previous `call`
                revert(0x00, 0x04)
            }

            // Emit the `DepositNative` event
            mstore(0x20, callvalue())
            log2(0x00, 0x40, _DEPOSIT_NATIVE_EVENT_SIGNATURE, recipient)

            mstore(0x40, m) // Restore the free memory pointer

            return(0x00, 0x20) // Return `shares` value stored in 0x00 from previous from call's
        }
    }

    /// @notice Withdraws the calling account's tokens from MaxApy's Vault, redeeming
    /// amount `shares` for the corresponding amount of tokens, which will be transferred to
    /// `recipient` in the form of the chain's native token
    /// @param shares How many shares to try and redeem for tokens
    /// @param recipient The address to issue the shares from MaxApy's Vault to
    /// @param maxLoss The maximum acceptable loss to sustain on withdrawal. Up to loss specified amount of shares may be
    /// burnt to cover losses on withdrawal
    function withdrawNative(uint256 shares, address recipient, uint256 maxLoss) external returns (uint256) {
        // Cache `wrappedToken` and `vault` due to assembly's immutable access restrictions
        address cachedWrappedToken = address(wrappedToken);
        address cachedVault = address(vault);

        assembly ("memory-safe") {
            // Check if `shares` passed by user is `type(uint256).max`
            if eq(shares, not(0)) {
                // Store `vault`'s `balanceOf()` function selector:
                // `bytes4(keccak256("balanceOf(address)"))`
                mstore(0x00, 0x70a08231)
                mstore(0x20, caller()) // append the `owner` argument as `msg.sender`

                // query `vault`'s `msg.sender` `balanceOf()`
                if iszero(
                    staticcall(
                        gas(), // Remaining amount of gas
                        cachedVault, // Address of `vault`
                        0x1c, // byte offset in memory where calldata starts
                        0x24, // size of the calldata to copy
                        0x00, // byte offset in memory to store the return data
                        0x20 // size of the return data
                    )
                ) {
                    // Revert if balance query fails
                    revert(0x00, 0x04)
                }

                // Store `msg.sender`'s balance returned by staticcall into `shares`
                shares := mload(0x00)
            }
        }

        // Transfer caller shares
        address(vault).safeTransferFrom(msg.sender, address(this), shares);

        uint256 amountWithdrawn;

        assembly ("memory-safe") {
            // Cache the free memory pointer
            let m := mload(0x40)

            // Store `vault`'s `withdraw()` function selector:
            // `bytes4(keccak256("withdraw(address)"))`
            mstore(0x00, 0xe63697c8)
            mstore(0x20, shares) // append the `shares` argument
            mstore(0x40, address()) // append the `address(this)` argument
            mstore(0x60, maxLoss) // append the `maxLoss` argument

            // Withdraw from MaxApy vault
            if iszero(
                call(
                    gas(), // Remaining amount of gas
                    cachedVault, // Address of `vault`
                    0, // `msg.value`
                    0x1c, // byte offset in memory where calldata starts
                    0x64, // size of the calldata to copy
                    0x00, // byte offset in memory to store the return data
                    0x20 // size of the return data
                )
            ) {
                // If call failed, throw the error thrown in the previous `call`
                revert(0x00, 0x04)
            }

            // Store `amountWithdrawn` returned by the previous call to `withdraw()`
            amountWithdrawn := mload(0x00)

            // Store `wrappedToken`'s `withdraw()` function selector:
            // `bytes4(keccak256("withdraw(uint256)"))`
            mstore(0x00, 0x2e1a7d4d)
            mstore(0x20, amountWithdrawn) // append the `amountWithdrawn` argument

            // Withdraw from wrapped token
            if iszero(
                call(
                    gas(), // Remaining amount of gas
                    cachedWrappedToken, // Address of `vault`
                    0, // `msg.value`
                    0x1c, // byte offset in memory where calldata starts
                    0x24, // size of the calldata to copy
                    0x00, // byte offset in memory to store the return data
                    0x20 // size of the return data
                )
            ) {
                // If call failed, throw the error thrown in the previous `call`
                revert(0x00, 0x04)
            }

            // Transfer native token back to user
            if iszero(call(gas(), recipient, amountWithdrawn, 0x00, 0x00, 0x00, 0x00)) {
                // If call failed, throw the `FailedNativeTransfer()` error
                mstore(0x00, 0x3c3f4130)
                revert(0x1c, 0x04)
            }

            // Emit the `WithdrawNative` event
            mstore(0x00, shares)
            mstore(0x20, amountWithdrawn)
            log2(0x00, 0x40, _WITHDRAW_NATIVE_EVENT_SIGNATURE, recipient)

            mstore(0x60, 0) // Restore the zero slot
            mstore(0x40, m) // Restore the free memory pointer

            return(0x20, 0x20) // Return `amountWithdrawn` value stored in 0x00 from previous from call's
        }
    }

    ////////////////////////////////////////////////////////////////
    ///                 RECEIVE()  function                      ///
    ////////////////////////////////////////////////////////////////

    /// @notice Receive function to accept native transfers
    /// @dev Note only the chain's wrapped token will be able to perform native token transfers
    /// to this contract
    receive() external payable {
        // Cache `wrappedToken` due to assembly immutable access restrictions
        address cachedWrappedToken = address(wrappedToken);

        assembly {
            // Check if caller is not the `wrappedToken`
            if iszero(eq(caller(), cachedWrappedToken)) {
                // Throw the `ReceiveNotAllowed()` error
                mstore(0x00, 0xcb263c3f)
                revert(0x1c, 0x04)
            }
        }
    }
}

File 2 of 5 : IWrappedToken.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;

interface IWrappedToken {
    function deposit() external payable;

    function transfer(address to, uint256 value) external returns (bool);

    function withdraw(uint256) external;
}

File 3 of 5 : IMaxApyVault.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;

import {StrategyData} from "../helpers/VaultTypes.sol";

/**
 * @notice MaxApyVault contains the main interface for MaxApy Vaults
 */
interface IMaxApyVault {
    /// User-facing vault functions
    function deposit(uint256 amount, address recipient) external returns (uint256);

    function withdraw(uint256 shares, address recipient, uint256 maxLoss) external returns (uint256);

    function report(uint128 gain, uint128 loss, uint128 debtPayment) external returns (uint256);

    /// ERC20 Token functions
    function name() external returns (string memory);

    function symbol() external returns (string memory);

    function decimals() external returns (uint8);

    function underlyingAsset() external view returns (address);

    function totalSupply() external view returns (uint256);

    function balanceOf(address user) external view returns (uint256);

    /// Ownership
    function transferOwnership(address newOwner) external payable;

    function renounceOwnership() external payable;

    function requestOwnershipHandover() external payable;

    function cancelOwnershipHandover() external payable;

    function completeOwnershipHandover(address pendingOwner) external payable;

    /// View ownership
    function ownershipHandoverExpiresAt(address pendingOwner) external view returns (uint256);

    function ownershipHandoverValidFor() external view returns (uint64);

    function owner() external view returns (address result);

    /// Roles
    function grantRoles(address user, uint256 roles) external payable;

    function revokeRoles(address user, uint256 roles) external payable;

    function renounceRoles(uint256 roles) external payable;

    /// View roles
    function ADMIN_ROLE() external returns (uint256);

    function EMERGENCY_ADMIN_ROLE() external returns (uint256);

    function KEEPER_ROLE() external returns (uint256);

    function STRATEGY_ROLE() external returns (uint256);

    function hasAnyRole(address user, uint256 roles) external view returns (bool result);

    function hasAllRoles(address user, uint256 roles) external view returns (bool result);

    function rolesOf(address user) external view returns (uint256 roles);

    function rolesFromOrdinals(uint8[] memory ordinals) external pure returns (uint256 roles);

    function ordinalsFromRoles(uint256 roles) external pure returns (uint8[] memory ordinals);

    /// Vault configuration
    function debtRatio() external returns (uint256);

    function totalDebt() external returns (uint256);

    function totalIdle() external returns (uint256);

    function strategies(address strategy) external returns (StrategyData memory);

    function withdrawalQueue(uint256 index) external returns (address);

    function emergencyShutdown() external returns (bool);

    /// Vault management
    function setEmergencyShutdown(bool _emergencyShutdown) external;

    function addStrategy(
        address newStrategy,
        uint256 strategyDebtRatio,
        uint256 strategyMaxDebtPerHarvest,
        uint256 strategyMinDebtPerHarvest,
        uint256 strategyPerformanceFee
    ) external;

    function revokeStrategy(address strategy) external;

    function removeStrategy(address strategy) external;

    function updateStrategyData(
        address strategy,
        uint256 newDebtRatio,
        uint256 newMaxDebtPerHarvest,
        uint256 newMinDebtPerHarvest,
        uint256 newPerformanceFee
    ) external;

    function setWithdrawalQueue(address[20] calldata queue) external;

    function setPerformanceFee(uint256 _performanceFee) external;

    function setManagementFee(uint256 _managementFee) external;

    function setLockedProfitDegradation(uint256 _lockedProfitDegradation) external;

    function setDepositLimit(uint256 _depositLimit) external;

    function setTreasury(address _treasury) external;

    /// Vault view functions
    function performanceFee() external returns (uint256);

    function managementFee() external returns (uint256);

    function lockedProfitDegradation() external view returns (uint256);

    function depositLimit() external returns (uint256);

    function MAXIMUM_STRATEGIES() external returns (uint256);

    function DEGRADATION_COEFFICIENT() external view returns (uint256);

    function shareValue(uint256 shares) external view returns (uint256);

    function sharesForAmount(uint256 amount) external view returns (uint256 shares);

    function debtOutstanding(address strategy) external view returns (uint256);

    function totalAssets() external view returns (uint256);

    function lastReport() external view returns (uint256);

    function lockedProfit() external view returns (uint256);

    function treasury() external view returns (address);
}

File 4 of 5 : SafeTransferLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Caution! This library won't check that a token has code, responsibility is delegated to the caller.
library SafeTransferLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ETH transfer has failed.
    error ETHTransferFailed();

    /// @dev The ERC20 `transferFrom` has failed.
    error TransferFromFailed();

    /// @dev The ERC20 `transfer` has failed.
    error TransferFailed();

    /// @dev The ERC20 `approve` has failed.
    error ApproveFailed();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Suggested gas stipend for contract receiving ETH
    /// that disallows any storage writes.
    uint256 internal constant _GAS_STIPEND_NO_STORAGE_WRITES = 2300;

    /// @dev Suggested gas stipend for contract receiving ETH to perform a few
    /// storage reads and writes, but low enough to prevent griefing.
    /// Multiply by a small constant (e.g. 2), if needed.
    uint256 internal constant _GAS_STIPEND_NO_GRIEF = 100000;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       ETH OPERATIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Sends `amount` (in wei) ETH to `to`.
    /// Reverts upon failure.
    function safeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer the ETH and check if it succeeded or not.
            if iszero(call(gas(), to, amount, 0, 0, 0, 0)) {
                // Store the function selector of `ETHTransferFailed()`.
                mstore(0x00, 0xb12d13eb)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    /// The `gasStipend` can be set to a low enough value to prevent
    /// storage writes or gas griefing.
    ///
    /// If sending via the normal procedure fails, force sends the ETH by
    /// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH.
    ///
    /// Reverts if the current contract has insufficient balance.
    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // If insufficient balance, revert.
            if lt(selfbalance(), amount) {
                // Store the function selector of `ETHTransferFailed()`.
                mstore(0x00, 0xb12d13eb)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Transfer the ETH and check if it succeeded or not.
            if iszero(call(gasStipend, to, amount, 0, 0, 0, 0)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                // We can directly use `SELFDESTRUCT` in the contract creation.
                // Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758
                if iszero(create(amount, 0x0b, 0x16)) {
                    // For better gas estimation.
                    if iszero(gt(gas(), 1000000)) { revert(0, 0) }
                }
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a gas stipend
    /// equal to `_GAS_STIPEND_NO_GRIEF`. This gas stipend is a reasonable default
    /// for 99% of cases and can be overriden with the three-argument version of this
    /// function if necessary.
    ///
    /// If sending via the normal procedure fails, force sends the ETH by
    /// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH.
    ///
    /// Reverts if the current contract has insufficient balance.
    function forceSafeTransferETH(address to, uint256 amount) internal {
        // Manually inlined because the compiler doesn't inline functions with branches.
        /// @solidity memory-safe-assembly
        assembly {
            // If insufficient balance, revert.
            if lt(selfbalance(), amount) {
                // Store the function selector of `ETHTransferFailed()`.
                mstore(0x00, 0xb12d13eb)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Transfer the ETH and check if it succeeded or not.
            if iszero(call(_GAS_STIPEND_NO_GRIEF, to, amount, 0, 0, 0, 0)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                // We can directly use `SELFDESTRUCT` in the contract creation.
                // Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758
                if iszero(create(amount, 0x0b, 0x16)) {
                    // For better gas estimation.
                    if iszero(gt(gas(), 1000000)) { revert(0, 0) }
                }
            }
        }
    }

    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    /// The `gasStipend` can be set to a low enough value to prevent
    /// storage writes or gas griefing.
    ///
    /// Simply use `gasleft()` for `gasStipend` if you don't need a gas stipend.
    ///
    /// Note: Does NOT revert upon failure.
    /// Returns whether the transfer of ETH is successful instead.
    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer the ETH and check if it succeeded or not.
            success := call(gasStipend, to, amount, 0, 0, 0, 0)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      ERC20 OPERATIONS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.

            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            // Store the function selector of `transferFrom(address,address,uint256)`.
            mstore(0x0c, 0x23b872dd000000000000000000000000)

            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                // Store the function selector of `TransferFromFailed()`.
                mstore(0x00, 0x7939f424)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends all of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferAllFrom(address token, address from, address to)
        internal
        returns (uint256 amount)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.

            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            // Store the function selector of `balanceOf(address)`.
            mstore(0x0c, 0x70a08231000000000000000000000000)
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
                )
            ) {
                // Store the function selector of `TransferFromFailed()`.
                mstore(0x00, 0x7939f424)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // Store the function selector of `transferFrom(address,address,uint256)`.
            mstore(0x00, 0x23b872dd)
            // The `amount` argument is already written to the memory word at 0x6c.
            amount := mload(0x60)

            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                // Store the function selector of `TransferFromFailed()`.
                mstore(0x00, 0x7939f424)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransfer(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            // Store the function selector of `transfer(address,uint256)`.
            mstore(0x00, 0xa9059cbb000000000000000000000000)

            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                // Store the function selector of `TransferFailed()`.
                mstore(0x00, 0x90b8ec18)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Restore the part of the free memory pointer that was overwritten.
            mstore(0x34, 0)
        }
    }

    /// @dev Sends all of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransferAll(address token, address to) internal returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
            mstore(0x20, address()) // Store the address of the current contract.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
                )
            ) {
                // Store the function selector of `TransferFailed()`.
                mstore(0x00, 0x90b8ec18)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            mstore(0x14, to) // Store the `to` argument.
            // The `amount` argument is already written to the memory word at 0x34.
            amount := mload(0x34)
            // Store the function selector of `transfer(address,uint256)`.
            mstore(0x00, 0xa9059cbb000000000000000000000000)

            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                // Store the function selector of `TransferFailed()`.
                mstore(0x00, 0x90b8ec18)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Restore the part of the free memory pointer that was overwritten.
            mstore(0x34, 0)
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// Reverts upon failure.
    function safeApprove(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            // Store the function selector of `approve(address,uint256)`.
            mstore(0x00, 0x095ea7b3000000000000000000000000)

            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                // Store the function selector of `ApproveFailed()`.
                mstore(0x00, 0x3e3f8f73)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Restore the part of the free memory pointer that was overwritten.
            mstore(0x34, 0)
        }
    }

    /// @dev Returns the amount of ERC20 `token` owned by `account`.
    /// Returns zero if the `token` does not exist.
    function balanceOf(address token, address account) internal view returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            // Store the function selector of `balanceOf(address)`.
            mstore(0x00, 0x70a08231000000000000000000000000)
            amount :=
                mul(
                    mload(0x20),
                    and( // The arguments of `and` are evaluated from right to left.
                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                    )
                )
        }
    }
}

File 5 of 5 : VaultTypes.sol
pragma solidity ^0.8.19;

/// @notice Stores all data from a single strategy
/// @dev Packed in two slots
struct StrategyData {
    /// Slot 0
    /// @notice Maximum percentage available to be lent to strategies(in BPS)
    /// @dev in BPS. uint16 is enough to cover the max BPS value of 10_000
    uint16 strategyDebtRatio;
    /// @notice The performance fee
    /// @dev in BPS. uint16 is enough to cover the max BPS value of 10_000
    uint16 strategyPerformanceFee;
    /// @notice Timestamp when the strategy was added.
    /// @dev Overflowing July 21, 2554
    uint48 strategyActivation;
    /// @notice block.timestamp of the last time a report occured
    /// @dev Overflowing July 21, 2554
    uint48 strategyLastReport;
    /// @notice Upper limit on the increase of debt since last harvest
    /// @dev max debt per harvest to be set to a maximum value of 4,722,366,482,869,645,213,695
    uint128 strategyMaxDebtPerHarvest;
    /// Slot 1
    /// @notice Lower limit on the increase of debt since last harvest
    /// @dev min debt per harvest to be set to a maximum value of 16,777,215
    uint128 strategyMinDebtPerHarvest;
    /// @notice Total returns that Strategy has realized for Vault
    /// @dev max strategy total gain of 79,228,162,514,264,337,593,543,950,335
    uint128 strategyTotalGain;
    /// Slot 2
    /// @notice Total outstanding debt that Strategy has
    /// @dev max total debt of 79,228,162,514,264,337,593,543,950,335
    uint128 strategyTotalDebt;
    /// @notice Total losses that Strategy has realized for Vault
    /// @dev max strategy total loss of 79,228,162,514,264,337,593,543,950,335
    uint128 strategyTotalLoss;
}

Settings
{
  "remappings": [
    "solady/=lib/solady/src/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract IWrappedToken","name":"_wrappedToken","type":"address"},{"internalType":"contract IMaxApyVault","name":"_vault","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FailedNativeTransfer","type":"error"},{"inputs":[],"name":"InvalidZeroValue","type":"error"},{"inputs":[],"name":"ReceiveNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DepositNative","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawNative","type":"event"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"depositNative","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract IMaxApyVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"maxLoss","type":"uint256"}],"name":"withdrawNative","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wrappedToken","outputs":[{"internalType":"contract IWrappedToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c060405234801561001057600080fd5b506040516105c33803806105c383398101604081905261002f916100c0565b6001600160a01b03808316608081905290821660a0526100529082600019610059565b50506100fa565b81601452806034526f095ea7b300000000000000000000000060005260206000604460106000875af13d15600160005114171661009e57633e3f8f736000526004601cfd5b6000603452505050565b6001600160a01b03811681146100bd57600080fd5b50565b600080604083850312156100d357600080fd5b82516100de816100a8565b60208401519092506100ef816100a8565b809150509250929050565b60805160a05161047c61014760003960008181610129015281816101700152818161024b01526102a6015260008181604a0152818160dd0152818161014f015261022a015261047c6000f3fe6080604052600436106100435760003560e01c806333bb7f91146100855780633f2aecb2146100ab578063996c6cc3146100cb578063fbfa77cf1461011757600080fd5b36610080577f000000000000000000000000000000000000000000000000000000000000000033811461007e5763cb263c3f6000526004601cfd5b005b600080fd5b6100986100933660046103ef565b61014b565b6040519081526020015b60405180910390f35b3480156100b757600080fd5b506100986100c6366004610411565b610226565b3480156100d757600080fd5b506100ff7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100a2565b34801561012357600080fd5b506100ff7f000000000000000000000000000000000000000000000000000000000000000081565b60007f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000346101a25763ef7a63d06000526004601cfd5b60405163d0e30db06000526000806024601c34875af16101ca576322cd23786000526004601cfd5b636e553f656000523460205284604052602060006044601c6000865af16101f15760046000fd5b34602052847f6bb902f8baf2580ae3dae24e58f4b874ecca85152076af921bfd172dce1c7e2860406000a28060405260206000f35b60007f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000060018601610299576370a0823160005233602052602060006024601c845afa6102935760046000fd5b60005195505b6102ce6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633308961037f565b600060405163e63697c8600052876020523060405285606052602060006064601c6000875af16102fe5760046000fd5b6000519150632e1a7d4d60005281602052602060006024601c6000885af16103265760046000fd5b600080600080858b5af161034257633c3f41306000526004601cfd5b8760005281602052867f5cb35f4e7dbc40dd34f0d58cec4f5548fc47638cb46d7964e4f07c48e97e4c7d60406000a2600060605280604052602080f35b60405181606052826040528360601b602c526323b872dd60601b600c52602060006064601c6000895af13d1560016000511417166103c557637939f4246000526004601cfd5b600060605260405250505050565b80356001600160a01b03811681146103ea57600080fd5b919050565b60006020828403121561040157600080fd5b61040a826103d3565b9392505050565b60008060006060848603121561042657600080fd5b83359250610436602085016103d3565b915060408401359050925092509256fea2646970667358221220e5c2ab65123540ff97b5bef75ddaab15204556dbf5b8bb24e687a69fa593b55564736f6c63430008130033000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000005da197c9bc9cfc36cd35c5f49954eae7527604c3

Deployed Bytecode

0x6080604052600436106100435760003560e01c806333bb7f91146100855780633f2aecb2146100ab578063996c6cc3146100cb578063fbfa77cf1461011757600080fd5b36610080577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc233811461007e5763cb263c3f6000526004601cfd5b005b600080fd5b6100986100933660046103ef565b61014b565b6040519081526020015b60405180910390f35b3480156100b757600080fd5b506100986100c6366004610411565b610226565b3480156100d757600080fd5b506100ff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6040516001600160a01b0390911681526020016100a2565b34801561012357600080fd5b506100ff7f0000000000000000000000005da197c9bc9cfc36cd35c5f49954eae7527604c381565b60007f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc27f0000000000000000000000005da197c9bc9cfc36cd35c5f49954eae7527604c3346101a25763ef7a63d06000526004601cfd5b60405163d0e30db06000526000806024601c34875af16101ca576322cd23786000526004601cfd5b636e553f656000523460205284604052602060006044601c6000865af16101f15760046000fd5b34602052847f6bb902f8baf2580ae3dae24e58f4b874ecca85152076af921bfd172dce1c7e2860406000a28060405260206000f35b60007f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc27f0000000000000000000000005da197c9bc9cfc36cd35c5f49954eae7527604c360018601610299576370a0823160005233602052602060006024601c845afa6102935760046000fd5b60005195505b6102ce6001600160a01b037f0000000000000000000000005da197c9bc9cfc36cd35c5f49954eae7527604c31633308961037f565b600060405163e63697c8600052876020523060405285606052602060006064601c6000875af16102fe5760046000fd5b6000519150632e1a7d4d60005281602052602060006024601c6000885af16103265760046000fd5b600080600080858b5af161034257633c3f41306000526004601cfd5b8760005281602052867f5cb35f4e7dbc40dd34f0d58cec4f5548fc47638cb46d7964e4f07c48e97e4c7d60406000a2600060605280604052602080f35b60405181606052826040528360601b602c526323b872dd60601b600c52602060006064601c6000895af13d1560016000511417166103c557637939f4246000526004601cfd5b600060605260405250505050565b80356001600160a01b03811681146103ea57600080fd5b919050565b60006020828403121561040157600080fd5b61040a826103d3565b9392505050565b60008060006060848603121561042657600080fd5b83359250610436602085016103d3565b915060408401359050925092509256fea2646970667358221220e5c2ab65123540ff97b5bef75ddaab15204556dbf5b8bb24e687a69fa593b55564736f6c63430008130033

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

000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000005da197c9bc9cfc36cd35c5f49954eae7527604c3

-----Decoded View---------------
Arg [0] : _wrappedToken (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [1] : _vault (address): 0x5Da197c9BC9cFC36Cd35C5F49954eaE7527604C3

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [1] : 0000000000000000000000005da197c9bc9cfc36cd35c5f49954eae7527604c3


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
Loading...
Loading
[ Download: CSV Export  ]
[ 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.