Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0xa2Bcd1a4Efbd04B63cd03f5aFf2561106ebCCE00
Balance 0.002727 ETH
Nonce 1
Code Size 8279 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

8279 bytes
0x5f3560e01c6002601b820660011b61200101601e395f51565b63d4b839928118611cf75734611ffd5760035460405260206040f3611cf7565b63c47339c2811861006557602436103417611ffd5760043560088111611ffd576004015460405260206040f35b63ddca3f438118611cf75734611ffd575f6105a052426105c05261087e56611cf7565b6327810b6e81186100a45734611ffd57600d5460405260206040f35b63427c9a958118611cf757602436103417611ffd576004358060a01c611ffd5760405260115433181561012d57600a6060527f4f6e6c79206f776e65720000000000000000000000000000000000000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6003546060525f60106060516020525f5260405f20556060517fbe9ca79c5858b597d131478211339014c63cf8066fc364a3a616e5635de82e6a5f60805260206080a2604051600355600660106040516020525f5260405f20556040517f529334a1c6836c58fdfaae38f1bc5b62d6a69e91fc4181371b8cd8db71831ea75f6080a26040517fbe9ca79c5858b597d131478211339014c63cf8066fc364a3a616e5635de82e6a600660805260206080a200611cf7565b636dfaf77281186101ff5734611ffd57600e5460405260206040f35b63d11d83ab8118611cf7576043361115611ffd5733620411c052610c2c56611cf7565b6359e63166811861025d57602436103417611ffd576004358060a01c611ffd5760405260106040516020525f5260405f205460605260206060f35b63755da8118118611cf757604436103417611ffd576004356004016040813511611ffd5780355f8160408111611ffd5780156102ba57905b8060051b6020850101358060a01c611ffd578160051b60600152600101818118610295575b50508060405250505f60405160408111611ffd57801561031b57905b8060051b6060015161086052610860516330c5408561088052803b15611ffd575f610880600461089c5f855af161030f573d5f5f3e3d5ffd5b506001018181186102d6575b505000611cf7565b638da5cb5b811861033f5734611ffd5760115460405260206040f35b63e07748628118611cf757602436103417611ffd576004358060a01c611ffd576040526011543318156103c857600a6060527f4f6e6c79206f776e65720000000000000000000000000000000000000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516301ffc9a76060527fa3b5e31100000000000000000000000000000000000000000000000000000000608052602060606024607c845afa61040e573d5f5f3e3d5ffd5b60203d10611ffd576060518060011c611ffd5760a05260a090505115611ffd57604051600d556040517f5d02513563a6890385b0d6684a867cbf8032b19adbd10bca1f78f430db041e375f6060a200611cf7565b6363a4042a811861047e5734611ffd5760125460405260206040f35b63900cf0cf8118611cf75734611ffd5742610320526105bc56611cf7565b6389afcb44811861059f576023361115611ffd576004358060a01c611ffd5760405273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee604051186105105760206120375f395f5163d0e30db0606052803b15611ffd575f60606004607c47855af161050a573d5f5f3e3d5ffd5b50610594565b6040516370a082316080523360a052602060806024609c845afa610536573d5f5f3e3d5ffd5b60203d10611ffd5760809050516060526040516323b872dd6080523360a0523060c05260605160e052602060806064609c5f855af1610577573d5f5f3e3d5ffd5b60203d10611ffd576080518060011c611ffd576101005261010050505b600160605260206060f35b635487c5778118611cf757602436103417611ffd57600435610320525b6020610320516040526105d0610340611cf9565b610340f3611cf7565b63dffe059c81186105f857602436103417611ffd574261050052610638565b63a4520aee8118611cf757604436103417611ffd5733610b40526111c956611cf7565b63b676f7488118611cf757604436103417611ffd57602435610500525b6004358060041c611ffd576104e05260406104e05160405261050051606052610662610520611dc1565b610520f3611cf7565b6339b37ab0811861069957602436103417611ffd576004358060041c611ffd576105a052426105c05261087e565b6397160c5b8118611cf757604436103417611ffd576004358060041c611ffd5760405260115433181561072257600a6060527f4f6e6c79206f776e65720000000000000000000000000000000000000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b60405160605260605160018103818111611ffd579050606051161561079d5760096080527f4261642045706f6368000000000000000000000000000000000000000000000060a0526080506080518060a001601f825f031636823750506308c379a06040526020606052601f19601f6080510116604401605cfd5b670de0b6b3a7640000602435111561080b57600b6080527f426164206d61785f66656500000000000000000000000000000000000000000060a0526080506080518060a001601f825f031636823750506308c379a06040526020606052601f19601f6080510116604401605cfd5b60243560405160088111611ffd57600401556040517f62c711266aa88195f0a4d039bff4072f30cd1171b5473007a6ed72225cf8f32960243560805260206080a200611cf7565b63939f5ea48118611cf757604436103417611ffd576004358060041c611ffd576105a0526024356105c0525b6105a0516108cd5760206105c05160405261089a6105e0611cf9565b6105e051610620526105c05161064052610620516104e05261064051610500526108c5610600611f44565b6106006108ee565b60206105a0516104e0526105c051610500526108ea6105e0611f44565b6105e05bf3611cf7565b630e67c6bc8118610c0757604436103417611ffd576004356004016040813511611ffd5780355f8160408111611ffd57801561097257905b606081026103400160608202602086010180358060a01c611ffd57825260208101358060a01c611ffd57602083015260408101356040830152505060010181811861092c575b5050806103205250505f54600214611ffd5760025f55600d543318156109f757600b611b40527f4f6e6c79204275726e6572000000000000000000000000000000000000000000611b6052611b4050611b405180611b6001601f825f031636823750506308c379a0611b00526020611b2052601f19601f611b40510116604401611b1cfd5b42604052610a06611b60611cf9565b611b6051611b40526006611b405116610a7e57600b611b60527f57726f6e672045706f6368000000000000000000000000000000000000000000611b8052611b6050611b605180611b8001601f825f031636823750506308c379a0611b20526020611b4052601f19601f611b60510116604401611b3cfd5b5f6103205160408111611ffd578015610bff57905b60608102610340018051611b60526020810151611b80526040810151611ba05250611b40516010611b60516020525f5260405f20541615610b3357600b611bc0527f4b696c6c656420636f696e000000000000000000000000000000000000000000611be052611bc050611bc05180611be001601f825f031636823750506308c379a0611b80526020611ba052601f19601f611bc0510116604401611b9cfd5b611ba051611bc052611bc05119610b8257611b60516370a08231611be05230611c00526020611be06024611bfc845afa610b6f573d5f5f3e3d5ffd5b60203d10611ffd57611be0905051611bc0525b611b605163a9059cbb611be052611b8051611c0052611bc051611c20526020611be06044611bfc5f855af1610bb9573d5f5f3e3d5ffd5b3d610bd057803b15611ffd576001611c4052610be9565b60203d10611ffd57611be0518060011c611ffd57611c40525b611c4090505115611ffd57600101818118610a93575b505060035f55005b63167f83f48118611cf7576063361115611ffd576024358060a01c611ffd57620411c0525b6004356004016020813511611ffd5780355f8160208111611ffd578015610cab57905b61206081026105c0018160051b602086010135602086010180358060081c611ffd5782526020810135602083015260408101358101612000813511611ffd57602081350160408401818382375050505050600101818118610c4f575b5050806105a0525050600254600214611ffd576002600255600842604052610cd5620411e0611cf9565b620411e0511815610d4e57600b62041200527f57726f6e672065706f6368000000000000000000000000000000000000000000620412205262041200506204120051806204122001601f825f031636823750506308c379a0620411c0526020620411e052601f19601f62041200510116604401620411dcfd5b600354620411e05260086010620411e0516020525f5260405f205460105f6020525f5260405f2054171615610deb57600662041200527f4b696c6c65640000000000000000000000000000000000000000000000000000620412205262041200506204120051806204122001601f825f031636823750506308c379a0620411c0526020620411e052601f19601f62041200510116604401620411dcfd5b600d54632eb078cd620412005260206204120060046204121c5f855af1610e14573d5f5f3e3d5ffd5b60203d10611ffd57620412005050620411e0516370a08231620412205230620412405260206204122060246204123c845afa610e52573d5f5f3e3d5ffd5b60203d10611ffd57620412209050516204120052600e54620412205262041220516369e15fcb620412605260206204126060046204127c845afa610e98573d5f5f3e3d5ffd5b60203d10611ffd5762041260905051620412405262041200516204124051620412005180828118828410021890509050808203828111611ffd5790509050620412005260086104e0524261050052610ef262041280611f44565b62041280516204120051808202811583838304141715611ffd5790509050670de0b6b3a7640000810490506204126052620411e05163a9059cbb6204128052620411c051620412a0526204126051620412c05260206204128060446204129c5f855af1610f61573d5f5f3e3d5ffd5b60203d10611ffd5762041280518060011c611ffd57620412e052620412e05050620411e05163a9059cbb62041280526204122051620412a05262041200516204126051808203828111611ffd5790509050620412c05260206204128060446204129c5f855af1610fd3573d5f5f3e3d5ffd5b60203d10611ffd5762041280518060011c611ffd57620412e052620412e0505042635f62a7008103818111611ffd57905062093a8081049050600f54101561107857620411e05163095ea7b362041280526204122051620412a0526204124051620412c052803b15611ffd575f6204128060446204129c5f855af161105a573d5f5f3e3d5ffd5b5042635f62a7008103818111611ffd57905062093a8081049050600f555b62041260516204122051638c88eb866204128052604080620412a05280620412a0015f6105a0518083528060051b5f8260208111611ffd57801561113857905b828160051b60208801015261206081026105c001836020880101606082518252602083015160208301528060408301526040830181830160208251018082828560045afa50508051806020830101601f825f03163682375050601f19601f82516020010116905090508101905090509050830192506001018181186110b8575b50508201602001915050905081019050620411c051620412c05250602062041280620414646204129c34855af1611171573d5f5f3e3d5ffd5b60203d10611ffd5762041280905051808201828110611ffd579050905062041260526020620412606003600255f3611cf7565b6342b1689d8118611cf757606436103417611ffd576024358060a01c611ffd57610b40525b6004356004016040813511611ffd5780355f8160408111611ffd57801561121257905b8060051b6020850101358060a01c611ffd578160051b61034001526001018181186111ec575b505080610320525050600154600214611ffd57600260015560024260405261123b610b60611cf9565b610b605118156112aa57600b610b80527f57726f6e672065706f6368000000000000000000000000000000000000000000610ba052610b8050610b805180610ba001601f825f031636823750506308c379a0610b40526020610b6052601f19601f610b80510116604401610b5cfd5b600260105f6020525f5260405f2054161561132457600c610b60527f4b696c6c65642065706f63680000000000000000000000000000000000000000610b8052610b6050610b605180610b8001601f825f031636823750506308c379a0610b20526020610b4052601f19601f610b60510116604401610b3cfd5b5f6103205160408111611ffd57801561148757905b80610b605260026010610b605161032051811015611ffd5760051b61034001516020525f5260405f205416156113ce57600b610b80527f4b696c6c656420636f696e000000000000000000000000000000000000000000610ba052610b8050610b805180610ba001601f825f031636823750506308c379a0610b40526020610b6052601f19601f610b80510116604401610b5cfd5b610b60511561147c57610b605160018103818111611ffd57905061032051811015611ffd5760051b6103400151610b605161032051811015611ffd5760051b61034001511361147c576010610b80527f436f696e73206e6f7420736f7274656400000000000000000000000000000000610ba052610b8050610b805180610ba001601f825f031636823750506308c379a0610b40526020610b6052601f19601f610b80510116604401610b5cfd5b600101818118611339575b5050600d546372a436a8610b6052604080610b805280610b80015f610320518083528060051b5f8260408111611ffd5780156114dd57905b8060051b61034001518160051b6020880101526001018181186114bf575b50508201602001915050905081019050610b4051610ba05250803b15611ffd575f610b60610864610b7c5f855af1611517573d5f5f3e3d5ffd5b50600360015500611cf7565b63dc7168e98118611cf757604436103417611ffd576004356004016040813511611ffd5780355f8160408111611ffd57801561158157905b8060051b6020850101358060a01c611ffd578160051b610340015260010181811861155b575b50508061032052505060044260405261159b610b40611cf9565b610b4051146115ab5760016115be565b600460105f6020525f5260405f20541615155b156115d2575f610b60526020610b60611636565b5f6103205160408111611ffd57801561162857905b8060051b6103400151610b405260046010610b40516020525f5260405f2054161561161d5750505f610b60526020610b60611636565b6001018181186115e7575b50506001610b40526020610b405bf3611cf7565b634e1602df8118611cf757606436103417611ffd576004356004016040813511611ffd5780355f8160408111611ffd5780156116a757905b8060061b6060018160061b602086010180358060a01c611ffd578252602081013560208301525050600101818118611674575b50508060405250506024358060a01c611ffd57611060523360115481186116cf5760016116d6565b6012548118155b905061174157600a6110a0527f4f6e6c79206f776e6572000000000000000000000000000000000000000000006110c0526110a0506110a051806110c001601f825f031636823750506308c379a061106052602061108052601f19601f6110a051011660440161107cfd5b5f60405160408111611ffd57801561187d57905b8060061b60600180516110805260208101516110a052506110a0516110c05273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee61108051186117d6576110c051196117a157476110c0525b611060516110c0515a5f6110e0526110e0505f5f6110e051611100858786f1905090509050611872573d5f5f3e3d5ffd611872565b6110c0511961181d57611080516370a082316110e052306111005260206110e060246110fc845afa61180a573d5f5f3e3d5ffd5b60203d10611ffd576110e09050516110c0525b6110805163a9059cbb6110e05261106051611100526110c0516111205260206110e060446110fc5f855af1611854573d5f5f3e3d5ffd5b60203d10611ffd576110e0518060011c611ffd576111405261114050505b600101818118611755575b505000611cf7565b63a35eba8d8118611cf757602436103417611ffd576004358060a01c611ffd5760405260115433181561190e57600a6060527f4f6e6c79206f776e65720000000000000000000000000000000000000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516301ffc9a76060527fe569b44d00000000000000000000000000000000000000000000000000000000608052602060606024607c845afa611954573d5f5f3e3d5ffd5b60203d10611ffd576060518060011c611ffd5760a05260a090505115611ffd57600e54156119b15760035463095ea7b3606052600e546080525f60a052803b15611ffd575f60606044607c5f855af16119af573d5f5f3e3d5ffd5b505b604051600e556040517f557aa1ccd69dcfb5220a0ee57e91034c3e2ae382692ffe000c16b2865fcca9695f6060a200611cf7565b633f4822d68118611cf757604436103417611ffd576004356004016040813511611ffd5780355f8160408111611ffd578015611a5857905b8060061b6060018160061b602086010180358060a01c611ffd57825260208101358060041c611ffd5760208301525050600101818118611a1d575b5050806040525050336011548118611a71576001611a78565b6012548118155b9050611ae357600a611080527f4f6e6c79206f776e6572000000000000000000000000000000000000000000006110a0526110805061108051806110a001601f825f031636823750506308c379a061104052602061106052601f19601f61108051011660440161105cfd5b5f60405160408111611ffd578015611b6057905b8060061b60600180516110605260208101516110805250611080516010611060516020525f5260405f2055611060517fbe9ca79c5858b597d131478211339014c63cf8066fc364a3a616e5635de82e6a611080516110a05260206110a0a2600101818118611af7575b505000611cf7565b637cb97b2b8118611cf757602436103417611ffd576004358060a01c611ffd57604052601154331815611bf157600a6060527f4f6e6c79206f776e65720000000000000000000000000000000000000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b60405115611ffd576040516011556040517f167d3e9c1016ab80e58802ca9da10ce5c6a0f4debc46a2e7a2cd9e56899a4fb55f6060a200611cf7565b637e1b1e4b8118611cf757602436103417611ffd576004358060a01c611ffd57604052601154331815611cb657600a6060527f4f6e6c79206f776e65720000000000000000000000000000000000000000000060805260605060605180608001601f825f031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b60405115611ffd576040516012556040517f8d244bde4451f1c7643d677f668fcf551617d4046657105728f1e0c6d1f41abd5f6060a200611cf756611cf7565b5b005b604051635f62a7008103818111611ffd57905062093a80810690506040526001608052600260a052600460c052600860e0525f6004905b8060051b608001516060526040366101003762054600610140525f6101605262069780610180526060366101a0376207e9006102005260e0366102203762093a80610300526101006060518060011b818160011c18611ffd57905060108111611ffd5760051b81019050516040511015611db1576060518352505050611dbf565b600101818118611d30575050fe5b565b60405160805260805160018103818111611ffd5790506080511615611e3c57600960a0527f4261642045706f6368000000000000000000000000000000000000000000000060c05260a05060a0518060c001601f825f031636823750506308c379a06060526020608052601f19601f60a0510116604401607cfd5b606051606051635f62a7008103818111611ffd57905062093a8081069050808203828111611ffd579050905060605260605160403660a0376205460060e0525f610100526206978061012052606036610140376207e9006101a05260e0366101c03762093a806102a05260a060405160108111611ffd5760051b8101905051808201828110611ffd579050905081526060516040366102c03762054600610300525f610320526206978061034052606036610360376207e9006103c05260e0366103e03762093a806104c0526102c06040518060011b818160011c18611ffd57905060108111611ffd5760051b8101905051808201828110611ffd5790509050602082015250565b604036610520376104e05160405261050051606052611f64610560611dc1565b61056080516105205260208101516105405250610540516105005110611f8d575f815250611ffb565b6104e05160088111611ffd57600401546105005160018101818110611ffd57905061052051808203828111611ffd5790509050808202811583838304141715611ffd57905090506105405161052051808203828111611ffd57905090508015611ffd57808204905090508152505b565b5f80fd08520038001803231cf608f411a4008819e501e3049c1cf61cf6152318851cf6061b05d904621b681cf6066b163c1cf61c2d1cf60222000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

Verified Source Code Partial Match

Compiler: v0.3.10+commit.91361694
FeeCollector.vy 472 lines
# pragma version 0.3.10
"""
@title FeeCollector
@license MIT
@author Curve Finance
@notice Collects fees and delegates to burner for exchange
"""


interface ERC20:
    def approve(_to: address, _value: uint256): nonpayable
    def transfer(_to: address, _value: uint256) -> bool: nonpayable
    def transferFrom(_from: address, _to: address, _value: uint256) -> bool: nonpayable
    def balanceOf(_owner: address) -> uint256: view

interface wETH:
    def balanceOf(_owner: address) -> uint256: view
    def transferFrom(_sender: address, _receiver: address, _amount: uint256): nonpayable
    def transfer(_receiver: address, _amount: uint256): nonpayable
    def withdraw(_amount: uint256): nonpayable
    def deposit(): payable

interface Curve:
    def withdraw_admin_fees(): nonpayable

interface Burner:
    def burn(_coins: DynArray[ERC20, MAX_LEN], _receiver: address): nonpayable
    def push_target() -> uint256: nonpayable
    def supportsInterface(_interface_id: bytes4) -> bool: view

interface Hooker:
    def duty_act(_hook_inputs: DynArray[HookInput, MAX_HOOK_LEN], _receiver: address=msg.sender) -> uint256: payable
    def buffer_amount() -> uint256: view
    def supportsInterface(_interface_id: bytes4) -> bool: view


event SetMaxFee:
    epoch: indexed(Epoch)
    max_fee: uint256

event SetBurner:
    burner: indexed(Burner)

event SetHooker:
    hooker: indexed(Hooker)

event SetTarget:
    target: indexed(ERC20)

event SetKilled:
    coin: indexed(ERC20)
    epoch_mask: Epoch

event SetOwner:
    owner: indexed(address)

event SetEmergencyOwner:
    emergency_owner: indexed(address)


enum Epoch:
    SLEEP  # 1
    COLLECT  # 2
    EXCHANGE  # 4
    FORWARD  # 8


struct Transfer:
    coin: ERC20
    to: address
    amount: uint256  # 2^256-1 for the whole balance


struct HookInput:
    hook_id: uint8
    value: uint256
    data: Bytes[8192]


struct RecoverInput:
    coin: ERC20
    amount: uint256


struct KilledInput:
    coin: ERC20
    killed: Epoch  # True where killed


ETH_ADDRESS: constant(address) = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
WETH: immutable(wETH)

MAX_LEN: constant(uint256) = 64
MAX_HOOK_LEN: constant(uint256) = 32
ONE: constant(uint256) = 10 ** 18  # Precision

START_TIME: constant(uint256) = 1600300800  # ts of distribution start
WEEK: constant(uint256) = 7 * 24 * 3600
EPOCH_TIMESTAMPS: constant(uint256[17]) = [
    0, 0,  # 1
    4 * 24 * 3600,  # 2
    0, 5 * 24 * 3600,   # 4
    0, 0, 0, 6 * 24 * 3600,  # 8
    0, 0, 0, 0, 0, 0, 0, WEEK,  # 16, next period
]

target: public(ERC20)  # coin swapped into
max_fee: public(uint256[9])  # max_fee[Epoch]

BURNER_INTERFACE_ID: constant(bytes4) = 0xa3b5e311
HOOKER_INTERFACE_ID: constant(bytes4) = 0xe569b44d
burner: public(Burner)
hooker: public(Hooker)

last_hooker_approve: uint256

is_killed: public(HashMap[ERC20, Epoch])
ALL_COINS: constant(ERC20) = empty(ERC20)  # Auxiliary indicator for all coins (=ZERO_ADDRESS)

owner: public(address)
emergency_owner: public(address)


@external
def __init__(_target_coin: ERC20, _weth: wETH, _owner: address, _emergency_owner: address):
    """
    @notice Contract constructor
    @param _target_coin Coin to swap to
    @param _weth Wrapped ETH(native coin) address
    @param _owner Owner address
    @param _emergency_owner Emergency owner address. Can kill the contract
    """
    self.target = _target_coin
    WETH = _weth
    self.owner = _owner
    self.emergency_owner = _emergency_owner

    self.max_fee[convert(Epoch.COLLECT, uint256)] = ONE / 100  # 1%
    self.max_fee[convert(Epoch.FORWARD, uint256)] = ONE / 100  # 1%

    self.is_killed[ALL_COINS] = Epoch.COLLECT | Epoch.FORWARD  # Set burner first
    self.is_killed[_target_coin] = Epoch.COLLECT | Epoch.EXCHANGE  # Keep target coin in contract

    log SetTarget(_target_coin)
    log SetOwner(_owner)
    log SetEmergencyOwner(_emergency_owner)
    log SetMaxFee(Epoch.COLLECT, ONE / 100)
    log SetMaxFee(Epoch.FORWARD, ONE / 100)
    log SetKilled(ALL_COINS, Epoch.COLLECT | Epoch.FORWARD)
    log SetKilled(_target_coin, Epoch.COLLECT | Epoch.FORWARD)


@external
@payable
def __default__():
    # Deposited ETH can be converted using `burn(ETH_ADDRESS)`
    pass


@external
def withdraw_many(_pools: DynArray[address, MAX_LEN]):
    """
    @notice Withdraw admin fees from multiple pools
    @param _pools List of pool address to withdraw admin fees from
    """
    for pool in _pools:
        Curve(pool).withdraw_admin_fees()


@external
@payable
def burn(_coin: address) -> bool:
    """
    @notice Transfer coin from contract with approval
    @dev Needed for back compatability along with dealing raw ETH
    @param _coin Coin to transfer
    @return True if did not fail, back compatability
    """
    if _coin == ETH_ADDRESS:  # Deposit
        WETH.deposit(value=self.balance)
    else:
        amount: uint256 = ERC20(_coin).balanceOf(msg.sender)
        ERC20(_coin).transferFrom(msg.sender, self, amount)
    return True


@internal
@pure
def _epoch_ts(ts: uint256) -> Epoch:
    ts = (ts - START_TIME) % WEEK
    for epoch in [Epoch.SLEEP, Epoch.COLLECT, Epoch.EXCHANGE, Epoch.FORWARD]:
        if ts < EPOCH_TIMESTAMPS[2 * convert(epoch, uint256)]:
            return epoch
    raise UNREACHABLE


@external
@view
def epoch(ts: uint256=block.timestamp) -> Epoch:
    """
    @notice Get epoch at certain timestamp
    @param ts Timestamp. Current by default
    @return Epoch
    """
    return self._epoch_ts(ts)


@internal
@pure
def _epoch_time_frame(epoch: Epoch, ts: uint256) -> (uint256, uint256):
    subset: uint256 = convert(epoch, uint256)
    assert subset & (subset - 1) == 0, "Bad Epoch"

    ts = ts - (ts - START_TIME) % WEEK
    return (ts + EPOCH_TIMESTAMPS[convert(epoch, uint256)], ts + EPOCH_TIMESTAMPS[2 * convert(epoch, uint256)])


@external
@view
def epoch_time_frame(_epoch: Epoch, _ts: uint256=block.timestamp) -> (uint256, uint256):
    """
    @notice Get time frame of certain epoch
    @param _epoch Epoch
    @param _ts Timestamp to anchor to. Current by default
    @return [start, end) time frame boundaries
    """
    return self._epoch_time_frame(_epoch, _ts)


@internal
@view
def _fee(epoch: Epoch, ts: uint256) -> uint256:
    start: uint256 = 0
    end: uint256 = 0
    start, end = self._epoch_time_frame(epoch, ts)
    if ts >= end:
        return 0
    return self.max_fee[convert(epoch, uint256)] * (ts + 1 - start) / (end - start)


@external
@view
def fee(_epoch: Epoch=empty(Epoch), _ts: uint256=block.timestamp) -> uint256:
    """
    @notice Calculate keeper's fee
    @param _epoch Epoch to count fee for
    @param _ts Timestamp of collection
    @return Fee with base 10^18
    """
    if _epoch == empty(Epoch):
        return self._fee(self._epoch_ts(_ts), _ts)
    return self._fee(_epoch, _ts)


@external
@nonreentrant("transfer")
def transfer(_transfers: DynArray[Transfer, MAX_LEN]):
    """
    @dev No approvals so can change burner easily
    @param _transfers Transfers to apply
    """
    assert msg.sender == self.burner.address, "Only Burner"
    epoch: Epoch = self._epoch_ts(block.timestamp)
    assert epoch in Epoch.COLLECT | Epoch.EXCHANGE, "Wrong Epoch"

    for transfer in _transfers:
        assert not self.is_killed[transfer.coin] in epoch, "Killed coin"

        amount: uint256 = transfer.amount
        if amount == max_value(uint256):
            amount = transfer.coin.balanceOf(self)
        assert transfer.coin.transfer(transfer.to, amount, default_return_value=True)


@external
@nonreentrant("collect")
def collect(_coins: DynArray[ERC20, MAX_LEN], _receiver: address=msg.sender):
    """
    @notice Collect earned fees. Collection should happen under callback to earn caller fees.
    @param _coins Coins to collect sorted in ascending order
    @param _receiver Receiver of caller `collect_fee`s
    """
    assert self._epoch_ts(block.timestamp) == Epoch.COLLECT, "Wrong epoch"
    assert not self.is_killed[ALL_COINS] in Epoch.COLLECT, "Killed epoch"

    for i in range(len(_coins), bound=MAX_LEN):
        assert not self.is_killed[_coins[i]] in Epoch.COLLECT, "Killed coin"
        # Eliminate case of repeated coins
        if i > 0:
            assert convert(_coins[i].address, uint160) > convert(_coins[i - 1].address, uint160), "Coins not sorted"

    self.burner.burn(_coins, _receiver)


@external
@view
def can_exchange(_coins: DynArray[ERC20, MAX_LEN]) -> bool:
    """
    @notice Check whether coins are allowed to be exchanged
    @param _coins Coins to exchange
    @return Boolean value if coins are allowed to be exchanged
    """
    if self._epoch_ts(block.timestamp) != Epoch.EXCHANGE or\
        self.is_killed[ALL_COINS] in Epoch.EXCHANGE:
        return False
    for coin in _coins:
        if self.is_killed[coin] in Epoch.EXCHANGE:
            return False
    return True


@external
@payable
@nonreentrant("forward")
def forward(_hook_inputs: DynArray[HookInput, MAX_HOOK_LEN], _receiver: address=msg.sender) -> uint256:
    """
    @notice Transfer target coin forward
    @param _hook_inputs Input parameters for forward hooks
    @param _receiver Receiver of caller `forward_fee`
    @return Amount of received fee
    """
    assert self._epoch_ts(block.timestamp) == Epoch.FORWARD, "Wrong epoch"
    target: ERC20 = self.target
    assert not (self.is_killed[ALL_COINS] | self.is_killed[target]) in Epoch.FORWARD, "Killed"

    self.burner.push_target()
    amount: uint256 = target.balanceOf(self)

    # Account buffer
    hooker: Hooker = self.hooker
    hooker_buffer: uint256 = hooker.buffer_amount()
    amount -= min(hooker_buffer, amount)

    fee: uint256 = self._fee(Epoch.FORWARD, block.timestamp) * amount / ONE
    target.transfer(_receiver, fee)

    target.transfer(hooker.address, amount - fee)
    if self.last_hooker_approve < (block.timestamp - START_TIME) / WEEK:  # First time this week
        target.approve(hooker.address, hooker_buffer)
        self.last_hooker_approve = (block.timestamp - START_TIME) / WEEK
    fee += hooker.duty_act(_hook_inputs, _receiver, value=msg.value)

    return fee


@external
def recover(_recovers: DynArray[RecoverInput, MAX_LEN], _receiver: address):
    """
    @notice Recover ERC20 tokens or Ether from this contract
    @dev Callable only by owner and emergency owner
    @param _recovers (Token, amount) to recover
    @param _receiver Receiver of coins
    """
    assert msg.sender in [self.owner, self.emergency_owner], "Only owner"

    for input in _recovers:
        amount: uint256 = input.amount
        if input.coin.address == ETH_ADDRESS:
            if amount == max_value(uint256):
                amount = self.balance
            raw_call(_receiver, b"", value=amount)
        else:
            if amount == max_value(uint256):
                amount = input.coin.balanceOf(self)
            input.coin.transfer(_receiver, amount)  # do not need safe transfer


@external
def set_max_fee(_epoch: Epoch, _max_fee: uint256):
    """
    @notice Set keeper's max fee
    @dev Callable only by owner
    @param _epoch Epoch to set fee for
    @param _max_fee Maximum fee to set
    """
    assert msg.sender == self.owner, "Only owner"
    subset: uint256 = convert(_epoch, uint256)
    assert subset & (subset - 1) == 0, "Bad Epoch"
    assert _max_fee <= ONE, "Bad max_fee"
    self.max_fee[convert(_epoch, uint256)] = _max_fee

    log SetMaxFee(_epoch, _max_fee)


@external
def set_burner(_new_burner: Burner):
    """
    @notice Set burner for exchanging coins, must implement BURNER_INTERFACE
    @dev Callable only by owner
    @param _new_burner Address of the new contract
    """
    assert msg.sender == self.owner, "Only owner"
    assert _new_burner.supportsInterface(BURNER_INTERFACE_ID)
    self.burner = _new_burner

    log SetBurner(_new_burner)


@external
def set_hooker(_new_hooker: Hooker):
    """
    @notice Set contract for hooks, must implement HOOKER_INTERFACE
    @dev Callable only by owner
    @param _new_hooker Address of the new contract
    """
    assert msg.sender == self.owner, "Only owner"
    assert _new_hooker.supportsInterface(HOOKER_INTERFACE_ID)

    if self.hooker != empty(Hooker):
        self.target.approve(self.hooker.address, 0)
    self.hooker = _new_hooker

    log SetHooker(_new_hooker)


@external
def set_target(_new_target: ERC20):
    """
    @notice Set new coin for fees accumulation
    @dev Callable only by owner
    @param _new_target Address of the new target coin
    """
    assert msg.sender == self.owner, "Only owner"

    target: ERC20 = self.target
    self.is_killed[target] = empty(Epoch)  # allow to collect and exchange
    log SetKilled(target, empty(Epoch))

    self.target = _new_target
    self.is_killed[_new_target] = Epoch.COLLECT | Epoch.EXCHANGE  # Keep target coin in contract
    log SetTarget(_new_target)
    log SetKilled(_new_target, Epoch.COLLECT | Epoch.EXCHANGE)


@external
def set_killed(_input: DynArray[KilledInput, MAX_LEN]):
    """
    @notice Stop a contract or specific coin to be burnt
    @dev Callable only by owner or emergency owner
    @param _input Array of (coin address, killed phases enum)
    """
    assert msg.sender in [self.owner, self.emergency_owner], "Only owner"

    for input in _input:
        self.is_killed[input.coin] = input.killed
        log SetKilled(input.coin, input.killed)


@external
def set_owner(_new_owner: address):
    """
    @notice Set owner of the contract
    @dev Callable only by current owner
    @param _new_owner Address of the new owner
    """
    assert msg.sender == self.owner, "Only owner"
    assert _new_owner != empty(address)
    self.owner = _new_owner
    log SetOwner(_new_owner)


@external
def set_emergency_owner(_new_owner: address):
    """
    @notice Set emergency owner of the contract
    @dev Callable only by current owner
    @param _new_owner Address of the new emergency owner
    """
    assert msg.sender == self.owner, "Only owner"
    assert _new_owner != empty(address)
    self.emergency_owner = _new_owner
    log SetEmergencyOwner(_new_owner)

Read Contract

burner 0x27810b6e → address
can_exchange 0xdc7168e9 → bool
emergency_owner 0x63a4042a → address
epoch 0x900cf0cf → uint256
epoch 0x5487c577 → uint256
epoch_time_frame 0xdffe059c → uint256, uint256
epoch_time_frame 0xb676f748 → uint256, uint256
fee 0xddca3f43 → uint256
fee 0x39b37ab0 → uint256
fee 0x939f5ea4 → uint256
hooker 0x6dfaf772 → address
is_killed 0x59e63166 → uint256
max_fee 0xc47339c2 → uint256
owner 0x8da5cb5b → address
target 0xd4b83992 → address

Write Contract 15 functions

These functions modify contract state and require a wallet transaction to execute.

burn 0x89afcb44
address _coin
returns: bool
collect 0xa4520aee
address[] _coins
collect 0x42b1689d
address[] _coins
address _receiver
forward 0xa6171aba
tuple[] _hook_inputs
returns: uint256
forward 0xfd37e0e5
tuple[] _hook_inputs
address _receiver
returns: uint256
recover 0x7ebf9f42
tuple[] _recovers
address _receiver
set_burner 0xe0774862
address _new_burner
set_emergency_owner 0x7e1b1e4b
address _new_owner
set_hooker 0xa35eba8d
address _new_hooker
set_killed 0x87a7050c
tuple[] _input
set_max_fee 0x97160c5b
uint256 _epoch
uint256 _max_fee
set_owner 0x7cb97b2b
address _new_owner
set_target 0x427c9a95
address _new_target
transfer 0xf06ed066
tuple[] _transfers
withdraw_many 0x755da811
address[] _pools

Recent Transactions

No transactions found for this address