ETH Price: $2,345.50 (-2.77%)

Contract

0x0FDC8648C00e749474345458059ac0e9b5398957
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x61197051202032152024-06-30 8:09:4767 days ago1719734987IN
 Contract Creation
0 ETH0.003695542.46997902

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

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

Contract Name:
AdapterVault Pendle Adapter

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 evm-version cancun
"""
@title AdapterVault Pendle Adapter
@license Copyright 2023, 2024 Biggest Lab Co Ltd, Benjamin Scherrey, Sajal Kayan, and Eike Caldeweyher
@author BiggestLab (https://biggestlab.io) Sajal Kayan
"""

from vyper.interfaces import ERC20

#gas optimization for swap things can be computed offchain
struct ApproxParams:
    guessMin: uint256 #The minimum value for binary search
    guessMax: uint256 #The maximum value for binary search
    guessOffchain: uint256 #This is the first answer to be checked before performing any binary search. If the answer already satisfies, we skip the search and save significant gas
    maxIteration: uint256 #The maximum number of times binary search will be performed
    eps: uint256 #The precision of binary search - the maximum proportion of the input that can be unused. eps is 1e18-based, so an eps of 1e14 implies that no more than 0.01% of the input might be unused


struct SwapData:
    swapType: uint8
    extRouter: address
    extCalldata: Bytes[100]
    needScale: bool


#Note: "If no aggregator is used, tokenIn = tokenMintSy, pendleSwap = address(0) & swapData is empty"
#This should always be the case for us, so in TokenInput and TokenOutput we dont need to care
# about pendleSwap and swapData as those would be empty.

struct TokenInput:
    tokenIn: address #Always asset in our case
    netTokenIn: uint256 #Amount of assets to "deposit"
    tokenMintSy: address #Should also be asset as we only deal with markets using asset directy
    pendleSwap: address #Address of swap helper, do not hardcode - empty for us
    swapData: SwapData #Empty for us

struct TokenOutput:
    tokenOut: address #Always asset in our case
    minTokenOut: uint256 #Minimum amount of assets to "withdraw"
    tokenRedeemSy: address #Should also be asset as we only deal with markets using asset directy
    pendleSwap: address #Address of swap helper, do not hardcode - empty for us
    swapData: SwapData #Empty for us

struct Order:
    salt: uint256
    expiry: uint256
    nonce: uint256
    orderType: uint8
    token: address
    YT: address
    maker: address
    receiver: address
    makingAmount: uint256
    lnImpliedRate: uint256
    failSafeRate: uint256
    permit: Bytes[100]

struct FillOrderParams:
    order: Order
    signature: Bytes[100]
    makingAmount: uint256

struct LimitOrderData:
    limitRouter: address
    epsSkipMarket: uint256
    normalFills: DynArray[FillOrderParams,1]
    flashFills: DynArray[FillOrderParams,1]
    optData: Bytes[100]

struct PregenInfo: #13 words, so 416 bytes. Is there need to compress this for l2? future optimization.
    assumed_asset_amount: uint256 #What asset amount is the below data corresponding to. Doesnt need to be exact
    mint_returns: uint256 #Expected PT gained when converting assumed_asset_amount to PT using mint method
    spot_returns: uint256 #Expected PT gained when converting assumed_asset_amount to PT using AMM method
    approx_params_swapExactYtForPt: ApproxParams #ApproxParams for swapping YT to PT (needed if deposit using mint method)
    approx_params_swapExactTokenForPt: ApproxParams #ApproxParams for swapping token to PT (needed if deposit using AMM method)


interface PendleRouter:
    #swapExactTokenForPt to swap asset to PT using AMM, docs mention there are
    #bits of the computation that can be done offchan and fed to the call.
    #Likely look for this in version 2 of the adapter.
    def swapExactTokenForPt(receiver: address, market: address, minPtOut: uint256, guessPtOut: ApproxParams, input: TokenInput, limit: LimitOrderData) -> (uint256, uint256, uint256): nonpayable 
    #swapExactPtForToken is used for converting PT to asset, typically to
    #service user withdrawals which would (almost) always occur mid-term
    def swapExactPtForToken(receiver: address, market: address, exactPtIn: uint256, output: TokenOutput, limit: LimitOrderData) -> (uint256, uint256, uint256) : nonpayable
    #RedeemPyToToken: PY stands for PT and YT. However, you no longer need YT post-expiry to redeem.
    #PEGGED: We would use this to redeem all outstanding PT to asset at end of term
    def redeemPyToToken(receiver: address, YT: address, netPyIn: uint256, output: TokenOutput) -> (uint256, uint256): nonpayable
    #PEGGED minting
    def mintPyFromToken(receiver: address, YT: address, minPyOut: uint256, input: TokenInput) -> (uint256, uint256): nonpayable
    #swapExactYtForPt to sell intermidiate YT minted for PT
    def swapExactYtForPt(receiver: address, market: address, exactYtIn: uint256, minPtOut: uint256, guessTotalPtFromSwap: ApproxParams) -> (uint256, uint256): nonpayable



interface PendleRouterStatic:
    def getPtToAssetRate(market: address) -> uint256: view
    def mintPyFromTokenStatic(YT: address, tokenIn: address, netTokenIn: uint256) -> uint256: view
    def swapExactYtForPtStatic(market: address, exactYtIn: uint256) -> (uint256, uint256, uint256, uint256, uint256): view
    def swapExactTokenForPtStatic(market: address, tokenIn: address, netTokenIn: uint256) -> (uint256, uint256, uint256, uint256, uint256): view

interface PendleMarket:
    def readTokens()  -> (address, address, address): view
    def expiry() -> uint256: view
    #NOTE: Currently markets checked have 1 reward token. If there is more please update the limit below
    def getRewardTokens() -> DynArray[address, 20]: view
    def redeemRewards(user: address) -> DynArray[uint256, 20]: nonpayable

interface SYToken:
    def previewDeposit(tokenIn: address, amountTokenToDeposit: uint256) -> uint256: view
    def previewRedeem(tokenOut: address, amountSharesToRedeem: uint256) -> uint256: view
    def exchangeRate() -> uint256: view
    def deposit(receiver: address, tokenIn: address, amountTokenToDeposit: uint256, minSharesOut: uint256) -> uint256: nonpayable

interface YieldToken:
    def pyIndexStored() -> uint256: view
    def doCacheIndexSameBlock() -> bool: view
    def pyIndexLastUpdatedBlock() -> uint128: view

interface PendlePtLpOracle:
    def getPtToAssetRate(market: address, duration: uint32) -> uint256: view
    def getPtToSyRate(market: address, duration: uint32) -> uint256: view
    def getOracleState(market: address, duration: uint32) -> (bool, uint16, bool): nonpayable


ONE: constant(uint256) = 10**18
TWAP_DURATION: constant(uint32) = 1200
asset: immutable(address)
pendleRouter: immutable(address)
pendleRouterStatic: immutable(address)
pendleMarket: immutable(address)
pendleOracle: immutable(address)
pt_token: immutable(address)
yt_token: immutable(address)
sy_token: immutable(address)
adapterAddr: immutable(address)
#Its immutable in pendle so we cache it here for cheaper access
expiry: immutable(uint256)

@external
def __init__(
    _asset: address,
    _pendleRouter: address,
    _pendleRouterStatic: address,
    _pendleMarket: address,
    _pendleOracle: address
    ):
    _sy: address = empty(address)
    _pt: address = empty(address)
    _yt: address = empty(address)

    _sy, _pt, _yt = PendleMarket(_pendleMarket).readTokens()
    sy_token = _sy
    pt_token = _pt
    yt_token = _yt
    asset = _asset
    pendleOracle = _pendleOracle
    pendleRouter = _pendleRouter
    pendleRouterStatic = _pendleRouterStatic
    pendleMarket = _pendleMarket
    adapterAddr = self
    expiry = PendleMarket(_pendleMarket).expiry()

    #Check oracle's cardinality
    increaseCardinalityRequired: bool= False
    cardinalityRequired: uint16 = 0
    oldestObservationSatisfied: bool = False
    increaseCardinalityRequired, cardinalityRequired, oldestObservationSatisfied = PendlePtLpOracle(pendleOracle).getOracleState(pendleMarket, TWAP_DURATION)
    assert increaseCardinalityRequired == False, "Oracle requires cardinality increase"
    assert oldestObservationSatisfied == True, "Oracle is not bootstrapped sufficiently"

#Workaround because vyper does not allow doing delegatecall from inside view.
#we do a static call instead, but need to fix the correct vault location for queries.
@internal
@view
def vault_location() -> address:
    if self == adapterAddr:
        #if "self" is adapter, meaning this is not delegate call and we treat msg.sender as the vault
        return msg.sender
    #Otherwise we are inside DELEGATECALL, therefore self would be the 4626
    return self


@internal
@view
def asset_to_sy(asset_amount: uint256) -> uint256:
    #How much SY does given asset amount mint
    return SYToken(sy_token).previewDeposit(asset, asset_amount)


@internal
@view
def sy_to_asset(sy_amount: uint256) -> uint256:
    #How much SY does given asset amount mint
    return SYToken(sy_token).previewRedeem(asset, sy_amount)

@internal
@view
def assetToPT(asset_amount: uint256) -> uint256:
    if asset_amount == 0:
        #optimization for empty adapter
        return 0
    sy_amount: uint256 = self.asset_to_sy(asset_amount)
    rate: uint256 = PendlePtLpOracle(pendleOracle).getPtToSyRate(pendleMarket, TWAP_DURATION)
    pt: uint256 = (sy_amount * ONE) / rate
    return pt

@internal
@view
def PTToAsset(pt: uint256) -> uint256:
    if pt == 0 :
        #optimization for empty adapter
        return 0
    rate: uint256 = PendlePtLpOracle(pendleOracle).getPtToSyRate(pendleMarket, TWAP_DURATION)
    sy_amount: uint256 = (pt * rate) / ONE
    return self.sy_to_asset(sy_amount)

@internal
@view
def is_matured() -> bool:
    #upstream solidity logic: return (expiry <= block.timestamp); 
    return expiry <= block.timestamp


@internal
@view
def _assetBalance() -> uint256:
    wrappedBalance: uint256 = ERC20(pt_token).balanceOf(self.vault_location()) #aToken
    unWrappedBalance: uint256 = self.PTToAsset(wrappedBalance) #asset
    return unWrappedBalance


#How much asset can be withdrawn in a single transaction
@external
@view
def maxWithdraw() -> uint256:
    """
    @notice returns the maximum possible asset amount thats withdrawable from Pendle
    @dev
        In case of pendle, all markets allow withdrawals...
    """
    #Should we check for funds availability in the AMM?
    return self._assetBalance()


#How much asset can be deposited in a single transaction
@external
@view
def maxDeposit() -> uint256:
    """
    @notice returns the maximum possible asset amount thats depositable into AAVE
    @dev
        So for Pendle, we would use zero if the market is matured or if its not active.
        Otherwise we send max uint
    """
    if self.is_matured():
        return 0
    return max_value(uint256)

#How much asset this LP is responsible for.
@external
@view
def totalAssets() -> uint256:
    """
    @notice returns the balance currently held by the adapter.
    @dev
        This method returns a valid response if it has been DELEGATECALL or
        STATICCALL-ed from the AdapterVault contract it services. It is not
        intended to be called directly by third parties.
    """
    return self._assetBalance()


@internal
@view
def estimate_spot_returns(asset_amount: uint256) -> uint256:
    """
    @notice estimates the PT amount returned if we based calculation on
    spot price alone, ignoring any slippage.
    """
    # rate: uint256 = PendleRouterStatic(pendleRouterStatic).getPtToAssetRate(pendleMarket)
    netPtOut: uint256 = 0
    netSyMinted: uint256 = 0
    netSyFee: uint256 = 0
    priceImpact: uint256 = 0
    exchangeRateAfter: uint256 = 0
    netPtOut, netSyMinted, netSyFee, priceImpact, exchangeRateAfter = PendleRouterStatic(pendleRouterStatic).swapExactTokenForPtStatic(pendleMarket, asset, asset_amount)
    return netPtOut

@internal
@view
def estimate_mint_returns(asset_amount: uint256) -> (uint256, uint256):
    """
    @notice estimates the PT amount returned if we based calculation on
    minting PY and then swapping the returned YT for PT.
    """
    if self.is_matured():
        #Not possible to mint after maturity
        return 0, 0
    #estimate asset to PY
    py_amount: uint256 = PendleRouterStatic(pendleRouterStatic).mintPyFromTokenStatic(yt_token, asset, asset_amount)
    #Estimate cost of YT to PT
    netPtOut: uint256 = 0
    totalPtSwapped: uint256 = 0
    netSyFee: uint256 = 0
    priceImpact: uint256 = 0
    exchangeRateAfter: uint256 = 0
    netPtOut, totalPtSwapped, netSyFee, priceImpact, exchangeRateAfter = PendleRouterStatic(pendleRouterStatic).swapExactYtForPtStatic(pendleMarket, py_amount)
    return (py_amount + netPtOut), totalPtSwapped

#Deposit the asset into underlying LP
@external
@nonpayable
def deposit(asset_amount: uint256, pregen_info: Bytes[4096]=empty(Bytes[4096])):
    """
    @notice deposit asset into Pendle market.
    @param asset_amount The amount of asset we want to deposit into Pendle market
    @param pregen_info optional argument of data computed off-chain to optimize the on-chain call
    @dev
        This method is only valid if it has been DELEGATECALL-ed
        from the AdapterVault contract it services. It is not intended to be
        called directly by third parties.
    """
    pg: PregenInfo = empty(PregenInfo)
    if len(pregen_info) > 0:
        pg = _abi_decode(pregen_info, PregenInfo)
    else:
        #Info not provided, compute it expensively
        pg.approx_params_swapExactYtForPt = self.default_approx_params()
        pg.approx_params_swapExactTokenForPt = self.default_approx_params()
        ytToPTL: uint256 = 0
        pg.mint_returns, ytToPTL = self.estimate_mint_returns(asset_amount)
        pg.spot_returns = self.estimate_spot_returns(asset_amount)
        #we already paid the tax... why not reuse it...
        pg.approx_params_swapExactTokenForPt.guessOffchain = pg.spot_returns
        pg.approx_params_swapExactYtForPt.guessOffchain = ytToPTL

    #mint if minting price is better, then sell the YT.
    if pg.mint_returns > pg.spot_returns:
        #Mint PY
        inp: TokenInput = empty(TokenInput)
        inp.tokenIn = asset
        inp.netTokenIn = asset_amount
        inp.tokenMintSy = asset

        netPyOut: uint256 = 0
        netSyInterm: uint256 = 0
        ERC20(asset).approve(pendleRouter, asset_amount)
        #Mint PY+PT using asset
        netPyOut, netSyInterm = PendleRouter(pendleRouter).mintPyFromToken(
            self,
            yt_token,
            0,
            inp
        )

        #Swap any YT gained to PT
        ERC20(yt_token).approve(pendleRouter, netPyOut)

        PendleRouter(pendleRouter).swapExactYtForPt(
            self,
            pendleMarket,
            netPyOut,
            0,
            pg.approx_params_swapExactYtForPt
        )

    else:
        #swapExactTokenForPt
        inp: TokenInput = empty(TokenInput)
        inp.tokenIn = asset
        inp.netTokenIn = asset_amount
        inp.tokenMintSy = asset

        limit: LimitOrderData = empty(LimitOrderData)
        ERC20(asset).approve(pendleRouter, asset_amount)
        PendleRouter(pendleRouter).swapExactTokenForPt(
            self,
            pendleMarket,
            0,
            pg.approx_params_swapExactTokenForPt,
            inp,
            limit
        )
        #NOTE: Not doing any checks and balances, minPtOut=0 is intentional.
        #It's up to the vault to revert if it does not like what it sees.

#Withdraw the asset from the LP
@external
@nonpayable
def withdraw(asset_amount: uint256 , withdraw_to: address, pregen_info: Bytes[4096]=empty(Bytes[4096])) -> uint256:
    """
    @notice withdraw asset from AAVE.
    @param asset_amount The amount of asset we want to withdraw from Pendle
    @param withdraw_to The ultimate reciepent of the withdrawn assets
    @param pregen_info optional argument of data computed off-chain to optimize the on-chain call
    @dev
        This method is only valid if it has been DELEGATECALL-ed
        from the AdapterVault contract it services. It is not intended to be
        called directly by third parties.
    """
    #NOTE: accepting pregen_info to satisfy the interface, but there is no need for
    #it during withdraw, unless we find an alternate withdrawal method.

    #Compute the amount of PT we must consume based on oracle
    pt_amount: uint256 = self.assetToPT(asset_amount)
    amount_withdrawn: uint256 = 0
    if self.is_matured():
        #redeemPyToToken
        #No positive slippage possible as we assume 1:1 peg
        ERC20(pt_token).approve(pendleRouter, pt_amount)

        out: TokenOutput = empty(TokenOutput)
        out.tokenOut = asset
        out.minTokenOut = 0 #remember slippage protection is by the vault
        out.tokenRedeemSy = asset

        netTokenOut: uint256 = 0
        netSyInterm: uint256 = 0

        netTokenOut, netSyInterm = PendleRouter(pendleRouter).redeemPyToToken(withdraw_to, yt_token, pt_amount, out)
        amount_withdrawn = netTokenOut
    else:
        #swapExactPtForToken
        #For now we so swapExactPtForToken to the vault, and then keep the positive yield as asset.
        #Would have liked the positive slippage remain as PT...

        ERC20(pt_token).approve(pendleRouter, pt_amount)

        out: TokenOutput = empty(TokenOutput)
        out.tokenOut = asset
        out.minTokenOut = 0 #remember slippage protection is by the vault
        out.tokenRedeemSy = asset

        limit: LimitOrderData = empty(LimitOrderData)

        #positive yield needs to goto the vault, check note above for optimization
        netTokenOut: uint256 = 0
        netSyFee: uint256 = 0
        netSyInterm: uint256 = 0
        netTokenOut, netSyFee, netSyInterm =  PendleRouter(pendleRouter).swapExactPtForToken(self, pendleMarket, pt_amount, out, limit)
        if netTokenOut > asset_amount:
            #Excess remains in vault as asset
            amount_withdrawn = asset_amount
        else:
            #Any slippage from oracle is users responsibility
            amount_withdrawn = netTokenOut
        if withdraw_to != self:
            ERC20(asset).transfer(withdraw_to, amount_withdrawn)

    return amount_withdrawn

@external
def claimRewards(claimant: address):
    """
    @notice hook to claim reward from underlying LP
    @param claimant An address who is to be the ultimate beneficiary of any tokens claimed
    @dev
        runs the IPMarket.redeemRewards method, and sends the loot to provided address
    """
    PendleMarket(pendleMarket).redeemRewards(self)
    tokens: DynArray[address, 20] = PendleMarket(pendleMarket).getRewardTokens()
    for token in tokens:
        if token == pt_token:
            #if its really rewarded in pt, let the vault have that
            continue
        #Assumes reward token is ERC20
        vault_balance: uint256 = ERC20(token).balanceOf(self)
        if vault_balance > 0:
            #A misbehaving token could potentially re-enter here, but
            #there is no harm as we are within the claim call, not touching
            #any vault logic
            ERC20(token).transfer(claimant, vault_balance)

@internal
@pure
def default_approx_params() -> ApproxParams:
    ap: ApproxParams = empty(ApproxParams)
    ap.guessMax = max_value(uint256)
    ap.maxIteration = 256
    ap.eps = 10**14
    return ap

@external
@view
def abi_helper() -> PregenInfo:
    """
    @notice This is just here so the PregenInfo struct is visible in ABI 
    """
    return empty(PregenInfo)

@external
@view
def generate_pregen_info(asset_amount: uint256) -> Bytes[4096]:
    """
    @notice 
        retuns byte data to be precomputed in an off-chain call which is
        to be included during on-chain call. Optimize gas costs.
    @param asset_amount The asset amount that is expected to be deposited or withdrawn 
    """
    #Under ideal situation, we pendle's hosted API to get better paramaters and inject here
    pg: PregenInfo = empty(PregenInfo)
    #Because we assume (approx) all asset amount will either go in or out of single adapter
    pg.assumed_asset_amount = asset_amount
    ytToPT: uint256 = 0
    pg.mint_returns, ytToPT = self.estimate_mint_returns(asset_amount)
    pg.spot_returns = self.estimate_spot_returns(asset_amount)
    
    #Not having approx params costs additional 180k gas (source: https://github.com/pendle-finance/pendle-examples-public/blob/9ce43f4d16003a3ea2a9fe3050e637f0fed64fee/src/StructGen.sol#L14)
    #Check with pendle about guidance on how this precompute works, maybe need to use their REST API

    #Hardcoding defaults
    pg.approx_params_swapExactYtForPt = self.default_approx_params()
    pg.approx_params_swapExactTokenForPt = self.default_approx_params()
    pg.approx_params_swapExactYtForPt.guessOffchain = ytToPT
    pg.approx_params_swapExactTokenForPt.guessOffchain = pg.spot_returns

    return _abi_encode(pg)

@external
@view
def managed_tokens() -> DynArray[address, 10]:
    ret: DynArray[address, 10] = empty(DynArray[address, 10])
    ret.append(pt_token)
    return ret

Contract Security Audit

Contract ABI

[{"stateMutability":"nonpayable","type":"constructor","inputs":[{"name":"_asset","type":"address"},{"name":"_pendleRouter","type":"address"},{"name":"_pendleRouterStatic","type":"address"},{"name":"_pendleMarket","type":"address"},{"name":"_pendleOracle","type":"address"}],"outputs":[]},{"stateMutability":"view","type":"function","name":"maxWithdraw","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"maxDeposit","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"totalAssets","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"deposit","inputs":[{"name":"asset_amount","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"deposit","inputs":[{"name":"asset_amount","type":"uint256"},{"name":"pregen_info","type":"bytes"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"withdraw","inputs":[{"name":"asset_amount","type":"uint256"},{"name":"withdraw_to","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"withdraw","inputs":[{"name":"asset_amount","type":"uint256"},{"name":"withdraw_to","type":"address"},{"name":"pregen_info","type":"bytes"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"claimRewards","inputs":[{"name":"claimant","type":"address"}],"outputs":[]},{"stateMutability":"view","type":"function","name":"abi_helper","inputs":[],"outputs":[{"name":"","type":"tuple","components":[{"name":"assumed_asset_amount","type":"uint256"},{"name":"mint_returns","type":"uint256"},{"name":"spot_returns","type":"uint256"},{"name":"approx_params_swapExactYtForPt","type":"tuple","components":[{"name":"guessMin","type":"uint256"},{"name":"guessMax","type":"uint256"},{"name":"guessOffchain","type":"uint256"},{"name":"maxIteration","type":"uint256"},{"name":"eps","type":"uint256"}]},{"name":"approx_params_swapExactTokenForPt","type":"tuple","components":[{"name":"guessMin","type":"uint256"},{"name":"guessMax","type":"uint256"},{"name":"guessOffchain","type":"uint256"},{"name":"maxIteration","type":"uint256"},{"name":"eps","type":"uint256"}]}]}]},{"stateMutability":"view","type":"function","name":"generate_pregen_info","inputs":[{"name":"asset_amount","type":"uint256"}],"outputs":[{"name":"","type":"bytes"}]},{"stateMutability":"view","type":"function","name":"managed_tokens","inputs":[],"outputs":[{"name":"","type":"address[]"}]}]

Deployed Bytecode

0x5f3560e01c60026009820660011b61183e01601e395f51565b63ac7a1b5b811861003a573461183a5760206100356101e06115f9565b6101e0f35b63cff54c8e81186113dd573461183a576101a0366040376101a06040f36113dd565b636083e59a81186100b6573461183a5761007660406115e8565b6040511561008b575f606052602060606100b4565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff604052602060405bf35b6362b2b5f081186113dd5760843610341761183a5760443560040161100081351161183a57602081350180826101a03750505b6024358060a01c61183a576101805260043560c0526101096111e0611490565b6111e0516111c0525f6111e0526101216112006115e8565b6112005161066d5760206118f05f395f5163095ea7b3611200526020611870611220396111c051611240526020611200604461121c5f855af1610166573d5f5f3e3d5ffd5b60203d1061183a57611200518060011c61183a5761126052611260505061018036611200376020611850611200395f61122052602061185061124039610700366113803760206118705f395f5163594a88cc611a805260a030611aa05260206118b0611ac0396111c051611ae05280611b005280611aa00160a061120051825261122051602083015261124051604083015261126051606083015280608083015280820160806112805182526112a051602083015280604083015280820160206112c05101806112c0835e508051806020830101601f825f03163682375050601f19601f8251602001011690508101905061136051606083015290508101905090508101905080611b205280611aa00160a06113805182526113a05160208301528060408301528082015f6113c0518083528060051b5f826001811161183a5780156103e457905b828160051b6020880101526102c081026113e0018360208801016060808252808201610180845182526020850151602083015260408501516040830152606085015160608301526080850151608083015260a085015160a083015260c085015160c083015260e085015160e083015261010085015161010083015261012085015161012083015261014085015161014083015280610160830152610160850181830160208251018083835e508051806020830101601f825f03163682375050601f19601f825160200101169050905081019050905081019050806020830152610200830181830160208251018083835e508051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506102a0830151604083015290509050830192506001018181186102ae575b505082016020019150509050810190508060608301528082015f6116a0518083528060051b5f826001811161183a57801561055157905b828160051b6020880101526102c081026116c0018360208801016060808252808201610180845182526020850151602083015260408501516040830152606085015160608301526080850151608083015260a085015160a083015260c085015160c083015260e085015160e083015261010085015161010083015261012085015161012083015261014085015161014083015280610160830152610160850181830160208251018083835e508051806020830101601f825f03163682375050601f19601f825160200101169050905081019050905081019050806020830152610200830181830160208251018083835e508051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506102a08301516040830152905090508301925060010181811861041b575b505082016020019150509050810190508060808301528082016020611980510180611980835e508051806020830101601f825f03163682375050601f19601f825160200101169050810190509050810150506060611a80610a64611a9c5f855af16105be573d5f5f3e3d5ffd5b60603d1061183a57611a8090508051611a20526020810151611a40526040810151611a605250600435611a2051116105fd57611a20516111e052610605565b6004356111e0525b3061018051146107f35760206118505f395f5163a9059cbb611a805261018051611aa0526111e051611ac0526020611a806044611a9c5f855af161064b573d5f5f3e3d5ffd5b60203d1061183a57611a80518060011c61183a57611ae052611ae050506107f3565b60206118f05f395f5163095ea7b3611220526020611870611240396111c051611260526020611220604461123c5f855af16106aa573d5f5f3e3d5ffd5b60203d1061183a57611220518060011c61183a5761128052611280505061018036611220376020611850611220395f611240526020611850611260396040366113a03760206118705f395f516347f1de226113e052608061018051611400526020611910611420396111c051611440528061146052806114000160a061122051825261124051602083015261126051604083015261128051606083015280608083015280820160806112a05182526112c051602083015280604083015280820160206112e05101806112e0835e508051806020830101601f825f03163682375050601f19601f8251602001011690508101905061138051606083015290508101905090508101505060406113e06102446113fc5f855af16107cd573d5f5f3e3d5ffd5b60403d1061183a576113e0905080516113a05260208101516113c052506113a0516111e0525b60206111e0f36113dd565b6301e1d1148118610820573461183a57602061081b6101e06115f9565b6101e0f35b63ef5cfb8c8118610a1d5760243610341761183a576004358060a01c61183a5760405260206118b05f395f51639262187b606052306080526102c060606024607c5f855af1610871573d5f5f3e3d5ffd5b60403d1061183a57606051606001601481511161183a57805160208160051b0180836103405e505050610340505060206118b05f395f5163c4f59f9b610300526102c0610300600461031c845afa6108cb573d5f5f3e3d5ffd5b60403d1061183a576103005161030001601481511161183a5780515f816014811161183a57801561091e57905b8060051b6020850101518060a01c61183a578160051b61060001526001018181186108f8575b5050806105e05250506105e09050805160208160051b01808360605e5050505f6060516014811161183a578015610a1957905b8060051b608001516103005260206118f05f395f51610300511861097457610a0e565b610300516370a082316103405230610360526020610340602461035c845afa61099f573d5f5f3e3d5ffd5b60203d1061183a57610340905051610320526103205115610a0e576103005163a9059cbb610340526040516103605261032051610380526020610340604461035c5f855af16109f0573d5f5f3e3d5ffd5b60203d1061183a57610340518060011c61183a576103a0526103a050505b600101818118610951575b5050005b63c7773e0081146003361116156113dd5760243610341761183a576101a0366101e0376004356101e0525f61038052600435604052610a5d6103a06116f1565b6103a080516102005260208101516103805250600435604052610a816103a061166c565b6103a05161022052610a946103a06117f7565b6103a060a0816102405e50610aaa6103a06117f7565b6103a060a0816102e05e5061038051610280526102205161032052602080610560526101a06101e06103c05e6101a06103a0526103a0816105600160208251018083835e508051806020830101601f825f03163682375050601f19601f825160200101169050905081019050610560f36113dd565b63b6b55f2581186113dd5760243610341761183a575f6101e052610b75566113dd565b635d303519811861132c5760643610341761183a5760243560040161100081351161183a57602081350180826101e03750505b6101a036611200376101e05115610bbe576101a06101e0511861183a5760606102006113a05e60a06102606114005e60a06103006114a05e6113a06101a0816112005e50610c3d565b610bc96113a06117f7565b6113a060a0816112605e50610bdf6113a06117f7565b6113a060a0816113005e505f6113a052600435604052610c006113c06116f1565b6113c080516112205260208101516113a05250600435604052610c246113c061166c565b6113c0516112405261124051611340526113a0516112a0525b6112405161122051116110f957610180366113a03760206118506113a0396004356113c05260206118506113e0396106a0366115203760206118505f395f5163095ea7b3611bc0526020611870611be039600435611c00526020611bc06044611bdc5f855af1610caf573d5f5f3e3d5ffd5b60203d1061183a57611bc0518060011c61183a57611c2052611c20505060206118705f395f5163c81f847a611bc05261014030611be05260206118b0611c00395f611c205260a0611300611c405e80611ce05280611be00160a06113a05182526113c05160208301526113e051604083015261140051606083015280608083015280820160806114205182526114405160208301528060408301528082016020611460510180611460835e508051806020830101601f825f03163682375050601f19601f8251602001011690508101905061150051606083015290508101905090508101905080611d005280611be00160a06115205182526115405160208301528060408301528082015f611560518083528060051b5f826001811161183a578015610f0d57905b828160051b6020880101526102c08102611580018360208801016060808252808201610180845182526020850151602083015260408501516040830152606085015160608301526080850151608083015260a085015160a083015260c085015160c083015260e085015160e083015261010085015161010083015261012085015161012083015261014085015161014083015280610160830152610160850181830160208251018083835e508051806020830101601f825f03163682375050601f19601f825160200101169050905081019050905081019050806020830152610200830181830160208251018083835e508051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506102a083015160408301529050905083019250600101818118610dd7575b505082016020019150509050810190508060608301528082015f611840518083528060051b5f826001811161183a57801561107a57905b828160051b6020880101526102c08102611860018360208801016060808252808201610180845182526020850151602083015260408501516040830152606085015160608301526080850151608083015260a085015160a083015260c085015160c083015260e085015160e083015261010085015161010083015261012085015161012083015261014085015161014083015280610160830152610160850181830160208251018083835e508051806020830101601f825f03163682375050601f19601f825160200101169050905081019050905081019050806020830152610200830181830160208251018083835e508051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506102a083015160408301529050905083019250600101818118610f44575b505082016020019150509050810190508060808301528082016020611b20510180611b20835e508051806020830101601f825f03163682375050601f19601f825160200101169050810190509050810150506060611bc0610b04611bdc5f855af16110e7573d5f5f3e3d5ffd5b60603d1061183a57611bc0505061132a565b610180366113a03760206118506113a0396004356113c05260206118506113e0396040366115203760206118505f395f5163095ea7b3611560526020611870611580396004356115a0526020611560604461157c5f855af161115d573d5f5f3e3d5ffd5b60203d1061183a57611560518060011c61183a576115c0526115c0505060206118705f395f5163d0f42385611560526080306115805260206119106115a0395f6115c052806115e052806115800160a06113a05182526113c05160208301526113e051604083015261140051606083015280608083015280820160806114205182526114405160208301528060408301528082016020611460510180611460835e508051806020830101601f825f03163682375050601f19601f82516020010116905081019050611500516060830152905081019050905081015050604061156061024461157c5f855af1611254573d5f5f3e3d5ffd5b60403d1061183a5761156090508051611520526020810151611540525060206119105f395f5163095ea7b361156052602061187061158039611520516115a0526020611560604461157c5f855af16112ae573d5f5f3e3d5ffd5b60203d1061183a57611560518060011c61183a576115c0526115c0505060206118705f395f5163448b9b9561156052306115805260206118b06115a039611520516115c0525f6115e05260a06112606116005e604061156061012461157c5f855af161131c573d5f5f3e3d5ffd5b60403d1061183a5761156050505b005b63ed21271881186113dd573461183a575f6040526040516009811161183a5760206118f08260051b6060013960018101604052506020806101a052806101a0015f6040518083528060051b5f82600a811161183a5780156113a657905b8060051b606001518160051b602088010152600101818118611389575b505082016020019150509050810190506101a0f36113dd565b62f714ce81186113dd5760443610341761183a575f6101a0526100e9565b5f5ffd5b60206119505f395f5130186113f957338152506113fe565b308152505b565b60206119305f395f5163b8f82b26606052602061185060803960405160a052602060606044607c845afa611436573d5f5f3e3d5ffd5b60203d1061183a576060905051815250565b60206119305f395f5163cbe52ae3606052602061185060803960405160a052602060606044607c845afa61147e573d5f5f3e3d5ffd5b60203d1061183a576060905051815250565b60c0516114a0575f815250611543565b60c0516040526114b1610100611400565b6101005160e05260206118d05f395f5163a31426d16101205260206118b0610140396104b0610160526020610120604461013c845afa6114f3573d5f5f3e3d5ffd5b60203d1061183a576101209050516101005260e051670de0b6b3a7640000810281670de0b6b3a764000082041861183a57905061010051801561183a578082049050905061012052610120518152505b565b60c051611555575f8152506115e6565b60206118d05f395f5163a31426d16101005260206118b0610120396104b0610140526020610100604461011c845afa611590573d5f5f3e3d5ffd5b60203d1061183a5761010090505160e05260c05160e05180820281158383830414171561183a5790509050670de0b6b3a76400008104905061010052610100516040526115de610120611448565b610120518152505b565b4260206119705f395f511115815250565b60206118f05f395f516370a082316101a0526116166101806113e1565b610180516101c05260206101a060246101bc845afa611637573d5f5f3e3d5ffd5b60203d1061183a576101a0905051610160526101605160c05261165b6101a0611545565b6101a0516101805261018051815250565b60a03660603760206118905f395f516326e44ccf6101005260206118b0610120396020611850610140396040516101605260a0610100606461011c845afa6116b6573d5f5f3e3d5ffd5b60a03d1061183a57610100905080516060526020810151608052604081015160a052606081015160c052608081015160e05250606051815250565b6116fb60606115e8565b60605115611712575f81525f6020820152506117f5565b60206118905f395f51635fbdb155608052602061191060a039602061185060c03960405160e052602060806064609c845afa611750573d5f5f3e3d5ffd5b60203d1061183a57608090505160605260a03660803760206118905f395f51633b672dcd6101205260206118b0610140396060516101605260a0610120604461013c845afa6117a1573d5f5f3e3d5ffd5b60a03d1061183a5761012090508051608052602081015160a052604081015160c052606081015160e0526080810151610100525060605160805180820182811061183a5790509050815260a0516020820152505b565b60a0366040377fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60605261010060a052655af3107a400060c05260a06040825e50565b5f80fd0b42001807fe0b1f005c13dd13dd13dd13bf000000000000000000000000fae103dc9cf190ed75350761e95403b7b8afa6c000000000000000000000000000000000005bbb0ef59571e58418f9a4357b68a0000000000000000000000000263833d47ea3fa4a30f269323aba6a107f9eb14c000000000000000000000000038c1b03dab3b891afbca4371ec807edaa3e6eb600000000000000000000000066a1096c6366b2529274df4f5d8247827fe4cea8000000000000000000000000f0574d8b9dc3a9de768eaa7dbb7bb0c68521b148000000000000000000000000d66b560f4e3e85f22c192d91da847886d5c5fd000000000000000000000000007786729eee8b9d30fe7d91fdff23a0f1d0c615d90000000000000000000000000fdc8648c00e749474345458059ac0e9b53989570000000000000000000000000000000000000000000000000000000066f4a400

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  ]

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.