Address Contract Partially Verified
Address
0x2c6C87E7E6195ab7A4f19d3CF31D867580Bb2a1b
Balance
9.6656 ETH
Nonce
1
Code Size
10176 bytes
Creator
0x8283ac36...c666 at tx 0x98e2aefc...d8c86f
Indexed Transactions
0
Contract Bytecode
10176 bytes
0x600436101561000d57612744565b600035601c526f7fffffffffffffffffffffffffffffff60405260001561053d575b61014052602061020060246370a0823161018052306101a05261019c6008545afa61005957600080fd5b601f3d1161006657600080fd5b600050610200516101605261016051600b548082101561008557600080fd5b808203905090506101805261016051600b55476101a0526101a051600c54808210156100b057600080fd5b808203905090506101c0526101a051600c556004546101e052426101e051808210156100db57600080fd5b8082039050905061020052426004556101e05162093a808082049050905062093a80808202821582848304141761011157600080fd5b809050905090506102205260006102405261026060006014818352015b6102205162093a8081818301101561014557600080fd5b80820190509050610240526102405142101561031d57610200511515610170576101e0514214610173565b60005b156101ff576102205166038d7ea4c68000811061018f57600080fd5b600560c052602060c020018054610180518181830110156101af57600080fd5b808201905090508155506102205166038d7ea4c6800081106101d057600080fd5b600660c052602060c0200180546101c0518181830110156101f057600080fd5b80820190509050815550610314565b6102205166038d7ea4c68000811061021657600080fd5b600560c052602060c02001805461018051426101e0518082101561023957600080fd5b80820390509050808202821582848304141761025457600080fd5b8090509050905061020051808061026a57600080fd5b82049050905081818301101561027f57600080fd5b808201905090508155506102205166038d7ea4c6800081106102a057600080fd5b600660c052602060c0200180546101c051426101e051808210156102c357600080fd5b8082039050905080820282158284830414176102de57600080fd5b809050905090506102005180806102f457600080fd5b82049050905081818301101561030957600080fd5b808201905090508155505b610501566104e0565b610200511515610335576101e0516102405114610338565b60005b156103c4576102205166038d7ea4c68000811061035457600080fd5b600560c052602060c0200180546101805181818301101561037457600080fd5b808201905090508155506102205166038d7ea4c68000811061039557600080fd5b600660c052602060c0200180546101c0518181830110156103b557600080fd5b808201905090508155506104df565b6102205166038d7ea4c6800081106103db57600080fd5b600560c052602060c02001805461018051610240516101e0518082101561040157600080fd5b80820390509050808202821582848304141761041c57600080fd5b8090509050905061020051808061043257600080fd5b82049050905081818301101561044757600080fd5b808201905090508155506102205166038d7ea4c68000811061046857600080fd5b600660c052602060c0200180546101c051610240516101e0518082101561048e57600080fd5b8082039050905080820282158284830414176104a957600080fd5b809050905090506102005180806104bf57600080fd5b8204905090508181830110156104d457600080fd5b808201905090508155505b5b610240516101e05261024051610220525b815160010180835281141561012e575b5050426102605261018051610280527fce749457b74e10f393f2c6b1ce4261b78791376db5a3f501477a809f03f500d66040610260a161014051565b63811a40fe60005114156105af57341561055657600080fd5b600e54331415610567576001610597565b60105415610593576004546201518081818301101561058557600080fd5b808201905090504211610596565b60005b5b5b6105a157600080fd5b6006580161002f565b600050005b60001561076a575b61018052610140526101605260006101a0526020610240600463900cf0cf6101e0526101fc610140515afa6105eb57600080fd5b601f3d116105f857600080fd5b600050610240516101c0526101e060006080818352015b6101c0516101a05110151561062357610756565b6101a0516101c05181818301101561063a57600080fd5b80820190509050600281818301101561065257600080fd5b80820190509050600280820490509050610200526102206080610320602463d1febfb96102a052610200516102c0526102bc610140515afa61069357600080fd5b607f3d116106a057600080fd5b61032080808080516103a0525050602081019050808080516103c0525050602081019050808080516103e05250506020810190508080805161040052505050506000506103a0805182528060200151826020015280604001518260400152806060015182606001525050610160516102605111151561072657610200516101a052610745565b6102005160018082101561073957600080fd5b808203905090506101c0525b5b815160010180835281141561060f575b50506101a051600052600051610180515650005b600015610903575b6101c0526101405261016052610180526101a05260006101e0526101a0516102005261022060006080818352015b610200516101e0511015156107b4576108ef565b6101e051610200518181830110156107cb57600080fd5b8082019050905060028181830110156107e357600080fd5b8082019050905060028082049050905061024052610260608061038060446328d09d476102e052610160516103005261024051610320526102fc610140515afa61082c57600080fd5b607f3d1161083957600080fd5b61038080808080516104005250506020810190508080805161042052505060208101905080808051610440525050602081019050808080516104605250505050600050610400805182528060200151826020015280604001518260400152806060015182606001525050610180516102a0511115156108bf57610240516101e0526108de565b610240516001808210156108d257600080fd5b80820390509050610200525b5b81516001018083528114156107a0575b50506101e0516000526000516101c0515650005b63ace296fb6000511415610b2157341561091c57600080fd5b60043560a01c1561092c57600080fd5b600754610140526020610200602463010ae757610180526004356101a05261019c610140515afa61095c57600080fd5b601f3d1161096957600080fd5b6000506102005161016052610140516101605161018051610140516101a0526004356101c0526024356101e0526101605161020052610200516101e0516101c0516101a05160065801610772565b6102605261018052610160526101405261026051610180526101a060806102c060446328d09d476102205260043561024052610180516102605261023c610140515afa610a0357600080fd5b607f3d11610a1057600080fd5b6102c080808080516103405250506020810190508080805161036052505060208101905080808051610380525050602081019050808080516103a052505050506000506103408051825280602001518260200152806040015182604001528060600151826060015250506101a0516101c0516024356101e05180821015610a9657600080fd5b80820390509050604051811115610aac57600080fd5b80820280806000811215610abc57195b607f1c15610ac957600080fd5b90509050905080820380806000811215610adf57195b607f1c15610aec57600080fd5b905090509050600080821215610b025780610b04565b815b905090506000811215610b1657600080fd5b60005260206000f350005b600015610ddf575b6101405260075461016052600154610180524262093a808082049050905062093a808082028215828483041417610b5f57600080fd5b809050905090506101a052610160513b610b7857600080fd5b60006000600463c2c4c5c16101c0526101dc6000610160515af1610b9b57600080fd5b6101c060006014818352015b6101a051610180511115610bbe57610dd056610d9d565b6101405161016051610180516101a0516101c0516101e051610160516102005261018051610220526102205161020051600658016105b7565b610280526101e0526101c0526101a052610180526101605261014052610280516101e0526102006080610300602463d1febfb9610280526101e0516102a05261029c610160515afa610c4857600080fd5b607f3d11610c5557600080fd5b6103008080808051610380525050602081019050808080516103a0525050602081019050808080516103c0525050602081019050808080516103e0525050505060005061038080518252806020015182602001528060400151826040015280606001518260600152505060006102805261024051610180511115610d0357610180516102405180821015610ce857600080fd5b80820390509050604051811115610cfe57600080fd5b610280525b61020051610220516102805180820280806000811215610d1f57195b607f1c15610d2c57600080fd5b90509050905080820380806000811215610d4257195b607f1c15610d4f57600080fd5b905090509050600080821215610d655780610d67565b815b905090506000811215610d7957600080fd5b6101805166038d7ea4c680008110610d9057600080fd5b600d60c052602060c02001555b610180805162093a80818183011015610db557600080fd5b808201905090508152505b8151600101808352811415610ba7575b50506101805160015561014051565b63b21ed5026000511415610e06573415610df857600080fd5b60065801610b29565b600050005b600015611656575b6101c0526101405261016052610180526101a0526060366101e03760206102e0602463010ae75761026052610140516102805261027c610160515afa610e5357600080fd5b601f3d11610e6057600080fd5b6000506102e0516102405260005461026052610240511515610edc57610280808080600081525050602081019050808060008152505060409050905060c05260c0516102c0525b60006102c051111515610eb957610ed5565b60206102c05103610280015160206102c051036102c052610ea7565b6101c05156505b60026101405160e05260c052604060c020546102c0526102c0511515610f9b576101406102e0525b6102e0515160206102e051016102e0526102e06102e0511015610f2657610f04565b61016051610300526101405161032052610260516103405261024051610360526103605161034051610320516103005160065801610772565b6103c0526102c06102e0525b6102e0515260206102e051036102e0526101406102e051101515610f8e57610f6b565b6103c0516101e052610fb2565b60036101405160e05260c052604060c020546101e0525b6101e0511515610fc35760016101e0525b6102e0608061040060446328d09d476103605261014051610380526101e0516103a05261037c610160515afa610ff857600080fd5b607f3d1161100557600080fd5b6104008080808051610480525050602081019050808080516104a0525050602081019050808080516104c0525050602081019050808080516104e052505050506000506104808051825280602001518260200152806040015182604001528060600151826060015250506102c05115156110dc576103205162093a8081818301101561109057600080fd5b808201905090506001808210156110a657600080fd5b8082039050905062093a808082049050905062093a8080820282158284830414176110d057600080fd5b809050905090506102c0525b610180516102c05110151561114b57610360808080600081525050602081019050808060008152505060409050905060c05260c0516103a0525b60006103a05111151561112857611144565b60206103a05103610360015160206103a051036103a052611116565b6101c05156505b610260516102c051101561116257610260516102c0525b6080366103a03761042060007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff818352015b6101a05115156111aa57603261042051116111ad565b60005b156111b95760016111c4565b610180516102c05110155b5b156111cf57611542565b610320516102c0511015156111ed57610240516101e05111156111f0565b60005b1561130b576101e08051600181818301101561120b57600080fd5b808201905090508152506103a06102e0805182528060200151826020015280604001518260400152806060015182606001525050610240516101e0511115611259576080366102e037611306565b6102e060806104e060446328d09d476104405261014051610460526101e0516104805261045c610160515afa61128e57600080fd5b607f3d1161129b57600080fd5b6104e0808080805161056052505060208101905080808051610580525050602081019050808080516105a0525050602081019050808080516105c052505050506000506105608051825280602001518260200152806040015182604001528060600151826060015250505b611531565b6102c0516103e0518082101561132057600080fd5b8082039050905060405181111561133657600080fd5b610440526103a051610440516103c0518082028080600081121561135657195b607f1c1561136357600080fd5b9050905090508082038080600081121561137957195b607f1c1561138657600080fd5b90509050905060008082121561139c578061139e565b815b9050905060008112156113b057600080fd5b610460526104605115156113cc57610240516101e051116113cf565b60005b156113d957611542565b600061046051111561150e576102008051610460516102c05166038d7ea4c68000811061140557600080fd5b600560c052602060c0200154808202821582848304141761142557600080fd5b809050905090506102c05166038d7ea4c68000811061144357600080fd5b600d60c052602060c0200154808061145a57600080fd5b82049050905081818301101561146f57600080fd5b808201905090508152506102208051610460516102c05166038d7ea4c68000811061149957600080fd5b600660c052602060c020015480820282158284830414176114b957600080fd5b809050905090506102c05166038d7ea4c6800081106114d757600080fd5b600d60c052602060c020015480806114ee57600080fd5b82049050905081818301101561150357600080fd5b808201905090508152505b6102c0805162093a8081818301101561152657600080fd5b808201905090508152505b5b8151600101808352811415611194575b5050610240516101e05160018082101561155b57600080fd5b80820390509050808211156115705780611572565b815b905090506101e0526101e05160036101405160e05260c052604060c020556102c05160026101405160e05260c052604060c02055610200516104205261022051610440526101e051610460526102405161048052610140517f7708755c9b641bf197be5047b04002d2e88fa658c173a351067747eb5dfc568a6080610420a261042080808061020051815250506020810190508080610220518152505060409050905060c05260c051610460525b6000610460511115156116325761164e565b6020610460510361042001516020610460510361046052611620565b6101c0515650005b600015611922575b6101805261014052610160526012541561167757600080fd5b600154421015156116a75761014051610160516101805160065801610b29565b6101805261016052610140526000505b6004546101a052601054156116db576101a051620151808181830110156116cd57600080fd5b8082019050905042116116de565b60005b15611715576101405161016051610180516101a0516006580161002f565b6101a052610180526101605261014052600050426101a0525b6101a05162093a808082049050905062093a80808202821582848304141761173c57600080fd5b809050905090506101a0526040366101c0376101405161016051610180516101a0516101c0516101e0516101405161020052600754610220526101a0516102405261016051610260526102605161024051610220516102005160065801610e0e565b6102c0526102e0526101e0526101c0526101a0526101805261016052610140526102c0808080805161030052505060208101905080808051610320525050505061030080516101c05280602001516101e0525060006101c0511815611875576008546102005260206102c0604463a9059cbb6102205261014051610240526101c0516102605261023c6000610200515af161183857600080fd5b601f3d1161184557600080fd5b6000506102c05161185557600080fd5b600b80546101c0518082101561186a57600080fd5b808203905090508155505b60006101e05118156118bd5760006000600060006101e051610140516000f161189d57600080fd5b600c80546101e051808210156118b257600080fd5b808203905090508155505b6102008080806101c0518152505060208101905080806101e0518152505060409050905060c05260c051610240525b6000610240511115156118fe5761191a565b60206102405103610200015160206102405103610240526118ec565b610180515650005b634e71d92d600051141561193a573361014052611970565b631e83409a60005114156119685760043560a01c1561195857600080fd5b6020600461014037600050611970565b600015611a22575b62ffffff541561197f57600080fd5b600162ffffff55341561199157600080fd5b61014051610140516101605260006101805261018051610160516006580161165e565b6101e05261020052610140526101e08080808051610220525050602081019050808080516102405250505050610220610260808080845181525050602081019050808084602001518152505060409050905060c052600062ffffff5560c051610260f39050600062ffffff55005b63520669056000511415611a3a573361014052611a70565b63ea9a97666000511415611a685760043560a01c15611a5857600080fd5b6020600461014037600050611a70565b600015611b22575b62ffffff5415611a7f57600080fd5b600162ffffff553415611a9157600080fd5b61014051610140516101605260016101805261018051610160516006580161165e565b6101e05261020052610140526101e08080808051610220525050602081019050808080516102405250505050610220610260808080845181525050602081019050808084602001518152505060409050905060c052600062ffffff5560c051610260f39050600062ffffff55005b637b935a236000511415611e885762ffffff5415611b3f57600080fd5b600162ffffff553415611b5157600080fd5b6000610120525b610120516004013560a01c15611b6d57600080fd5b6020610120510161012052610280610120511015611b8a57611b58565b60125415611b9757600080fd5b60015442101515611baf5760065801610b29565b6000505b6004546101405260105415611be3576101405162015180818183011015611bd557600080fd5b808201905090504211611be6565b60005b15611c0557610140516006580161002f565b6101405260005042610140525b6101405162093a808082049050905062093a808082028215828483041417611c2c57600080fd5b809050905090506101405260075461016052600854610180526040366101a03761020060006014818352015b60206102005102600401356101e0526101e0511515611c7657611e13565b604036610220376101405161016051610180516101a0516101c0516101e0516102005161022051610240516101e051610260526101605161028052610140516102a05260006102c0526102c0516102a051610280516102605160065801610e0e565b61032052610340526102405261022052610200526101e0526101c0526101a0526101805261016052610140526103208080808051610360525050602081019050808080516103805250505050610360805161022052806020015161024052506000610220511815611db7576020610300604463a9059cbb610260526101e05161028052610220516102a05261027c6000610180515af1611d7757600080fd5b601f3d11611d8457600080fd5b60005061030051611d9457600080fd5b6101a0805161022051818183011015611dac57600080fd5b808201905090508152505b6000610240511815611e02576000600060006000610240516101e0516000f1611ddf57600080fd5b6101c0805161024051818183011015611df757600080fd5b808201905090508152505b5b8151600101808352811415611c58575b505060006101a0511815611e4157600b80546101a05180821015611e3657600080fd5b808203905090508155505b60006101c0511815611e6d57600c80546101c05180821015611e6257600080fd5b808203905090508155505b6001600052600062ffffff5560206000f350600062ffffff55005b6389afcb446000511415611fd55760043560a01c15611ea657600080fd5b60085460043514611eb657600080fd5b60125415611ec357600080fd5b60206101e060246370a0823161016052336101805261017c6004355afa611ee957600080fd5b601f3d11611ef657600080fd5b6000506101e051610140526000610140511815611f5757602061022060646323b872dd610160523361018052306101a052610140516101c05261017c60006004355af1611f4257600080fd5b601f3d11611f4f57600080fd5b600050610220505b6000610140511815611f6a576001611f70565b60003414155b5b15611faa5760105415611fa25760045462015180818183011015611f9457600080fd5b808201905090504211611fa5565b60005b611fad565b60005b5b15611fc857610140516006580161002f565b610140526000505b600160005260206000f350005b63b1d3db756000511415612042573415611fee57600080fd5b60043560a01c15611ffe57600080fd5b600e54331461200c57600080fd5b600435600f55600435610140527f59a407284ae6e2986675fa1400d6498af928ed01f4fd2dd6be4a2a8b4fc35b346020610140a1005b63c0e991a660005114156120b757341561205b57600080fd5b600e54331461206957600080fd5b6000600f541861207857600080fd5b600f546101405261014051600e5561014051610160527f756f845176805c8ebf249854e909627308157f63c96e470e44a9e8549ba6fb1e6020610160a1005b632121bfc3600051141561211e5734156120d057600080fd5b600e5433146120de57600080fd5b60105415610140526101405160105561014051610160527fdbe6ac1081ebd8e648718341126659456f4009fcadfe1c23f66f5e61522610b26020610160a1005b63e369885360005114156121f257341561213757600080fd5b600e54331461214557600080fd5b60016012556000600060006000476011546000f161216257600080fd5b6008546101405260206102a0604463a9059cbb610200526011546102205260206101e060246370a0823161016052306101805261017c610140515afa6121a757600080fd5b601f3d116121b457600080fd5b6000506101e0516102405261021c6000610140515af16121d357600080fd5b601f3d116121e057600080fd5b6000506102a0516121f057600080fd5b005b63db2f5f7960005114156123c557341561220b57600080fd5b60043560a01c1561221b57600080fd5b600e54331461222957600080fd5b6008546004351861223957600080fd5b60206101e060246370a0823161016052306101805261017c6004355afa61225f57600080fd5b601f3d1161226c57600080fd5b6000506101e05161014052600060046101c0527fa9059cbb000000000000000000000000000000000000000000000000000000006101e0526101c060048060208461022001018260208501600060045af150508051820191505060115460208261022001015260208101905061014051602082610220010152602081019050806102205261022090508051602001806102c08284600060045af161230f57600080fd5b505060206103806102c0516102e060006004355af161232d57600080fd5b60203d8082111561233e5780612340565b815b90509050610360526103608051602001806101608284600060045af161236557600080fd5b505060006101605118156123b85761016080602001516000825180602090131561238e57600080fd5b809190121561239c57600080fd5b806020036101000a820490509050905015156123b757600080fd5b5b600160005260206000f350005b63834ee41760005114156123ec5734156123de57600080fd5b60005460005260206000f350005b63127dcbd3600051141561241357341561240557600080fd5b60015460005260206000f350005b632a2a314b600051141561245857341561242c57600080fd5b60043560a01c1561243c57600080fd5b600260043560e05260c052604060c0205460005260206000f350005b63d5d46e88600051141561249d57341561247157600080fd5b60043560a01c1561248157600080fd5b600360043560e05260c052604060c0205460005260206000f350005b637f58e8f860005114156124c45734156124b657600080fd5b60045460005260206000f350005b63edf59997600051141561250a5734156124dd57600080fd5b60043566038d7ea4c6800081106124f357600080fd5b600560c052602060c020015460005260206000f350005b63084e58bd600051141561255057341561252357600080fd5b60043566038d7ea4c68000811061253957600080fd5b600660c052602060c020015460005260206000f350005b63dfe05031600051141561257757341561256957600080fd5b60075460005260206000f350005b63fc0c546a600051141561259e57341561259057600080fd5b60085460005260206000f350005b632f0c222e60005114156125c55734156125b757600080fd5b60095460005260206000f350005b63bf33e4a560005114156125ec5734156125de57600080fd5b600a5460005260206000f350005b6322b04bfc600051141561261357341561260557600080fd5b600b5460005260206000f350005b6373beca25600051141561263a57341561262c57600080fd5b600c5460005260206000f350005b63d4dafba8600051141561268057341561265357600080fd5b60043566038d7ea4c68000811061266957600080fd5b600d60c052602060c020015460005260206000f350005b63f851a44060005114156126a757341561269957600080fd5b600e5460005260206000f350005b6317f7182a60005114156126ce5734156126c057600080fd5b600f5460005260206000f350005b63aeba473760005114156126f55734156126e757600080fd5b60105460005260206000f350005b632c3f531e600051141561271c57341561270e57600080fd5b60115460005260206000f350005b639c868ac0600051141561274357341561273557600080fd5b60125460005260206000f350005b5b6012541561275157600080fd5b3461014052337fbe8ee6217029517b2fc45b7840f3064181a02443e29456e7243f5dc1a670c1426020610140a2601054156127aa576004546201518081818301101561279c57600080fd5b8082019050905042116127ad565b60005b156127bf576006580161002f565b6000505b
Verified Source Code Partial Match
Compiler: v0.2.7+commit.0b3f3b3
Vyper_contract.vy 538 lines
# @version 0.2.7
"""
@title Curve Fee Distribution
@author Curve Finance
@license MIT
"""
from vyper.interfaces import ERC20
interface VotingEscrow:
def user_point_epoch(addr: address) -> uint256: view
def epoch() -> uint256: view
def user_point_history(addr: address, loc: uint256) -> Point: view
def point_history(loc: uint256) -> Point: view
def checkpoint(): nonpayable
event CommitAdmin:
admin: address
event ApplyAdmin:
admin: address
event ToggleAllowCheckpointToken:
toggle_flag: bool
event CheckpointToken:
time: uint256
tokens: uint256
event Claimed:
recipient: indexed(address)
amount: uint256
amount_eth: uint256
claim_epoch: uint256
max_epoch: uint256
event EtherSent:
amount: uint256
sender: indexed(address)
struct Point:
bias: int128
slope: int128 # - dweight / dt
ts: uint256
blk: uint256 # block
WEEK: constant(uint256) = 7 * 86400
TOKEN_CHECKPOINT_DEADLINE: constant(uint256) = 86400
start_time: public(uint256)
time_cursor: public(uint256)
time_cursor_of: public(HashMap[address, uint256])
user_epoch_of: public(HashMap[address, uint256])
last_token_time: public(uint256)
tokens_per_week: public(uint256[1000000000000000])
eth_per_week: public(uint256[1000000000000000])
voting_escrow: public(address)
token: public(address)
total_received: public(uint256)
total_eth_received: public(uint256)
token_last_balance: public(uint256)
eth_last_balance: public(uint256)
ve_supply: public(uint256[1000000000000000]) # VE total supply at week bounds
admin: public(address)
future_admin: public(address)
can_checkpoint_token: public(bool)
emergency_return: public(address)
is_killed: public(bool)
@external
def __init__(
_voting_escrow: address,
_start_time: uint256,
_token: address,
_admin: address,
_emergency_return: address
):
"""
@notice Contract constructor
@param _voting_escrow VotingEscrow contract address
@param _start_time Epoch time for fee distribution to start
@param _token Fee token address (3CRV)
@param _admin Admin address
@param _emergency_return Address to transfer `_token` balance to
if this contract is killed
"""
t: uint256 = _start_time / WEEK * WEEK
self.start_time = t
self.last_token_time = t
self.time_cursor = t
self.token = _token
self.voting_escrow = _voting_escrow
self.admin = _admin
self.emergency_return = _emergency_return
@internal
def _checkpoint_token():
token_balance: uint256 = ERC20(self.token).balanceOf(self)
to_distribute: uint256 = token_balance - self.token_last_balance
self.token_last_balance = token_balance
eth_balance: uint256 = self.balance
to_distribute_eth: uint256 = eth_balance - self.eth_last_balance
self.eth_last_balance = eth_balance
t: uint256 = self.last_token_time
since_last: uint256 = block.timestamp - t
self.last_token_time = block.timestamp
this_week: uint256 = t / WEEK * WEEK
next_week: uint256 = 0
for i in range(20):
next_week = this_week + WEEK
if block.timestamp < next_week:
if since_last == 0 and block.timestamp == t:
self.tokens_per_week[this_week] += to_distribute
self.eth_per_week[this_week] += to_distribute_eth
else:
self.tokens_per_week[this_week] += to_distribute * (block.timestamp - t) / since_last
self.eth_per_week[this_week] += to_distribute_eth * (block.timestamp - t) / since_last
break
else:
if since_last == 0 and next_week == t:
self.tokens_per_week[this_week] += to_distribute
self.eth_per_week[this_week] += to_distribute_eth
else:
self.tokens_per_week[this_week] += to_distribute * (next_week - t) / since_last
self.eth_per_week[this_week] += to_distribute_eth * (next_week - t) / since_last
t = next_week
this_week = next_week
log CheckpointToken(block.timestamp, to_distribute)
@external
def checkpoint_token():
"""
@notice Update the token checkpoint
@dev Calculates the total number of tokens to be distributed in a given week.
During setup for the initial distribution this function is only callable
by the contract owner. Beyond initial distro, it can be enabled for anyone
to call.
"""
assert (msg.sender == self.admin) or\
(self.can_checkpoint_token and (block.timestamp > self.last_token_time + TOKEN_CHECKPOINT_DEADLINE))
self._checkpoint_token()
@internal
def _find_timestamp_epoch(ve: address, _timestamp: uint256) -> uint256:
_min: uint256 = 0
_max: uint256 = VotingEscrow(ve).epoch()
for i in range(128):
if _min >= _max:
break
_mid: uint256 = (_min + _max + 2) / 2
pt: Point = VotingEscrow(ve).point_history(_mid)
if pt.ts <= _timestamp:
_min = _mid
else:
_max = _mid - 1
return _min
@view
@internal
def _find_timestamp_user_epoch(ve: address, user: address, _timestamp: uint256, max_user_epoch: uint256) -> uint256:
_min: uint256 = 0
_max: uint256 = max_user_epoch
for i in range(128):
if _min >= _max:
break
_mid: uint256 = (_min + _max + 2) / 2
pt: Point = VotingEscrow(ve).user_point_history(user, _mid)
if pt.ts <= _timestamp:
_min = _mid
else:
_max = _mid - 1
return _min
@view
@external
def ve_for_at(_user: address, _timestamp: uint256) -> uint256:
"""
@notice Get the veCRV balance for `_user` at `_timestamp`
@param _user Address to query balance for
@param _timestamp Epoch time
@return uint256 veCRV balance
"""
ve: address = self.voting_escrow
max_user_epoch: uint256 = VotingEscrow(ve).user_point_epoch(_user)
epoch: uint256 = self._find_timestamp_user_epoch(ve, _user, _timestamp, max_user_epoch)
pt: Point = VotingEscrow(ve).user_point_history(_user, epoch)
return convert(max(pt.bias - pt.slope * convert(_timestamp - pt.ts, int128), 0), uint256)
@internal
def _checkpoint_total_supply():
ve: address = self.voting_escrow
t: uint256 = self.time_cursor
rounded_timestamp: uint256 = block.timestamp / WEEK * WEEK
VotingEscrow(ve).checkpoint()
for i in range(20):
if t > rounded_timestamp:
break
else:
epoch: uint256 = self._find_timestamp_epoch(ve, t)
pt: Point = VotingEscrow(ve).point_history(epoch)
dt: int128 = 0
if t > pt.ts:
# If the point is at 0 epoch, it can actually be earlier than the first deposit
# Then make dt 0
dt = convert(t - pt.ts, int128)
self.ve_supply[t] = convert(max(pt.bias - pt.slope * dt, 0), uint256)
t += WEEK
self.time_cursor = t
@external
def checkpoint_total_supply():
"""
@notice Update the veCRV total supply checkpoint
@dev The checkpoint is also updated by the first claimant each
new epoch week. This function may be called independently
of a claim, to reduce claiming gas costs.
"""
self._checkpoint_total_supply()
@internal
def _claim(addr: address, ve: address, _last_token_time: uint256, claim_all: bool) -> (uint256, uint256):
# Minimal user_epoch is 0 (if user had no point)
user_epoch: uint256 = 0
to_distribute_tokens: uint256 = 0
to_distribute_eth: uint256 = 0
max_user_epoch: uint256 = VotingEscrow(ve).user_point_epoch(addr)
_start_time: uint256 = self.start_time
if max_user_epoch == 0:
# No lock = no fees
return 0, 0
week_cursor: uint256 = self.time_cursor_of[addr]
if week_cursor == 0:
# Need to do the initial binary search
user_epoch = self._find_timestamp_user_epoch(ve, addr, _start_time, max_user_epoch)
else:
user_epoch = self.user_epoch_of[addr]
if user_epoch == 0:
user_epoch = 1
user_point: Point = VotingEscrow(ve).user_point_history(addr, user_epoch)
if week_cursor == 0:
week_cursor = (user_point.ts + WEEK - 1) / WEEK * WEEK
if week_cursor >= _last_token_time:
return 0, 0
if week_cursor < _start_time:
week_cursor = _start_time
old_user_point: Point = empty(Point)
# Iterate over weeks
for i in range(MAX_UINT256):
if (not claim_all and i > 50) or (week_cursor >= _last_token_time):
break
if week_cursor >= user_point.ts and user_epoch <= max_user_epoch:
user_epoch += 1
old_user_point = user_point
if user_epoch > max_user_epoch:
user_point = empty(Point)
else:
user_point = VotingEscrow(ve).user_point_history(addr, user_epoch)
else:
# Calc
# + i * 2 is for rounding errors
dt: int128 = convert(week_cursor - old_user_point.ts, int128)
balance_of: uint256 = convert(max(old_user_point.bias - dt * old_user_point.slope, 0), uint256)
if balance_of == 0 and user_epoch > max_user_epoch:
break
if balance_of > 0:
to_distribute_tokens += balance_of * self.tokens_per_week[week_cursor] / self.ve_supply[week_cursor]
to_distribute_eth += balance_of * self.eth_per_week[week_cursor] / self.ve_supply[week_cursor]
week_cursor += WEEK
user_epoch = min(max_user_epoch, user_epoch - 1)
self.user_epoch_of[addr] = user_epoch
self.time_cursor_of[addr] = week_cursor
log Claimed(addr, to_distribute_tokens, to_distribute_eth, user_epoch, max_user_epoch)
return to_distribute_tokens, to_distribute_eth
@internal
def _checkpoint_and_claim(_addr: address, claim_all: bool) -> (uint256, uint256):
assert not self.is_killed
if block.timestamp >= self.time_cursor:
self._checkpoint_total_supply()
last_token_time: uint256 = self.last_token_time
if self.can_checkpoint_token and (block.timestamp > last_token_time + TOKEN_CHECKPOINT_DEADLINE):
self._checkpoint_token()
last_token_time = block.timestamp
last_token_time = last_token_time / WEEK * WEEK
tokens_amount: uint256 = 0
eth_amount: uint256 = 0
tokens_amount, eth_amount = self._claim(_addr, self.voting_escrow, last_token_time, claim_all)
if tokens_amount != 0:
token: address = self.token
assert ERC20(token).transfer(_addr, tokens_amount)
self.token_last_balance -= tokens_amount
if eth_amount != 0:
send(_addr, eth_amount)
self.eth_last_balance -= eth_amount
return tokens_amount, eth_amount
@external
@nonreentrant('lock')
def claim(_addr: address = msg.sender) -> (uint256, uint256):
"""
@notice Claim fees for `_addr`
@dev Each call to claim look at a maximum of 50 user veCRV points.
For accounts with many veCRV related actions, this function
may need to be called more than once to claim all available
fees. In the `Claimed` event that fires, if `claim_epoch` is
less than `max_epoch`, the account may claim again.
@param _addr Address to claim fees for
@return uint256 Amount of fees claimed in the call
"""
return self._checkpoint_and_claim(_addr, False)
@external
@nonreentrant('lock')
def claim_all(_addr: address = msg.sender) -> (uint256, uint256):
"""
@notice Claim fees without 50 week limit for `_addr`
@dev Call to claim look at all the possible user veCRV points
till now instead of 50 limit of simple claim.
For accounts with many veCRV related actions, this function
can be called once to claim all available fees.
Although the caller should be aware of gas limits as looping
over a large count of veCRV points could result in exceeding
block gas limits resulting in this function to fail/costing
a lot of gas at once.
@param _addr Address to claim fees for
@return uint256 Amount of fees claimed in the call
"""
return self._checkpoint_and_claim(_addr, True)
@external
@nonreentrant('lock')
def claim_many(_receivers: address[20]) -> bool:
"""
@notice Make multiple fee claims in a single call
@dev Used to claim for many accounts at once, or to make
multiple claims for the same address when that address
has significant veCRV history
@param _receivers List of addresses to claim for. Claiming
terminates at the first `ZERO_ADDRESS`.
@return bool success
"""
assert not self.is_killed
if block.timestamp >= self.time_cursor:
self._checkpoint_total_supply()
last_token_time: uint256 = self.last_token_time
if self.can_checkpoint_token and (block.timestamp > last_token_time + TOKEN_CHECKPOINT_DEADLINE):
self._checkpoint_token()
last_token_time = block.timestamp
last_token_time = last_token_time / WEEK * WEEK
voting_escrow: address = self.voting_escrow
token: address = self.token
total_tokens: uint256 = 0
total_eth: uint256 = 0
for addr in _receivers:
if addr == ZERO_ADDRESS:
break
tokens_amount: uint256 = 0
eth_amount: uint256 = 0
tokens_amount, eth_amount = self._claim(addr, voting_escrow, last_token_time, False)
if tokens_amount != 0:
assert ERC20(token).transfer(addr, tokens_amount)
total_tokens += tokens_amount
if eth_amount != 0:
send(addr, eth_amount)
total_eth += eth_amount
if total_tokens != 0:
self.token_last_balance -= total_tokens
if total_eth != 0:
self.eth_last_balance -= total_eth
return True
@external
@payable
def burn(_coin: address) -> bool:
"""
@notice Receive 3CRV into the contract and trigger a token checkpoint
@param _coin Address of the coin being received (must be 3CRV)
@return bool success
"""
assert _coin == self.token
assert not self.is_killed
amount: uint256 = ERC20(_coin).balanceOf(msg.sender)
if amount != 0:
ERC20(_coin).transferFrom(msg.sender, self, amount)
if (amount != 0 or msg.value != 0) and self.can_checkpoint_token and (block.timestamp > self.last_token_time + TOKEN_CHECKPOINT_DEADLINE):
self._checkpoint_token()
return True
@external
@payable
def __default__():
assert not self.is_killed
log EtherSent(msg.value, msg.sender)
if self.can_checkpoint_token and (block.timestamp > self.last_token_time + TOKEN_CHECKPOINT_DEADLINE):
self._checkpoint_token()
@external
def commit_admin(_addr: address):
"""
@notice Commit transfer of ownership
@param _addr New admin address
"""
assert msg.sender == self.admin # dev: access denied
self.future_admin = _addr
log CommitAdmin(_addr)
@external
def apply_admin():
"""
@notice Apply transfer of ownership
"""
assert msg.sender == self.admin
assert self.future_admin != ZERO_ADDRESS
future_admin: address = self.future_admin
self.admin = future_admin
log ApplyAdmin(future_admin)
@external
def toggle_allow_checkpoint_token():
"""
@notice Toggle permission for checkpointing by any account
"""
assert msg.sender == self.admin
flag: bool = not self.can_checkpoint_token
self.can_checkpoint_token = flag
log ToggleAllowCheckpointToken(flag)
@external
def kill_me():
"""
@notice Kill the contract
@dev Killing transfers the entire 3CRV balance to the emergency return address
and blocks the ability to claim or burn. The contract cannot be unkilled.
"""
assert msg.sender == self.admin
self.is_killed = True
send(self.emergency_return, self.balance)
token: address = self.token
assert ERC20(token).transfer(self.emergency_return, ERC20(token).balanceOf(self))
@external
def recover_balance(_coin: address) -> bool:
"""
@notice Recover ERC20 tokens from this contract
@dev Tokens are sent to the emergency return address.
@param _coin Token address
@return bool success
"""
assert msg.sender == self.admin
assert _coin != self.token
amount: uint256 = ERC20(_coin).balanceOf(self)
response: Bytes[32] = raw_call(
_coin,
concat(
method_id("transfer(address,uint256)"),
convert(self.emergency_return, bytes32),
convert(amount, bytes32),
),
max_outsize=32,
)
if len(response) != 0:
assert convert(response, bool)
return True
Read Contract
admin 0xf851a440 → address
can_checkpoint_token 0xaeba4737 → bool
emergency_return 0x2c3f531e → address
eth_last_balance 0x73beca25 → uint256
eth_per_week 0x084e58bd → uint256
future_admin 0x17f7182a → address
is_killed 0x9c868ac0 → bool
last_token_time 0x7f58e8f8 → uint256
start_time 0x834ee417 → uint256
time_cursor 0x127dcbd3 → uint256
time_cursor_of 0x2a2a314b → uint256
token 0xfc0c546a → address
token_last_balance 0x22b04bfc → uint256
tokens_per_week 0xedf59997 → uint256
total_eth_received 0xbf33e4a5 → uint256
total_received 0x2f0c222e → uint256
user_epoch_of 0xd5d46e88 → uint256
ve_for_at 0xace296fb → uint256
ve_supply 0xd4dafba8 → uint256
voting_escrow 0xdfe05031 → address
Write Contract 13 functions
These functions modify contract state and require a wallet transaction to execute.
apply_admin 0xc0e991a6
No parameters
burn 0x89afcb44
address _coin
returns: bool
checkpoint_token 0x811a40fe
No parameters
checkpoint_total_supply 0xb21ed502
No parameters
claim 0x4e71d92d
No parameters
returns: uint256, uint256
claim 0x1e83409a
address _addr
returns: uint256, uint256
claim_all 0x52066905
No parameters
returns: uint256, uint256
claim_all 0xea9a9766
address _addr
returns: uint256, uint256
claim_many 0x7b935a23
address[20] _receivers
returns: bool
commit_admin 0xb1d3db75
address _addr
kill_me 0xe3698853
No parameters
recover_balance 0xdb2f5f79
address _coin
returns: bool
toggle_allow_checkpoint_token 0x2121bfc3
No parameters
Token Balances (1)
View Transfers →Recent Transactions
No transactions found for this address