ETH Price: $3,095.79 (-0.50%)
Gas: 3 Gwei

Contract

0x945f0cf0DDb3A20a4737d3e1f3cA43DE9C185440
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Deposit201925162024-06-28 20:16:3512 days ago1719605795IN
0x945f0cf0...E9C185440
0 ETH0.00220932

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To Value
201390352024-06-21 8:55:2319 days ago1718960123  Contract Creation0 ETH
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0xBe687E1f...a04B8ae29
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
Adapter.FI Multi-Vault

Compiler Version
vyper:0.3.10

Optimization Enabled:
N/A

Other Settings:
BSL 1.1 license

Contract Source Code (Vyper language format)

#pragma version 0.3.10
#pragma optimize codesize
#pragma evm-version cancun
"""
@title Adapter.FI Multi-Vault
@license Copyright 2023, 2024 Biggest Lab Co Ltd, Benjamin Scherrey, Sajal Kayan, and Eike Caldeweyher
@author BiggestLab (https://biggestlab.io) Benjamin Scherrey, Sajal Kayan
"""
from vyper.interfaces import ERC20
from vyper.interfaces import ERC4626

implements: ERC20
# BDM HACK! We have some additional optional parameters that it doesn't like.
# implements: ERC4626

interface IAdapter:
    def maxWithdraw() -> uint256: view
    def maxDeposit() -> uint256: view
    def totalAssets() -> uint256: view
    def deposit(asset_amount: uint256, pregen_info: Bytes[4096]=empty(Bytes[4096])): payable
    def withdraw(asset_amount: uint256 , withdraw_to: address, pregen_info: Bytes[4096]=empty(Bytes[4096])) -> uint256 : payable 
    def claimRewards(claimant: address): payable
    def managed_tokens() -> DynArray[address, 10]: view 

interface FundsAllocator:
    def getTargetBalances(_vault_balance: uint256, _d4626_asset_target: uint256, _total_assets: uint256, _total_ratios: uint256, _adapter_balances: BalanceAdapter[MAX_ADAPTERS], _min_outgoing_tx: uint256, _withdraw_only: bool) -> (uint256, int256, uint256, BalanceAdapter[MAX_ADAPTERS], address[MAX_ADAPTERS]): pure
    def getBalanceTxs(_vault_balance: uint256, _target_asset_balance: uint256, _min_proposer_payout: uint256, _total_assets: uint256, _total_ratios: uint256, _adapter_states: BalanceAdapter[MAX_ADAPTERS], _withdraw_only: bool) -> (BalanceTX[MAX_ADAPTERS], address[MAX_ADAPTERS]): pure

# Number of potential lenging platform adapters.
MAX_ADAPTERS : constant(uint256) = 5

MAX_SLIPPAGE_PERCENT : immutable(decimal)

# Contract owner hold 2% of the yield.
YIELD_FEE_PERCENTAGE : constant(uint256) = 2

# 0% of the yield belongs to the Strategy proposer.
PROPOSER_FEE_PERCENTAGE: constant(uint256) = 0

# For use in support of _claim_fees
enum FeeType:
    BOTH
    YIELDS
    PROPOSER

# ERC-20 attributes for this Vault's share token.
name: public(immutable(String[64]))
symbol: public(immutable(String[32]))
decimals: public(immutable(uint8))
asset: public(immutable(address))

# Controlling & Governance DAOs/Wallets
owner: public(address)
governance: public(address)
funds_allocator: public(address)
adapters : public(DynArray[address, MAX_ADAPTERS])
managed_tokens: HashMap[address, address] #mapping between token to adapter

vault_asset_balance_cache: transient(uint256)
adapters_asset_balance_cache: transient(HashMap[address, uint256])
total_asset_balance_cache: transient(uint256)

# Strategy Management
current_proposer: public(address)
min_proposer_payout: public(uint256)

struct AdapterValue:
    ratio: uint256
    last_asset_value: uint256

strategy: public(HashMap[address, AdapterValue])


# Summary Financial History of the Vault
total_assets_deposited: public(uint256)
total_assets_withdrawn: public(uint256)
total_yield_fees_claimed: public(uint256)
total_strategy_fees_claimed: public(uint256)


# ERC20 Representation of Vault Shares
totalSupply: public(uint256)
balanceOf: public(HashMap[address, uint256])
allowance: public(HashMap[address, HashMap[address, uint256]])


event AdapterAdded:
    sender: indexed(address)
    adapter_addr: indexed(address)

event AdapterRemoved:   
    sender: indexed(address)
    afapter_addr: indexed(address)
    final_balance: uint256
    forced: bool  

event Transfer:
    sender: indexed(address)
    receiver: indexed(address)
    value: uint256

event Approval:
    owner: indexed(address)
    spender: indexed(address)
    value: uint256    

event Deposit:
    sender: indexed(address)
    owner: indexed(address)
    assets: uint256
    shares: uint256 

event SlippageDeposit:
    sender: indexed(address)
    owner: indexed(address)
    assets: uint256
    desired_shares: uint256     
    actual_shares: uint256

event Withdraw:
    sender: indexed(address)
    receiver: indexed(address)
    owner: indexed(address)
    assets: uint256
    shares: uint256

event SlippageWithdraw:
    sender: indexed(address)
    receiver: indexed(address)
    owner: indexed(address)
    assets: uint256
    shares: uint256    
    actual_assets : uint256

struct AdapterStrategy:
    adapter: address
    ratio: uint256    

event StrategyActivation:
    strategy: AdapterStrategy[MAX_ADAPTERS]
    proposer: address

event AdapterLoss:
    adapter: indexed(address)
    last_value: uint256
    current_value: uint256

event GovernanceChanged:
    new_governor: indexed(address)
    old_governor: indexed(address)

event VaultDeployed:
    name: indexed(String[64])
    symbol: indexed(String[32])
    decimals: uint8
    asset: indexed(address)

event FundsAllocatorChanged:
    new_allocator: indexed(address)
    old_allocator: indexed(address)   

event OwnerChanged:
    new_owner: indexed(address)
    old_owner: indexed(address)    


@external
def __init__(_name: String[64], _symbol: String[32], _decimals: uint8, _erc20asset : address, _governance: address, _funds_allocator: address, _max_slippage_percent: decimal):
    """
    @notice Constructor for 4626 contract.
    @param _name of shares token
    @param _symbol identifier of shares token
    @param _decimals increment for division of shares token 
    @param _erc20asset : contract address for asset ERC20 token
    @param _governance contract address
    @param _funds_allocator contract address
    @param _max_slippage_percent default maximum acceptable slippage for deposits/withdraws as a percentage
    """
    # BDM - had to remove these two assertions so the code size would be small enough to deploy.
    #assert _governance != empty(address), "Governance cannot be null address."
    #assert _funds_allocator != empty(address), "Fund allocator cannot be null address."
    MAX_SLIPPAGE_PERCENT = _max_slippage_percent

    name = _name
    symbol = _symbol
    decimals = _decimals

    asset = _erc20asset

    self.owner = msg.sender
    self.governance = _governance
    self.funds_allocator = _funds_allocator
    self.totalSupply = 0

    log VaultDeployed(_name, _symbol, _decimals, _erc20asset)
    log OwnerChanged(msg.sender, empty(address))
    log GovernanceChanged(_governance, empty(address))
    log FundsAllocatorChanged(_funds_allocator, empty(address))


@external
def replaceOwner(_new_owner: address) -> bool:
    """
    @notice replace the current 4626 owner with a new one.
    @param _new_owner address of the new contract owner
    @return True, if contract owner was replaced, False otherwise
    """
    assert msg.sender == self.owner, "Only existing owner can replace the owner."
    assert _new_owner != empty(address), "Owner cannot be null address."

    log OwnerChanged(_new_owner, self.owner)

    self.owner = _new_owner
    
    return True


@external
def replaceGovernanceContract(_new_governance: address) -> bool:
    """
    @notice replace the current Governance contract with a new one.
    @param _new_governance address of the new governance contract 
    @return True, if governance contract was replaced, False otherwise
    """
    assert msg.sender == self.governance, "Only existing Governance contract may replace itself."
    assert _new_governance != empty(address), "Governance cannot be null address."

    log GovernanceChanged(_new_governance, self.governance)

    self.governance = _new_governance    

    return True


@external
def replaceFundsAllocator(_new_funds_allocator: address) -> bool:
    """
    @notice replace the current funds allocator contract with a new one.
    @param _new_funds_allocator address of the new contract
    @return True, if funds allocator contract was replaced, False otherwise
    """
    assert msg.sender == self.owner, "Only owner can change the funds allocation contract!"
    assert _new_funds_allocator != empty(address), "FundsAllocator cannot be null address."

    log FundsAllocatorChanged(_new_funds_allocator, self.funds_allocator)

    self.funds_allocator = _new_funds_allocator

    return True


# Can't simply have a public adapters variable due to this Vyper issue:
# https://github.com/vyperlang/vyper/issues/2897
@view
@external
def adapter_list() -> DynArray[address, MAX_ADAPTERS]: 
    """
    @notice convenience function returning list of adapters
    @return list of lending adapter addresses
    """
    return self.adapters


@internal
def _set_strategy(_proposer: address, _strategies : AdapterStrategy[MAX_ADAPTERS], _min_proposer_payout : uint256, pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS]) -> bool:
    assert msg.sender == self.governance, "Only Governance DAO may set a new strategy."
    assert _proposer != empty(address), "Proposer can't be null address."

    # Are we replacing the old proposer?
    if self.current_proposer != _proposer:

        current_assets : uint256 = self._totalAssetsNoCache() # self._totalAssetsCached()

        # Is there enough payout to actually do a transaction?
        yield_fees : uint256 = 0
        strat_fees : uint256 = 0
        yield_fees, strat_fees = self._claimable_fees_available(current_assets)

        if strat_fees > self.min_proposer_payout:
                
            # Pay prior proposer his earned fees.
            self._claim_fees(FeeType.PROPOSER, 0, pregen_info, current_assets)

        self.current_proposer = _proposer
        self.min_proposer_payout = _min_proposer_payout

    # Clear out all existing ratio allocations.
    for adapter in self.adapters:
        self.strategy[adapter].ratio = 0

    # Now set strategies according to the new plan.
    for strategy in _strategies:
        plan : AdapterValue = empty(AdapterValue)
        plan.ratio = strategy.ratio
        plan.last_asset_value = self.strategy[strategy.adapter].last_asset_value
        self.strategy[strategy.adapter] = plan

    log StrategyActivation(_strategies, _proposer)

    return True


@external
def set_strategy(_proposer: address, _strategies : AdapterStrategy[MAX_ADAPTERS], _min_proposer_payout : uint256, pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS]=empty(DynArray[Bytes[4096], MAX_ADAPTERS])) -> bool:
    """
    @notice establishes new strategy of adapter ratios and minumum value of automatic txs into adapters
    @param _proposer address of wallet who proposed strategy and will be entitled to fees during its activation
    @param _strategies list of ratios for each adapter for funds allocation
    @param _min_proposer_payout for automated txs into adapters or automatic payout of fees to proposer upon activation of new strategy
    @param pregen_info Optional list of bytes to be sent to each adapter. These are usually off-chain computed results which optimize the on-chain call
    @return True if strategy was activated, False overwise
    """
    applied: bool = self._set_strategy(_proposer, _strategies, _min_proposer_payout, pregen_info)
    self._dirtyAssetCache()
    return applied


@internal 
def _add_adapter(_adapter: address) -> bool:    
    # Is this from the owner?
    assert msg.sender == self.owner, "Only owner can add new Lending Adapters."

    # Do we already support this adapter?
    assert (_adapter in self.adapters) == False, "adapter already supported."

    # Is this likely to be an actual IAdapter contract?
    # BDM - for some reason this raw_call blows up the contract size!
    #response: Bytes[32] = empty(Bytes[32])
    #result_ok: bool = empty(bool)

    #result_ok, response = raw_call(_adapter, method_id("maxDeposit()"), max_outsize=32, is_static_call=True, revert_on_failure=False)
    #assert (response != empty(Bytes[32])), "Doesn't appear to be an IAdapter."

    self.adapters.append(_adapter)

    self._manage_adapter(_adapter, 0x0000000000000000000000000000000000000000)

    log AdapterAdded(msg.sender, _adapter)

    return True


@external 
def add_adapter(_adapter: address) -> bool: 
    """
    @notice adds a new Adapter adapter to the 4626 vault.
    @param _adapter Address for new adapter to evaluate
    @return True if adapter was added, False otherwise
    @dev If the current strategy doesn't already have an allocation ratio for this adapter it will receive no funds until a new strategy is activated and a balanceAdapters or deposit/withdraw tx is made.

    """
    return self._add_adapter(_adapter)


@internal
@pure
def _defaultSlippage(_desiredAssets: uint256, _minAssets: uint256) -> uint256:
    min_transfer_balance : uint256 = _minAssets
    if _minAssets == 0:        
        calc : uint256 = convert(convert(_desiredAssets, decimal) * (MAX_SLIPPAGE_PERCENT/100.0), uint256)
        min_transfer_balance = _desiredAssets - calc
    assert _desiredAssets >= min_transfer_balance, "Desired assets cannot be less than minimum assets!"
    
    return min_transfer_balance


@internal
def _slippageAllowedBalance(_assetsToMove: uint256, _minAssetsToMove: uint256) -> uint256:
    """
    Balancing Adapters theoretically should result in zero loss in total assets.
    Slippage allowances change this so we determine the difference between the targeted
    funds moved and the allowable minimum funds moved and apply this delta to the
    total assets controlled by the vault as the minimum remaining total assets controlled
    by this vault post adapter balancing.

    If _assetsToMove is zero then we're looking at a deposit and _minAssetsToMove 
    becomes the maximum slippage value.
    
    This value should be provided to the _min_tasset_balance of _balanceAdapters requests.
    """
    if _assetsToMove == 0:
        return self._totalAssetsCached() - _minAssetsToMove
    _minAssetsToMove = self._defaultSlippage(_assetsToMove, _minAssetsToMove)
    return self._totalAssetsCached() - (_assetsToMove - _minAssetsToMove)    


@internal
def _remove_adapter(_adapter: address, pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS], _rebalance: bool = True, _force: bool = False, _min_assets: uint256 = 0) -> bool:
    # Is this from the owner?    
    assert msg.sender == self.owner, "Only owner can remove Lending Adapters."

    if _adapter not in self.adapters: return False

    # Determine acceptable slippage.
    adapter_assets : uint256 = self._adapterAssets(_adapter)
    min_transfer_balance : uint256 = self._defaultSlippage(adapter_assets, _min_assets)
    max_loss : uint256 = adapter_assets - min_transfer_balance

    # Clear out any strategy ratio this adapter may have.
    self.strategy[_adapter].ratio = 0

    if _rebalance == True:
        initialVaultAssets : uint256 = self._totalAssetsCached()
        self._balanceAdapters(0, max_loss, pregen_info, False)
        if not _force:
            afterVaultAssets : uint256 = self._totalAssetsCached()
            if afterVaultAssets < initialVaultAssets:
                # We've taken some loss across the balancing transactions.
                loss : uint256 = initialVaultAssets - afterVaultAssets
                assert adapter_assets >= loss, "ERROR - loss was greater than adapter assets. Try to remove without rebalancing."
                assert max_loss >= loss, "ERROR - too much slippage removing adapter. Try to remove without rebalancing."
    else:
        if adapter_assets > 0:
            assets_withdrawn : uint256 = self._adapter_withdraw(_adapter, adapter_assets, self, pregen_info, _force)
            if not _force:
                # If force semantics was chosen it means the contract owner is willing to leave any assets
                # behind in this adapter because it isn't behaving properly and we urgently need it gone.
                assert self._adapterAssets(_adapter) == 0, "ERROR - adapter adapter to be removed still has assets!"
                assert min_transfer_balance <= assets_withdrawn, "ERROR - too much slippage on adapter withdraw."

    # Walk over the list of adapters and get rid of this one.
    new_adapters : DynArray[address, MAX_ADAPTERS] = empty(DynArray[address, MAX_ADAPTERS])
    for adapter in self.adapters:
        if adapter != _adapter:
            new_adapters.append(adapter)

    self.adapters = new_adapters            
    #UnLock adapter's tokens
    self._manage_adapter(0x0000000000000000000000000000000000000000, _adapter)

    log AdapterRemoved(msg.sender, _adapter, self._adapterAssets(_adapter), _force)

    return True


@external
def remove_adapter(_adapter: address, _rebalance: bool = True, _force: bool = False, _min_assets: uint256 = 0, pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS]=empty(DynArray[Bytes[4096], MAX_ADAPTERS])) -> bool:
    """
    @notice removes Adapter adapter from the 4626 vault.
    @param _adapter address to be removed 
    @param _rebalance if True will empty adapter before removal.
    @param _force causes adapter to be removed despite any slippage.
    @param _min_assets the minimum amount of assets that should be recovered from the adapter.
    @param pregen_info Optional list of bytes to be sent to each adapter. These are usually off-chain computed results which optimize the on-chain call
    @return True if adapter was removed, False otherwise
    """
    return self._remove_adapter(_adapter, pregen_info, _rebalance, _force, _min_assets)
    


@internal
def _swap_adapters(_adapterOld: address, _adapterNew: address, _force: bool = False, _min_assets : uint256 = 0) -> bool:
    # Is this from the owner?    
    assert msg.sender == self.owner, "Only owner can swap Lending Adapters."
    assert _adapterOld != empty(address) and _adapterNew != empty(address), "Can't have empty address for adapter."

    OldAssets : uint256 = self._adapterAssets(_adapterOld)
    NewAssets : uint256 = self._adapterAssets(_adapterNew)

    if not _force and OldAssets > 0:
        # Is there any slippage?
        if NewAssets < OldAssets:
            min_transfer_balance : uint256 = self._defaultSlippage(OldAssets, _min_assets)

            assert min_transfer_balance <= NewAssets, "ERROR - Swap exceeds maximum slippage."

    # Now find the old adapter and replace with the new one.
    pos: uint256 = 0
    found : bool = False
    for adapter in self.adapters:
        if adapter == _adapterOld:
            found = True
            break
        pos += 1

    assert found, "Adapter to be replaced was not found."
    self.adapters[pos] = _adapterNew
    self.strategy[_adapterNew].ratio = self.strategy[_adapterOld].ratio
    self.strategy[_adapterNew].last_asset_value = NewAssets
    self.strategy[_adapterOld] = empty(AdapterValue)

    #Transfer adapter's tokens locks
    self._manage_adapter(_adapterNew, _adapterOld)

    log AdapterRemoved(msg.sender, _adapterOld, self._adapterAssets(_adapterOld), _force)
    log AdapterAdded(msg.sender, _adapterNew)

    return True


@external
def swap_adapters(_adapterOld: address, _adapterNew: address, _force: bool = False, _min_assets : uint256 = 0) -> bool:
    """
    @notice changes swaps address for a adapter. This is the upgrade mechanism for an adapter.
    @param _adapterOld Address of the current adapter contract
    @param _adapterNew Address of the replacement adapter contract
    @param _force if True then complete the swap regardless of slippage.
    @param _min_assets the minimum amount of assets the replaement contract should report
    """
    return self._swap_adapters(_adapterOld, _adapterNew, _force, _min_assets)


@internal 
def _dirtyAssetCache(_clearVaultBalance : bool = True, _clearAdapters : bool = True, _adapter : address = empty(address)):
    self.total_asset_balance_cache = 0
    if _clearVaultBalance:
        self.vault_asset_balance_cache = 0 
    if _clearAdapters:        
        if _adapter == empty(address):
            # Clear them all
            for adapter in self.adapters:
                self.adapters_asset_balance_cache[adapter] = 0
        else:
            self.adapters_asset_balance_cache[_adapter] = 0


@internal
def _vaultAssets() -> uint256:
    if self.vault_asset_balance_cache == 0:
        self.vault_asset_balance_cache = ERC20(asset).balanceOf(self)
        self.total_asset_balance_cache = 0
    return self.vault_asset_balance_cache


@internal
def _adapterAssets(_adapter: address) -> uint256:
    if _adapter == empty(address):
        return 0

    result : uint256 = self.adapters_asset_balance_cache[_adapter]
    if result != 0:
        return result

    result = IAdapter(_adapter).totalAssets()
    self.adapters_asset_balance_cache[_adapter] = result
    self.total_asset_balance_cache = 0
    return result


@internal
def _totalAssetsCached() -> uint256:
    if self.total_asset_balance_cache > 0:
        return self.total_asset_balance_cache
    assetqty : uint256 = self._vaultAssets()
    for adapter in self.adapters:
        assetqty += self._adapterAssets(adapter)

    self.total_asset_balance_cache = assetqty

    return assetqty


@external
def totalAssetsCached() -> uint256:
    return self._totalAssetsCached()


@internal
@view 
def _totalAssetsNoCache() -> uint256:
    assetqty : uint256 = ERC20(asset).balanceOf(self)
    for adapter in self.adapters:
        assetqty += IAdapter(adapter).totalAssets()

    return assetqty


@external
@view
def totalAssets() -> uint256: 
    """
    @notice returns current total asset value for 4626 vault & all its attached Adapter adapters.
    @return sum of assets
    """
    return self._totalAssetsNoCache()
    

@internal
@view 
def _totalReturns(_current_assets : uint256) -> int256:
    # Avoid having to call _totalAssets if we already know the value.
    current_holdings : uint256 = _current_assets
    if current_holdings == 0:
        current_holdings = self._totalAssetsNoCache()

    total_returns: int256 = convert(self.total_assets_withdrawn + \
                                    current_holdings + \
                                    self.total_yield_fees_claimed + \
                                    self.total_strategy_fees_claimed, int256) - \
                            convert(self.total_assets_deposited, int256)
    return total_returns    


@external
@view 
def totalReturns() -> int256:
    """
    @notice computes current profits (denominated in assets) available under control of this 4626 vault.
    @return total assets held by adapter above what is currently deposited.
    @dev This includes the fees owed to 4626 contract owner and current strategy proposer.
    """
    assets : uint256 = self._totalAssetsNoCache()
    return self._totalReturns(assets)    


@internal
@view 
def _claimable_fees_available(_current_assets : uint256 = 0) -> (uint256, uint256):
    """
    Returns yield fees, strategy fees available.
    """
    total_assets : uint256 = _current_assets

    # Only call _totalAssets() if it wasn't passed in.
    if total_assets == 0:
        total_assets = self._totalAssetsNoCache()

    total_returns : int256 = self._totalReturns(total_assets)
    if total_returns <= 0: 
        return 0, 0

    yield_fees_available: uint256 = 0
    strategy_fees_available : uint256 = 0

    total_yield_ever : uint256 = (convert(total_returns,uint256) * YIELD_FEE_PERCENTAGE) / 100
    total_strat_fees_ever : uint256 = (convert(total_returns,uint256) * PROPOSER_FEE_PERCENTAGE) / 100

    if self.total_yield_fees_claimed < total_yield_ever:
        yield_fees_available = total_yield_ever - self.total_yield_fees_claimed

    if self.total_strategy_fees_claimed < total_strat_fees_ever:
        strategy_fees_available = total_strat_fees_ever - self.total_strategy_fees_claimed

    return yield_fees_available, strategy_fees_available


@external
@view    
def claimable_yield_fees_available(_current_assets : uint256 = 0) -> uint256:
    """
    @notice determines total yields aailable for 4626 vault owner.
    @param _current_assets optional parameter if current total assets is already known.
    @return total assets contract owner could withdraw now in fees.
    """
    yield_fees : uint256 = 0 
    strategy_fees: uint256 = 0
    yield_fees, strategy_fees = self._claimable_fees_available(_current_assets)    
    return yield_fees


@external
@view    
def claimable_strategy_fees_available(_current_assets : uint256 = 0) -> uint256:
    """
    @notice determines total yields aailable for current strategy proposer.
    @param _current_assets optional parameter if current total assets is already known.
    @return total assets strategy proposer is owed presently.
    """
    yield_fees : uint256 = 0 
    strategy_fees: uint256 = 0
    yield_fees, strategy_fees = self._claimable_fees_available(_current_assets)  
    return strategy_fees


@external
@view    
def claimable_all_fees_available(_current_assets : uint256 = 0) -> uint256:
    """
    @notice determines total fees owed for both 4626 vault owner & proposer of current strategy.
    @param _current_assets optional parameter if current total assets is already known.
    @return Claimable fees available for yield and proposer
    """
    yield_fees : uint256 = 0 
    strategy_fees: uint256 = 0
    yield_fees, strategy_fees = self._claimable_fees_available(_current_assets)  
    return yield_fees + strategy_fees     


@internal
def _claimable_fees_by_me(_yield : FeeType, _asset_amount: uint256, _current_assets: uint256) -> (uint256, uint256):
    yield_fees : uint256 = 0
    strat_fees : uint256 = 0

    yield_fees, strat_fees = self._claimable_fees_available(_current_assets)

    # Only yields, no strategy.
    if _yield == FeeType.YIELDS:
        strat_fees = 0

    # Only strategy, no yields.
    if _yield == FeeType.PROPOSER:
        yield_fees = 0

    # If current proposer is zero address then we won't pay yield fees.
    if self.current_proposer == empty(address):
        yield_fees = 0

    # Only owner may claim yield fees.
    if (_yield == FeeType.YIELDS or _yield == FeeType.BOTH) and msg.sender != self.owner:
        yield_fees = 0        

    # Only current proposer or governance may claim strategy fees.
    if _yield == FeeType.PROPOSER or _yield == FeeType.BOTH: 
        assert msg.sender == self.current_proposer or msg.sender == self.governance, "Only curent proposer or governance may claim strategy fees."

    # Do we have enough fees to pay out the request? If so how much should we extract?
    assert _asset_amount <= yield_fees + strat_fees, "Not enough fees to fulfill requested amount."
    return yield_fees, strat_fees    


@internal
def _claim_fees(_yield : FeeType, _asset_amount: uint256, pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS], _current_assets : uint256 = 0, _min_assets: uint256 = 0) -> uint256:
    yield_fees : uint256 = 0
    strat_fees : uint256 = 0

    yield_fees, strat_fees = self._claimable_fees_by_me(_yield, _asset_amount, _current_assets)

    fees_to_claim : uint256 = yield_fees + strat_fees
    if _asset_amount > 0:               # Otherwise we take it all.
        fees_to_claim = _asset_amount   # This will be lower than or equal to the total available fees.

    # Do we have enough balance locally to satisfy the claim?
    current_vault_assets : uint256 = self._vaultAssets()
    if current_vault_assets < fees_to_claim:
        # Need to liquidate some shares to fulfill. Insist on withdraw only semantics.
        # Note - there is a chance that balance adapters could return more than we asked for so
        #        don't just give it all away in case there's an overage.
        fees_to_claim = min(self._balanceAdapters(fees_to_claim, _min_assets, pregen_info, True), fees_to_claim)
    else:
        fees_to_claim = min(fees_to_claim, current_vault_assets)

    # Adjust fees proportionally to account for slippage.
    if strat_fees > 0 and yield_fees > 0:
        strat_fees = convert((convert(strat_fees, decimal)/convert(strat_fees+yield_fees, decimal))*convert(fees_to_claim, decimal), uint256)     
        yield_fees = fees_to_claim - strat_fees   
    elif strat_fees > 0:
        strat_fees = fees_to_claim
    else:
        yield_fees = fees_to_claim

    # Update our global payout records.
    self.total_yield_fees_claimed += yield_fees
    self.total_strategy_fees_claimed += strat_fees

    # Do we have something independent for the strategy proposer?
    if strat_fees > 0 and self.owner != self.current_proposer:
        # We only pay out if the amount is high enough, otherwise the vault keeps it.
        # Unless the person requesting the payout is the current proposer then he must
        # want it anyway.
        if msg.sender == self.current_proposer or strat_fees >= self.min_proposer_payout:
            ERC20(asset).transfer(self.current_proposer, strat_fees, default_return_value=True)
        strat_fees = 0

    # Is there anything left over to transfer for Yield? (Which might also include strat)
    if yield_fees + strat_fees > 0:
        ERC20(asset).transfer(self.owner, yield_fees + strat_fees, default_return_value=True)    

    # Clear all caches!        
    self._dirtyAssetCache() 

    return fees_to_claim


@external
def claim_yield_fees(_asset_request: uint256 = 0, pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS]=empty(DynArray[Bytes[4096], MAX_ADAPTERS])) -> uint256:
    """
    @notice used by 4626 vault owner to withdraw fees.
    @param _asset_request total assets desired for withdrawl. 
    @param pregen_info Optional list of bytes to be sent to each adapter. These are usually off-chain computed results which optimize the on-chain call
    @return total assets transferred.    
    @dev If _asset_request is 0 then will withdrawl all eligible assets.
    """
    return self._claim_fees(FeeType.YIELDS, _asset_request, pregen_info)


@external
def claim_strategy_fees(_asset_request: uint256 = 0, pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS]=empty(DynArray[Bytes[4096], MAX_ADAPTERS])) -> uint256:
    """
    @notice user by current Strategy proposer to withdraw fees.
    @param _asset_request total assets desired for withdrawl. 
    @param pregen_info Optional list of bytes to be sent to each adapter. These are usually off-chain computed results which optimize the on-chain call
    @return total assets transferred.    
    @dev If _asset_request is 0 then will withdrawl all eligible assets.
    """
    return self._claim_fees(FeeType.PROPOSER, _asset_request, pregen_info)


@external
def claim_all_fees(_asset_request: uint256 = 0, pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS]=empty(DynArray[Bytes[4096], MAX_ADAPTERS])) -> uint256:
    """
    @notice if 4626 vault owner and Strategy proposer are same wallet address, used to withdraw all fees at once.
    @param _asset_request total assets desired for withdrawl. 
    @param pregen_info Optional list of bytes to be sent to each adapter. These are usually off-chain computed results which optimize the on-chain call
    @return total assets transferred.    
    @dev If _asset_request is 0 then will withdrawl all eligible assets.
    """
    return self._claim_fees(FeeType.BOTH, _asset_request, pregen_info)


@internal
@view
def _convertToShares(_asset_amount: uint256, _starting_assets: uint256) -> uint256:
    shareqty : uint256 = self.totalSupply
    yield_fees : uint256 = 0
    strat_fees : uint256 = 0
    yield_fees, strat_fees = self._claimable_fees_available(_starting_assets)
    claimable_fees : uint256 = yield_fees + strat_fees

    # If there aren't any shares/assets yet it's going to be 1:1.
    if shareqty == 0 : return _asset_amount
    if _starting_assets == 0 : return _asset_amount

    # Less fees
    assert _starting_assets >= claimable_fees, "_convertToShares sanity failure!" # BDM
    assetqty : uint256 = _starting_assets - claimable_fees

    return _asset_amount * shareqty / assetqty 


@external
@view
def convertToShares(_asset_amount: uint256) -> uint256: 
    """
    @notice calculates the current number of 4626 shares would be received for a deposit of assets.
    @param _asset_amount the quantity of assets to be converted to shares.
    @return current share value for the asset quantity
    @dev any fees owed to 4626 owner or strategy proposer are removed before conversion.
    """
    return self._convertToShares(_asset_amount, self._totalAssetsNoCache())


@internal
@view
def _convertToAssets(_share_amount: uint256, _starting_assets: uint256) -> uint256:
    shareqty : uint256 = self.totalSupply
    yield_fees : uint256 = 0
    strat_fees : uint256 = 0
    yield_fees, strat_fees = self._claimable_fees_available(_starting_assets)
    claimable_fees : uint256 = yield_fees + strat_fees
    
    # Less fees
    assert _starting_assets >= claimable_fees, "_convertToAssets sanity failure!" # BDM    

    # If there aren't any shares yet it's going to be 1:1.
    if shareqty == 0: return _share_amount    
    if _starting_assets - claimable_fees == 0 : return _share_amount    

    return _share_amount * (_starting_assets - claimable_fees) / shareqty


@external
@view
def convertToAssets(_share_amount: uint256) -> uint256:
    """
    @notice calculates the current quantity of assets would be received for a deposit of 4626 shares.
    @param _share_amount the quantity of 4626 shares to be converted to assets.
    @return current asset value for the share quantity
    @dev any fees owed to 4626 owner or strategy proposer are removed before conversion.
    """
    return self._convertToAssets(_share_amount, self._totalAssetsNoCache())


@external
@view
def maxDeposit(_spender: address) -> uint256:
    """
    @notice Maximum amount of the underlying asset that can be deposited into the Vault for the receiver, through a deposit call.
    @param _spender address (ignored)
    @return a really big number that we'll never hit.
    @dev Due to the nature of the LPs that we depend upon there's no way to properly support this part of the EIP-4626 spec.
    """
    return convert(max_value(int128), uint256)


@external
@view
def previewDeposit(_asset_amount: uint256) -> uint256:
    """
    @notice This function converts asset amount to shares in deposit
    @param _asset_amount Number amount of assets to evaluate
    @return Shares per asset amount in deposit
    """
    return self._convertToShares(_asset_amount, self._totalAssetsNoCache())


@external
@view
def maxMint(_receiver: address) -> uint256:
    """
    @notice Maximum amount of shares that can be minted from the Vault for the receiver, through a mint call.
    @param _receiver address (ignored)
    @return a really big number that we'll never hit.
    @dev Due to the nature of the LPs that we depend upon there's no way to properly support this part of the EIP-4626 spec.
    """
    return convert(max_value(int128), uint256)


@external
@view 
def previewMint(_share_amount: uint256) -> uint256:
    """
    @notice This function returns asset qty that would be returned for this share_amount per mint
    @param _share_amount Number amount of shares to evaluate
    @return Assets per share amount in mint
    """
    return self._convertToAssets(_share_amount, self._totalAssetsNoCache())


@external
def mint(_share_amount: uint256, _receiver: address, pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS] = empty(DynArray[Bytes[4096], MAX_ADAPTERS])) -> uint256:
    """
    @notice This function mints asset qty that would be returned for this share_amount to receiver
    @param _share_amount Number amount of shares to evaluate
    @param _receiver Address of receiver to evaluate
    @param pregen_info Optional list of bytes to be sent to each adapter. These are usually off-chain computed results which optimize the on-chain call
    @return Asset value of _share_amount
    """
    assetqty : uint256 = self._convertToAssets(_share_amount, self._totalAssetsCached())
    shares : uint256 = 0
    assets : uint256 = 0
    shares, assets = self._deposit(assetqty, _receiver, 0, pregen_info)
    self._dirtyAssetCache()
    return assets


@external
@view 
def maxWithdraw(_owner: address) -> uint256:
    """
    @notice This function returns maximum assets this _owner can extract
    @param _owner Address of owner of assets to evaluate
    @return maximum assets this _owner can withdraw
    """
    return self._convertToAssets(self.balanceOf[_owner], self._totalAssetsNoCache())


@external
@view 
def previewWithdraw(_asset_amount: uint256) -> uint256:
    """
    @notice This function returns asset qty per share amount for withdraw
    @param _asset_amount Number amount of assets to evaluate
    @return Share qty per asset amount in withdraw
    """
    return self._convertToShares(_asset_amount, self._totalAssetsNoCache())


@external
@view 
# Returns maximum shares this _owner can redeem.
def maxRedeem(_owner: address) -> uint256:
    """
    @notice This function returns maximum shares this _owner can redeem
    @param _owner Address of owner of assets to evaluate
    @return maximum shares this _owner can redeem
    """
    return self.balanceOf[_owner]


@external
@view 
def previewRedeem(_share_amount: uint256) -> uint256:
    """
    @notice This function returns asset qty per share amount for redemption
    @param _share_amount Number amount of shares to evaluate
    @return asset qty per share amount in redemption
    """
    return self._convertToAssets(_share_amount, self._totalAssetsNoCache())


@external
def redeem(_share_amount: uint256, _receiver: address, _owner: address, pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS]=empty(DynArray[Bytes[4096], MAX_ADAPTERS])) -> uint256:
    """
    @notice This function redeems asset qty that would be returned for this share_amount to receiver from owner
    @param _share_amount Number amount of shares to evaluate
    @param _receiver Address of receiver to evaluate
    @param _owner Address of owner of assets to evaluate
    @param pregen_info Optional list of bytes to be sent to each adapter. These are usually off-chain computed results which optimize the on-chain call
    @return Asset qty withdrawn
    """
    assetqty: uint256 = self._convertToAssets(_share_amount, self._totalAssetsCached())
    # NOTE - this is accepting the MAX_SLIPPAGE_PERCENT % slippage default.
    shares : uint256 = 0 
    assets : uint256 = 0 
    shares, assets = self._withdraw(assetqty, _receiver, _owner, 0, pregen_info)
    self._dirtyAssetCache()
    return assets


# This structure must match definition in Funds Allocator contract.
struct BalanceTX:
    qty: int256
    adapter: address

# This structure must match definition in Funds Allocator contract.
struct BalanceAdapter:
    adapter: address
    current: uint256
    last_value: uint256
    max_deposit: int256
    max_withdraw: int256 # represented as a negative number
    ratio: uint256
    target: uint256 
    delta: int256


@internal
@view
def _getAdapterMaxWithdraw(_adapter: address) -> int256:
    """
    @dev Given an adapter's address return the maximum withdraw 
    amount allowed for that adapter. 
    """
    # If the value is higher than what can be represented by an int256 
    # make it the maximum value possible with an int256.
    _umax : uint256 = IAdapter(_adapter).maxWithdraw()
    if _umax > convert(max_value(int256), uint256):
        _umax = convert(max_value(int256), uint256)

    return convert(_umax, int256) * -1        


@internal
@view
def _getAdapterMaxDeposit(_adapter: address) -> int256:
    """
    @dev Given an adapter's address return the maximum deposit 
    amount allowed for that adapter. This will be a negative number.
    """
    # If the value is higher than what can be represented by an int256 
    # make it the maximum value possible with an int256.
    _umax : uint256 = IAdapter(_adapter).maxDeposit()
    if _umax > convert(max_value(int256), uint256):
        return max_value(int256)

    return convert(_umax, int256)


# Returns current 4626 asset balance, first 3 parts of BalanceAdapters, total Assets, & total ratios of Strategy.
@internal
def _getCurrentBalances() -> (uint256, BalanceAdapter[MAX_ADAPTERS], uint256, uint256):
    current_local_asset_balance : uint256 = self._vaultAssets()

    adapter_balances: BalanceAdapter[MAX_ADAPTERS] = empty(BalanceAdapter[MAX_ADAPTERS])

    # If there are no adapters then nothing to do.
    if len(self.adapters) == 0: return current_local_asset_balance, adapter_balances, current_local_asset_balance, 0

    total_balance: uint256 = current_local_asset_balance
    total_ratios: uint256 = 0
    pos: uint256 = 0

    for adapter in self.adapters:
        adapter_balances[pos].adapter = adapter
        adapter_balances[pos].current = self._adapterAssets(adapter)
        total_balance += adapter_balances[pos].current

        adapter_balances[pos].max_withdraw = self._getAdapterMaxWithdraw(adapter)
        adapter_balances[pos].max_deposit = self._getAdapterMaxDeposit(adapter)

        plan : AdapterValue = self.strategy[adapter]

        adapter_balances[pos].ratio = plan.ratio

        total_ratios += plan.ratio
        adapter_balances[pos].last_value = plan.last_asset_value
        
        pos += 1

    return current_local_asset_balance, adapter_balances, total_balance, total_ratios


@external
def getCurrentBalances() -> (uint256, BalanceAdapter[MAX_ADAPTERS], uint256, uint256): 
    """
    @notice This function returns current balances of adapters
    @return Current balances of adapters
    """
    current_local_asset_balance: uint256 = 0
    adapter_balances: BalanceAdapter[MAX_ADAPTERS] = empty(BalanceAdapter[MAX_ADAPTERS])
    total_balance: uint256 = 0
    total_ratios: uint256 = 0
    current_local_asset_balance, adapter_balances, total_balance, total_ratios = self._getCurrentBalances()
    self._dirtyAssetCache()
    return current_local_asset_balance, adapter_balances, total_balance, total_ratios


@internal
@view
def _getBalanceTxs(_target_asset_balance: uint256, _min_proposer_payout: uint256, _total_assets: uint256, _total_ratios: uint256, _adapter_states: BalanceAdapter[MAX_ADAPTERS], _withdraw_only : bool) -> (BalanceTX[MAX_ADAPTERS], address[MAX_ADAPTERS]): 
    current_local_asset_balance : uint256 = ERC20(asset).balanceOf(self)
    return FundsAllocator(self.funds_allocator).getBalanceTxs(current_local_asset_balance, _target_asset_balance, _min_proposer_payout, _total_assets, _total_ratios, _adapter_states, _withdraw_only)


@internal
def _balanceAdapters(_target_asset_balance: uint256, _min_target_asset_balance: uint256, pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS], _withdraw_only : bool ) -> uint256:
    # If _target_asset_balance is zero then we're looking at a deposit and _min_target_asset_balance
    # becomes the maximum slippage value (via _slippageAllowedBalance).

    # Make sure we have enough assets to send to _receiver.
    txs: BalanceTX[MAX_ADAPTERS] = empty(BalanceTX[MAX_ADAPTERS])
    blocked_adapters: address[MAX_ADAPTERS] = empty(address[MAX_ADAPTERS])

    min_total_asset_balance : uint256 = self._slippageAllowedBalance(_target_asset_balance, _min_target_asset_balance)

    # If there are no adapters then nothing to do.
    if len(self.adapters) == 0: return ERC20(asset).balanceOf(self)

    # Setup current state of vault & adapters & strategy.
    d4626_assets: uint256 = 0
    adapter_states: BalanceAdapter[MAX_ADAPTERS] = empty(BalanceAdapter[MAX_ADAPTERS])
    total_assets: uint256 = 0
    total_ratios: uint256 = 0
    d4626_assets, adapter_states, total_assets, total_ratios = self._getCurrentBalances()

    txs, blocked_adapters = self._getBalanceTxs(_target_asset_balance, self.min_proposer_payout, total_assets, total_ratios, adapter_states, _withdraw_only)

    # If there are blocked_adapters then set their strategy ratios to zero.
    for adapter in blocked_adapters:
        if adapter == empty(address): break

        new_strat : AdapterValue = self.strategy[adapter]
        new_strat.ratio = 0
        self.strategy[adapter] = new_strat
        new_strat_asset_value : uint256 = self._adapterAssets(adapter)

        # Adjust minimum acceptable balances downwards because this is not a slippage loss.
        min_total_asset_balance -= (new_strat.last_asset_value - new_strat_asset_value)

        log AdapterLoss(adapter, new_strat.last_asset_value, new_strat_asset_value)

    # Move the funds in/out of Lending Adapters as required.
    for dtx in txs:
        if dtx.adapter == empty(address): break
        if dtx.qty == 0: continue

        # If the outgoing tx is larger than the min_proposer_payout then do it, otherwise ignore it.
        if dtx.qty >= convert(self.min_proposer_payout, int256):
            # Move funds into the lending adapter's adapter.

            # It's possible due to slippage we may not have enough assets in the vault to
            # fulfill the entire deposit transfer.
            deposit_qty : uint256 = min(convert(dtx.qty, uint256), self._vaultAssets())

            self._adapter_deposit(dtx.adapter, deposit_qty, pregen_info)

        # Negative quanties indicate a withdraw from the adapter into the vault.
        elif dtx.qty < 0:
            # Liquidate funds from lending adapter's adapter.
            qty: uint256 = convert(dtx.qty * -1, uint256)         
            assets_withdrawn : uint256 = self._adapter_withdraw(dtx.adapter, qty, self, pregen_info)

    final_asset_balance : uint256 = self._totalAssetsCached()

    assert self._totalAssetsCached() >= min_total_asset_balance, "Slippage exceeded!"

    return self._vaultAssets()


@external
def balanceAdapters(_target_asset_balance: uint256, _min_tasset_balance: uint256 = 0, _withdraw_only : bool = False, pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS]=empty(DynArray[Bytes[4096], MAX_ADAPTERS])) -> uint256:
    """
    @notice The function provides a way to balance adapters
    @dev   returns the actual balances of assets held in the local vault (not including adapters) after balancing.
    @param _target_asset_balance Target amount for assets balance in vault (not including adapters).
    @param _min_tasset_balance Minimum total assets (including adapters) post transaction accounting for slippage.
    @param _withdraw_only If true no funds will move from vault into adapters during this tx.
    @param pregen_info Optional list of bytes to be sent to each adapter. These are usually off-chain computed results which optimize the on-chain call
    """
    assert msg.sender == self.owner, "only owner can call balanceAdapters"

    ret: uint256 = self._balanceAdapters(_target_asset_balance, _min_tasset_balance, pregen_info, _withdraw_only)
    self._dirtyAssetCache()
    return ret


@internal
def _mint(_receiver: address, _share_amount: uint256) -> uint256:
    """
    @dev Mint an amount of the token and assigns it to an account.
         This encapsulates the modification of balances such that the
         proper events are emitted.
    @param _to The account that will receive the created tokens.
    @param _value The amount that will be created.
    """
    assert _receiver != empty(address), "Receiver cannot be zero."
    self.totalSupply += _share_amount
    self.balanceOf[_receiver] += _share_amount
    log Transfer(empty(address), _receiver, _share_amount)
    return _share_amount


@internal
@view
def _extract_pregen_info(_pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS], _adapter: address) -> Bytes[4096]:
    #Only extract if pregeninfo len matches lending adapters
    if len(_pregen_info) == len(self.adapters):
        #find idx current adapter
        idx: uint256 = 0
        for adapter in self.adapters:
            if _adapter == adapter:
                return _pregen_info[idx]
            idx+=1
    return empty(Bytes[4096])


@internal
def _adapter_deposit(_adapter: address, _asset_amount: uint256, _pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS]):
    pregen_info: Bytes[4096] = self._extract_pregen_info(_pregen_info, _adapter)
    response: Bytes[32] = empty(Bytes[32])

    starting_assets : uint256 = self._adapterAssets(_adapter)

    response = raw_call(
        _adapter,
        _abi_encode(_asset_amount, pregen_info, method_id=method_id("deposit(uint256,bytes)")),
        max_outsize=32,
        is_delegate_call=True,
        revert_on_failure=True
        )

    # Clear the asset cache for vault and adapter.
    self._dirtyAssetCache(True, True, _adapter)

    new_assets : uint256 = self._adapterAssets(_adapter)

    # Update our last_asset_value in our strategy for protection against LP exploits.
    self.strategy[_adapter].last_asset_value = new_assets


@internal
def _adapter_withdraw(_adapter: address, _asset_amount: uint256, _withdraw_to: address, _pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS], _force: bool = False) -> uint256:
    pregen_info: Bytes[4096] = self._extract_pregen_info(_pregen_info, _adapter)
    balbefore : uint256 = ERC20(asset).balanceOf(_withdraw_to)
    response: Bytes[32] = empty(Bytes[32])
    result_ok : bool = True

    assert _adapter != empty(address), "EMPTY ADAPTER!"
    assert _withdraw_to != empty(address), "EMPTY WITHDRAW_TO!"

    if _force:

        # For revert_on_failure = True
        result_ok, response = raw_call(
            _adapter,
            _abi_encode(_asset_amount, _withdraw_to, pregen_info, method_id=method_id("withdraw(uint256,address,bytes)")),
            max_outsize=32,
            is_delegate_call=True,
            revert_on_failure=False
            )
    else:
        # For revert_on_failure = False
        response = raw_call(
            _adapter,
            _abi_encode(_asset_amount, _withdraw_to, pregen_info, method_id=method_id("withdraw(uint256,address,bytes)")),
            max_outsize=32,
            is_delegate_call=True,
            revert_on_failure=True
            )

    # Clear the asset cache for vault and adapter.
    self._dirtyAssetCache(True, True, _adapter)                        

    balafter : uint256 = ERC20(asset).balanceOf(_withdraw_to)
    
    # Update our last_asset_value in our strategy for protection against LP exploits.
    self.strategy[_adapter].last_asset_value = self._adapterAssets(_adapter)

    return balafter - balbefore


@internal
def _deposit(_asset_amount: uint256, _receiver: address, _min_shares : uint256, pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS]) -> (uint256, uint256):
    """
    returns shares minted, assets taken
    """
    assert _receiver != empty(address), "Cannot send shares to zero address."

    assert _asset_amount <= ERC20(asset).balanceOf(msg.sender), "4626Deposit insufficient funds."

    total_starting_assets : uint256 = self._totalAssetsCached()

    # MUST COMPUTE IDEAL TRANSFER SHARES FIRST!
    transfer_shares : uint256 = self._convertToShares(_asset_amount, total_starting_assets)
    if _min_shares > 0:
        assert transfer_shares >= _min_shares, "Deposit too low to receive minimum shares."
    else:
        _min_shares = self._defaultSlippage(transfer_shares, _min_shares)
    min_share_value : uint256 = self._convertToAssets(_min_shares, total_starting_assets)

    # Move assets to this contract from caller in one go.
    ERC20(asset).transferFrom(msg.sender, self, _asset_amount, default_return_value=True)

    # Clear the asset cache for vault but not adapters.
    self._dirtyAssetCache(True, False)

    bal_diff: uint256 = self._balanceAdapters(empty(uint256), _asset_amount - min_share_value, pregen_info, False)

    total_after_assets : uint256 = self._totalAssetsCached()
    assert total_after_assets > total_starting_assets, "ERROR - deposit resulted in loss of assets!"

    deposit_value : uint256 = total_after_assets-total_starting_assets

    # We use total_starting_assests to get a quote for the actual shares based on prior rates
    # as we have not minted any new shares to account for the deposit.
    real_shares : uint256 = self._convertToShares(deposit_value, total_starting_assets)    

    if real_shares < transfer_shares:
        assert real_shares >= _min_shares, "ERROR - unable to meet minimum slippage for this deposit!"

        # We'll transfer what was received.
        # NOTE - updating transfer_shares means that we are unable to fulfill mint semantics
        #        for a 4626 that has to deal with slippage. The issue is we cannot fix the share
        #        qty because we have no ability to predict the actual asset qty required to get
        #        these shares as it's only AFTER we transfer the assets from the minter/depositer
        #        that we can discover what the adapter with slippage actually credits us with.        
        transfer_shares = real_shares
        log SlippageDeposit(msg.sender, _receiver, _asset_amount, transfer_shares, transfer_shares)

    # Now mint assets to return to investor.    
    self._mint(_receiver, transfer_shares)

    # Update all-time assets deposited for yield tracking.
    assets_received : uint256 = total_after_assets - total_starting_assets
    self.total_assets_deposited += assets_received

    log Deposit(msg.sender, _receiver, assets_received, transfer_shares)

    return transfer_shares, _asset_amount


@external
def deposit(_asset_amount: uint256, _receiver: address, _min_shares : uint256 = 0, pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS]=empty(DynArray[Bytes[4096], MAX_ADAPTERS])) -> uint256: 
    """
    @notice This function provides a way to transfer an asset amount from message sender to receiver
    @param _asset_amount Number amount of assets to evaluate
    @param _receiver Address of receiver to evaluate
    @param _min_shares Minmum number of shares that is acceptable. If 0 then apply MAX_SLIPPAGE_PERCENT % allowable slippage.
    @param pregen_info Optional list of bytes to be sent to each adapter. These are usually off-chain computed results which optimize the on-chain call
    @return Share amount deposited to receiver
    """
    shares : uint256 = 0
    assets : uint256 = 0
    shares, assets = self._deposit(_asset_amount, _receiver, _min_shares, pregen_info)
    self._dirtyAssetCache()
    return shares


@internal
def _withdraw(_asset_amount: uint256, _receiver: address, _owner: address, _min_assets: uint256, pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS]) -> (uint256, uint256):
    """
    returns shares consumed, assets returned
    """

    # How many shares does it take to get the requested asset amount?
    # NOTE - it is CRITICAL that shares is fixed immediately before slippage is considered
    #        because we implement redeem in terms of _withdraw.
    shares: uint256 = self._convertToShares(_asset_amount, self._totalAssetsCached())

    # Owner has adequate shares?
    assert self.balanceOf[_owner] >= shares, "Owner has inadequate shares for this withdraw."

    # Withdrawl is handled by someone other than the owner?
    if msg.sender != _owner:

        assert self.allowance[_owner][msg.sender] >= shares, "Not authorized to move enough owner's shares."
        self.allowance[_owner][msg.sender] -= shares

    # Burn the shares.
    self.balanceOf[_owner] -= shares    

    self.totalSupply -= shares
    log Transfer(_owner, empty(address), shares)

    # Make sure we have enough assets to send to _receiver. Do a withdraw only balance.
    current_balance : uint256 = self._balanceAdapters(_asset_amount, _min_assets, pregen_info, True ) 

    if _asset_amount > current_balance:
        log SlippageWithdraw(msg.sender, _receiver, _owner, _asset_amount, shares, current_balance)
        _asset_amount = current_balance

    # Now send assets to _receiver.
    ERC20(asset).transfer(_receiver, _asset_amount, default_return_value=True)

    # Clear the asset cache for vault but not adapters.
    self._dirtyAssetCache(True, False)

    # Update all-time assets withdrawn for yield tracking.
    self.total_assets_withdrawn += _asset_amount

    log Withdraw(msg.sender, _receiver, _owner, _asset_amount, shares)

    return (shares, _asset_amount)


@external
def withdraw(_asset_amount: uint256,_receiver: address,_owner: address, _min_assets: uint256 = 0, pregen_info: DynArray[Bytes[4096], MAX_ADAPTERS]=empty(DynArray[Bytes[4096], MAX_ADAPTERS])) -> uint256:
    """
    @notice This function provides a way to withdraw an asset amount to receiver
    @param _asset_amount Number amount of assets to evaluate
    @param _receiver Address of receiver to evaluate
    @param _owner Address of owner of assets to evaluate
    @param _min_assets Minimum assets that must be returned (due to slippage) or else reverts. If not specified will be MAX_SLIPPAGE_PERCENT % by default.
    @param pregen_info Optional list of bytes to be sent to each adapter. These are usually off-chain computed results which optimize the on-chain call
    @return Share amount withdrawn to receiver
    """
    shares : uint256 = 0
    assets : uint256 = 0
    shares, assets = self._withdraw(_asset_amount, _receiver, _owner, _min_assets, pregen_info)
    self._dirtyAssetCache()
    return shares


### ERC20 functionality.

@internal
def _transfer(_from: address, _to: address, _value: uint256):
    assert self.balanceOf[_from] >= _value, "ERC20 transfer insufficient funds."
    self.balanceOf[_from] -= _value
    self.balanceOf[_to] += _value
    log Transfer(_from, _to, _value)


@internal
def _approve(_owner: address, _spender: address, _value: uint256):
    self.allowance[_owner][_spender] = _value
    log Approval(_owner, _spender, _value)


@internal
def _transferFrom(_operator: address, _from: address, _to:address, _value: uint256):
    assert self.balanceOf[_from] >= _value, "ERC20 transferFrom insufficient funds."
    self.balanceOf[_from] -= _value
    self.balanceOf[_to] += _value

    assert self.allowance[_from][_operator] >= _value, "ERC20 transfer insufficient allowance."

    self.allowance[_from][_operator] -= _value
    log Transfer(_from, _to, _value)


@external
def transfer(_to : address, _value : uint256) -> bool:
    """
    @dev Transfer token for a specified address
    @param _to The address to transfer to.
    @param _value The amount to be transferred.
    """
    self._transfer(msg.sender, _to, _value)
    return True


@external
def transferFrom(_from : address, _to : address, _value : uint256) -> bool:
    """
     @dev Transfer tokens from one address to another.
     @param _from address The address which you want to send tokens from
     @param _to address The address which you want to transfer to
     @param _value uint256 the amount of tokens to be transferred
    """
    self._transferFrom(msg.sender, _from, _to, _value)
    return True


@external
def approve(_spender : address, _value : uint256) -> bool:
    """
    @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
         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
    @param _spender The address which will spend the funds.
    @param _value The amount of tokens to be spent.
    """
    self._approve(msg.sender, _spender, _value) 
    return True    


@external
def claimRewards(_adapter: address, reciepent: address):
    assert msg.sender == self.owner, "Only owner can claimRewards!"
    assert _adapter in self.adapters, "Not a valid adapter"
    raw_call(
        _adapter,
        _abi_encode(reciepent, method_id=method_id("claimRewards(address)")),
        max_outsize=0,
        is_delegate_call=True,
        revert_on_failure=True
    )

@internal
def _manage_adapter(incoming_adapter: address, outgoing_adapter: address):
    #If there is an incoming adapter, take an exclusive lock, ensuring nobody (aside from possibly outgoing_adapter) has it locked.
    if incoming_adapter != 0x0000000000000000000000000000000000000000:
        #Update managed_tokens, while ensuring unique token lock
        incoming_handled: DynArray[address, 10] = IAdapter(incoming_adapter).managed_tokens()
        for token in incoming_handled:
            old: address = self.managed_tokens[token]
            assert old==outgoing_adapter, "incoming token already handled"
            self.managed_tokens[token] = incoming_adapter
    #In case of adapter removal... ensure all its magaged tokens are either transfered to new adapter or are released
    if outgoing_adapter != 0x0000000000000000000000000000000000000000:
        outgoing_handled: DynArray[address, 10] = IAdapter(outgoing_adapter).managed_tokens()
        for token in outgoing_handled:
            old: address = self.managed_tokens[token]
            if incoming_adapter == 0x0000000000000000000000000000000000000000:
                assert old == outgoing_adapter, "outgoing token already handled"
                self.managed_tokens[token] = 0x0000000000000000000000000000000000000000
            else:
                #ensures all old adapters tokens have been consumed by the new
                assert old == incoming_adapter, "outgoing token already handled"

Contract Security Audit

Contract ABI

[{"name":"AdapterAdded","inputs":[{"name":"sender","type":"address","indexed":true},{"name":"adapter_addr","type":"address","indexed":true}],"anonymous":false,"type":"event"},{"name":"AdapterRemoved","inputs":[{"name":"sender","type":"address","indexed":true},{"name":"afapter_addr","type":"address","indexed":true},{"name":"final_balance","type":"uint256","indexed":false},{"name":"forced","type":"bool","indexed":false}],"anonymous":false,"type":"event"},{"name":"Transfer","inputs":[{"name":"sender","type":"address","indexed":true},{"name":"receiver","type":"address","indexed":true},{"name":"value","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Approval","inputs":[{"name":"owner","type":"address","indexed":true},{"name":"spender","type":"address","indexed":true},{"name":"value","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Deposit","inputs":[{"name":"sender","type":"address","indexed":true},{"name":"owner","type":"address","indexed":true},{"name":"assets","type":"uint256","indexed":false},{"name":"shares","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"SlippageDeposit","inputs":[{"name":"sender","type":"address","indexed":true},{"name":"owner","type":"address","indexed":true},{"name":"assets","type":"uint256","indexed":false},{"name":"desired_shares","type":"uint256","indexed":false},{"name":"actual_shares","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Withdraw","inputs":[{"name":"sender","type":"address","indexed":true},{"name":"receiver","type":"address","indexed":true},{"name":"owner","type":"address","indexed":true},{"name":"assets","type":"uint256","indexed":false},{"name":"shares","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"SlippageWithdraw","inputs":[{"name":"sender","type":"address","indexed":true},{"name":"receiver","type":"address","indexed":true},{"name":"owner","type":"address","indexed":true},{"name":"assets","type":"uint256","indexed":false},{"name":"shares","type":"uint256","indexed":false},{"name":"actual_assets","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"StrategyActivation","inputs":[{"name":"strategy","type":"tuple[5]","components":[{"name":"adapter","type":"address"},{"name":"ratio","type":"uint256"}],"indexed":false},{"name":"proposer","type":"address","indexed":false}],"anonymous":false,"type":"event"},{"name":"AdapterLoss","inputs":[{"name":"adapter","type":"address","indexed":true},{"name":"last_value","type":"uint256","indexed":false},{"name":"current_value","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"GovernanceChanged","inputs":[{"name":"new_governor","type":"address","indexed":true},{"name":"old_governor","type":"address","indexed":true}],"anonymous":false,"type":"event"},{"name":"VaultDeployed","inputs":[{"name":"name","type":"string","indexed":true},{"name":"symbol","type":"string","indexed":true},{"name":"decimals","type":"uint8","indexed":false},{"name":"asset","type":"address","indexed":true}],"anonymous":false,"type":"event"},{"name":"FundsAllocatorChanged","inputs":[{"name":"new_allocator","type":"address","indexed":true},{"name":"old_allocator","type":"address","indexed":true}],"anonymous":false,"type":"event"},{"name":"OwnerChanged","inputs":[{"name":"new_owner","type":"address","indexed":true},{"name":"old_owner","type":"address","indexed":true}],"anonymous":false,"type":"event"},{"stateMutability":"nonpayable","type":"constructor","inputs":[{"name":"_name","type":"string"},{"name":"_symbol","type":"string"},{"name":"_decimals","type":"uint8"},{"name":"_erc20asset","type":"address"},{"name":"_governance","type":"address"},{"name":"_funds_allocator","type":"address"},{"name":"_max_slippage_percent","type":"fixed168x10"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"replaceOwner","inputs":[{"name":"_new_owner","type":"address"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"replaceGovernanceContract","inputs":[{"name":"_new_governance","type":"address"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"replaceFundsAllocator","inputs":[{"name":"_new_funds_allocator","type":"address"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"adapter_list","inputs":[],"outputs":[{"name":"","type":"address[]"}]},{"stateMutability":"nonpayable","type":"function","name":"set_strategy","inputs":[{"name":"_proposer","type":"address"},{"name":"_strategies","type":"tuple[5]","components":[{"name":"adapter","type":"address"},{"name":"ratio","type":"uint256"}]},{"name":"_min_proposer_payout","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"set_strategy","inputs":[{"name":"_proposer","type":"address"},{"name":"_strategies","type":"tuple[5]","components":[{"name":"adapter","type":"address"},{"name":"ratio","type":"uint256"}]},{"name":"_min_proposer_payout","type":"uint256"},{"name":"pregen_info","type":"bytes[]"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"add_adapter","inputs":[{"name":"_adapter","type":"address"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"remove_adapter","inputs":[{"name":"_adapter","type":"address"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"remove_adapter","inputs":[{"name":"_adapter","type":"address"},{"name":"_rebalance","type":"bool"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"remove_adapter","inputs":[{"name":"_adapter","type":"address"},{"name":"_rebalance","type":"bool"},{"name":"_force","type":"bool"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"remove_adapter","inputs":[{"name":"_adapter","type":"address"},{"name":"_rebalance","type":"bool"},{"name":"_force","type":"bool"},{"name":"_min_assets","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"remove_adapter","inputs":[{"name":"_adapter","type":"address"},{"name":"_rebalance","type":"bool"},{"name":"_force","type":"bool"},{"name":"_min_assets","type":"uint256"},{"name":"pregen_info","type":"bytes[]"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"swap_adapters","inputs":[{"name":"_adapterOld","type":"address"},{"name":"_adapterNew","type":"address"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"swap_adapters","inputs":[{"name":"_adapterOld","type":"address"},{"name":"_adapterNew","type":"address"},{"name":"_force","type":"bool"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"swap_adapters","inputs":[{"name":"_adapterOld","type":"address"},{"name":"_adapterNew","type":"address"},{"name":"_force","type":"bool"},{"name":"_min_assets","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"totalAssetsCached","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"totalAssets","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"totalReturns","inputs":[],"outputs":[{"name":"","type":"int256"}]},{"stateMutability":"view","type":"function","name":"claimable_yield_fees_available","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"claimable_yield_fees_available","inputs":[{"name":"_current_assets","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"claimable_strategy_fees_available","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"claimable_strategy_fees_available","inputs":[{"name":"_current_assets","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"claimable_all_fees_available","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"claimable_all_fees_available","inputs":[{"name":"_current_assets","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"claim_yield_fees","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"claim_yield_fees","inputs":[{"name":"_asset_request","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"claim_yield_fees","inputs":[{"name":"_asset_request","type":"uint256"},{"name":"pregen_info","type":"bytes[]"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"claim_strategy_fees","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"claim_strategy_fees","inputs":[{"name":"_asset_request","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"claim_strategy_fees","inputs":[{"name":"_asset_request","type":"uint256"},{"name":"pregen_info","type":"bytes[]"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"claim_all_fees","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"claim_all_fees","inputs":[{"name":"_asset_request","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"claim_all_fees","inputs":[{"name":"_asset_request","type":"uint256"},{"name":"pregen_info","type":"bytes[]"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"convertToShares","inputs":[{"name":"_asset_amount","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"convertToAssets","inputs":[{"name":"_share_amount","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"maxDeposit","inputs":[{"name":"_spender","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"previewDeposit","inputs":[{"name":"_asset_amount","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"maxMint","inputs":[{"name":"_receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"previewMint","inputs":[{"name":"_share_amount","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"mint","inputs":[{"name":"_share_amount","type":"uint256"},{"name":"_receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"mint","inputs":[{"name":"_share_amount","type":"uint256"},{"name":"_receiver","type":"address"},{"name":"pregen_info","type":"bytes[]"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"maxWithdraw","inputs":[{"name":"_owner","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"previewWithdraw","inputs":[{"name":"_asset_amount","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"maxRedeem","inputs":[{"name":"_owner","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"previewRedeem","inputs":[{"name":"_share_amount","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"redeem","inputs":[{"name":"_share_amount","type":"uint256"},{"name":"_receiver","type":"address"},{"name":"_owner","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"redeem","inputs":[{"name":"_share_amount","type":"uint256"},{"name":"_receiver","type":"address"},{"name":"_owner","type":"address"},{"name":"pregen_info","type":"bytes[]"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"getCurrentBalances","inputs":[],"outputs":[{"name":"","type":"uint256"},{"name":"","type":"tuple[5]","components":[{"name":"adapter","type":"address"},{"name":"current","type":"uint256"},{"name":"last_value","type":"uint256"},{"name":"max_deposit","type":"int256"},{"name":"max_withdraw","type":"int256"},{"name":"ratio","type":"uint256"},{"name":"target","type":"uint256"},{"name":"delta","type":"int256"}]},{"name":"","type":"uint256"},{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"balanceAdapters","inputs":[{"name":"_target_asset_balance","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"balanceAdapters","inputs":[{"name":"_target_asset_balance","type":"uint256"},{"name":"_min_tasset_balance","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"balanceAdapters","inputs":[{"name":"_target_asset_balance","type":"uint256"},{"name":"_min_tasset_balance","type":"uint256"},{"name":"_withdraw_only","type":"bool"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"balanceAdapters","inputs":[{"name":"_target_asset_balance","type":"uint256"},{"name":"_min_tasset_balance","type":"uint256"},{"name":"_withdraw_only","type":"bool"},{"name":"pregen_info","type":"bytes[]"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"deposit","inputs":[{"name":"_asset_amount","type":"uint256"},{"name":"_receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"deposit","inputs":[{"name":"_asset_amount","type":"uint256"},{"name":"_receiver","type":"address"},{"name":"_min_shares","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"deposit","inputs":[{"name":"_asset_amount","type":"uint256"},{"name":"_receiver","type":"address"},{"name":"_min_shares","type":"uint256"},{"name":"pregen_info","type":"bytes[]"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"withdraw","inputs":[{"name":"_asset_amount","type":"uint256"},{"name":"_receiver","type":"address"},{"name":"_owner","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"withdraw","inputs":[{"name":"_asset_amount","type":"uint256"},{"name":"_receiver","type":"address"},{"name":"_owner","type":"address"},{"name":"_min_assets","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"withdraw","inputs":[{"name":"_asset_amount","type":"uint256"},{"name":"_receiver","type":"address"},{"name":"_owner","type":"address"},{"name":"_min_assets","type":"uint256"},{"name":"pregen_info","type":"bytes[]"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"transfer","inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"transferFrom","inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"approve","inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"claimRewards","inputs":[{"name":"_adapter","type":"address"},{"name":"reciepent","type":"address"}],"outputs":[]},{"stateMutability":"view","type":"function","name":"name","inputs":[],"outputs":[{"name":"","type":"string"}]},{"stateMutability":"view","type":"function","name":"symbol","inputs":[],"outputs":[{"name":"","type":"string"}]},{"stateMutability":"view","type":"function","name":"decimals","inputs":[],"outputs":[{"name":"","type":"uint8"}]},{"stateMutability":"view","type":"function","name":"asset","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"owner","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"governance","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"funds_allocator","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"adapters","inputs":[{"name":"arg0","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"current_proposer","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"min_proposer_payout","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"strategy","inputs":[{"name":"arg0","type":"address"}],"outputs":[{"name":"","type":"tuple","components":[{"name":"ratio","type":"uint256"},{"name":"last_asset_value","type":"uint256"}]}]},{"stateMutability":"view","type":"function","name":"total_assets_deposited","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"total_assets_withdrawn","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"total_yield_fees_claimed","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"total_strategy_fees_claimed","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"totalSupply","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"balanceOf","inputs":[{"name":"arg0","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"allowance","inputs":[{"name":"arg0","type":"address"},{"name":"arg1","type":"address"}],"outputs":[{"name":"","type":"uint256"}]}]

Deployed Bytecode

0x5f3560e01c60056005600a8306026159d401601b395f5160088160ff16838360181c0260181c0660031b8260081c61ffff1601601839505f51818160201c14600336111661004c57611ab8565b8061fffe163610348260011602176159d0578060101c61ffff16565b6020806040528060400160206020615ca65f395f510180615ca68339508051806020830101601f825f03163682375050601f19601f825160200101169050810190506040f35b6020806040528060400160206020615d065f395f510180615d068339508051806020830101601f825f03163682375050601f19601f825160200101169050810190506040f35b6020615d4660403960206040f35b6020615d6660403960206040f35b5f5460405260206040f35b60015460405260206040f35b60025460405260206040f35b6004356003548110156159d0576004015460405260206040f35b600d5460405260206040f35b600e5460405260206040f35b6004358060a01c6159d057604052600f6040516020525f5260405f20805460605260018101546080525060406060f35b60105460405260206040f35b60115460405260206040f35b60125460405260206040f35b60135460405260206040f35b60145460405260206040f35b6004358060a01c6159d05760405260156040516020525f5260405f205460605260206060f35b6004358060a01c6159d0576040526024358060a01c6159d05760605260166040516020525f5260405f20806060516020525f5260405f2090505460805260206080f35b6004358060a01c6159d0576040525f543318156102d157602a6060527f4f6e6c79206578697374696e67206f776e65722063616e207265706c616365206080527f746865206f776e65722e0000000000000000000000000000000000000000000060a05260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b60405161033457601d6060527f4f776e65722063616e6e6f74206265206e756c6c20616464726573732e00000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b5f546040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c5f6060a36040515f55600160605260206060f35b6004358060a01c6159d0576040526001543318156104065760356060527f4f6e6c79206578697374696e6720476f7665726e616e636520636f6e747261636080527f74206d6179207265706c61636520697473656c662e000000000000000000000060a05260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b60405161048d5760226060527f476f7665726e616e63652063616e6e6f74206265206e756c6c206164647265736080527f732e00000000000000000000000000000000000000000000000000000000000060a05260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6001546040517f3aaaebeb4821d6a7e5c77ece53cff0afcc56c82add2c978dbbb7f73e84cbcfd25f6060a3604051600155600160605260206060f35b6004358060a01c6159d0576040525f543318156105605760346060527f4f6e6c79206f776e65722063616e206368616e6765207468652066756e6473206080527f616c6c6f636174696f6e20636f6e74726163742100000000000000000000000060a05260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516105e75760266060527f46756e6473416c6c6f6361746f722063616e6e6f74206265206e756c6c2061646080527f64726573732e000000000000000000000000000000000000000000000000000060a05260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6002546040517f55b78759f76af43b8df65e695ca7be30a78c78d2717322edb8141fb5a02389bf5f6060a3604051600255600160605260206060f35b602080604052806040015f6003548083528060051b5f82600581116159d057801561066457905b80600401548160051b60208801015260010181811861064a575b505082016020019150509050810190506040f35b5f6201c960526106ec565b6101843560040160058135116159d05780355f81600581116159d05780156106e157905b8060051b60208501013560208501016110008135116159d057602081350161102083026201c98001818382375050506001018181186106a7575b5050806201c9605250505b6004358060a01c6159d0576201c800526024358060a01c6159d0576201c820526044356201c840526064358060a01c6159d0576201c860526084356201c8805260a4358060a01c6159d0576201c8a05260c4356201c8c05260e4358060a01c6159d0576201c8e052610104356201c90052610124358060a01c6159d0576201c92052610144356201c940526201c8005162017460526101406201c820620174805e61016435620175c0526201c960515f81600581116159d05780156107d857905b61102081026201c980016020815101611020830262017600018183825e5050506001018181186107ad575b505080620175e052506107ed62021a40613574565b62021a405162021a2052600160405260016060525f60805261080d612765565b602062021a20f35b6004358060a01c6159d057610560526020610560516104e052610839610580613bba565b610580f35b60016201750052606036620175203761095f565b6024358060011c6159d0576201750052606036620175203761095f565b6024358060011c6159d05762017500526044358060011c6159d0576201752052604036620175403761095f565b6024358060011c6159d05762017500526044358060011c6159d057620175205260643562017540525f620175605261095f565b6024358060011c6159d05762017500526044358060011c6159d0576201752052606435620175405260843560040160058135116159d05780355f81600581116159d057801561095457905b8060051b60208501013560208501016110008135116159d0576020813501611020830262017580018183823750505060010181811861091a575b505080620175605250505b6004358060a01c6159d057620174e0526020620174e051620122205262017560515f81600581116159d05780156109bd57905b611020810262017580016020815101611020830262012260018183825e505050600101818118610992575b505080620122405250606062017500620173005e6109dd6201c620613d5e565b6201c620f35b60403661068037610a1f565b6044358060011c6159d057610680525f6106a052610a1f565b6044358060011c6159d057610680526064356106a0525b6004358060a01c6159d057610640526024358060a01c6159d05761066052602060806106406104e05e610a536106c061443d565b6106c0f35b6020610a65610120611fe3565b610120f35b6020610a7660c0611abc565b60c0f35b610a85610140611abc565b610140516101205260206101205160c052610aa1610140611b6c565b610140f35b5f61020052610ab8565b600435610200525b604036610220376102005161012052610ad2610260611bf4565b610260805161022052602081015161024052506020610220f35b5f61020052610afe565b600435610200525b604036610220376102005161012052610b18610260611bf4565b610260805161022052602081015161024052506020610240f35b5f61020052610b44565b600435610200525b604036610220376102005161012052610b5e610260611bf4565b6102608051610220526020810151610240525061022051610240518082018281106159d05790509050610260526020610260f35b6040366201746037610c22565b60043562017460525f6201748052610c22565b600435620174605260243560040160058135116159d05780355f81600581116159d0578015610c1757905b8060051b60208501013560208501016110008135116159d05760208135016110208302620174a00181838237505050600101818118610bdd575b505080620174805250505b6020600262012220526201746051620122405262017480515f81600581116159d0578015610c7757905b6110208102620174a0016020815101611020830262012280018183825e505050600101818118610c4c575b5050806201226052506040366201732037610c946201c540613133565b6201c540f35b6040366201746037610d2a565b60043562017460525f6201748052610d2a565b600435620174605260243560040160058135116159d05780355f81600581116159d0578015610d1f57905b8060051b60208501013560208501016110008135116159d05760208135016110208302620174a00181838237505050600101818118610ce5575b505080620174805250505b6020600462012220526201746051620122405262017480515f81600581116159d0578015610d7f57905b6110208102620174a0016020815101611020830262012280018183825e505050600101818118610d54575b5050806201226052506040366201732037610d9c6201c540613133565b6201c540f35b6040366201746037610e32565b60043562017460525f6201748052610e32565b600435620174605260243560040160058135116159d05780355f81600581116159d0578015610e2757905b8060051b60208501013560208501016110008135116159d05760208135016110208302620174a00181838237505050600101818118610ded575b505080620174805250505b6020600162012220526201746051620122405262017480515f81600581116159d0578015610e8757905b6110208102620174a0016020815101611020830262012280018183825e505050600101818118610e5c575b5050806201226052506040366201732037610ea46201c540613133565b6201c540f35b602060043561034052610ebe610300611abc565b610300516103605260406103406102005e610eda610320614878565b610320f35b602060043561034052610ef3610300611abc565b610300516103605260406103406102005e610f0f6103206149ae565b610320f35b6004358060a01c6159d0576040526f7fffffffffffffffffffffffffffffff60605260206060f35b602060043561034052610f50610300611abc565b610300516103605260406103406102005e610f6c610320614878565b610320f35b6004358060a01c6159d0576040526f7fffffffffffffffffffffffffffffff60605260206060f35b602060043561034052610fad610300611abc565b610300516103605260406103406102005e610fc96103206149ae565b610320f35b5f620174a052611041565b60443560040160058135116159d05780355f81600581116159d057801561103657905b8060051b60208501013560208501016110008135116159d05760208135016110208302620174c00181838237505050600101818118610ffc575b505080620174a05250505b6024358060a01c6159d05762017480526004356201c5c0526110656201c580611fe3565b6201c580516201c5e05260406201c5c06102005e6110856201c5a06149ae565b6201c5a0516201c560526040366201c580376201c560516201222052620174805162012240525f6201226052620174a0515f81600581116159d05780156110f357905b6110208102620174c00160208151016110208302620122a0018183825e5050506001018181186110c8575b5050806201228052506111086201c5c0614bc4565b6201c5c080516201c5805260208101516201c5a05250600160405260016060525f608052611134612765565b60206201c5a0f35b6004358060a01c6159d0576103005260206015610300516020525f5260405f20546103605261116c610320611abc565b610320516103805260406103606102005e6111886103406149ae565b610340f35b6020600435610340526111a1610300611abc565b610300516103605260406103406102005e6111bd610320614878565b610320f35b6004358060a01c6159d05760405260156040516020525f5260405f205460605260206060f35b6020600435610340526111fc610300611abc565b610300516103605260406103406102005e6112186103206149ae565b610320f35b5f6201746052611290565b60643560040160058135116159d05780355f81600581116159d057801561128557905b8060051b60208501013560208501016110008135116159d0576020813501611020830262017480018183823750505060010181811861124b575b505080620174605250505b6024358060a01c6159d05762017420526044358060a01c6159d05762017440526004356201c580526112c46201c540611fe3565b6201c540516201c5a05260406201c5806102005e6112e46201c5606149ae565b6201c560516201c520526040366201c540376201c52051620122205262017420516201224052620174405162012260525f620122805262017460515f81600581116159d057801561135c57905b6110208102620174800160208151016110208302620122c0018183825e505050600101818118611331575b505080620122a052506113716201c580615229565b6201c58080516201c5405260208101516201c5605250600160405260016060525f60805261139d612765565b60206201c560f35b610560366106a0376113b8610c00612367565b610c0080516106a05260208101610500816106c05e50610520810151610bc052610540810151610be05250600160405260016060525f6080526113f9612765565b6106a051610c00526105006106c0610c205e6040610bc06111205e610560610c00f35b60603662012220376114e1565b602435620122205260403662012240376114e1565b60243562012220526044358060011c6159d05762012240525f62012260526114e1565b60243562012220526044358060011c6159d057620122405260643560040160058135116159d05780355f81600581116159d05780156114d657905b8060051b60208501013560208501016110008135116159d0576020813501611020830262012280018183823750505060010181811861149c575b505080620122605250505b5f5433181561157e57602362017320527f6f6e6c79206f776e65722063616e2063616c6c2062616c616e6365416461707462017340527f6572730000000000000000000000000000000000000000000000000000000000620173605262017320506201732051806201734001601f825f031636823750506308c379a0620172e05260206201730052601f19601f62017320510116604401620172fcfd5b60043561c44052620122205161c4605262012260515f81600581116159d05780156115cf57905b611020810262012280016020815101611020830261c4a0018183825e5050506001018181186115a5575b50508061c4805250620122405162011540526115ed62017340612cc5565b62017340516201732052600160405260016060525f60805261160d612765565b602062017320f35b604036620174a0376116a5565b604435620174a0525f620174c0526116a5565b604435620174a05260643560040160058135116159d05780355f81600581116159d057801561169a57905b8060051b60208501013560208501016110008135116159d05760208135016110208302620174e00181838237505050600101818118611660575b505080620174c05250505b6024358060a01c6159d05762017480526040366201c580376004356201222052604062017480620122405e620174c0515f81600581116159d057801561171257905b6110208102620174e00160208151016110208302620122a0018183825e5050506001018181186116e7575b5050806201228052506117276201c5c0614bc4565b6201c5c080516201c5805260208101516201c5a05250600160405260016060525f608052611753612765565b60206201c580f35b60403662017460376117eb565b60643562017460525f62017480526117eb565b606435620174605260843560040160058135116159d05780355f81600581116159d05780156117e057905b8060051b60208501013560208501016110008135116159d05760208135016110208302620174a001818382375050506001018181186117a6575b505080620174805250505b6024358060a01c6159d05762017420526044358060a01c6159d05762017440526040366201c540376004356201222052606062017420620122405e62017480515f81600581116159d057801561186857905b6110208102620174a00160208151016110208302620122c0018183825e50505060010181811861183d575b505080620122a0525061187d6201c580615229565b6201c58080516201c5405260208101516201c5605250600160405260016060525f6080526118a9612765565b60206201c540f35b6004358060a01c6159d0576101005233604052610100516060526024356080526118d9615677565b6001610120526020610120f35b6004358060a01c6159d057610120526024358060a01c6159d0576101405233604052604061012060605e60443560a05261191e6157e0565b6001610160526020610160f35b6004358060a01c6159d05760c0523360405260c05160605260243560805261195161578b565b600160e052602060e0f35b6004358060a01c6159d0576040526024358060a01c6159d0576060525f543318156119dd57601c6080527f4f6e6c79206f776e65722063616e20636c61696d52657761726473210000000060a0526080506080518060a001601f825f031636823750506308c379a06040526020606052601f19601f6080510116604401605cfd5b6040515f6080525f600354600581116159d0578015611a1857905b80600401548318611a0d576001608052611a18565b6001018181186119f8575b50506080519050611a7f57601360a0527f4e6f7420612076616c696420616461707465720000000000000000000000000060c05260a05060a0518060c001601f825f031636823750506308c379a06060526020608052601f19601f60a0510116604401607cfd5b6040515a63ef5cfb8c608452600460605160a4526020016080526080505f5f60805160a08585f490509050611ab6573d5f5f3e3d5ffd5b005b5f5ffd5b6020615d665f395f516370a0823160605230608052602060606024607c845afa611ae8573d5f5f3e3d5ffd5b60203d106159d05760609050516040525f600354600581116159d0578015611b6257905b80600401546060526040516060516301e1d114608052602060806004609c845afa611b39573d5f5f3e3d5ffd5b60203d106159d05760809050518082018281106159d05790509050604052600101818118611b0c575b5050604051815250565b60c05160e05260e051611b8c57611b84610100611abc565b6101005160e0525b60115460e0518082018281106159d057905090506012548082018281106159d057905090506013548082018281106159d057905090508060ff1c6159d0576010548060ff1c6159d0578082038281135f8312186159d057905090506101005261010051815250565b610120516101405261014051611c1857611c0f610160611abc565b61016051610140525b6101405160c052611c2a610180611b6c565b61018051610160525f6101605113611c4b575f81525f602082015250611cf8565b60403661018037610160515f81126159d0578060011b818160011c186159d05790506064810490506101c052610160515f81126159d0576001811517156159d0575f90506064810490506101e0526101c0516012541015611cc0576101c0516012548082038281116159d05790509050610180525b6101e0516013541015611ce7576101e0516013548082038281116159d057905090506101a0525b6101805181526101a0516020820152505b565b604036610260376102405161012052611d146102a0611bf4565b6102a08051610260526020810151610280525060026102005118611d38575f610280525b60046102005118611d49575f610260525b600d54611d56575f610260525b60026102005118611d68576001611d71565b60016102005118155b611d7b575f611d81565b5f543314155b15611d8c575f610260525b60046102005118611d9e576001611da7565b60016102005118155b15611e5157600d543318611dbc576001611dc3565b6001543318155b611e5157603b6102a0527f4f6e6c7920637572656e742070726f706f736572206f7220676f7665726e616e6102c0527f6365206d617920636c61696d20737472617465677920666565732e00000000006102e0526102a0506102a051806102c001601f825f031636823750506308c379a061026052602061028052601f19601f6102a051011660440161027cfd5b61026051610280518082018281106159d05790509050610220511115611efb57602c6102a0527f4e6f7420656e6f756768206665657320746f2066756c66696c6c2072657175656102c0527f7374656420616d6f756e742e00000000000000000000000000000000000000006102e0526102a0506102a051806102c001601f825f031636823750506308c379a061026052602061028052601f19601f6102a051011660440161027cfd5b61026051815261028051602082015250565b600a5c611f55576020615d665f395f516370a0823160405230606052602060406024605c845afa611f40573d5f5f3e3d5ffd5b60203d106159d0576040905051600a5d5f600c5d5b600a5c815250565b604051611f6d575f815250611fe1565b600b6040516020525f5260405f205c60605260605115611f9257606051815250611fe1565b6040516301e1d114608052602060806004609c845afa611fb4573d5f5f3e3d5ffd5b60203d106159d0576080905051606052606051600b6040516020525f5260405f205d5f600c5d6060518152505b565b600c5c15611ff657600c5c815250612065565b61200060e0611f0d565b60e05160c0525f600354600581116159d057801561205657905b806004015460e05260c05160e051604052612036610100611f5d565b610100518082018281106159d0579050905060c05260010181811861201a575b505060c051600c5d60c0518152505b565b606051608052606051612111576040516402540be4007036f9bfb3af7b756fad5cd10396a21346cb82116159d057810290506020615c865f395f5164e8d4a510006402540be4008202058060140b81186159d05790508082028115838383051417156159d0576402540be40081058060140b81186159d0579050905090506402540be4005f82126159d0578105905060a05260405160a0518082038281116159d057905090506080525b608051604051101561219d57603260a0527f44657369726564206173736574732063616e6e6f74206265206c65737320746860c0527f616e206d696e696d756d2061737365747321000000000000000000000000000060e05260a05060a0518060c001601f825f031636823750506308c379a06060526020608052601f19601f60a0510116604401607cfd5b608051815250565b610120516121d6576121b8610160611fe3565b61016051610140518082038281116159d05790509050815250612228565b604061012060405e6121e9610160612067565b61016051610140526121fc610160611fe3565b6101605161012051610140518082038281116159d057905090508082038281116159d057905090508152505b565b60405163ac7a1b5b608052602060806004609c845afa61224c573d5f5f3e3d5ffd5b60203d106159d05760809050516060527f8000000000000000000000000000000000000000000000000000000000000000606051106122aa577f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6060525b6060518060ff1c6159d057805f03600160ff1b82141582825f031416156159d0579050815250565b604051636083e59a608052602060806004609c845afa6122f4573d5f5f3e3d5ffd5b60203d106159d05760809050516060527f800000000000000000000000000000000000000000000000000000000000000060605110612356577f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff815250612365565b6060518060ff1c6159d0578152505b565b61237160e0611f0d565b60e05160c0526105003660e0376003546123ac5760c05181526020810161050060e0825e5060c0516105208201525f61054082015250612566565b60c0516105e052604036610600375f600354600581116159d057801561253d57905b8060040154610640526106405161062051600481116159d05760081b60e0015261064051604052612400610660611f5d565b6106605161062051600481116159d05760081b60e001602081019050526105e05161062051600481116159d05760081b60e001602081019050518082018281106159d057905090506105e0526106405160405261245e61066061222a565b6106605161062051600481116159d05760081b60e001608081019050526106405160405261248d6106606122d2565b6106605161062051600481116159d05760081b60e00160608101905052600f610640516020525f5260405f20805461066052600181015461068052506106605161062051600481116159d05760081b60e00160a0810190505261060051610660518082018281106159d05790509050610600526106805161062051600481116159d05760081b60e0016040810190505261062051600181018181106159d0579050610620526001018181186123ce575b505060c05181526020810161050060e0825e506105e05161052082015261060051610540820152505b565b6020615d665f395f516370a082316106005230610620526020610600602461061c845afa612598573d5f5f3e3d5ffd5b60203d106159d0576106009050516105e052600254633c64f7d8610600526105e0516106205260405161064052606060606106605e61050060c06106c05e6105c051610bc0526101e06106006105c461061c845afa6125f9573d5f5f3e3d5ffd5b6101e03d106159d05761060051610be052610620518060a01c6159d057610c005261064051610c2052610660518060a01c6159d057610c405261068051610c60526106a0518060a01c6159d057610c80526106c051610ca0526106e0518060a01c6159d057610cc05261070051610ce052610720518060a01c6159d057610d0052610740518060a01c6159d057610d2052610760518060a01c6159d057610d4052610780518060a01c6159d057610d60526107a0518060a01c6159d057610d80526107c0518060a01c6159d057610da052610be090506101e081835e5050565b6003546040511861275e575f615120525f600354600581116159d057801561275b57905b80600401546151405261514051615100511861273b57611020615120516040518110156159d0570260600160208151018082865e5050505050612763565b61512051600181018181106159d0579050615120526001018181186126fd575b50505b5f8152505b565b5f600c5d60405115612776575f600a5d5b606051156127d4576080516127c3575f600354600581116159d05780156127bc57905b806004015460a0525f600b60a0516020525f5260405f205d600101818118612799575b50506127d4565b5f600b6080516020525f5260405f205d5b565b6151a0515f81600581116159d057801561281457905b61102081026151c001602081510161102083026060018183825e5050506001018181186127ec575b50508060405250615160516151005261282e61b2806126d9565b61b2806020815101808261a2605e50505f61b280526151605160405261285561b2e0611f5d565b61b2e05161b2c052615160515a635d30351961b2e452600460406151805161b304528061b324528061b30401602061a26051018061a260835e508051806020830101601f825f03163682375050601f19601f825160200101169050810190500161b2e05261b2e050602061c3a061b2e05161b3008585f4905090506128dc573d5f5f3e3d5ffd5b3d602081183d602010021861c3805261c3806020815101808261b2805e50506001604052600160605261516051608052612914612765565b6151605160405261292661b300611f5d565b61b3005161b2e05261b2e051600f615160516020525f5260405f2060018101905055565b6151c0515f81600581116159d057801561298857905b61102081026151e001602081510161102083026060018183825e505050600101818118612960575b5050806040525061516051615100526129a261b2c06126d9565b61b2c06020815101808261a2a05e50506020615d665f395f516370a0823161b2e0526151a05161b30052602061b2e0602461b2fc845afa6129e5573d5f5f3e3d5ffd5b60203d106159d05761b2e090505161b2c0525f61b2e052600161b3205261516051612a6f57600e61b340527f454d50545920414441505445522100000000000000000000000000000000000061b3605261b3405061b340518061b36001601f825f031636823750506308c379a061b30052602061b32052601f19601f61b34051011660440161b31cfd5b6151a051612adc57601261b340527f454d5054592057495448445241575f544f21000000000000000000000000000061b3605261b3405061b340518061b36001601f825f031636823750506308c379a061b30052602061b32052601f19601f61b34051011660440161b31cfd5b61a28051612b8857615160515a6362b2b5f061b3445260046060604061518061b3645e8061b3a4528061b36401602061a2a051018061a2a0835e508051806020830101601f825f03163682375050601f19601f825160200101169050810190500161b3405261b34050602061c42061b3405161b3608585f490509050612b64573d5f5f3e3d5ffd5b3d602081183d602010021861c4005261c4006020815101808261b2e05e5050612c20565b615160515a6362b2b5f061b3445260046060604061518061b3645e8061b3a4528061b36401602061a2a051018061a2a0835e508051806020830101601f825f03163682375050601f19601f825160200101169050810190500161b3405261b34050602061c42061b3405161b3608585f49050905061b320523d602081183d602010021861c4005261c4006020815101808261b2e05e50505b6001604052600160605261516051608052612c39612765565b6020615d665f395f516370a0823161b360526151a05161b38052602061b360602461b37c845afa612c6c573d5f5f3e3d5ffd5b60203d106159d05761b36090505161b3405261516051604052612c9061b360611f5d565b61b36051600f615160516020525f5260405f206001810190505561b3405161b2c0518082038281116159d05790509050815250565b6101e0366201156037604061c4406101205e612ce3620117606121a5565b62011760516201174052600354612d3f576020615d665f395f516370a08231620117605230620117805260206201176060246201177c845afa612d28573d5f5f3e3d5ffd5b60203d106159d05762011760905051815250613131565b610560366201176037612d5462011cc0612367565b62011cc0805162011760526020810161050081620117805e5061052081015162011c805261054081015162011ca0525061c44051604052600e54606052604062011c8060805e6105006201178060c05e62011540516105c052612db962011cc0612568565b62011cc061014081620115605e610140810160a081620116a05e50505f6005905b8060051b620116a0015162011cc05262011cc051612df757612ed2565b600f62011cc0516020525f5260405f20805462011ce052600181015462011d0052505f62011ce052600f62011cc0516020525f5260405f2062011ce051815562011d005160018201555062011cc051604052612e5562011d40611f5d565b62011d405162011d2052620117405162011d005162011d20518082038281116159d057905090508082038281116159d05790509050620117405262011cc0517f8af0bf5fccd11158fcb7ce9747ad88f3bc6f4c3d21019bc157b1fea3f052ddcc604062011d0062011d405e604062011d40a2600101818118612dda575b50505f6005905b8060061b620115600160408162011cc05e5062011ce051612ef95761307a565b62011cc051612f075761306f565b600e548060ff1c6159d05762011cc0511215612fe7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff62011cc0511361306f5762011cc051805f03600160ff1b82141582825f031416156159d05790505f81126159d05762011d0052604062011ce06151605e306151a05261c480515f81600581116159d0578015612fbf57905b611020810261c4a001602081510161102083026151e0018183825e505050600101818118612f96575b5050806151c052505f61a28052612fd862011d4061294a565b62011d405162011d205261306f565b62011cc0515f81126159d057612fff62011d20611f0d565b62011d20518082811882841002189050905062011d0052604062011ce06151605e61c480515f81600581116159d057801561305f57905b611020810261c4a001602081510161102083026151c0018183825e505050600101818118613036575b5050806151a0525061306f6127d6565b600101818118612ed9575b505061308862011ce0611fe3565b62011ce05162011cc05262011740516130a362011ce0611fe3565b62011ce051101561311c57601262011d00527f536c69707061676520657863656564656421000000000000000000000000000062011d205262011d005062011d00518062011d2001601f825f031636823750506308c379a062011cc052602062011ce052601f19601f62011d0051011660440162011cdcfd5b61312862011ce0611f0d565b62011ce0518152505b565b60403662017360376040620122206102005e62017320516102405261315a620173a0611cfa565b620173a0805162017360526020810151620173805250620173605162017380518082018281106159d05790509050620173a0526201224051156131a2576201224051620173a0525b6131ae620173e0611f0d565b620173e051620173c052620173a051620173c051106131e857620173a051620173c05180828118828410021890509050620173a052613273565b620173a05161c44052620173405161c4605262012260515f81600581116159d057801561323b57905b611020810262012280016020815101611020830261c4a0018183825e505050600101818118613211575b50508061c480525060016201154052613256620173e0612cc5565b620173e051620173a05180828118828410021890509050620173a0525b620173805115613289576201736051151561328b565b5f5b6132b7576201738051156132a857620173a05162017380526133b9565b620173a05162017360526133b9565b62017380516402540be4007036f9bfb3af7b756fad5cd10396a21346cb82116159d05781029050620173805162017360518082018281106159d057905090506402540be4007036f9bfb3af7b756fad5cd10396a21346cb82116159d0578102905080156159d057806402540be4008302058060140b81186159d05790509050620173a0516402540be4007036f9bfb3af7b756fad5cd10396a21346cb82116159d057810290508082028115838383051417156159d0576402540be40081058060140b81186159d0579050905090506402540be4005f82126159d057810590506201738052620173a05162017380518082038281116159d0579050905062017360525b60125462017360518082018281106159d0579050905060125560135462017380518082018281106159d0579050905060135562017380511561340157600d545f541415613403565b5f5b156134aa57600d543318613418576001613423565b600e54620173805110155b156134a3576020615d665f395f5163a9059cbb620173e052600d546201740052620173805162017420526020620173e06044620173fc5f855af1613469573d5f5f3e3d5ffd5b3d61348157803b156159d0576001620174405261349c565b60203d106159d057620173e0518060011c6159d05762017440525b6201744050505b5f62017380525b620173605162017380518082018281106159d0579050905015613554576020615d665f395f5163a9059cbb620173e0525f546201740052620173605162017380518082018281106159d0579050905062017420526020620173e06044620173fc5f855af161351a573d5f5f3e3d5ffd5b3d61353257803b156159d0576001620174405261354d565b60203d106159d057620173e0518060011c6159d05762017440525b6201744050505b600160405260016060525f60805261356a612765565b620173a051815250565b60015433181561361257602b6201c6a0527f4f6e6c7920476f7665726e616e63652044414f206d6179207365742061206e656201c6c0527f772073747261746567792e0000000000000000000000000000000000000000006201c6e0526201c6a0506201c6a051806201c6c001601f825f031636823750506308c379a06201c6605260206201c68052601f19601f6201c6a05101166044016201c67cfd5b620174605161368957601f6201c6a0527f50726f706f7365722063616e2774206265206e756c6c20616464726573732e006201c6c0526201c6a0506201c6a051806201c6c001601f825f031636823750506308c379a06201c6605260206201c68052601f19601f6201c6a05101166044016201c67cfd5b6201746051600d5414613778576136a26201c6c0611abc565b6201c6c0516201c6a0526040366201c6c0376201c6a051610120526136c96201c700611bf4565b6201c70080516201c6c05260208101516201c6e05250600e546201c6e051111561376757600462012220525f6201224052620175e0515f81600581116159d057801561373c57905b611020810262017600016020815101611020830262012280018183825e505050600101818118613711575b5050806201226052506201c6a05162017320525f62017340526137616201c700613133565b6201c700505b6201746051600d55620175c051600e555b5f600354600581116159d05780156137b357905b80600401546201c6a0525f600f6201c6a0516020525f5260405f205560010181811861378c575b50505f6005905b8060061b62017480016040816201c6a05e506040366201c6e0376201c6c0516201c6e052600f6201c6a0516020525f5260405f20600181019050546201c70052600f6201c6a0516020525f5260405f206201c6e05181556201c700516001820155506001018181186137ba5750507f357e53e5fd1ca670f6f6f6174e30cb36eda3d81b8ca610e6cc90668610c810f4610140620174806201c6a05e62017460516201c7e0526101606201c6a0a16001815250565b604051156139d55760405163ed2127186101e0526101806101e060046101fc845afa61389c573d5f5f3e3d5ffd5b60403d106159d0576101e0516101e001600a8151116159d05780515f81600a81116159d05780156138ef57905b8060051b6020850101518060a01c6159d0578160051b6103a001526001018181186138c9575b5050806103805250506103809050805160208160051b01808360805e5050505f608051600a81116159d05780156139d257905b8060051b60a001516101e05260096101e0516020525f5260405f2054610200526060516102005118156139b457601e610220527f696e636f6d696e6720746f6b656e20616c72656164792068616e646c656400006102405261022050610220518061024001601f825f031636823750506308c379a06101e052602061020052601f19601f6102205101166044016101fcfd5b60405160096101e0516020525f5260405f2055600101818118613922575b50505b60605115613bb85760605163ed2127186101e0526101806101e060046101fc845afa613a03573d5f5f3e3d5ffd5b60403d106159d0576101e0516101e001600a8151116159d05780515f81600a81116159d0578015613a5657905b8060051b6020850101518060a01c6159d0578160051b6103a00152600101818118613a30575b5050806103805250506103809050805160208160051b01808360805e5050505f608051600a81116159d0578015613bb557905b8060051b60a001516101e05260096101e0516020525f5260405f205461020052604051613b3857606051610200511815613b2257601e610220527f6f7574676f696e6720746f6b656e20616c72656164792068616e646c656400006102405261022050610220518061024001601f825f031636823750506308c379a06101e052602061020052601f19601f6102205101166044016101fcfd5b5f60096101e0516020525f5260405f2055613baa565b604051610200511815613baa57601e610220527f6f7574676f696e6720746f6b656e20616c72656164792068616e646c656400006102405261022050610220518061024001601f825f031636823750506308c379a06101e052602061020052601f19601f6102205101166044016101fcfd5b600101818118613a89575b50505b565b5f54331815613c4d576028610500527f4f6e6c79206f776e65722063616e20616464206e6577204c656e64696e672041610520527f646170746572732e0000000000000000000000000000000000000000000000006105405261050050610500518061052001601f825f031636823750506308c379a06104c05260206104e052601f19601f6105005101166044016104dcfd5b6104e0515f610500525f600354600581116159d0578015613c8b57905b80600401548318613c8057600161050052613c8b565b600101818118613c6a575b505061050051905015613cfd57601a610520527f6164617074657220616c726561647920737570706f727465642e0000000000006105405261052050610520518061054001601f825f031636823750506308c379a06104e052602061050052601f19601f6105205101166044016104fcfd5b600354600481116159d0576104e051816004015560018101600355506104e0516040525f606052613d2c61386e565b6104e051337f4b3749a16ab97cf0e9866299c183369da7570769bb78bd2c62a7df5c8da426315f610500a36001815250565b5f54331815613dfb57602762017360527f4f6e6c79206f776e65722063616e2072656d6f7665204c656e64696e6720416462017380527f6170746572732e00000000000000000000000000000000000000000000000000620173a05262017360506201736051806201738001601f825f031636823750506308c379a0620173205260206201734052601f19601f620173605101166044016201733cfd5b6201222051600162017360525f600354600581116159d0578015613e3c57905b80600401548318613e31575f6201736052613e3c565b600101818118613e1b575b50506201736051905015613e53575f81525061443b565b6201222051604052613e6762017380611f5d565b6201738051620173605262017360516040526201734051606052613e8d620173a0612067565b620173a0516201738052620173605162017380518082038281116159d05790509050620173a0525f600f62012220516020525f5260405f2055600162017300511861413a57613ede620173e0611fe3565b620173e051620173c0525f61c44052620173a05161c4605262012240515f81600581116159d0578015613f3757905b611020810262012260016020815101611020830261c4a0018183825e505050600101818118613f0d575b50508061c48052505f6201154052613f51620173e0612cc5565b620173e050620173205161432257613f6b62017400611fe3565b6201740051620173e052620173c051620173e051101561432257620173c051620173e0518082038281116159d05790509050620174005262017400516201736051101561406c57605062017420527f4552524f52202d206c6f7373207761732067726561746572207468616e20616462017440527f6170746572206173736574732e2054727920746f2072656d6f7665207769746862017460527f6f757420726562616c616e63696e672e00000000000000000000000000000000620174805262017420506201742051806201744001601f825f031636823750506308c379a0620173e05260206201740052601f19601f62017420510116604401620173fcfd5b6201740051620173a051101561432257604e62017420527f4552524f52202d20746f6f206d75636820736c6970706167652072656d6f766962017440527f6e6720616461707465722e2054727920746f2072656d6f766520776974686f7562017460527f7420726562616c616e63696e672e000000000000000000000000000000000000620174805262017420506201742051806201744001601f825f031636823750506308c379a0620173e05260206201740052601f19601f62017420510116604401620173fcfd614322565b62017360511561432257620122205161516052620173605161518052306151a05262012240515f81600581116159d057801561419c57905b61102081026201226001602081510161102083026151e0018183825e505050600101818118614172575b5050806151c05250620173205161a280526141b9620173e061294a565b620173e051620173c05262017320516143225762012220516040526141e0620173e0611f5d565b620173e0511561427e57603762017400527f4552524f52202d2061646170746572206164617074657220746f20626520726562017420527f6d6f766564207374696c6c206861732061737365747321000000000000000000620174405262017400506201740051806201742001601f825f031636823750506308c379a0620173c0526020620173e052601f19601f62017400510116604401620173dcfd5b620173c0516201738051111561432257602e620173e0527f4552524f52202d20746f6f206d75636820736c697070616765206f6e2061646162017400527f707465722077697468647261772e0000000000000000000000000000000000006201742052620173e050620173e051806201740001601f825f031636823750506308c379a0620173a0526020620173c052601f19601f620173e0510116604401620173bcfd5b5f620173c0525f600354600581116159d057801561438757905b80600401546201748052620122205162017480511461437c57620173c051600481116159d05762017480518160051b620173e0015260018101620173c052505b60010181811861433c575b5050620173c05160208160051b015f81601f0160051c600681116159d05780156143c757905b8060051b620173c0015181600301556001018181186143ad575b505050505f60405262012220516060526143df61386e565b6201222051337f25a12528a39d56c4ad0183f3bbb17f4d36cb1bcf8f360da144ad4fd321f78eae620122205160405261441a62017480611f5d565b6201748051620174a0526201732051620174c0526040620174a0a360018152505b565b5f543318156144d0576025610560527f4f6e6c79206f776e65722063616e2073776170204c656e64696e672041646170610580527f746572732e0000000000000000000000000000000000000000000000000000006105a05261056050610560518061058001601f825f031636823750506308c379a061052052602061054052601f19601f61056051011660440161053cfd5b6104e051156144e4576105005115156144e6565b5f5b614574576025610560527f43616e2774206861766520656d707479206164647265737320666f7220616461610580527f707465722e0000000000000000000000000000000000000000000000000000006105a05261056050610560518061058001601f825f031636823750506308c379a061052052602061054052601f19601f61056051011660440161053cfd5b6104e051604052614586610580611f5d565b6105805161056052610500516040526145a06105a0611f5d565b6105a05161058052610520516145bb576105605115156145bd565b5f5b1561468957610560516105805110156146895761056051604052610540516060526145e96105c0612067565b6105c0516105a052610580516105a05111156146895760266105c0527f4552524f52202d20537761702065786365656473206d6178696d756d20736c696105e0527f70706167652e0000000000000000000000000000000000000000000000000000610600526105c0506105c051806105e001601f825f031636823750506308c379a06105805260206105a052601f19601f6105c051011660440161059cfd5b6040366105a0375f600354600581116159d05780156146e557905b80600401546105e0526104e0516105e051186146c55760016105c0526146e5565b6105a051600181018181106159d05790506105a0526001018181186146a4575b50506105c0516147795760256105e0527f4164617074657220746f206265207265706c6163656420776173206e6f742066610600527f6f756e642e000000000000000000000000000000000000000000000000000000610620526105e0506105e0518061060001601f825f031636823750506308c379a06105a05260206105c052601f19601f6105e05101166044016105bcfd5b610500516105a0516003548110156159d05760040155600f6104e0516020525f5260405f2054600f610500516020525f5260405f205561058051600f610500516020525f5260405f2060018101905055600f6104e0516020525f5260405f205f81555f600182015550610500516040526104e0516060526147f861386e565b6104e051337f25a12528a39d56c4ad0183f3bbb17f4d36cb1bcf8f360da144ad4fd321f78eae6104e0516040526148306105e0611f5d565b6105e0516106005261052051610620526040610600a361050051337f4b3749a16ab97cf0e9866299c183369da7570769bb78bd2c62a7df5c8da426315f6105e0a36001815250565b601454610240526040366102603761022051610120526148996102a0611bf4565b6102a08051610260526020810151610280525061026051610280518082018281106159d057905090506102a052610240516148da57610200518152506149ac565b610220516148ee57610200518152506149ac565b6102a0516102205110156149615760206102c0527f5f636f6e76657274546f5368617265732073616e697479206661696c757265216102e0526102c0506102c051806102e001601f825f031636823750506308c379a06102805260206102a052601f19601f6102c051011660440161029cfd5b610220516102a0518082038281116159d057905090506102c05261020051610240518082028115838383041417156159d057905090506102c05180156159d057808204905090508152505b565b601454610240526040366102603761022051610120526149cf6102a0611bf4565b6102a08051610260526020810151610280525061026051610280518082018281106159d057905090506102a0526102a051610220511015614a6f5760206102c0527f5f636f6e76657274546f4173736574732073616e697479206661696c757265216102e0526102c0506102c051806102e001601f825f031636823750506308c379a06102805260206102a052601f19601f6102c051011660440161029cfd5b61024051614a835761020051815250614aec565b610220516102a0518082038281116159d05790509050614aa95761020051815250614aec565b61020051610220516102a0518082038281116159d057905090508082028115838383041417156159d057905090506102405180156159d057808204905090508152505b565b604051614b515760186080527f52656365697665722063616e6e6f74206265207a65726f2e000000000000000060a0526080506080518060a001601f825f031636823750506308c379a06040526020606052601f19601f6080510116604401605cfd5b6014546060518082018281106159d0579050905060145560156040516020525f5260405f2080546060518082018281106159d057905090508155506040515f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60605160805260206080a3606051815250565b6201224051614c6157602362017340527f43616e6e6f742073656e642073686172657320746f207a65726f20616464726562017360527f73732e0000000000000000000000000000000000000000000000000000000000620173805262017340506201734051806201736001601f825f031636823750506308c379a0620173005260206201732052601f19601f620173405101166044016201731cfd5b6020615d665f395f516370a08231620173405233620173605260206201734060246201735c845afa614c95573d5f5f3e3d5ffd5b60203d106159d0576201734090505162012220511115614d1d57601f62017380527f343632364465706f73697420696e73756666696369656e742066756e64732e00620173a0526201738050620173805180620173a001601f825f031636823750506308c379a0620173405260206201736052601f19601f620173805101166044016201735cfd5b614d2962017360611fe3565b62017360516201734052620122205161020052620173405161022052614d5162017380614878565b62017380516201736052620122605115614e0d57620122605162017360511015614e3457602a62017380527f4465706f73697420746f6f206c6f7720746f2072656365697665206d696e696d620173a0527f756d207368617265732e00000000000000000000000000000000000000000000620173c0526201738050620173805180620173a001601f825f031636823750506308c379a0620173405260206201736052601f19601f620173805101166044016201735cfd614e34565b62017360516040526201226051606052614e2962017380612067565b620173805162012260525b620122605161020052620173405161022052614e52620173a06149ae565b620173a05162017380526020615d665f395f516323b872dd620173a05233620173c05230620173e052620122205162017400526020620173a06064620173bc5f855af1614ea1573d5f5f3e3d5ffd5b3d614eb957803b156159d05760016201742052614ed4565b60203d106159d057620173a0518060011c6159d05762017420525b6201742050506001604052604036606037614eed612765565b5f61c44052620122205162017380518082038281116159d0579050905061c4605262012280515f81600581116159d0578015614f4f57905b6110208102620122a0016020815101611020830261c4a0018183825e505050600101818118614f25575b50508061c48052505f6201154052614f69620173c0612cc5565b620173c051620173a052614f7f620173e0611fe3565b620173e051620173c0526201734051620173c0511161502c57602b620173e0527f4552524f52202d206465706f73697420726573756c74656420696e206c6f737362017400527f206f6620617373657473210000000000000000000000000000000000000000006201742052620173e050620173e051806201740001601f825f031636823750506308c379a0620173a0526020620173c052601f19601f620173e0510116604401620173bcfd5b620173c05162017340518082038281116159d05790509050620173e052620173e0516102005262017340516102205261506762017420614878565b6201742051620174005262017360516201740051101561517c5762012260516201740051101561512557603962017420527f4552524f52202d20756e61626c6520746f206d656574206d696e696d756d207362017440527f6c69707061676520666f722074686973206465706f7369742100000000000000620174605262017420506201742051806201744001601f825f031636823750506308c379a0620173e05260206201740052601f19601f62017420510116604401620173fcfd5b620174005162017360526201224051337f9ffac2e4ff765185a768380c36a424716e6da986209dddf40813bc110c497187620122205162017420526201736051620174405262017360516201746052606062017420a35b6201224051604052620173605160605261519862017420614aee565b6201742050620173c05162017340518082038281116159d05790509050620174205260105462017420518082018281106159d057905090506010556201224051337fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d76201742051620174405262017360516201746052604062017440a3620173605181526201222051602082015250565b6201222051620173c05261523f62017380611fe3565b6201738051620173e0526040620173c06102005e61525f620173a0614878565b620173a05162017360526201736051601562012260516020525f5260405f2054101561531957602e62017380527f4f776e65722068617320696e61646571756174652073686172657320666f7220620173a0527f746869732077697468647261772e000000000000000000000000000000000000620173c0526201738050620173805180620173a001601f825f031636823750506308c379a0620173405260206201736052601f19601f620173805101166044016201735cfd5b62012260513314615417576201736051601662012260516020525f5260405f2080336020525f5260405f2090505410156153e157602d62017380527f4e6f7420617574686f72697a656420746f206d6f766520656e6f756768206f77620173a0527f6e65722773207368617265732e00000000000000000000000000000000000000620173c0526201738050620173805180620173a001601f825f031636823750506308c379a0620173405260206201736052601f19601f620173805101166044016201735cfd5b601662012260516020525f5260405f2080336020525f5260405f209050805462017360518082038281116159d057905090508155505b601562012260516020525f5260405f20805462017360518082038281116159d0579050905081555060145462017360518082038281116159d057905090506014555f62012260517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef62017360516201738052602062017380a3620122205161c44052620122805161c46052620122a0515f81600581116159d05780156154e357905b6110208102620122c0016020815101611020830261c4a0018183825e5050506001018181186154b9575b50508061c4805250600162011540526154fe620173a0612cc5565b620173a05162017380526201738051620122205111156155745762012260516201224051337fccee2505ffa87c9ac83adf384e5220eb5002aea81a8f925018510d483afbc13c6201222051620173a0526201736051620173c0526201738051620173e0526060620173a0a4620173805162012220525b6020615d665f395f5163a9059cbb620173a0526201224051620173c0526201222051620173e0526020620173a06044620173bc5f855af16155b7573d5f5f3e3d5ffd5b3d6155cf57803b156159d057600162017400526155ea565b60203d106159d057620173a0518060011c6159d05762017400525b6201740050506001604052604036606037615603612765565b60115462012220518082018281106159d0579050905060115562012260516201224051337ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db6201222051620173a0526201736051620173c0526040620173a0a4620173605181526201222051602082015250565b60805160156040516020525f5260405f2054101561570f57602260a0527f4552433230207472616e7366657220696e73756666696369656e742066756e6460c0527f732e00000000000000000000000000000000000000000000000000000000000060e05260a05060a0518060c001601f825f031636823750506308c379a06060526020608052601f19601f60a0510116604401607cfd5b60156040516020525f5260405f2080546080518082038281116159d0579050905081555060156060516020525f5260405f2080546080518082018281106159d057905090508155506060516040517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60805160a052602060a0a3565b60805160166040516020525f5260405f20806060516020525f5260405f209050556060516040517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560805160a052602060a0a3565b60a05160156060516020525f5260405f2054101561587957602660c0527f4552433230207472616e7366657246726f6d20696e73756666696369656e742060e0527f66756e64732e00000000000000000000000000000000000000000000000000006101005260c05060c0518060e001601f825f031636823750506308c379a0608052602060a052601f19601f60c0510116604401609cfd5b60156060516020525f5260405f20805460a0518082038281116159d0579050905081555060156080516020525f5260405f20805460a0518082018281106159d0579050905081555060a05160166060516020525f5260405f20806040516020525f5260405f20905054101561596957602660c0527f4552433230207472616e7366657220696e73756666696369656e7420616c6c6f60e0527f77616e63652e00000000000000000000000000000000000000000000000000006101005260c05060c0518060e001601f825f031636823750506308c379a0608052602060a052601f19601f60c0510116604401609cfd5b60166060516020525f5260405f20806040516020525f5260405f209050805460a0518082038281116159d057905090508155506080516060517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60a05160c052602060c0a3565b5f80fd00015b260400155aae0501515c4e07249b5ad60a00605ba60803f65a66090c475b460c00735be60800065c260548545a060c80d0e2750a58000506fdde030068000594bf804d0fce0045b68a6a670aa60005f40b817d036e0025bc157ac116220065095ea7b3192b00454a44f4cb0b92000523b872dd18e600656e553f6516150045a39a45b7023a0025bccabb7513a50005bc5c98b70678018538d52e0f01020005228bfd9f01650025b3d7f6b90f990025c8a872cb0aec000595d89b4100ae000518160ddd01c50005125151d701b900058da5cb5b0110000570a0823101d1002524fe17210b3c002505935a4f01a10005313ce56700f40005e134a7f704c90025e2c02ee5177b00c5a64fa59909ef0065b613ab9708150025f1e42ccd195c0045ef8b30f70f3c0025ce96cb77113c002521ab18870ca700250a28a477118d0025c55b0091015900055aa6e675011b000560a916d00127000501e1d1140a6a0005a2de9ae80dc200653f4ee62c08cf00c5b87b8a10163500a5e37074560cba00654ef501ac013300257d92535c089c0085870774120da20005736d8b6c146100a571f06c280a080085c1665ba00b9f00258d5a59380ab00025a10801600af60025320ad2ba0852004507a2d13a0edf00251d2ac68c01ad0005a318c1a417680085733272a0122800a5ba087652121d0065b460af94175b0065414e8486014d0005c6e6f5920eaa002596fee0600bb2006500c435030a7a0005af62a18f068301c5ae24a3a9019500055959397509e30045402d267d0f140025a9059cbb18b100458675c757142900453e1dcc7f141c002591dc418a143e00654cdad50611e80025a706bc840daf0025dd62ed3e01f70045c63d75b60f710025d905777e11c200252a068b460b32000525c4d9e8083e00251f55182a086f0065f94a7dfe0fd900858484ac7406230005d9c99c940c9a000500000000000000000000000000000000000000000000000000000004a817c8000000000000000000000000000000000000000000000000000000000000000016416461707465722050542052656e7a6f20657a45544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000096150542d657a45544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000000000000000000000000bf5495efe5db9ce00f80364c8b423567e58d2110

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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