ETH Price: $1,965.84 (-5.30%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Initialize Appro...243900792026-02-05 10:37:2310 days ago1770287843IN
0x3e872D07...bf608C6e3
0 ETH0.000036870.22022204

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CharmStrategyUSD1V2

Compiler Version
v0.8.30+commit.73712a01

Optimization Enabled:
Yes with 200 runs

Other Settings:
prague EvmVersion
File 1 of 10 : CharmStrategyUSD1V2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

/**
 * @title CharmStrategyUSD1V2
 * @notice Improved Charm vault strategy for USD1/WLFI with slippage protection
 * 
 * @dev DEPLOY WITH CREATE2 for vanity address 0x47...
 *      1. Get bytecode: abi.encodePacked(type(CharmStrategyUSD1V2).creationCode, constructorArgs)
 *      2. Find salt: deployer.findSalt47(bytecode, 0, 100000)
 *      3. Deploy: deployer.deployWithPrefix(bytecode, salt, 0x47)
 * 
 * @dev IMPROVEMENTS OVER V1:
 *      1. Uses POOL PRICE for swap calculations (not oracle) - prevents bad swap rates
 *      2. Slippage protection on all swaps (configurable, default 3%)
 *      3. Try/catch on Charm deposits (graceful failure, returns tokens)
 *      4. Pre-deposit range check (skips if Charm vault out of range)
 *      5. Single atomic deposit (no batching - simpler & cheaper)
 *      6. Max swap percentage limits (prevents excessive swaps)
 *      7. Configurable parameters without redeployment
 */

interface ICharmVault {
    function deposit(
        uint256 amount0Desired,
        uint256 amount1Desired,
        uint256 amount0Min,
        uint256 amount1Min,
        address to
    ) external returns (uint256 shares, uint256 amount0, uint256 amount1);
    
    function withdraw(
        uint256 shares,
        uint256 amount0Min,
        uint256 amount1Min,
        address to
    ) external returns (uint256 amount0, uint256 amount1);
    
    function getTotalAmounts() external view returns (uint256 total0, uint256 total1);
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    
    // Tick range functions
    function baseLower() external view returns (int24);
    function baseUpper() external view returns (int24);
    function pool() external view returns (address);
}

interface ISwapRouter {
    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 deadline;
        uint256 amountIn;
        uint256 amountOutMinimum;
        uint160 sqrtPriceLimitX96;
    }
    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
}

/// @notice zRouter - gas-efficient multi-AMM DEX aggregator
/// @dev Deployed: 0x00000000008892d085e0611eb8C8BDc9FD856fD3
interface IzRouter {
    function swapV3(
        address tokenIn,
        address tokenOut,
        uint24 fee,
        uint256 amountIn,
        uint256 amountOutMin,
        uint256 deadline
    ) external payable returns (uint256 amountOut);
}

/// @notice Uniswap V3 Factory for pool discovery
interface IUniswapV3Factory {
    function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool);
}

interface IUniswapV3Pool {
    function slot0() external view returns (
        uint160 sqrtPriceX96,
        int24 tick,
        uint16 observationIndex,
        uint16 observationCardinality,
        uint16 observationCardinalityNext,
        uint8 feeProtocol,
        bool unlocked
    );
    function token0() external view returns (address);
    function token1() external view returns (address);
    function liquidity() external view returns (uint128);
}

interface IStrategy {
    function deposit(uint256 wlfiAmount, uint256 usd1Amount) external returns (uint256 shares);
    function withdraw(uint256 value) external returns (uint256 wlfiAmount, uint256 usd1Amount);
    function getTotalAmounts() external view returns (uint256 wlfiAmount, uint256 usd1Amount);
}

contract CharmStrategyUSD1V2 is IStrategy, ReentrancyGuard, Ownable {
    using SafeERC20 for IERC20;

    // =================================
    // STATE VARIABLES
    // =================================

    address public immutable EAGLE_VAULT;
    IERC20 public immutable WLFI;
    IERC20 public immutable USD1;
    ISwapRouter public immutable UNISWAP_ROUTER;

    ICharmVault public charmVault;
    IUniswapV3Pool public swapPool;  // USD1/WLFI pool for accurate pricing

    /// @notice zRouter for gas-efficient swaps (optional)
    /// @dev Ethereum: 0x00000000008892d085e0611eb8C8BDc9FD856fD3
    IzRouter public zRouter;
    bool public useZRouter = false;  // Toggle to use zRouter vs Uniswap

    /// @notice Uniswap V3 Factory for auto fee tier discovery
    /// @dev Ethereum: 0x1F98431c8aD98523631AE4a59f267346ea31F984
    IUniswapV3Factory public uniFactory;
    bool public autoFeeTier = false;  // Auto-discover best fee tier

    /// @notice Configurable parameters
    uint256 public maxSwapPercent = 30;          // Max 30% of tokens swapped
    uint256 public swapSlippageBps = 300;        // 3% max swap slippage
    uint256 public depositSlippageBps = 500;     // 5% deposit slippage
    uint24 public swapPoolFee = 3000;            // 0.3% fee tier (default)

    bool public active = true;

    // =================================
    // EVENTS
    // =================================

    event StrategyDeposit(uint256 wlfiAmount, uint256 usd1Amount, uint256 shares);
    event StrategyWithdraw(uint256 shares, uint256 wlfiAmount, uint256 usd1Amount);
    event TokensSwapped(address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOut);
    event DepositFailed(string reason);
    event UnusedTokensReturned(uint256 usd1Amount, uint256 wlfiAmount);
    event ParametersUpdated(uint256 maxSwapPercent, uint256 swapSlippageBps);

    // =================================
    // ERRORS
    // =================================

    error NotVault();
    error NotActive();
    error ZeroAddress();
    error SlippageExceeded(uint256 expected, uint256 actual);

    // =================================
    // MODIFIERS
    // =================================

    modifier onlyVault() {
        if (msg.sender != EAGLE_VAULT) revert NotVault();
        _;
    }

    modifier whenActive() {
        if (!active) revert NotActive();
        _;
    }

    // =================================
    // CONSTRUCTOR
    // =================================

    constructor(
        address _vault,
        address _charmVault,
        address _wlfi,
        address _usd1,
        address _uniswapRouter,
        address _swapPool,
        address _owner
    ) Ownable(_owner) {
        if (_vault == address(0) || _wlfi == address(0) || 
            _usd1 == address(0) || _uniswapRouter == address(0)) {
            revert ZeroAddress();
        }

        EAGLE_VAULT = _vault;
        WLFI = IERC20(_wlfi);
        USD1 = IERC20(_usd1);
        UNISWAP_ROUTER = ISwapRouter(_uniswapRouter);

        if (_charmVault != address(0)) {
            charmVault = ICharmVault(_charmVault);
        }
        if (_swapPool != address(0)) {
            swapPool = IUniswapV3Pool(_swapPool);
        }
    }

    // =================================
    // CONFIGURATION
    // =================================

    function setCharmVault(address _charmVault) external onlyOwner {
        charmVault = ICharmVault(_charmVault);
    }

    function setSwapPool(address _swapPool) external onlyOwner {
        swapPool = IUniswapV3Pool(_swapPool);
    }

    /// @notice Set zRouter address for gas-efficient swaps
    /// @param _zRouter zRouter contract address (0x00000000008892d085e0611eb8C8BDc9FD856fD3 on Ethereum)
    function setZRouter(address _zRouter) external onlyOwner {
        zRouter = IzRouter(_zRouter);
    }

    /// @notice Toggle between zRouter (gas-efficient) and Uniswap Router
    function setUseZRouter(bool _useZRouter) external onlyOwner {
        useZRouter = _useZRouter;
    }

    /// @notice Set Uniswap V3 Factory for auto fee tier discovery
    /// @param _factory Factory address (0x1F98431c8aD98523631AE4a59f267346ea31F984 on Ethereum)
    function setUniFactory(address _factory) external onlyOwner {
        uniFactory = IUniswapV3Factory(_factory);
    }

    /// @notice Toggle automatic fee tier discovery
    function setAutoFeeTier(bool _autoFeeTier) external onlyOwner {
        autoFeeTier = _autoFeeTier;
    }

    /// @notice Find best fee tier for a token pair (checks liquidity)
    /// @dev Checks 0.01%, 0.05%, 0.3%, 1% fee tiers
    function _findBestFeeTier(address tokenIn, address tokenOut) internal view returns (uint24 bestFee) {
        if (address(uniFactory) == address(0) || !autoFeeTier) {
            return swapPoolFee; // Return default
        }

        uint24[4] memory fees = [uint24(100), uint24(500), uint24(3000), uint24(10000)];
        uint128 bestLiquidity = 0;
        bestFee = swapPoolFee; // Default fallback

        for (uint256 i = 0; i < fees.length; i++) {
            address pool = uniFactory.getPool(tokenIn, tokenOut, fees[i]);
            if (pool != address(0)) {
                try IUniswapV3Pool(pool).liquidity() returns (uint128 liq) {
                    if (liq > bestLiquidity) {
                        bestLiquidity = liq;
                        bestFee = fees[i];
                    }
                } catch {
                    continue;
                }
            }
        }
    }

    /**
     * @notice Check if strategy is initialized (required by vault)
     */
    function isInitialized() external view returns (bool) {
        return active && address(charmVault) != address(0);
    }

    function setParameters(
        uint256 _maxSwapPercent,
        uint256 _swapSlippageBps,
        uint256 _depositSlippageBps,
        uint24 _swapPoolFee
    ) external onlyOwner {
        maxSwapPercent = _maxSwapPercent;
        swapSlippageBps = _swapSlippageBps;
        depositSlippageBps = _depositSlippageBps;
        swapPoolFee = _swapPoolFee;
        
        emit ParametersUpdated(_maxSwapPercent, _swapSlippageBps);
    }

    function setActive(bool _active) external onlyOwner {
        active = _active;
    }

    function initializeApprovals() external onlyOwner {
        WLFI.forceApprove(address(UNISWAP_ROUTER), type(uint256).max);
        USD1.forceApprove(address(UNISWAP_ROUTER), type(uint256).max);
        if (address(charmVault) != address(0)) {
            WLFI.forceApprove(address(charmVault), type(uint256).max);
            USD1.forceApprove(address(charmVault), type(uint256).max);
        }
    }

    // =================================
    // DEPOSIT WITH SLIPPAGE PROTECTION
    // =================================

    function deposit(uint256 wlfiAmount, uint256 usd1Amount) 
        external 
        onlyVault
        whenActive
        nonReentrant
        returns (uint256 shares) 
    {
        if (address(charmVault) == address(0)) {
            _returnAllTokens();
            return 0;
        }

        // Pull tokens
        if (wlfiAmount > 0) {
            try WLFI.transferFrom(EAGLE_VAULT, address(this), wlfiAmount) {} catch {}
        }
        if (usd1Amount > 0) {
            try USD1.transferFrom(EAGLE_VAULT, address(this), usd1Amount) {} catch {}
        }

        uint256 totalWlfi = WLFI.balanceOf(address(this));
        uint256 totalUsd1 = USD1.balanceOf(address(this));

        if (totalWlfi == 0 && totalUsd1 == 0) return 0;

        // Get Charm vault ratio
        (uint256 charmUsd1, uint256 charmWlfi) = charmVault.getTotalAmounts();

        uint256 finalUsd1;
        uint256 finalWlfi;

        if (charmUsd1 > 0 && charmWlfi > 0) {
            // Calculate required WLFI for our USD1
            uint256 wlfiNeeded = (totalUsd1 * charmWlfi) / charmUsd1;

            if (totalWlfi >= wlfiNeeded) {
                // Have enough WLFI - use all USD1 and matching WLFI
                finalUsd1 = totalUsd1;
                finalWlfi = wlfiNeeded;
            } else if (totalWlfi > 0) {
                // Have some WLFI but not enough - calculate how much USD1 we can use
                uint256 usd1Usable = (totalWlfi * charmUsd1) / charmWlfi;
                
                // Check if we should swap some USD1 → WLFI to use more USD1
                uint256 excessUsd1 = totalUsd1 - usd1Usable;
                uint256 maxSwapUsd1 = (totalUsd1 * maxSwapPercent) / 100;
                uint256 usd1ToSwap = excessUsd1 > maxSwapUsd1 ? maxSwapUsd1 : excessUsd1;
                
                if (usd1ToSwap > 0) {
                    uint256 moreWlfi = _swapUsd1ToWlfiSafe(usd1ToSwap);
                    totalWlfi = totalWlfi + moreWlfi;
                    totalUsd1 = totalUsd1 - usd1ToSwap;
                    
                    // Recalculate with new balances
                    wlfiNeeded = (totalUsd1 * charmWlfi) / charmUsd1;
                    finalUsd1 = totalUsd1;
                    finalWlfi = totalWlfi > wlfiNeeded ? wlfiNeeded : totalWlfi;
                } else {
                    finalUsd1 = usd1Usable;
                    finalWlfi = totalWlfi;
                }
            } else {
                // No WLFI at all - swap some USD1 → WLFI
                uint256 maxSwapUsd1 = (totalUsd1 * maxSwapPercent) / 100;
                if (maxSwapUsd1 > 0) {
                    uint256 moreWlfi = _swapUsd1ToWlfiSafe(maxSwapUsd1);
                    totalWlfi = moreWlfi;
                    totalUsd1 = totalUsd1 - maxSwapUsd1;
                    
                    // Calculate how much USD1 we can use with new WLFI
                    uint256 usd1Usable = (totalWlfi * charmUsd1) / charmWlfi;
                    finalUsd1 = usd1Usable > totalUsd1 ? totalUsd1 : usd1Usable;
                    finalWlfi = totalWlfi;
                } else {
                    finalUsd1 = 0;
                    finalWlfi = 0;
                }
            }
        } else {
            // Charm empty - deposit both as-is
            finalUsd1 = totalUsd1;
            finalWlfi = totalWlfi;
        }

        // Deposit with graceful failure
        shares = _depositToCharmSafe(finalUsd1, finalWlfi);

        // Return unused
        _returnUnusedTokens();

        emit StrategyDeposit(finalWlfi, finalUsd1, shares);
    }

    /**
     * @notice Check if Charm vault is in range for deposits
     */
    function isCharmInRange() public view returns (bool inRange, int24 currentTick, int24 lower, int24 upper) {
        if (address(charmVault) == address(0)) return (false, 0, 0, 0);
        
        try charmVault.pool() returns (address poolAddr) {
            IUniswapV3Pool pool = IUniswapV3Pool(poolAddr);
            (, currentTick,,,,,) = pool.slot0();
            
            try charmVault.baseLower() returns (int24 _lower) {
                lower = _lower;
            } catch {
                lower = -887200;
            }
            
            try charmVault.baseUpper() returns (int24 _upper) {
                upper = _upper;
            } catch {
                upper = 887200;
            }
            
            inRange = currentTick >= lower && currentTick <= upper;
        } catch {
            inRange = true;
        }
    }

    /**
     * @notice Safe Charm deposit - SINGLE ATOMIC (no batching)
     */
    function _depositToCharmSafe(uint256 usd1Amount, uint256 wlfiAmount) 
        internal 
        returns (uint256 shares) 
    {
        if (usd1Amount == 0 && wlfiAmount == 0) return 0;

        // PRE-CHECK: Is Charm vault in range?
        (bool inRange,,,) = isCharmInRange();
        if (!inRange) {
            emit DepositFailed("Charm vault out of range");
            return 0;
        }

        // Calculate min amounts with slippage
        uint256 minUsd1 = (usd1Amount * (10000 - depositSlippageBps)) / 10000;
        uint256 minWlfi = (wlfiAmount * (10000 - depositSlippageBps)) / 10000;

        // SINGLE ATOMIC DEPOSIT
        try charmVault.deposit(usd1Amount, wlfiAmount, minUsd1, minWlfi, address(this)) 
            returns (uint256 _shares, uint256, uint256) 
        {
            shares = _shares;
        } catch Error(string memory reason) {
            emit DepositFailed(reason);
        } catch {
            emit DepositFailed("Deposit failed");
        }
    }

    /**
     * @notice Swap WLFI → USD1 with slippage protection
     * @dev Uses zRouter if enabled, auto fee tier if enabled, otherwise defaults
     */
    function _swapWlfiToUsd1Safe(uint256 amountIn) internal returns (uint256 amountOut) {
        if (amountIn == 0) return 0;

        // Auto-discover best fee tier if enabled
        uint24 fee = _findBestFeeTier(address(WLFI), address(USD1));

        // Calculate expected based on pool price
        uint256 wlfiPerUsd1 = _getPoolPrice();
        uint256 expectedOut = (amountIn * 1e18) / wlfiPerUsd1;
        uint256 minOut = (expectedOut * (10000 - swapSlippageBps)) / 10000;

        // Try zRouter first if enabled (8-18% gas savings)
        if (useZRouter && address(zRouter) != address(0)) {
            try zRouter.swapV3(
                address(WLFI),
                address(USD1),
                fee,
                amountIn,
                minOut,
                block.timestamp
            ) returns (uint256 out) {
                amountOut = out;
                emit TokensSwapped(address(WLFI), address(USD1), amountIn, amountOut);
                return amountOut;
            } catch {
                // Fall through to Uniswap Router
            }
        }

        // Fallback to Uniswap Router
        try UNISWAP_ROUTER.exactInputSingle(
            ISwapRouter.ExactInputSingleParams({
                tokenIn: address(WLFI),
                tokenOut: address(USD1),
                fee: fee,
                recipient: address(this),
                deadline: block.timestamp,
                amountIn: amountIn,
                amountOutMinimum: minOut,
                sqrtPriceLimitX96: 0
            })
        ) returns (uint256 out) {
            amountOut = out;
            emit TokensSwapped(address(WLFI), address(USD1), amountIn, amountOut);
        } catch {
            amountOut = 0;
        }
    }

    /**
     * @notice Swap USD1 → WLFI with slippage protection
     * @dev Uses zRouter if enabled, auto fee tier if enabled, otherwise defaults
     */
    function _swapUsd1ToWlfiSafe(uint256 amountIn) internal returns (uint256 amountOut) {
        if (amountIn == 0) return 0;

        // Auto-discover best fee tier if enabled
        uint24 fee = _findBestFeeTier(address(USD1), address(WLFI));

        // Calculate expected based on pool price (wlfiPerUsd1)
        uint256 wlfiPerUsd1 = _getPoolPrice();
        uint256 expectedOut = (amountIn * wlfiPerUsd1) / 1e18;
        uint256 minOut = (expectedOut * (10000 - swapSlippageBps)) / 10000;

        // Try zRouter first if enabled (8-18% gas savings)
        if (useZRouter && address(zRouter) != address(0)) {
            try zRouter.swapV3(
                address(USD1),
                address(WLFI),
                fee,
                amountIn,
                minOut,
                block.timestamp
            ) returns (uint256 out) {
                amountOut = out;
                emit TokensSwapped(address(USD1), address(WLFI), amountIn, amountOut);
                return amountOut;
            } catch {
                // Fall through to Uniswap Router
            }
        }

        // Fallback to Uniswap Router
        try UNISWAP_ROUTER.exactInputSingle(
            ISwapRouter.ExactInputSingleParams({
                tokenIn: address(USD1),
                tokenOut: address(WLFI),
                fee: fee,
                recipient: address(this),
                deadline: block.timestamp,
                amountIn: amountIn,
                amountOutMinimum: minOut,
                sqrtPriceLimitX96: 0
            })
        ) returns (uint256 out) {
            amountOut = out;
            emit TokensSwapped(address(USD1), address(WLFI), amountIn, amountOut);
        } catch {
            amountOut = 0;
        }
    }

    /**
     * @notice Get pool price (WLFI per USD1)
     */
    function _getPoolPrice() internal view returns (uint256 wlfiPerUsd1) {
        if (address(swapPool) == address(0)) {
            return 7e18; // Fallback ~7 WLFI per USD1
        }

        (uint160 sqrtPriceX96,,,,,,) = swapPool.slot0();
        
        uint256 price = (uint256(sqrtPriceX96) * uint256(sqrtPriceX96)) >> 192;
        
        // Adjust for token order
        if (swapPool.token0() == address(USD1)) {
            // USD1 is token0, price is WLFI per USD1
            wlfiPerUsd1 = price * 1e18;
        } else {
            // WLFI is token0, need inverse
            if (price > 0) {
                wlfiPerUsd1 = (1e18 * 1e18) / price;
            } else {
                wlfiPerUsd1 = 7e18;
            }
        }

        // Sanity check
        if (wlfiPerUsd1 == 0) wlfiPerUsd1 = 7e18;
    }

    // =================================
    // WITHDRAW
    // =================================

    function withdraw(uint256 value) 
        external 
        onlyVault
        nonReentrant
        returns (uint256 wlfiAmount, uint256 usd1Amount) 
    {
        if (address(charmVault) == address(0)) return (0, 0);

        (uint256 totalWlfi, uint256 totalUsd1) = getTotalAmounts();
        uint256 totalValue = totalWlfi + totalUsd1;
        if (totalValue == 0) return (0, 0);

        uint256 ourShares = charmVault.balanceOf(address(this));
        uint256 sharesToWithdraw = (ourShares * value) / totalValue;
        if (sharesToWithdraw > ourShares) sharesToWithdraw = ourShares;

        try charmVault.withdraw(sharesToWithdraw, 0, 0, address(this)) 
            returns (uint256 usd1Received, uint256 wlfiReceived) 
        {
            wlfiAmount = wlfiReceived;
            usd1Amount = usd1Received;

            if (wlfiAmount > 0) WLFI.safeTransfer(EAGLE_VAULT, wlfiAmount);
            if (usd1Amount > 0) USD1.safeTransfer(EAGLE_VAULT, usd1Amount);
        } catch {}

        emit StrategyWithdraw(sharesToWithdraw, wlfiAmount, usd1Amount);
    }

    // =================================
    // VIEW FUNCTIONS
    // =================================

    function getTotalAmounts() public view returns (uint256 wlfiAmount, uint256 usd1Amount) {
        if (address(charmVault) == address(0)) {
            return (WLFI.balanceOf(address(this)), USD1.balanceOf(address(this)));
        }

        uint256 ourShares = charmVault.balanceOf(address(this));
        uint256 totalShares = charmVault.totalSupply();
        
        if (totalShares == 0 || ourShares == 0) {
            return (WLFI.balanceOf(address(this)), USD1.balanceOf(address(this)));
        }

        (uint256 totalUsd1, uint256 totalWlfi) = charmVault.getTotalAmounts();
        
        uint256 ourUsd1 = (totalUsd1 * ourShares) / totalShares;
        uint256 ourWlfi = (totalWlfi * ourShares) / totalShares;

        // Convert USD1 to WLFI equivalent
        uint256 wlfiPerUsd1 = _getPoolPrice();
        uint256 usd1InWlfi = (ourUsd1 * wlfiPerUsd1) / 1e18;

        wlfiAmount = ourWlfi + usd1InWlfi + WLFI.balanceOf(address(this));
        usd1Amount = USD1.balanceOf(address(this));
    }

    // =================================
    // HELPERS
    // =================================

    function _returnAllTokens() internal {
        uint256 wlfiBal = WLFI.balanceOf(address(this));
        uint256 usd1Bal = USD1.balanceOf(address(this));
        
        if (wlfiBal > 0) WLFI.safeTransfer(EAGLE_VAULT, wlfiBal);
        if (usd1Bal > 0) USD1.safeTransfer(EAGLE_VAULT, usd1Bal);
    }

    function _returnUnusedTokens() internal {
        uint256 wlfiBal = WLFI.balanceOf(address(this));
        uint256 usd1Bal = USD1.balanceOf(address(this));
        
        if (wlfiBal > 0 || usd1Bal > 0) {
            if (wlfiBal > 0) WLFI.safeTransfer(EAGLE_VAULT, wlfiBal);
            if (usd1Bal > 0) USD1.safeTransfer(EAGLE_VAULT, usd1Bal);
            emit UnusedTokensReturned(usd1Bal, wlfiBal);
        }
    }

    // =================================
    // EMERGENCY
    // =================================

    function emergencyWithdraw(address token, address to, uint256 amount) external onlyOwner {
        IERC20(token).safeTransfer(to, amount);
    }

    function emergencyWithdrawFromCharm() external onlyOwner returns (uint256 usd1, uint256 wlfi) {
        if (address(charmVault) == address(0)) return (0, 0);
        
        uint256 ourShares = charmVault.balanceOf(address(this));
        if (ourShares > 0) {
            (usd1, wlfi) = charmVault.withdraw(ourShares, 0, 0, address(this));
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)

pragma solidity >=0.6.2;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

File 8 of 10 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)

pragma solidity >=0.4.16;

import {IERC20} from "../token/ERC20/IERC20.sol";

File 9 of 10 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)

pragma solidity >=0.4.16;

import {IERC165} from "../utils/introspection/IERC165.sol";

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Settings
{
  "remappings": [
    "@openzeppelin/=node_modules/@openzeppelin/",
    "@layerzerolabs/=node_modules/@layerzerolabs/",
    "@chainlink/=node_modules/@chainlink/",
    "@uniswap/=node_modules/@uniswap/",
    "solidity-bytes-utils/=node_modules/solidity-bytes-utils/",
    "hardhat/=node_modules/hardhat/",
    "hardhat-deploy/=node_modules/hardhat-deploy/",
    "eth-gas-reporter/=node_modules/eth-gas-reporter/",
    "base64-sol/=node_modules/base64-sol/",
    "@eth-optimism/=node_modules/@eth-optimism/",
    "@axelar-network/=node_modules/@axelar-network/",
    "forge-std/=lib/forge-std/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "prague",
  "viaIR": true
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_charmVault","type":"address"},{"internalType":"address","name":"_wlfi","type":"address"},{"internalType":"address","name":"_usd1","type":"address"},{"internalType":"address","name":"_uniswapRouter","type":"address"},{"internalType":"address","name":"_swapPool","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"NotActive","type":"error"},{"inputs":[],"name":"NotVault","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"SlippageExceeded","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"reason","type":"string"}],"name":"DepositFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxSwapPercent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"swapSlippageBps","type":"uint256"}],"name":"ParametersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"wlfiAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"usd1Amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"StrategyDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"wlfiAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"usd1Amount","type":"uint256"}],"name":"StrategyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"TokensSwapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"usd1Amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"wlfiAmount","type":"uint256"}],"name":"UnusedTokensReturned","type":"event"},{"inputs":[],"name":"EAGLE_VAULT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNISWAP_ROUTER","outputs":[{"internalType":"contract ISwapRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USD1","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WLFI","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"active","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"autoFeeTier","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"charmVault","outputs":[{"internalType":"contract ICharmVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"wlfiAmount","type":"uint256"},{"internalType":"uint256","name":"usd1Amount","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositSlippageBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyWithdrawFromCharm","outputs":[{"internalType":"uint256","name":"usd1","type":"uint256"},{"internalType":"uint256","name":"wlfi","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getTotalAmounts","outputs":[{"internalType":"uint256","name":"wlfiAmount","type":"uint256"},{"internalType":"uint256","name":"usd1Amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initializeApprovals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isCharmInRange","outputs":[{"internalType":"bool","name":"inRange","type":"bool"},{"internalType":"int24","name":"currentTick","type":"int24"},{"internalType":"int24","name":"lower","type":"int24"},{"internalType":"int24","name":"upper","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSwapPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_active","type":"bool"}],"name":"setActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_autoFeeTier","type":"bool"}],"name":"setAutoFeeTier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_charmVault","type":"address"}],"name":"setCharmVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxSwapPercent","type":"uint256"},{"internalType":"uint256","name":"_swapSlippageBps","type":"uint256"},{"internalType":"uint256","name":"_depositSlippageBps","type":"uint256"},{"internalType":"uint24","name":"_swapPoolFee","type":"uint24"}],"name":"setParameters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_swapPool","type":"address"}],"name":"setSwapPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_factory","type":"address"}],"name":"setUniFactory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_useZRouter","type":"bool"}],"name":"setUseZRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_zRouter","type":"address"}],"name":"setZRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapPool","outputs":[{"internalType":"contract IUniswapV3Pool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapPoolFee","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapSlippageBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniFactory","outputs":[{"internalType":"contract IUniswapV3Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"useZRouter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"wlfiAmount","type":"uint256"},{"internalType":"uint256","name":"usd1Amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"zRouter","outputs":[{"internalType":"contract IzRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

6101003461031457601f612b8f38819003918201601f19168301916001600160401b038311848410176103185780849260e094604052833981010312610314576100488161032c565b906100556020820161032c565b6100616040830161032c565b61006d6060840161032c565b6100796080850161032c565b9161009260c061008b60a0880161032c565b960161032c565b60015f556001600160a01b031695861561030157600180546001600160a01b03198116891790915560405197906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a36004805460ff60a01b19908116909155600580549091169055601e60065561012c6007556101f46008556009805463ffffffff19166301000bb81790556001600160a01b0381161580156102f0575b80156102df575b80156102ce575b6102bf576080526001600160a01b0390811660a05290811660c05290811660e05216806102a5575b506001600160a01b03168061028b575b5061284e90816103418239608051818181610311015281816105b6015281816108e001528181610d5a01528181610dab015281816117cc015281816117fe01528181611a7801528181611b3501528181611ca50152611cd7015260a0518181816107ba0152818161096a01528181610dcc01528181610f65015281816110ce01528181611237015281816115b301528181611b7501528181611bf2015261203d015260c051818181610841015281816109c201528181610d7b01528181610fc5015281816111230152818161128b0152818161160d01528181611ab801528181611c4801528181611f240152612018015260e0518181816103e90152818161098b015261217c0152f35b600380546001600160a01b0319169190911790555f610181565b600280546001600160a01b0319169190911790555f610171565b63d92e233d60e01b5f5260045ffd5b506001600160a01b03841615610149565b506001600160a01b03831615610142565b506001600160a01b0382161561013b565b631e4fbdf760e01b5f525f60045260245ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036103145756fe6080806040526004361015610012575f80fd5b5f3560e01c90816302fb0c5e14610a3d575080632245d26414610a1b57806327f8eaac146109505780632ae1c8ef146109335780632e1a7d4d146108cd578063339b5eac146108b0578063392e53cd14610870578063443863211461082c57806359b1707e146107e95780635e787f19146107a5578063656016cd1461078857806365861a51146107455780636c3d5eb11461072057806370e0fbef146106dd578063715018a61461068257806376771d4b1461065a57806388946252146106355780638da5cb5b1461060d578063982697dd146105e5578063a0b660b5146105a1578063acec338a1461055e578063b4abdcc4146104e0578063bc6840f91461049d578063c4a7761e14610477578063cc52e2971461043a578063cfd3542714610418578063d8264920146103d4578063e08edf5b1461038f578063e2bbb158146102fe578063e63ea408146102b1578063e6ff0a2f14610289578063f2fde38b14610203578063fb4750b3146101be5763ff99756314610192575f80fd5b346101ba575f3660031901126101ba576004546040516001600160a01b039091168152602090f35b5f80fd5b346101ba5760203660031901126101ba576004358015158091036101ba576101e4611d69565b6004805460ff60a01b191660a09290921b60ff60a01b16919091179055005b346101ba5760203660031901126101ba5761021c610a5f565b610224611d69565b6001600160a01b0316801561027657600180546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b631e4fbdf760e01b5f525f60045260245ffd5b346101ba575f3660031901126101ba576002546040516001600160a01b039091168152602090f35b346101ba5760603660031901126101ba576102ca610a5f565b602435906001600160a01b03821682036101ba576102fc916102ea611d69565b604435916001600160a01b0316611e68565b005b346101ba5760403660031901126101ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036103805760ff60095460181c161561037157610355611e4a565b602061036560243560043561157f565b60015f55604051908152f35b634065aaf160e11b5f5260045ffd5b6362df054560e01b5f5260045ffd5b346101ba5760203660031901126101ba576004358015158091036101ba576103b5611d69565b6005805460ff60a01b191660a09290921b60ff60a01b16919091179055005b346101ba575f3660031901126101ba576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101ba575f3660031901126101ba57602062ffffff60095416604051908152f35b346101ba575f3660031901126101ba576080610454611381565b91604051931515845260020b602084015260020b604083015260020b6060820152f35b346101ba575f3660031901126101ba576040610491610e6f565b82519182526020820152f35b346101ba5760203660031901126101ba576104b6610a5f565b6104be611d69565b600280546001600160a01b0319166001600160a01b0392909216919091179055005b346101ba5760803660031901126101ba57600435602435906064359062ffffff82168092036101ba577ffaccb0639ff7851e0e24f3b2d9ab03cd62ffb63f5b4d90aaeff85bb078c1fa4892604092610536611d69565b826006558160075560443560085562ffffff19600954161760095582519182526020820152a1005b346101ba5760203660031901126101ba576004358015158091036101ba57610584611d69565b63ff0000006009549160181b169063ff0000001916176009555f80f35b346101ba575f3660031901126101ba576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101ba575f3660031901126101ba576003546040516001600160a01b039091168152602090f35b346101ba575f3660031901126101ba576001546040516001600160a01b039091168152602090f35b346101ba575f3660031901126101ba57602060ff60045460a01c166040519015158152f35b346101ba575f3660031901126101ba576005546040516001600160a01b039091168152602090f35b346101ba575f3660031901126101ba5761069a611d69565b600180546001600160a01b031981169091555f906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346101ba5760203660031901126101ba576106f6610a5f565b6106fe611d69565b600380546001600160a01b0319166001600160a01b0392909216919091179055005b346101ba575f3660031901126101ba57602060ff60055460a01c166040519015158152f35b346101ba5760203660031901126101ba5761075e610a5f565b610766611d69565b600480546001600160a01b0319166001600160a01b0392909216919091179055005b346101ba575f3660031901126101ba576020600654604051908152f35b346101ba575f3660031901126101ba576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101ba5760203660031901126101ba57610802610a5f565b61080a611d69565b600580546001600160a01b0319166001600160a01b0392909216919091179055005b346101ba575f3660031901126101ba576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101ba575f3660031901126101ba5760ff60095460181c168061089c575b6020906040519015158152f35b506002546001600160a01b0316151561088f565b346101ba575f3660031901126101ba576020600854604051908152f35b346101ba5760203660031901126101ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316330361038057610916611e4a565b6040610923600435610c1a565b60015f5582519182526020820152f35b346101ba575f3660031901126101ba576020600754604051908152f35b346101ba575f3660031901126101ba57610968611d69565b7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166109bd8183611d90565b6109e87f00000000000000000000000000000000000000000000000000000000000000009182611d90565b6002546001600160a01b031691826109fc57005b6102fc92610a0991611d90565b6002546001600160a01b031690611d90565b346101ba575f3660031901126101ba57610a33611d69565b6040610491610ac1565b346101ba575f3660031901126101ba5760209060ff60095460181c1615158152f35b600435906001600160a01b03821682036101ba57565b90601f8019910116810190811067ffffffffffffffff821117610a9757604052565b634e487b7160e01b5f52604160045260245ffd5b91908260409103126101ba576020825192015190565b6002545f9182916001600160a01b03168015610bbf576040516370a0823160e01b8152306004820152602081602481855afa908115610b82575f91610b8d575b5080610b0b575050565b60409294505f93506084908351948593849263d331bef760e01b845260048401528160248401528160448401523060648401525af18015610b82575f915f91610b5357509091565b9050610b77915060403d604011610b7b575b610b6f8183610a75565b810190610aab565b9091565b503d610b65565b6040513d5f823e3d90fd5b90506020813d602011610bb7575b81610ba860209383610a75565b810103126101ba57515f610b01565b3d9150610b9b565b505f9250829150565b91908201809211610bd557565b634e487b7160e01b5f52601160045260245ffd5b81810292918115918404141715610bd557565b8115610c06570490565b634e487b7160e01b5f52601260045260245ffd5b6002545f92839290916001600160a01b03168015610e6557610c43610c3d610e6f565b90610bc8565b8015610e5a576040516370a0823160e01b815230600482015292602084602481865afa938415610b82575f94610e22575b5090610c83610c889285610be9565b610bfc565b91808311610e19575b5060405f91608482518094819363d331bef760e01b83528760048401528160248401528160448401523060648401525af190815f915f93610df6575b50610d15575b5050604080519182526020820185905281018390527f9b4015fbfa21a538378486da76932c7362cc536aa85cc6d6ddbe3a41fec4f6da9080606081015b0390a1565b90945092507f9b4015fbfa21a538378486da76932c7362cc536aa85cc6d6ddbe3a41fec4f6da908490848280610da5575b5080610d54575b5091610cd3565b610d9f907f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000611e68565b5f610d4d565b610df0907f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000611e68565b5f610d46565b909250610e12915060403d604011610b7b57610b6f8183610a75565b915f610ccd565b91506040610c91565b919093506020823d602011610e52575b81610e3f60209383610a75565b810103126101ba57905192610c83610c74565b3d9150610e32565b505f94508493505050565b505f935083925050565b6002546001600160a01b0316801561121a576040516370a0823160e01b8152306004820152602081602481855afa908115610b82575f916111e8575b506040516318160ddd60e01b8152602081600481865afa908115610b82575f916111b6575b50801580156111ae575b6110ae5760408051636253bb0f60e11b815293849060049082905afa918215610b8257610f49935f905f94611065575b5082610c8383610f2d670de0b6b3a764000096610c83610f4297610f3397610be9565b96610be9565b92610f3c611ea3565b90610be9565b0490610bc8565b6040516370a0823160e01b8152306004820152906020826024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610b82575f9161102f575b610fa79250610bc8565b6040516370a0823160e01b81523060048201529091906020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610b82575f91611000575090565b90506020813d602011611027575b8161101b60209383610a75565b810103126101ba575190565b3d915061100e565b90506020823d60201161105d575b8161104a60209383610a75565b810103126101ba57610fa7915190610f9d565b3d915061103d565b829450610f33915092610c83610f4293610f2d83610c8361109d670de0b6b3a76400009960403d604011610b7b57610b6f8183610a75565b9a9097505050965050935050610f0a565b50506040516370a0823160e01b81523060048201529190506020826024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa918215610b82575f9261117a575b506040516370a0823160e01b8152306004820152916020836024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa928315610b82575f9361115f57509190565b9092506020813d602011611027578161101b60209383610a75565b9091506020813d6020116111a6575b8161119660209383610a75565b810103126101ba5751905f611106565b3d9150611189565b508115610eda565b90506020813d6020116111e0575b816111d160209383610a75565b810103126101ba57515f610ed0565b3d91506111c4565b90506020813d602011611212575b8161120360209383610a75565b810103126101ba57515f610eab565b3d91506111f6565b506040516370a0823160e01b8152306004820152906020826024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa918215610b82575f9261117a57506040516370a0823160e01b8152306004820152916020836024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa928315610b82575f9361115f57509190565b908160209103126101ba57516001600160a01b03811681036101ba5790565b51908160020b82036101ba57565b519061ffff821682036101ba57565b519081151582036101ba57565b908160e09103126101ba5780516001600160a01b03811681036101ba579161133a602083016112e6565b91611347604082016112f4565b91611354606083016112f4565b91611361608082016112f4565b9160a082015160ff811681036101ba5760c061137e919301611303565b90565b6002545f90819081906001600160a01b03168015611564576040516316f0115b60e01b8152602081600481855afa5f9181611533575b506113c3575050600193565b604051633850c7bd60e01b8152945090925060e09150839060049082906001600160a01b03165afa918215610b82575f926114fb575b5060405163fa08274360e01b81528290602081600481865afa5f91816114bf575b506114b4575060046020620d899f19935b604051632222a44d60e21b815292839182905afa5f9181611478575b506114725750620d89a0905b60020b8260020b8112159081611467575093565b90508160020b121593565b90611453565b9091506020813d6020116114ac575b8161149460209383610a75565b810103126101ba576114a5906112e6565b905f611447565b3d9150611487565b60206004919361142b565b9091506020813d6020116114f3575b816114db60209383610a75565b810103126101ba576114ec906112e6565b905f61141a565b3d91506114ce565b61151e91925060e03d60e01161152c575b6115168183610a75565b810190611310565b50505050509050905f6113f9565b503d61150c565b61155691925060203d60201161155d575b61154e8183610a75565b8101906112c7565b905f6113b7565b503d611544565b505050505f905f905f905f90565b91908203918211610bd557565b6002546001600160a01b031615611bdb5780611b1e575b5080611a61575b506040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038116929190602082602481875afa918215610b82575f92611a2d575b506040516370a0823160e01b8152306004820152907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0381169190602084602481865afa938415610b82575f946119f9575b5084159384806119f1575b6119e65760025460408051636253bb0f60e11b815291829060049082906001600160a01b03165afa908115610b82576024975f915f936119c3575b50811515806119ba575b156119af576116b282610c838587610be9565b978882106118bc575050505093925b60206116cd85876123a6565b98604051978880926370a0823160e01b82523060048301525afa958615610b82575f96611887575b50946020602496604051978880926370a0823160e01b82523060048301525afa908115610b82575f91611833575b7fe92d6d2dfb3946d2655ac9a4ed7e724c4bcf0d2d993c5ab9b70e9a4785bd205596508015928315809461182a575b61177b575b50506040805194855260208501959095525050509081018490528060608101610d10565b7f4f3aef3cf11fd9405846420fd580666c49868d4f5c814b48ec46092b91a1b9cb94826040956117f8575b505082806117c6575b505082519182526020820152a15f80808080611757565b6117f1917f000000000000000000000000000000000000000000000000000000000000000090611e68565b5f826117af565b611823917f000000000000000000000000000000000000000000000000000000000000000090611e68565b5f826117a6565b50821515611752565b90506020863d60201161187f575b8161184e60209383610a75565b810103126101ba577fe92d6d2dfb3946d2655ac9a4ed7e724c4bcf0d2d993c5ab9b70e9a4785bd2055955190611723565b3d9150611841565b95506020863d6020116118b4575b816118a260209383610a75565b810103126101ba5794519460206116f5565b3d9150611895565b909192939750155f14611957576118d783610c838484610be9565b906118e28289611572565b60646118f06006548b610be9565b04908181111561194f5750915b821561194257506119228261191c610c8393610c3d6119299796612007565b99611572565b9384610be9565b90948181111561193b57505b926116c1565b9050611935565b93509650505093926116c1565b9050916118fd565b5090606461196760065488610be9565b0480156119a15790610c836119828361191c61198995612007565b9388610be9565b8181111561199a57505b93926116c1565b9050611993565b50505092505f925f926116c1565b9650505093926116c1565b5082151561169f565b9092506119df915060403d604011610b7b57610b6f8183610a75565b915f611695565b505f96505050505050565b50801561165a565b9093506020813d602011611a25575b81611a1560209383610a75565b810103126101ba5751925f61164f565b3d9150611a08565b9091506020813d602011611a59575b81611a4960209383610a75565b810103126101ba5751905f6115f6565b3d9150611a3c565b6040516323b872dd60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660048201523060248201526044810191909152602081806064810103815f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af11561159d576020813d602011611b16575b81611b0060209383610a75565b810103126101ba57611b1190611303565b61159d565b3d9150611af3565b6040516323b872dd60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660048201523060248201526044810191909152602081806064810103815f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af115611596576020813d602011611bd3575b81611bbd60209383610a75565b810103126101ba57611bce90611303565b611596565b3d9150611bb0565b50506040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906020816024816001600160a01b0386165afa908115610b82575f91611d37575b506040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000009290916020836024816001600160a01b0388165afa928315610b82575f93611d03575b5080611cd1575b505080611c9f575b50505f90565b611cca917f000000000000000000000000000000000000000000000000000000000000000090611e68565b5f80611c99565b611cfc917f000000000000000000000000000000000000000000000000000000000000000090611e68565b5f80611c91565b9092506020813d602011611d2f575b81611d1f60209383610a75565b810103126101ba5751915f611c8a565b3d9150611d12565b90506020813d602011611d61575b81611d5260209383610a75565b810103126101ba57515f611c32565b3d9150611d45565b6001546001600160a01b03163303611d7d57565b63118cdaa760e01b5f523360045260245ffd5b6040519060205f8184019463095ea7b360e01b865260018060a01b0316948560248601528119604486015260448552611dca606486610a75565b84519082855af15f513d82611e25575b505015611de657505050565b611e1e611e23936040519063095ea7b360e01b602083015260248201525f604482015260448152611e18606482610a75565b826125cc565b6125cc565b565b909150611e4257506001600160a01b0381163b15155b5f80611dda565b600114611e3b565b60025f5414611e595760025f55565b633ee5aeb560e01b5f5260045ffd5b60405163a9059cbb60e01b60208201526001600160a01b039092166024830152604480830193909352918152611e2391611e1e606483610a75565b6003546001600160a01b03168015611ffa57604051633850c7bd60e01b815260e081600481855afa8015610b8257611ef16020916004935f91611fd5575b506001600160a01b031680610be9565b60c01c9260405192838092630dfe168160e01b82525afa908115610b82575f91611fb6575b506001600160a01b039081167f000000000000000000000000000000000000000000000000000000000000000090911603611f8357670de0b6b3a7640000810290808204670de0b6b3a76400001490151715610bd557905b8115611f7657565b676124fee993bc00009150565b801580611fa557610c06576ec097ce7bc90715b34b9f10000000000490611f6e565b5050676124fee993bc000090611f6e565b611fcf915060203d60201161155d5761154e8183610a75565b5f611f16565b611fee915060e03d60e01161152c576115168183610a75565b5050505050505f611ee1565b50676124fee993bc000090565b90811561232d576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811692907f0000000000000000000000000000000000000000000000000000000000000000166120678185612649565b93670de0b6b3a764000061208261207c611ea3565b85610be9565b0460075461271003906127108211610bd557612710916120a191610be9565b0460045460ff8160a01c168061231b575b61223a575b506040519061010082019682881067ffffffffffffffff891117610a97576040978852838352602080840186815262ffffff928316858b019081523060608701908152426080880190815260a088018b815260c089019788525f60e08a018181529e5163414bf38960e01b815299516001600160a01b0390811660048c01529551861660248b015293519096166044890152905183166064880152516084870152925160a4860152925160c48501529751821660e484015291969187916101049183917f0000000000000000000000000000000000000000000000000000000000000000165af15f9581612206575b506121b357505f93505050565b604080516001600160a01b039283168152929091166020830152810191909152606081018390527f25f1d03755df23c30e25db2dbd3891e31ce084bdfbfc46f9fe5e446ee5f9b2d4908060808101610d10565b9095506020813d602011612232575b8161222260209383610a75565b810103126101ba5751945f6121a6565b3d9150612215565b60205f9160c460405180948193631ae498b760e21b835288600484015289602484015262ffffff8d1660448401528a60648401528760848401524260a484015260018060a01b03165af15f91816122e7575b50156120b757604080516001600160a01b03948516815294909316602085015291830193909352606082018190529293507f25f1d03755df23c30e25db2dbd3891e31ce084bdfbfc46f9fe5e446ee5f9b2d49150608090a190565b9091506020813d602011612313575b8161230360209383610a75565b810103126101ba5751905f61228c565b3d91506122f6565b506001600160a01b03811615156120b2565b5f9150565b5f60443d1061137e576040513d600319016004823e8051913d602484011167ffffffffffffffff8411176123a0578282019283519167ffffffffffffffff8311612398573d84016003190185840160200111612398575061137e92910160200190610a75565b949350505050565b92915050565b91905f928015806125c4575b6125bd576123be611381565b5050501561255d5760085461271003916127108311610bd55760a4825f6127106123f6816123ee89606099610be9565b049786610be9565b0460018060a01b036002541690604051978896879563365d0ed760e01b875260048701526024860152604485015260648401523060848401525af15f9181612529575b50612525575060015f60033d11612515575b6308c379a0146124a7575b61245c57565b7f63299ad14374170063e6f2e5559417926f3a23da67eefa83fc2e9bf9f21e915c606060405160208152600e60208201526d11195c1bdcda5d0819985a5b195960921b6040820152a1565b6124af612332565b806124bb575b50612456565b90507f63299ad14374170063e6f2e5559417926f3a23da67eefa83fc2e9bf9f21e915c602060405f93815192839181835280519182918282860152018484015e5f828201840152601f01601f19168101030190a15f6124b5565b5060045f803e5f5160e01c61244b565b9150565b9091506060813d606011612555575b8161254560609383610a75565b810103126101ba5751905f612439565b3d9150612538565b505090507f63299ad14374170063e6f2e5559417926f3a23da67eefa83fc2e9bf9f21e915c606060405160208152601860208201527f436861726d207661756c74206f7574206f662072616e676500000000000000006040820152a15f90565b505f925050565b5081156123b2565b905f602091828151910182855af115610b82575f513d61261b57506001600160a01b0381163b155b6125fb5750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b600114156125f4565b9060048110156126355760051b0190565b634e487b7160e01b5f52603260045260245ffd5b6005549192916001600160a01b03811691908215908115612809575b506127fb576040516080810181811067ffffffffffffffff821117610a9757604052606481526101f46020820152610bb8604082015261271060608201525f9262ffffff60095416955f5b600481106126c057505050505050565b62ffffff6126ce8286612624565b51604051630b4c774160e11b81526001600160a01b0388811660048301528516602482015291166044820152602081606481875afa908115610b82575f916127dd575b506001600160a01b03168061272c575b506001905b016126b0565b602060049160405192838092630d34328160e11b82525afa5f918161279a575b5061275a5750600190612726565b6001600160801b0387166001600160801b0382161161277c575b506001612721565b9097509450600162ffffff6127918986612624565b51169790612774565b9091506020813d82116127d5575b816127b560209383610a75565b810103126101ba57516001600160801b03811681036101ba57905f61274c565b3d91506127a8565b6127f5915060203d811161155d5761154e8183610a75565b5f612711565b505060095462ffffff169150565b60ff915060a01c16155f61266556fea264697066735822122091b02f9145b50efb974d484b32e10de76f31eeb9c8113fe8b530b1181964316064736f6c634300081e003300000000000000000000000047b3ef629d9cb8dfcf8a6c61058338f4e99d795300000000000000000000000022828dbf15f5fba2394ba7cf8fa9a96bdb444b71000000000000000000000000da5e1988097297dcdc1f90d4dfe7909e847cbef60000000000000000000000008d0d000ee44948fc98c9b98a4fa4921476f08b0d000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564000000000000000000000000f9f5e6f7a44ee10c72e67bded6654afaf4d0c85d0000000000000000000000007310dd6ef89b7f829839f140c6840bc929ba2031

Deployed Bytecode

0x6080806040526004361015610012575f80fd5b5f3560e01c90816302fb0c5e14610a3d575080632245d26414610a1b57806327f8eaac146109505780632ae1c8ef146109335780632e1a7d4d146108cd578063339b5eac146108b0578063392e53cd14610870578063443863211461082c57806359b1707e146107e95780635e787f19146107a5578063656016cd1461078857806365861a51146107455780636c3d5eb11461072057806370e0fbef146106dd578063715018a61461068257806376771d4b1461065a57806388946252146106355780638da5cb5b1461060d578063982697dd146105e5578063a0b660b5146105a1578063acec338a1461055e578063b4abdcc4146104e0578063bc6840f91461049d578063c4a7761e14610477578063cc52e2971461043a578063cfd3542714610418578063d8264920146103d4578063e08edf5b1461038f578063e2bbb158146102fe578063e63ea408146102b1578063e6ff0a2f14610289578063f2fde38b14610203578063fb4750b3146101be5763ff99756314610192575f80fd5b346101ba575f3660031901126101ba576004546040516001600160a01b039091168152602090f35b5f80fd5b346101ba5760203660031901126101ba576004358015158091036101ba576101e4611d69565b6004805460ff60a01b191660a09290921b60ff60a01b16919091179055005b346101ba5760203660031901126101ba5761021c610a5f565b610224611d69565b6001600160a01b0316801561027657600180546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b631e4fbdf760e01b5f525f60045260245ffd5b346101ba575f3660031901126101ba576002546040516001600160a01b039091168152602090f35b346101ba5760603660031901126101ba576102ca610a5f565b602435906001600160a01b03821682036101ba576102fc916102ea611d69565b604435916001600160a01b0316611e68565b005b346101ba5760403660031901126101ba577f00000000000000000000000047b3ef629d9cb8dfcf8a6c61058338f4e99d79536001600160a01b031633036103805760ff60095460181c161561037157610355611e4a565b602061036560243560043561157f565b60015f55604051908152f35b634065aaf160e11b5f5260045ffd5b6362df054560e01b5f5260045ffd5b346101ba5760203660031901126101ba576004358015158091036101ba576103b5611d69565b6005805460ff60a01b191660a09290921b60ff60a01b16919091179055005b346101ba575f3660031901126101ba576040517f000000000000000000000000e592427a0aece92de3edee1f18e0157c058615646001600160a01b03168152602090f35b346101ba575f3660031901126101ba57602062ffffff60095416604051908152f35b346101ba575f3660031901126101ba576080610454611381565b91604051931515845260020b602084015260020b604083015260020b6060820152f35b346101ba575f3660031901126101ba576040610491610e6f565b82519182526020820152f35b346101ba5760203660031901126101ba576104b6610a5f565b6104be611d69565b600280546001600160a01b0319166001600160a01b0392909216919091179055005b346101ba5760803660031901126101ba57600435602435906064359062ffffff82168092036101ba577ffaccb0639ff7851e0e24f3b2d9ab03cd62ffb63f5b4d90aaeff85bb078c1fa4892604092610536611d69565b826006558160075560443560085562ffffff19600954161760095582519182526020820152a1005b346101ba5760203660031901126101ba576004358015158091036101ba57610584611d69565b63ff0000006009549160181b169063ff0000001916176009555f80f35b346101ba575f3660031901126101ba576040517f00000000000000000000000047b3ef629d9cb8dfcf8a6c61058338f4e99d79536001600160a01b03168152602090f35b346101ba575f3660031901126101ba576003546040516001600160a01b039091168152602090f35b346101ba575f3660031901126101ba576001546040516001600160a01b039091168152602090f35b346101ba575f3660031901126101ba57602060ff60045460a01c166040519015158152f35b346101ba575f3660031901126101ba576005546040516001600160a01b039091168152602090f35b346101ba575f3660031901126101ba5761069a611d69565b600180546001600160a01b031981169091555f906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346101ba5760203660031901126101ba576106f6610a5f565b6106fe611d69565b600380546001600160a01b0319166001600160a01b0392909216919091179055005b346101ba575f3660031901126101ba57602060ff60055460a01c166040519015158152f35b346101ba5760203660031901126101ba5761075e610a5f565b610766611d69565b600480546001600160a01b0319166001600160a01b0392909216919091179055005b346101ba575f3660031901126101ba576020600654604051908152f35b346101ba575f3660031901126101ba576040517f000000000000000000000000da5e1988097297dcdc1f90d4dfe7909e847cbef66001600160a01b03168152602090f35b346101ba5760203660031901126101ba57610802610a5f565b61080a611d69565b600580546001600160a01b0319166001600160a01b0392909216919091179055005b346101ba575f3660031901126101ba576040517f0000000000000000000000008d0d000ee44948fc98c9b98a4fa4921476f08b0d6001600160a01b03168152602090f35b346101ba575f3660031901126101ba5760ff60095460181c168061089c575b6020906040519015158152f35b506002546001600160a01b0316151561088f565b346101ba575f3660031901126101ba576020600854604051908152f35b346101ba5760203660031901126101ba577f00000000000000000000000047b3ef629d9cb8dfcf8a6c61058338f4e99d79536001600160a01b0316330361038057610916611e4a565b6040610923600435610c1a565b60015f5582519182526020820152f35b346101ba575f3660031901126101ba576020600754604051908152f35b346101ba575f3660031901126101ba57610968611d69565b7f000000000000000000000000da5e1988097297dcdc1f90d4dfe7909e847cbef67f000000000000000000000000e592427a0aece92de3edee1f18e0157c058615646001600160a01b03166109bd8183611d90565b6109e87f0000000000000000000000008d0d000ee44948fc98c9b98a4fa4921476f08b0d9182611d90565b6002546001600160a01b031691826109fc57005b6102fc92610a0991611d90565b6002546001600160a01b031690611d90565b346101ba575f3660031901126101ba57610a33611d69565b6040610491610ac1565b346101ba575f3660031901126101ba5760209060ff60095460181c1615158152f35b600435906001600160a01b03821682036101ba57565b90601f8019910116810190811067ffffffffffffffff821117610a9757604052565b634e487b7160e01b5f52604160045260245ffd5b91908260409103126101ba576020825192015190565b6002545f9182916001600160a01b03168015610bbf576040516370a0823160e01b8152306004820152602081602481855afa908115610b82575f91610b8d575b5080610b0b575050565b60409294505f93506084908351948593849263d331bef760e01b845260048401528160248401528160448401523060648401525af18015610b82575f915f91610b5357509091565b9050610b77915060403d604011610b7b575b610b6f8183610a75565b810190610aab565b9091565b503d610b65565b6040513d5f823e3d90fd5b90506020813d602011610bb7575b81610ba860209383610a75565b810103126101ba57515f610b01565b3d9150610b9b565b505f9250829150565b91908201809211610bd557565b634e487b7160e01b5f52601160045260245ffd5b81810292918115918404141715610bd557565b8115610c06570490565b634e487b7160e01b5f52601260045260245ffd5b6002545f92839290916001600160a01b03168015610e6557610c43610c3d610e6f565b90610bc8565b8015610e5a576040516370a0823160e01b815230600482015292602084602481865afa938415610b82575f94610e22575b5090610c83610c889285610be9565b610bfc565b91808311610e19575b5060405f91608482518094819363d331bef760e01b83528760048401528160248401528160448401523060648401525af190815f915f93610df6575b50610d15575b5050604080519182526020820185905281018390527f9b4015fbfa21a538378486da76932c7362cc536aa85cc6d6ddbe3a41fec4f6da9080606081015b0390a1565b90945092507f9b4015fbfa21a538378486da76932c7362cc536aa85cc6d6ddbe3a41fec4f6da908490848280610da5575b5080610d54575b5091610cd3565b610d9f907f00000000000000000000000047b3ef629d9cb8dfcf8a6c61058338f4e99d79537f0000000000000000000000008d0d000ee44948fc98c9b98a4fa4921476f08b0d611e68565b5f610d4d565b610df0907f00000000000000000000000047b3ef629d9cb8dfcf8a6c61058338f4e99d79537f000000000000000000000000da5e1988097297dcdc1f90d4dfe7909e847cbef6611e68565b5f610d46565b909250610e12915060403d604011610b7b57610b6f8183610a75565b915f610ccd565b91506040610c91565b919093506020823d602011610e52575b81610e3f60209383610a75565b810103126101ba57905192610c83610c74565b3d9150610e32565b505f94508493505050565b505f935083925050565b6002546001600160a01b0316801561121a576040516370a0823160e01b8152306004820152602081602481855afa908115610b82575f916111e8575b506040516318160ddd60e01b8152602081600481865afa908115610b82575f916111b6575b50801580156111ae575b6110ae5760408051636253bb0f60e11b815293849060049082905afa918215610b8257610f49935f905f94611065575b5082610c8383610f2d670de0b6b3a764000096610c83610f4297610f3397610be9565b96610be9565b92610f3c611ea3565b90610be9565b0490610bc8565b6040516370a0823160e01b8152306004820152906020826024817f000000000000000000000000da5e1988097297dcdc1f90d4dfe7909e847cbef66001600160a01b03165afa908115610b82575f9161102f575b610fa79250610bc8565b6040516370a0823160e01b81523060048201529091906020816024817f0000000000000000000000008d0d000ee44948fc98c9b98a4fa4921476f08b0d6001600160a01b03165afa908115610b82575f91611000575090565b90506020813d602011611027575b8161101b60209383610a75565b810103126101ba575190565b3d915061100e565b90506020823d60201161105d575b8161104a60209383610a75565b810103126101ba57610fa7915190610f9d565b3d915061103d565b829450610f33915092610c83610f4293610f2d83610c8361109d670de0b6b3a76400009960403d604011610b7b57610b6f8183610a75565b9a9097505050965050935050610f0a565b50506040516370a0823160e01b81523060048201529190506020826024817f000000000000000000000000da5e1988097297dcdc1f90d4dfe7909e847cbef66001600160a01b03165afa918215610b82575f9261117a575b506040516370a0823160e01b8152306004820152916020836024817f0000000000000000000000008d0d000ee44948fc98c9b98a4fa4921476f08b0d6001600160a01b03165afa928315610b82575f9361115f57509190565b9092506020813d602011611027578161101b60209383610a75565b9091506020813d6020116111a6575b8161119660209383610a75565b810103126101ba5751905f611106565b3d9150611189565b508115610eda565b90506020813d6020116111e0575b816111d160209383610a75565b810103126101ba57515f610ed0565b3d91506111c4565b90506020813d602011611212575b8161120360209383610a75565b810103126101ba57515f610eab565b3d91506111f6565b506040516370a0823160e01b8152306004820152906020826024817f000000000000000000000000da5e1988097297dcdc1f90d4dfe7909e847cbef66001600160a01b03165afa918215610b82575f9261117a57506040516370a0823160e01b8152306004820152916020836024817f0000000000000000000000008d0d000ee44948fc98c9b98a4fa4921476f08b0d6001600160a01b03165afa928315610b82575f9361115f57509190565b908160209103126101ba57516001600160a01b03811681036101ba5790565b51908160020b82036101ba57565b519061ffff821682036101ba57565b519081151582036101ba57565b908160e09103126101ba5780516001600160a01b03811681036101ba579161133a602083016112e6565b91611347604082016112f4565b91611354606083016112f4565b91611361608082016112f4565b9160a082015160ff811681036101ba5760c061137e919301611303565b90565b6002545f90819081906001600160a01b03168015611564576040516316f0115b60e01b8152602081600481855afa5f9181611533575b506113c3575050600193565b604051633850c7bd60e01b8152945090925060e09150839060049082906001600160a01b03165afa918215610b82575f926114fb575b5060405163fa08274360e01b81528290602081600481865afa5f91816114bf575b506114b4575060046020620d899f19935b604051632222a44d60e21b815292839182905afa5f9181611478575b506114725750620d89a0905b60020b8260020b8112159081611467575093565b90508160020b121593565b90611453565b9091506020813d6020116114ac575b8161149460209383610a75565b810103126101ba576114a5906112e6565b905f611447565b3d9150611487565b60206004919361142b565b9091506020813d6020116114f3575b816114db60209383610a75565b810103126101ba576114ec906112e6565b905f61141a565b3d91506114ce565b61151e91925060e03d60e01161152c575b6115168183610a75565b810190611310565b50505050509050905f6113f9565b503d61150c565b61155691925060203d60201161155d575b61154e8183610a75565b8101906112c7565b905f6113b7565b503d611544565b505050505f905f905f905f90565b91908203918211610bd557565b6002546001600160a01b031615611bdb5780611b1e575b5080611a61575b506040516370a0823160e01b81523060048201527f000000000000000000000000da5e1988097297dcdc1f90d4dfe7909e847cbef66001600160a01b038116929190602082602481875afa918215610b82575f92611a2d575b506040516370a0823160e01b8152306004820152907f0000000000000000000000008d0d000ee44948fc98c9b98a4fa4921476f08b0d6001600160a01b0381169190602084602481865afa938415610b82575f946119f9575b5084159384806119f1575b6119e65760025460408051636253bb0f60e11b815291829060049082906001600160a01b03165afa908115610b82576024975f915f936119c3575b50811515806119ba575b156119af576116b282610c838587610be9565b978882106118bc575050505093925b60206116cd85876123a6565b98604051978880926370a0823160e01b82523060048301525afa958615610b82575f96611887575b50946020602496604051978880926370a0823160e01b82523060048301525afa908115610b82575f91611833575b7fe92d6d2dfb3946d2655ac9a4ed7e724c4bcf0d2d993c5ab9b70e9a4785bd205596508015928315809461182a575b61177b575b50506040805194855260208501959095525050509081018490528060608101610d10565b7f4f3aef3cf11fd9405846420fd580666c49868d4f5c814b48ec46092b91a1b9cb94826040956117f8575b505082806117c6575b505082519182526020820152a15f80808080611757565b6117f1917f00000000000000000000000047b3ef629d9cb8dfcf8a6c61058338f4e99d795390611e68565b5f826117af565b611823917f00000000000000000000000047b3ef629d9cb8dfcf8a6c61058338f4e99d795390611e68565b5f826117a6565b50821515611752565b90506020863d60201161187f575b8161184e60209383610a75565b810103126101ba577fe92d6d2dfb3946d2655ac9a4ed7e724c4bcf0d2d993c5ab9b70e9a4785bd2055955190611723565b3d9150611841565b95506020863d6020116118b4575b816118a260209383610a75565b810103126101ba5794519460206116f5565b3d9150611895565b909192939750155f14611957576118d783610c838484610be9565b906118e28289611572565b60646118f06006548b610be9565b04908181111561194f5750915b821561194257506119228261191c610c8393610c3d6119299796612007565b99611572565b9384610be9565b90948181111561193b57505b926116c1565b9050611935565b93509650505093926116c1565b9050916118fd565b5090606461196760065488610be9565b0480156119a15790610c836119828361191c61198995612007565b9388610be9565b8181111561199a57505b93926116c1565b9050611993565b50505092505f925f926116c1565b9650505093926116c1565b5082151561169f565b9092506119df915060403d604011610b7b57610b6f8183610a75565b915f611695565b505f96505050505050565b50801561165a565b9093506020813d602011611a25575b81611a1560209383610a75565b810103126101ba5751925f61164f565b3d9150611a08565b9091506020813d602011611a59575b81611a4960209383610a75565b810103126101ba5751905f6115f6565b3d9150611a3c565b6040516323b872dd60e01b81526001600160a01b037f00000000000000000000000047b3ef629d9cb8dfcf8a6c61058338f4e99d79531660048201523060248201526044810191909152602081806064810103815f7f0000000000000000000000008d0d000ee44948fc98c9b98a4fa4921476f08b0d6001600160a01b03165af11561159d576020813d602011611b16575b81611b0060209383610a75565b810103126101ba57611b1190611303565b61159d565b3d9150611af3565b6040516323b872dd60e01b81526001600160a01b037f00000000000000000000000047b3ef629d9cb8dfcf8a6c61058338f4e99d79531660048201523060248201526044810191909152602081806064810103815f7f000000000000000000000000da5e1988097297dcdc1f90d4dfe7909e847cbef66001600160a01b03165af115611596576020813d602011611bd3575b81611bbd60209383610a75565b810103126101ba57611bce90611303565b611596565b3d9150611bb0565b50506040516370a0823160e01b81523060048201527f000000000000000000000000da5e1988097297dcdc1f90d4dfe7909e847cbef6906020816024816001600160a01b0386165afa908115610b82575f91611d37575b506040516370a0823160e01b81523060048201527f0000000000000000000000008d0d000ee44948fc98c9b98a4fa4921476f08b0d9290916020836024816001600160a01b0388165afa928315610b82575f93611d03575b5080611cd1575b505080611c9f575b50505f90565b611cca917f00000000000000000000000047b3ef629d9cb8dfcf8a6c61058338f4e99d795390611e68565b5f80611c99565b611cfc917f00000000000000000000000047b3ef629d9cb8dfcf8a6c61058338f4e99d795390611e68565b5f80611c91565b9092506020813d602011611d2f575b81611d1f60209383610a75565b810103126101ba5751915f611c8a565b3d9150611d12565b90506020813d602011611d61575b81611d5260209383610a75565b810103126101ba57515f611c32565b3d9150611d45565b6001546001600160a01b03163303611d7d57565b63118cdaa760e01b5f523360045260245ffd5b6040519060205f8184019463095ea7b360e01b865260018060a01b0316948560248601528119604486015260448552611dca606486610a75565b84519082855af15f513d82611e25575b505015611de657505050565b611e1e611e23936040519063095ea7b360e01b602083015260248201525f604482015260448152611e18606482610a75565b826125cc565b6125cc565b565b909150611e4257506001600160a01b0381163b15155b5f80611dda565b600114611e3b565b60025f5414611e595760025f55565b633ee5aeb560e01b5f5260045ffd5b60405163a9059cbb60e01b60208201526001600160a01b039092166024830152604480830193909352918152611e2391611e1e606483610a75565b6003546001600160a01b03168015611ffa57604051633850c7bd60e01b815260e081600481855afa8015610b8257611ef16020916004935f91611fd5575b506001600160a01b031680610be9565b60c01c9260405192838092630dfe168160e01b82525afa908115610b82575f91611fb6575b506001600160a01b039081167f0000000000000000000000008d0d000ee44948fc98c9b98a4fa4921476f08b0d90911603611f8357670de0b6b3a7640000810290808204670de0b6b3a76400001490151715610bd557905b8115611f7657565b676124fee993bc00009150565b801580611fa557610c06576ec097ce7bc90715b34b9f10000000000490611f6e565b5050676124fee993bc000090611f6e565b611fcf915060203d60201161155d5761154e8183610a75565b5f611f16565b611fee915060e03d60e01161152c576115168183610a75565b5050505050505f611ee1565b50676124fee993bc000090565b90811561232d576001600160a01b037f0000000000000000000000008d0d000ee44948fc98c9b98a4fa4921476f08b0d811692907f000000000000000000000000da5e1988097297dcdc1f90d4dfe7909e847cbef6166120678185612649565b93670de0b6b3a764000061208261207c611ea3565b85610be9565b0460075461271003906127108211610bd557612710916120a191610be9565b0460045460ff8160a01c168061231b575b61223a575b506040519061010082019682881067ffffffffffffffff891117610a97576040978852838352602080840186815262ffffff928316858b019081523060608701908152426080880190815260a088018b815260c089019788525f60e08a018181529e5163414bf38960e01b815299516001600160a01b0390811660048c01529551861660248b015293519096166044890152905183166064880152516084870152925160a4860152925160c48501529751821660e484015291969187916101049183917f000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564165af15f9581612206575b506121b357505f93505050565b604080516001600160a01b039283168152929091166020830152810191909152606081018390527f25f1d03755df23c30e25db2dbd3891e31ce084bdfbfc46f9fe5e446ee5f9b2d4908060808101610d10565b9095506020813d602011612232575b8161222260209383610a75565b810103126101ba5751945f6121a6565b3d9150612215565b60205f9160c460405180948193631ae498b760e21b835288600484015289602484015262ffffff8d1660448401528a60648401528760848401524260a484015260018060a01b03165af15f91816122e7575b50156120b757604080516001600160a01b03948516815294909316602085015291830193909352606082018190529293507f25f1d03755df23c30e25db2dbd3891e31ce084bdfbfc46f9fe5e446ee5f9b2d49150608090a190565b9091506020813d602011612313575b8161230360209383610a75565b810103126101ba5751905f61228c565b3d91506122f6565b506001600160a01b03811615156120b2565b5f9150565b5f60443d1061137e576040513d600319016004823e8051913d602484011167ffffffffffffffff8411176123a0578282019283519167ffffffffffffffff8311612398573d84016003190185840160200111612398575061137e92910160200190610a75565b949350505050565b92915050565b91905f928015806125c4575b6125bd576123be611381565b5050501561255d5760085461271003916127108311610bd55760a4825f6127106123f6816123ee89606099610be9565b049786610be9565b0460018060a01b036002541690604051978896879563365d0ed760e01b875260048701526024860152604485015260648401523060848401525af15f9181612529575b50612525575060015f60033d11612515575b6308c379a0146124a7575b61245c57565b7f63299ad14374170063e6f2e5559417926f3a23da67eefa83fc2e9bf9f21e915c606060405160208152600e60208201526d11195c1bdcda5d0819985a5b195960921b6040820152a1565b6124af612332565b806124bb575b50612456565b90507f63299ad14374170063e6f2e5559417926f3a23da67eefa83fc2e9bf9f21e915c602060405f93815192839181835280519182918282860152018484015e5f828201840152601f01601f19168101030190a15f6124b5565b5060045f803e5f5160e01c61244b565b9150565b9091506060813d606011612555575b8161254560609383610a75565b810103126101ba5751905f612439565b3d9150612538565b505090507f63299ad14374170063e6f2e5559417926f3a23da67eefa83fc2e9bf9f21e915c606060405160208152601860208201527f436861726d207661756c74206f7574206f662072616e676500000000000000006040820152a15f90565b505f925050565b5081156123b2565b905f602091828151910182855af115610b82575f513d61261b57506001600160a01b0381163b155b6125fb5750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b600114156125f4565b9060048110156126355760051b0190565b634e487b7160e01b5f52603260045260245ffd5b6005549192916001600160a01b03811691908215908115612809575b506127fb576040516080810181811067ffffffffffffffff821117610a9757604052606481526101f46020820152610bb8604082015261271060608201525f9262ffffff60095416955f5b600481106126c057505050505050565b62ffffff6126ce8286612624565b51604051630b4c774160e11b81526001600160a01b0388811660048301528516602482015291166044820152602081606481875afa908115610b82575f916127dd575b506001600160a01b03168061272c575b506001905b016126b0565b602060049160405192838092630d34328160e11b82525afa5f918161279a575b5061275a5750600190612726565b6001600160801b0387166001600160801b0382161161277c575b506001612721565b9097509450600162ffffff6127918986612624565b51169790612774565b9091506020813d82116127d5575b816127b560209383610a75565b810103126101ba57516001600160801b03811681036101ba57905f61274c565b3d91506127a8565b6127f5915060203d811161155d5761154e8183610a75565b5f612711565b505060095462ffffff169150565b60ff915060a01c16155f61266556fea264697066735822122091b02f9145b50efb974d484b32e10de76f31eeb9c8113fe8b530b1181964316064736f6c634300081e0033

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

00000000000000000000000047b3ef629d9cb8dfcf8a6c61058338f4e99d795300000000000000000000000022828dbf15f5fba2394ba7cf8fa9a96bdb444b71000000000000000000000000da5e1988097297dcdc1f90d4dfe7909e847cbef60000000000000000000000008d0d000ee44948fc98c9b98a4fa4921476f08b0d000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564000000000000000000000000f9f5e6f7a44ee10c72e67bded6654afaf4d0c85d0000000000000000000000007310dd6ef89b7f829839f140c6840bc929ba2031

-----Decoded View---------------
Arg [0] : _vault (address): 0x47b3ef629D9cB8DFcF8A6c61058338f4e99d7953
Arg [1] : _charmVault (address): 0x22828Dbf15f5FBa2394Ba7Cf8fA9A96BdB444B71
Arg [2] : _wlfi (address): 0xdA5e1988097297dCdc1f90D4dFE7909e847CBeF6
Arg [3] : _usd1 (address): 0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d
Arg [4] : _uniswapRouter (address): 0xE592427A0AEce92De3Edee1F18E0157C05861564
Arg [5] : _swapPool (address): 0xf9f5E6f7A44Ee10c72E67Bded6654afAf4D0c85d
Arg [6] : _owner (address): 0x7310Dd6EF89b7f829839F140C6840bc929ba2031

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 00000000000000000000000047b3ef629d9cb8dfcf8a6c61058338f4e99d7953
Arg [1] : 00000000000000000000000022828dbf15f5fba2394ba7cf8fa9a96bdb444b71
Arg [2] : 000000000000000000000000da5e1988097297dcdc1f90d4dfe7909e847cbef6
Arg [3] : 0000000000000000000000008d0d000ee44948fc98c9b98a4fa4921476f08b0d
Arg [4] : 000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564
Arg [5] : 000000000000000000000000f9f5e6f7a44ee10c72e67bded6654afaf4d0c85d
Arg [6] : 0000000000000000000000007310dd6ef89b7f829839f140c6840bc929ba2031


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.

`; } let ensZeroWidthWarningHtml = ""; if ($("#hdnIsEnsContainZeroWidthChars").val() == "true") { ensZeroWidthWarningHtml = `
${zeroWidthWarningMessage} Check the actual text at ENS.
`; } const contentHtml = `
Additional Info
Full Name:
ENS Name


Note:
  • Name tag is displayed due to forward and reverse resolution. Find out more.
  • A Domain Name is not necessarily held by a person popularly associated with the name.
${ensUnicodeWarningHtml} ${ensZeroWidthWarningHtml}
`; $('#ensName').popover({ html: true, content: contentHtml, trigger: 'manual', placement: 'right' }); $('#ensName').click(function (event) { $("#ensName").popover('toggle'); event.stopPropagation(); }); $('#ensName').on('shown.bs.popover', async () => { //disable tooltip when hovering over ens name in the main page $("[rel='tooltipEns']").each(function () { $(this).tooltip('hide'); $(this).tooltip('disable'); }); //call ajax here to get result if (!otherENSNamesHtml) { const resolvedAddressesModel = await getEnsResolvedAddress($("#hdnAddress").val(), $("#hdnEnsText").val()); otherENSNamesHtml = generateEnsPopoverGrid(resolvedAddressesModel.d); if (!otherENSNamesHtml) { otherENSNamesHtml = "There are no other names resolving to this address." } } $(".popOverEnsOwnedAddressTable").html(otherENSNamesHtml); $("#divENSDisplayName").html(ensDisplayName); // append more copy button for ENS let domainName = $("#hdnEnsText").val(); const copyEnsButtonHtml = ` `; $("#spanCopyENSAddress").html(copyEnsButtonHtml); $("[data-bs-toggle='tooltip']").tooltip(); }); $('#ensName').on('hidden.bs.popover', () => { $("[rel='tooltipEns']").each(function () { $(this).tooltip('enable'); }); }); $('#ensName').on('hide.bs.popover', () => { $("[data-bs-toggle='tooltip']").tooltip('hide'); }); $(document).click(function (e) { //$("#ensName").popover('hide'); const popoverElement = document.getElementById('popover-ens-preview'); const popoverTrigger = document.getElementById('ensName'); if (!popoverTrigger.contains(e.target) && (!popoverElement || !popoverElement.contains(e.target))) { $("#ensName").popover('hide'); } }) } async function getEnsResolvedAddress(address, currentEnsText) { try { const requestModel = { "lookupAddress": address, "primaryDomainName": currentEnsText, "provider": "ENS" }; const response = await $.ajax({ url: "/name-lookup-search.aspx/GetOtherDomainNameForAddress", type: "POST", contentType: "application/json", dataType: "json", data: JSON.stringify({ requestModel: requestModel }) }) return response; } catch { return ""; } } function generateEnsPopoverGrid(model) { if (!model || model.DomainNames.length == 0) { return ""; } let listOtherENSNames = ""; model.DomainNames.forEach(x => listOtherENSNames += x.Name); let moreOtherENSNames = ""; if (model.Total > 5) { moreOtherENSNames = `More ` } const result = `
Other names resolving to this address:
${listOtherENSNames} ${moreOtherENSNames}
`; return result; } // ===== end ENS name tag const tooltipForTokenHolding = '1 Token Contract'; var adjustPosition = 0; $(document).ready(function () { switchAmountToValue(document.getElementById("headerAmountValue"), 'Value (USD)', 'Amount', true); switchAmountToValue(document.getElementById("headerIntAmountValue"), 'Value (USD)', 'Amount', true); switchMethodColumn(document.getElementById("headerMethod"), 'Method', 'Action', true); switchMethodColumn(document.getElementById("headerMethod_internaltx"), 'Method', 'Action', true); onDocumentReady(); $("[rel='tooltip']").tooltip(); $("[data-bs-toggle-second='tooltip']").tooltip({ trigger: 'hover' }); $("[rel='tooltipEns']").each(function () { $(this).tooltip({ title: $(this).attr("tooltip-title") }); }); //if (hash != '') { // activaTab(hash); //}; onAddressDocReady(); //// Note: this is causing "Copied" tooltip not showing when copy button is clicked in V3, and seems like not applicable to v3, comment out first in case there is issue //$('[data-bs-toggle="tooltip"]').click(function () { // $('[data-bs-toggle="tooltip"]').tooltip("hide"); //}); if (document.getElementById("copyaddressbutton")) { document.getElementById("copyaddressbutton").classList.remove("disabled"); } if ($("#txtSearchContract").length) { initialiseKeyupOnDocReady(); } if (!!$('#ensName')[0]) { initEnsNamePopOver(); } handleToggle(); $("#btnLoginRequired").attr("href", "/login?ref=" + window.location.pathname.slice(1)); if (window.matchMedia("(max-width: 767px)").matches) { // Mobile adjustPosition = 90; } else { // Others adjustPosition = 50; } if (tooltipForTokenHolding) { const dropdownMenuBalance = document.getElementById("dropdownMenuBalance"); if (dropdownMenuBalance) { const dropdownWrapper = dropdownMenuBalance.closest(".dropdown"); if (dropdownWrapper) { dropdownWrapper.setAttribute("title", tooltipForTokenHolding); new bootstrap.Tooltip(dropdownWrapper); } } } setIOState(); setFiltersStatus(); }); function displayAudit() { $('html, body').animate({ scrollTop: $("#auditReportId").offset().top - adjustPosition }); } function handleToggle() { var className = document.getElementsByClassName('editor'); var classNameCount = className.length; for (var j = 0; j t.innerWidth()) { if (mb + d > tb) { t.css('padding-bottom', ((mb + d) - tb)); } } else { t.css('overflow', 'visible'); } }).on('hidden.bs.dropdown', function () { $(this).css({ 'padding-bottom': '', 'overflow': '' }); }); var btn_ERC20_sort = { count: 0, reminder_count: 2, list: [], default_list: [], ERC20_sort_start: function (count) { if (document.getElementsByClassName('list-custom-divider-ERC20')[0]) { var self = this if (count != undefined) { self.count = count } var before_el = document.getElementsByClassName('list-custom-divider-ERC20')[0] var parent_el = before_el.parentNode var element_selector = parent_el.querySelectorAll(".list-custom-ERC20"); if (self.list.length == 0) { element_selector.forEach(function (e) { self.list.push(e); self.default_list.push(e); }); } $(".list-custom-ERC20").remove() var type = self.count % self.reminder_count self.sortList(type, parent_el, before_el); self.count++ } }, sortList: function (type, parent_el, before_el) { var self = this var sorted_list = [] var icon_el = $(before_el).find('button').find('i') switch (type) { case 1: icon_el.attr("class", "fad fa-sort-up") sorted_list = self.sortUsdAsc() break; default: icon_el.attr("class", "fad fa-sort-down") sorted_list = self.sortUsdDesc() } for (var i = sorted_list.length - 1; i >= 0; i--) { before_el.insertAdjacentElement('afterend', sorted_list[i]) } }, sortUsdAsc: function () { var self = this var sort_list = self.list sort_list.sort(function (a, b) { var target_a_value = self.formatCurrencyToNumber(a.querySelector('.list-usd-value').textContent.trim() || -1); var target_b_value = self.formatCurrencyToNumber(b.querySelector('.list-usd-value').textContent.trim() || -1); if (target_a_value == -1 || target_b_value == -1) { return 1; } if (target_a_value target_b_value) { return 1; } return 0 }); return sort_list }, sortUsdDesc: function () { var self = this var sort_list = self.list sort_list.sort(function (a, b) { var target_a_value = self.formatCurrencyToNumber(a.querySelector('.list-usd-value').textContent.trim() || -1); var target_b_value = self.formatCurrencyToNumber(b.querySelector('.list-usd-value').textContent.trim() || -1); if (target_a_value target_b_value) { return -1; } return 0 }); return sort_list }, formatCurrencyToNumber: function (strCurrency) { if (typeof strCurrency == "number") return strCurrency else return Number(strCurrency.replace(/[^0-9.-]+/g, "")); }, } $("#btn_ERC20_sort").on("click", function (event) { event.preventDefault(); setTimeout(function () { btn_ERC20_sort.ERC20_sort_start() }, 10) }) function hrefTokenHolding() { var location = "/tokenholdings?a=0x3e872d07c5a73e684b13a3b097c3599bf608c6e3" var queryString = $("input.form-control.form-control-xs.search.mb-3")[0].value if (queryString) { location += "&q=" + queryString } window.location.href = location } function toggleLoginModal() { $('#loginRequiredModal').modal('toggle'); } function setIOState() { const mainAddress = $("#hdnAddress").val()?.toLowerCase(); const currentFilters = new URLSearchParams(window.location.search); const faddr = currentFilters.get("fadd")?.toLowerCase(); const taddr = currentFilters.get("tadd")?.toLowerCase(); $(".dropdown-item-io").removeClass("active"); if (taddr) { if (taddr.indexOf(mainAddress) != -1) { $("#btnInTxFilter").addClass("active"); $("#btnInIntlTxFilter").addClass("active"); $(".js-listbox-item").text("IN"); } else { $("#btnOutTxFilter").addClass("active"); $("#btnOutIntlTxFilter").addClass("active"); $(".js-listbox-item").text("OUT"); } } else if (faddr) { if (faddr.indexOf(mainAddress) != -1) { $("#btnOutTxFilter").addClass("active"); $("#btnOutIntlTxFilter").addClass("active"); $(".js-listbox-item").text("OUT"); } else { $("#btnInTxFilter").addClass("active"); $("#btnInIntlTxFilter").addClass("active"); $(".js-listbox-item").text("IN"); } } else { $("#btnAnyTxFilter").addClass("active"); $("#btnAnyIntlTxFilter").addClass("active"); $(".js-listbox-item").text("ANY"); } } function setFiltersStatus() { if (isSignedIn == "0") { disableControl("#dropdownMethod"); disableControl("#dropdownAge"); disableControl("#dropdownFrom"); disableControl("#dropdownIO"); disableControl("#dropdownTo"); disableControl("#btnDropdownAmount"); disableControl("#dropdownAgeIntlTxns"); disableControl("#dropdownFromIntlTxns"); disableControl("#dropdownIOIntlTxns"); disableControl("#dropdownToIntlTxns"); disableControl("#btnDropdownAmountIntlTxns"); $(".dropdown-filters").tooltip(); } } function disableControl(selector) { $(selector).prop("disabled", true); }