Address Contract Partially Verified
Address
0x42b25284E8ae427D79da78b65DFFC232aAECc016
Balance
0 ETH
Nonce
1
Code Size
5502 bytes
Creator
0x0bd00700...17c9 at tx 0x9a96931d...1f3a0f
Indexed Transactions
0 (1 on-chain, 0.7% indexed)
Contract Bytecode
5502 bytes
0x5f3560e01c60026025820660011b61151401601e395f51565b63a9059cbb8118610b9d57604436103417611510576004358060a01c611510576101e052336040526101e051606052602435608052610055610ba1565b6001610200526020610200f35b6323b872dd8118610b9d57606436103417611510576004358060a01c611510576101e0526024358060a01c61151057610200526044351561011b5760066101e0516020525f5260405f2080336020525f5260405f20905054610220527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610220511461011b5761022051604435808203828111611510579050905060066101e0516020525f5260405f2080336020525f5260405f209050555b60406101e060405e604435608052610131610ba1565b6001610220526020610220f35b63095ea7b381186101c357604436103417611510576004358060a01c6115105760405260405115611510576024356006336020525f5260405f20806040516020525f5260405f20905055604051337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560243560605260206060a3600160605260206060f35b6301e1d1148118610b9d57346115105760045460405260206040f35b63b6b55f258118610b9d57602436103417611510573361018052610223565b636e553f65811861024657604436103417611510576024358060a01c61151057610180525b61018051604052600435606052610238610cb1565b6004356101a05260206101a0f35b62f714ce811861027357604436103417611510576024358060a01c611510576103a052336103c0526103f8565b63dd62ed3e8118610b9d57604436103417611510576004358060a01c611510576040526024358060a01c6115105760605260066040516020525f5260405f20806060516020525f5260405f2090505460805260206080f35b63a0712d688118610b9d5760243610341761151057336101805261030f565b6394bf804d8118610b9d57604436103417611510576024358060a01c61151057610180525b61018051604052600435606052610324610cb1565b6004356101a05260206101a0f35b632e17de78811861035b57602436103417611510573360a05260043560c052610359610ef9565b005b63836992758118610b9d57602436103417611510576004358060a01c61151057606052606060076060516020525f5260405f205460405261039c6080610e58565b6080f35b632e1a7d4d8118610b9d5760243610341761151057336103a052336103c0526103f8565b63b460af94811861042557606436103417611510576024358060a01c611510576103a0526044358060a01c611510576103c0525b6103c05161022052600435610240526103a051610260526104176110ba565b6004356103e05260206103e0f35b63cd7033c48118610b9d57346115105760035460405260206040f35b63db006a7581186104655760243610341761151057336103a052336103c052610658565b6318160ddd8118610b9d57346115105760045460405260206040f35b637bde82f281186104af57604436103417611510576024358060a01c611510576103a052336103c052610658565b636ea056a981186105af57604436103417611510576024356060525b6004358060a01c611510576040525f54331861151057602061155e5f395f51604051146115105760605160805260605119610537576040516370a0823160a0523060c052602060a0602460bc845afa610526573d5f5f3e3d5ffd5b60203d106115105760a09050516080525b60405163a9059cbb60a0523360c05260805160e052602060a0604460bc5f855af1610564573d5f5f3e3d5ffd5b3d61057b57803b15611510576001610100526105a2565b3d602081183d60201002188060a00160c0116115105760a0518060011c6115105761010052505b6101009050511561151057005b6306fdde038118610b9d573461151057602080608052600a6040527f5374616b65642059464900000000000000000000000000000000000000000000606052604081608001602a82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506080f35b63ba087652811861068557606436103417611510576024358060a01c611510576103a0526044358060a01c611510576103c0525b6103c05161022052600435610240526103a051610260526106776110ba565b6004356103e05260206103e0f35b630c3605218118610b9d57602436103417611510576004358060a01c611510576040525f543318611510576040516003556040517fdb0670e174c4203280e70166db52920a0ddc53923128a7e0e964c5350de54f1f5f6060a2005b63c6e6f5928118610701576024361034176115105760043560405260206040f35b63402d267d8118610b9d57602436103417611510576004358060a01c6115105760405260025415610739575f60605260206060610762565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff606052602060605bf35b6307a2d13a8118610785576024361034176115105760043560405260206040f35b63ce96cb778118610b9d57602436103417611510576004358060a01c611510576101e05260206101e05160c0526107bd6102006113e8565b610200f35b63ef8b30f78118610b9d576024361034176115105760043560405260206040f35b63c63d75b68118610b9d57602436103417611510576004358060a01c611510576040526002541561081b575f60605260206060610844565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff606052602060605bf35b63b3d7f6b98118610b9d576024361034176115105760043560405260206040f35b630a28a4778118610b9d576024361034176115105760043560405260206040f35b63d905777e81186108c557602436103417611510576004358060a01c611510576101e05260206101e05160c0526108c06102006113e8565b610200f35b6338d52e0f81186108e3573461151057602061155e60403960206040f35b63770817ec8118610b9d57346115105760015460405260206040f35b634cdad5068118610b9d576024361034176115105760043560405260206040f35b6301681a62811861095e57602436103417611510577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6060526104cb565b631f3a0e418118610b9d57346115105760025460405260206040f35b6390b2299781186109d957602436103417611510576004358060011c611510576040525f543318611510576040516002557ff6a23ecf31263066d4cc1ac21837c1714818045ecc5c0dd89f279e0bd4b7ef8760405160605260206060a1005b6370a082318118610a1457602436103417611510576004358060a01c6115105760405260056040516020525f5260405f205460605260206060f35b63ed50920b8118610b9d57602436103417611510576004358060a01c6115105760405260076040516020525f5260405f205460605260206060f35b63fd066ecc8118610b9d57602436103417611510576004358060a01c611510576040525f543318611510576040516001556040517fe7b5cc087e6e47e33e86bdfe4720b7e849891938b18ff6e0c3f92299de79e60c5f6060a2005b63759be10c8118610b9d5734611510576001543318611510575f600155335f55337fafe23f9e1f603b288748a507d5a993957e9f14313a5889d5a070851299939d595f6040a2005b6388a8d6028118610b9d5734611510575f5460405260206040f35b63313ce5678118610b9d573461151057601260405260206040f35b6395d89b418118610b9d57346115105760208060805260056040527f7374594649000000000000000000000000000000000000000000000000000000606052604081608001602582825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506080f35b5f5ffd5b606051604051146115105760605115610bbf57306060511415610bc1565b5f5b156115105760056040516020525f5260405f205460a05260056060516020525f5260405f205460c05260a051608051808203828111611510579050905060056040516020525f5260405f205560c051608051808201828110611510579050905060056060516020525f5260405f205560035463a92d8b5260e0523361010052604060406101205e60045461016052604060a06101805e6080516101c052803b15611510575f60e060e460fc5f855af1610c7c573d5f5f3e3d5ffd5b506060516040517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60805160e052602060e0a3565b6002546115105760405115610ccb57306040511415610ccd565b5f5b156115105760045460805260056040516020525f5260405f205460a052608051606051808201828110611510579050905060045560a051606051808201828110611510579050905060056040516020525f5260405f2055602061155e5f395f516323b872dd60c0523360e052306101005260605161012052602060c0606460dc5f855af1610d5d573d5f5f3e3d5ffd5b3d610d7457803b1561151057600161014052610d9b565b3d602081183d60201002188060c00160e0116115105760c0518060011c6115105761014052505b610140905051156115105760035463311c744f60c0523360e052604051610100526080516101205260a0516101405260605161016052803b15611510575f60c060a460dc5f855af1610def573d5f5f3e3d5ffd5b50604051337fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d760605160c05260605160e052604060c0a36040515f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60605160c052602060c0a3565b60405160d81c81526d0fffffffffffffffffffffffffff604051606c1c1660208201526d0fffffffffffffffffffffffffff60405116604082015250565b64ffffffffff6040511115610eab575f610ede565b6d0fffffffffffffffffffffffffff6060511115610ec9575f610ede565b6d0fffffffffffffffffffffffffff60805111155b1561151057608051606051606c1b60405160d81b1717815250565b60c051156115105760045460e052600560a0516020525f5260405f20546101005260e05160c05180820382811161151057905090506004556101005160c0518082038281116115105790509050600560a0516020525f5260405f205560603661012037600760a0516020525f5260405f2054604052610f79610180610e58565b61018080516101205260208101516101405260408101516101605250426040526101405161016051808203828111611510579050905060c05180820182811061151057905090506060525f608052610fd2610180610e96565b61018051600760a0516020525f5260405f205560035463abdf48846101805260a0516101a05260e0516101c052610100516101e05260c05161020052803b15611510575f610180608461019c5f855af161102e573d5f5f3e3d5ffd5b505f60a0517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60c051610180526020610180a3565b60035463f26c71ba606052604051608052602060606024607c845afa61108b573d5f5f3e3d5ffd5b3d602081183d602010021880606001608011611510576060518060011c6115105760a0525060a0905051815250565b61026051156110cf57306102605114156110d1565b5f5b156115105733610220511461115f576006610220516020525f5260405f2080336020525f5260405f20905054610280527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610280511461115f57610280516102405180820382811161151057905090506006610220516020525f5260405f2080336020525f5260405f209050555b606036610280376007610220516020525f5260405f20546040526111846102e0610e58565b6102e080516102805260208101516102a05260408101516102c05250610220516040526111b2610300611063565b610300516102e0525f61030052610280511561125a576102e0516111fd5742610280518082038281116115105790509050621275008181186212750083100218905061030052611206565b62127500610300525b6102a051610300518082028115838383041417156115105790509050621275008104905061030052610300516102c05161030051808281188284100218905090508082038281116115105790509050610300525b6102e051611268575f611272565b6103005161024051115b6112a257610240516103005110611510576102c0516102405180820182811061151057905090506102c0526112d3565b6102205160a0526102405161030051808203828111611510579050905060c0526112ca610ef9565b6102a0516102c0525b6102a0516102c051106112f6575f6007610220516020525f5260405f205561131e565b606061028060405e611309610320610e96565b610320516007610220516020525f5260405f20555b602061155e5f395f5163a9059cbb61032052610260516103405261024051610360526020610320604461033c5f855af161135a573d5f5f3e3d5ffd5b3d61137157803b156115105760016103805261139b565b3d602081183d602010021880610320016103401161151057610320518060011c6115105761038052505b61038090505115611510576102205161026051337ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db610240516103205261024051610340526040610320a4565b5f60e05260c0516040526113fd610120611063565b6101205161010052610100511561142157600560c0516020525f5260405f205460e0525b60603661012037600760c0516020525f5260405f2054604052611445610180610e58565b61018080516101205260208101516101405260408101516101605250610120516114745760e05181525061150e565b610100516114a957426101205180820382811161151057905090506212750081811862127500831002189050610120526114b2565b62127500610120525b610140516101205180820281158383830414171561151057905090506212750081049050610160518082811882841102189050905061016051808203828111611510579050905060e05180820182811061151057905090508152505b565b5f80fd0b2801fe0b0d0b9d09200b9d02ea07c20b9d0481033200180af208670b9d0aaa0a4f08ff0b9d01df06e00b9d013e08880b9d0b9d03a00846044107e303c40b9d062402cb07640062097a0000000000000000000000000bc529c00c6401aef6d220be8c6ea1667f6ad93e
Verified Source Code Partial Match
Compiler: v0.4.2+commit.c216787f
StakedYFI.vy 541 lines
# pragma version 0.4.2
# pragma optimize gas
# pragma evm-version cancun
"""
@title Staked YFI
@author Yearn Finance
@license GNU AGPLv3
@notice ERC4626 vault that is 1:1 to the underlying, intended to be the YFI token.
Staked (deposited) assets can only be withdrawn by first unstaking them, which burns the
vault shares immediately and releases the underlying tokens in a stream, making
them claimable through the regular 4626 `withdraw` or `redeem` methods.
Operations modifiying the amount of shares are passed through to a hook.
"""
from ethereum.ercs import IERC20
from ethereum.ercs import IERC4626
interface IHooks:
def on_transfer(_caller: address, _from: address, _to: address, _supply: uint256, _prev_staked_from: uint256, _prev_staked_to: uint256, _value: uint256): nonpayable
def on_stake(_caller: address, _account: address, _prev_supply: uint256, _prev_staked: uint256, _value: uint256): nonpayable
def on_unstake(_account: address, _prev_supply: uint256, _prev_staked: uint256, _value: uint256): nonpayable
def instant_withdrawal(_account: address) -> bool: view
implements: IERC20
implements: IERC4626
asset: public(immutable(address))
management: public(address)
pending_management: public(address)
killed: public(bool)
hooks: public(IHooks)
totalSupply: public(uint256)
balanceOf: public(HashMap[address, uint256])
allowance: public(HashMap[address, HashMap[address, uint256]])
packed_streams: public(HashMap[address, uint256]) # time | total | claimed
decimals: public(constant(uint8)) = 18
name: public(constant(String[10])) = "Staked YFI"
symbol: public(constant(String[5])) = "stYFI"
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 Withdraw:
sender: indexed(address)
receiver: indexed(address)
owner: indexed(address)
assets: uint256
shares: uint256
event SetKilled:
killed: bool
event SetHooks:
hooks: indexed(address)
event PendingManagement:
management: indexed(address)
event SetManagement:
management: indexed(address)
SMALL_MASK: constant(uint256) = 2**40 - 1
BIG_MASK: constant(uint256) = 2**108 - 1
STREAM_DURATION: constant(uint256) = 14 * 24 * 60 * 60
@deploy
def __init__(_asset: address):
"""
@notice Constructor
@param _asset Underlying asset of the vault
"""
asset = _asset
self.management = msg.sender
@external
def transfer(_to: address, _value: uint256) -> bool:
"""
@notice Transfer tokens to another user
@param _to User to transfer tokens to
@param _value Amount of tokens to transfer
@return Always True
@dev Reverts if caller does not have at least `_value` tokens
"""
self._transfer(msg.sender, _to, _value)
return True
@external
def transferFrom(_from: address, _to: address, _value: uint256) -> bool:
"""
@notice Transfer another user's tokens by spending an allowance
@param _from User to transfer tokens from
@param _to User to transfer tokens to
@param _value Amount of tokens to transfer
@return Always True
@dev Reverts if `_from` does not have at least `_value` tokens, or if caller
does not have at least `_value` allowance to spend from `_from`
"""
if _value > 0:
allowance: uint256 = self.allowance[_from][msg.sender]
if allowance < max_value(uint256):
self.allowance[_from][msg.sender] = allowance - _value
self._transfer(_from, _to, _value)
return True
@external
def approve(_spender: address, _value: uint256) -> bool:
"""
@notice Approve spending of the caller's tokens
@param _spender User that is allowed to spend caller's tokens
@param _value Amount of tokens spender is allowed to spend
@return Always True
"""
assert _spender != empty(address)
self.allowance[msg.sender][_spender] = _value
log Approval(owner=msg.sender, spender=_spender, value=_value)
return True
@external
def deposit(_assets: uint256, _receiver: address = msg.sender) -> uint256:
"""
@notice Deposit assets
@param _assets Amount of assets to deposit
@param _receiver Recipient of the shares
@return Amount of shares minted
"""
self._stake(_receiver, _assets)
return _assets
@external
def mint(_shares: uint256, _receiver: address = msg.sender) -> uint256:
"""
@notice Mint shares
@param _shares Amount of shares to mint
@param _receiver Recipient of the shares
@return Amount of assets deposited
"""
self._stake(_receiver, _shares)
return _shares
@external
def unstake(_assets: uint256):
"""
@notice Unstake assets, streaming them out
@param _assets Amount of assets to unstake
@dev Adds existing stream to new stream, if applicable
"""
self._unstake(msg.sender, _assets)
@external
def withdraw(_assets: uint256, _receiver: address = msg.sender, _owner: address = msg.sender) -> uint256:
"""
@notice Withdraw assets
@param _assets Amount of assets to withdraw
@param _receiver Recipient of the assets
@param _owner Owner of the shares
@return Amount of shares redeemed
@dev Requires unstaking before assets become withdrawable in a stream
"""
self._withdraw(_owner, _assets, _receiver)
return _assets
@external
def redeem(_shares: uint256, _receiver: address = msg.sender, _owner: address = msg.sender) -> uint256:
"""
@notice Redeem shares
@param _shares Amount of shares to redeem
@param _receiver Recipient of the assets
@param _owner Owner of the shares
@return Amount of assets withdrawn
@dev Requires unstaking before assets become withdrawable in a stream
"""
self._withdraw(_owner, _shares, _receiver)
return _shares
@view
@external
def totalAssets() -> uint256:
"""
@notice Get the total amount of assets in the vault
@return Total amount of assets
@dev Does not include any assets that are currently being unstaked
"""
return self.totalSupply
@view
@external
def convertToShares(_assets: uint256) -> uint256:
"""
@notice Convert an amount of assets to shares
@param _assets Amount of assets
@return Amount of shares
"""
return _assets
@view
@external
def convertToAssets(_shares: uint256) -> uint256:
"""
@notice Convert an amount of shares to assets
@param _shares Amount of shares
@return Amount of assets
"""
return _shares
@view
@external
def maxDeposit(_owner: address) -> uint256:
"""
@notice Get the maximum amount of assets a user can deposit
@param _owner User depositing
@return Maximum amount of assets that can be deposited
"""
if self.killed:
return 0
return max_value(uint256)
@view
@external
def previewDeposit(_assets: uint256) -> uint256:
"""
@notice Preview a deposit
@param _assets Amount of assets to be deposited
@return Equivalent amount of shares to be minted
"""
return _assets
@view
@external
def maxMint(_owner: address) -> uint256:
"""
@notice Get the maximum amount of shares a user can mint
@param _owner User minting
@return Maximum amount of shares that can be minted
"""
if self.killed:
return 0
return max_value(uint256)
@view
@external
def previewMint(_shares: uint256) -> uint256:
"""
@notice Preview a mint
@param _shares Amount of shares to be minted
@return Equivalent amount of assets to be deposited
"""
return _shares
@view
@external
def maxWithdraw(_owner: address) -> uint256:
"""
@notice Get the maximum amount of assets a user can withdraw
@param _owner User withdrawing
@return Maximum amount of assets that can be withdrawn
"""
return self._withdrawable(_owner)
@view
@external
def previewWithdraw(_assets: uint256) -> uint256:
"""
@notice Preview a withdrawal
@param _assets Amount of assets to be withdrawn
@return Equivalent amount of shares to be burned
"""
return _assets
@view
@external
def maxRedeem(_owner: address) -> uint256:
"""
@notice Get the maximum amount of shares a user can redeem
@param _owner User redeeming
@return Maximum amount of shares that can be redeemed
"""
return self._withdrawable(_owner)
@view
@external
def previewRedeem(_shares: uint256) -> uint256:
"""
@notice Preview a redemption
@param _shares Amount of shares to be redeemed
@return Equivalent amount of assets to be withdrawn
"""
return _shares
@external
@view
def streams(_account: address) -> (uint256, uint256, uint256):
"""
@notice Get a user's stream details
@param _account User address
@return Tuple with stream start time, stream amount, claimed amount
"""
return self._unpack(self.packed_streams[_account])
@external
def sweep(_token: address, _amount: uint256 = max_value(uint256)):
"""
@notice Transfer out a token
@param _token The token address
@param _amount The amount of tokens. Defaults to all
@dev Can only be called by management
"""
assert msg.sender == self.management
assert _token != asset
amount: uint256 = _amount
if _amount == max_value(uint256):
amount = staticcall IERC20(_token).balanceOf(self)
assert extcall IERC20(_token).transfer(msg.sender, amount, default_return_value=True)
@external
def set_killed(_killed: bool):
"""
@notice Set the killed status
@param _killed True: kill the vault, disabling deposits
@dev Can only be called by management
"""
assert msg.sender == self.management
self.killed = _killed
log SetKilled(killed=_killed)
@external
def set_hooks(_hooks: address):
"""
@notice Set the hooks address
@param _hooks New hooks address
@dev Can only be called by management
"""
assert msg.sender == self.management
self.hooks = IHooks(_hooks)
log SetHooks(hooks=_hooks)
@external
def set_management(_management: address):
"""
@notice Set the pending management address.
Needs to be accepted by that account separately to transfer management over
@param _management New pending management address
"""
assert msg.sender == self.management
self.pending_management = _management
log PendingManagement(management=_management)
@external
def accept_management():
"""
@notice Accept management role.
Can only be called by account previously marked as pending by current management
"""
assert msg.sender == self.pending_management
self.pending_management = empty(address)
self.management = msg.sender
log SetManagement(management=msg.sender)
@internal
def _transfer(_from: address, _to: address, _value: uint256):
"""
@notice Transfer vault shares from one owner to another
"""
assert _from != _to
assert _to != empty(address) and _to != self
prev_from: uint256 = self.balanceOf[_from]
prev_to: uint256 = self.balanceOf[_to]
self.balanceOf[_from] = prev_from - _value
self.balanceOf[_to] = prev_to + _value
extcall self.hooks.on_transfer(msg.sender, _from, _to, self.totalSupply, prev_from, prev_to, _value)
log Transfer(sender=_from, receiver=_to, value=_value)
@internal
def _stake(_receiver: address, _value: uint256):
"""
@notice Mint shares and take underlying tokens from caller
"""
assert not self.killed
assert _receiver != empty(address) and _receiver != self
prev_supply: uint256 = self.totalSupply
prev_balance: uint256 = self.balanceOf[_receiver]
self.totalSupply = prev_supply + _value
self.balanceOf[_receiver] = prev_balance + _value
assert extcall IERC20(asset).transferFrom(msg.sender, self, _value, default_return_value=True)
extcall self.hooks.on_stake(msg.sender, _receiver, prev_supply, prev_balance, _value)
log Deposit(sender=msg.sender, owner=_receiver, assets=_value, shares=_value)
log Transfer(sender=empty(address), receiver=_receiver, value=_value)
@internal
def _unstake(_owner: address, _value: uint256):
"""
@notice Burn shares and create/update the stream
"""
assert _value > 0
prev_supply: uint256 = self.totalSupply
prev_balance: uint256 = self.balanceOf[_owner]
self.totalSupply = prev_supply - _value
self.balanceOf[_owner] = prev_balance - _value
time: uint256 = 0
total: uint256 = 0
claimed: uint256 = 0
time, total, claimed = self._unpack(self.packed_streams[_owner])
self.packed_streams[_owner] = self._pack(block.timestamp, total - claimed + _value, 0)
extcall self.hooks.on_unstake(_owner, prev_supply, prev_balance, _value)
log Transfer(sender=_owner, receiver=empty(address), value=_value)
@internal
@view
def _withdrawable(_account: address) -> uint256:
"""
@notice Get immediate withdrawable amount
"""
claimable: uint256 = 0
instant: bool = self._instant(_account)
if instant:
claimable = self.balanceOf[_account]
# claimable from stream
time: uint256 = 0
total: uint256 = 0
claimed: uint256 = 0
time, total, claimed = self._unpack(self.packed_streams[_account])
if time == 0:
return claimable
if instant:
time = STREAM_DURATION
else:
time = min(block.timestamp - time, STREAM_DURATION)
return max(total * time // STREAM_DURATION, claimed) - claimed + claimable
@internal
def _withdraw(_owner: address, _value: uint256, _receiver: address):
"""
@notice Withdraw from the stream. May unstake if owner has instant withdrawal permissions
"""
assert _receiver != empty(address) and _receiver != self
# check allowance
if _owner != msg.sender:
allowance: uint256 = self.allowance[_owner][msg.sender]
if allowance < max_value(uint256):
self.allowance[_owner][msg.sender] = allowance - _value
time: uint256 = 0
total: uint256 = 0
claimed: uint256 = 0
time, total, claimed = self._unpack(self.packed_streams[_owner])
instant: bool = self._instant(_owner)
claimable: uint256 = 0
if time > 0:
# calculate time since unstake
if instant:
claimable = STREAM_DURATION
else:
claimable = min(block.timestamp - time, STREAM_DURATION)
claimable = total * claimable // STREAM_DURATION
# if instant withdrawability has changed, `claimed` could be larger than `claimable`
claimable = claimable - min(claimed, claimable)
if instant and _value > claimable:
# the existing stream is not enough to cover the instant withdrawal, attempt to unstake
self._unstake(_owner, _value - claimable)
# zero out stream
claimed = total
else:
assert claimable >= _value
claimed += _value
if claimed < total:
self.packed_streams[_owner] = self._pack(time, total, claimed)
else:
self.packed_streams[_owner] = 0
assert extcall IERC20(asset).transfer(_receiver, _value, default_return_value=True)
log Withdraw(sender=msg.sender, receiver=_receiver, owner=_owner, assets=_value, shares=_value)
@internal
@view
def _instant(_account: address) -> bool:
"""
@notice Check whether an account can bypass the unstaking stream
"""
return staticcall self.hooks.instant_withdrawal(_account)
@internal
@pure
def _pack(_a: uint256, _b: uint256, _c: uint256) -> uint256:
"""
@notice Pack a small value and two big values into a single storage slot
"""
assert _a <= SMALL_MASK and _b <= BIG_MASK and _c <= BIG_MASK
return (_a << 216) | (_b << 108) | _c
@internal
@pure
def _unpack(_packed: uint256) -> (uint256, uint256, uint256):
"""
@notice Unpack a small value and two big values from a single storage slot
"""
return _packed >> 216, (_packed >> 108) & BIG_MASK, _packed & BIG_MASK
Read Contract
allowance 0xdd62ed3e → uint256
asset 0x38d52e0f → address
balanceOf 0x70a08231 → uint256
convertToAssets 0x07a2d13a → uint256
convertToShares 0xc6e6f592 → uint256
decimals 0x313ce567 → uint8
hooks 0xcd7033c4 → address
killed 0x1f3a0e41 → bool
management 0x88a8d602 → address
maxDeposit 0x402d267d → uint256
maxMint 0xc63d75b6 → uint256
maxRedeem 0xd905777e → uint256
maxWithdraw 0xce96cb77 → uint256
name 0x06fdde03 → string
packed_streams 0xed50920b → uint256
pending_management 0x770817ec → address
previewDeposit 0xef8b30f7 → uint256
previewMint 0xb3d7f6b9 → uint256
previewRedeem 0x4cdad506 → uint256
previewWithdraw 0x0a28a477 → uint256
streams 0x83699275 → uint256, uint256, uint256
symbol 0x95d89b41 → string
totalAssets 0x01e1d114 → uint256
totalSupply 0x18160ddd → uint256
Write Contract 20 functions
These functions modify contract state and require a wallet transaction to execute.
accept_management 0x759be10c
No parameters
approve 0x095ea7b3
address _spender
uint256 _value
returns: bool
deposit 0xb6b55f25
uint256 _assets
returns: uint256
deposit 0x6e553f65
uint256 _assets
address _receiver
returns: uint256
mint 0xa0712d68
uint256 _shares
returns: uint256
mint 0x94bf804d
uint256 _shares
address _receiver
returns: uint256
redeem 0xdb006a75
uint256 _shares
returns: uint256
redeem 0x7bde82f2
uint256 _shares
address _receiver
returns: uint256
redeem 0xba087652
uint256 _shares
address _receiver
address _owner
returns: uint256
set_hooks 0x0c360521
address _hooks
set_killed 0x90b22997
bool _killed
set_management 0xfd066ecc
address _management
sweep 0x01681a62
address _token
sweep 0x6ea056a9
address _token
uint256 _amount
transfer 0xa9059cbb
address _to
uint256 _value
returns: bool
transferFrom 0x23b872dd
address _from
address _to
uint256 _value
returns: bool
unstake 0x2e17de78
uint256 _assets
withdraw 0x2e1a7d4d
uint256 _assets
returns: uint256
withdraw 0x00f714ce
uint256 _assets
address _receiver
returns: uint256
withdraw 0xb460af94
uint256 _assets
address _receiver
address _owner
returns: uint256
Recent Transactions
This address has 1 on-chain transactions, but only 0.7% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →