Address Contract Partially Verified
Address
0x73E4C11B670Ef9C025A030A20b72CB9150E54523
Balance
0 ETH
Nonce
1
Code Size
23270 bytes
Creator
0xE9E8C89c...78e5 at tx 0x233a8180...9f4668
Indexed Transactions
0
Contract Bytecode
23270 bytes
0x6003361161000c57612165565b60003560e01c34615a74576371da8a8d811861007a5760243610615a74576004358060a01c615a745760c0523360405260086060526100496159de565b60c05160155560c0517f28709a2dab2a5d5e8688e96159011151c51644ab21839a8a45b449634d7c8b2b600060e0a2005b632d9caa4e81186102585760443610615a7457600435600401600a813511615a745780358060c052600081600a8111615a745780156100da57905b8060051b6020850101358060a01c615a74578160051b60e001526001018181186100b5575b505050503360405260106060526100ef6159de565b600060c051600a8111615a7457801561019757905b8060051b60e001516102205260016102205160205260005260406000205461018c576009610240527f21696e61637469766500000000000000000000000000000000000000000000006102605261024050610240518061026001601f826000031636823750506308c379a061020052602061022052601f19601f61024051011660440161021cfd5b600101818118610104575b505060c051806002558060051b600081601f0160051c600a8111615a745780156101d557905b8060051b60e0015181600301556001018181186101bd575b505050507f0bc0cb8c5ccee13e6a2fd26a699f57ad7ff6e454e6aae97ec41cd2eb9ebd63a5602080610220528061022001600060c0518083528060051b600082600a8111615a7457801561024257905b8060051b60e001518160051b602088010152600101818118610225575b50508201602001915050905081019050610220a1005b6329c8a33b81186102be5760243610615a74576004358060011c615a745760c05233604052601060605261028a6159de565b60c051600d557f1f88e73ebc721f227812938fe07a069ec1f7136aafacb397ed460bd15dee13f160c05160e052602060e0a1005b636fe01d1e81186103835760243610615a7457602154615a7457336040526101006060526102ea6159de565b6016541561034f57600c60c0527f7573696e67206d6f64756c65000000000000000000000000000000000000000060e05260c05060c0518060e001601f826000031636823750506308c379a0608052602060a052601f19601f60c0510116604401609cfd5b6004356014557fae565aab888bca5e19e25a13db7b0c9144305bf55cb0f3f4d724f730e5acdd6260043560c052602060c0a1005b63bb43546681186104565760243610615a74576004358060a01c615a745760c052602154615a7457336040526101006060526103bd6159de565b601454191561042557601360e0527f7573696e67206465706f736974206c696d6974000000000000000000000000006101005260e05060e0518061010001601f826000031636823750506308c379a060a052602060c052601f19601f60e051011660440160bcfd5b60c05160165560c0517f777d215db24fb9fee4ded85c66b422abd7162a1caa6ed3ec4c031f6cd29ada52600060e0a2005b637b67589481186104ba5760243610615a74576004358060a01c615a745760c052336040526102006060526104896159de565b60c05160175560c0517fce6e3f8beda82a13c441d76efd4a6335760f219f38c60502e6680060874e109d600060e0a2005b63bdd81c0181186105135760243610615a7457336040526104006060526104df6159de565b6004356013557f01a4494beed88920b88742cc58f2744e198f55ff192635a1fbabc6be8ffade8160043560c052602060c0a1005b63df69b22a81186106075760243610615a7457336040526108006060526105386159de565b6301e1855860043511156105a357601b60c0527f70726f66697420756e6c6f636b2074696d6520746f6f206c6f6e67000000000060e05260c05060c0518060e001601f826000031636823750506308c379a0608052602060a052601f19601f60c0510116604401609cfd5b6004356105d357600e30602052600052604060002054604052306060526105c861291e565b600060245560006023555b6004356022557ff361aed463da6fa20358e45c6209f1d3e16d4eca706e6eab0b0aeb338729c77a60043560c052602060c0a1005b632cf7fd8581186106815760443610615a74576004358060a01c615a745760405260243580600e1c615a7457606052601a543318615a745760605160186040516020526000526040600020556060516040517f78557646b1d8efa2cd49740d66df5aca39eb610ca8ca0e1ccac08979b6b2c46e60006080a3005b63a97cefa2811861071b5760443610615a74576004358060a01c615a745760405260243580600e1c615a7457606052601a543318615a7457606051601860405160205260005260406000205417601860405160205260005260406000205560186040516020526000526040600020546040517f78557646b1d8efa2cd49740d66df5aca39eb610ca8ca0e1ccac08979b6b2c46e60006080a3005b63e2bf56dd81186107b95760443610615a74576004358060a01c615a745760405260243580600e1c615a7457606052601a543318615a7457606051613fff18601860405160205260005260406000205416601860405160205260005260406000205560186040516020526000526040600020546040517f78557646b1d8efa2cd49740d66df5aca39eb610ca8ca0e1ccac08979b6b2c46e60006080a3005b630b10dd8081186108235760243610615a745760043580600e1c615a7457604052601a543318615a74576001601960405160205260005260406000205560016040517ffe075e51fb76b038a5d44dd2e56b16e6c928e35c0f3cc237312ad09bbca5aee560006060a3005b63d52fe498811861088d5760243610615a745760043580600e1c615a7457604052601a543318615a74576000601960405160205260005260406000205560026040517ffe075e51fb76b038a5d44dd2e56b16e6c928e35c0f3cc237312ad09bbca5aee560006060a3005b63ef54cefd81186108bf5760243610615a74576004358060a01c615a7457604052601a543318615a7457604051601b55005b63f776bf1f811861090d5760043610615a7457601b543318615a745733601a556000601b55337fce93baa0b608a7d420822b6b90cfcccb70574363ba4fd26ef5ac17dd465016c460006040a2005b63bf86d690811861092c5760043610615a745760215460405260206040f35b63d9a0e97a811861094f5760043610615a7457602061094b6080612981565b6080f35b6399530b0681186109955760043610615a745760206020615aa6600039600051604d8111615a745780600a0a905060a052600160c052610990610140612a6e565b610140f35b63a9bbf1cc81186109ff5760043610615a74576020806040528060400160006002548083528060051b600082600a8111615a745780156109eb57905b80600301548160051b6020880101526001018181186109d1575b505082016020019150509050810190506040f35b636ec2b8d48118610a605760243610615a74576004358060a01c615a74576104e052600054600214615a74576002600055336040526020606052610a416159de565b60406104e0516101a052610a566105006151a9565b6105006003600055f35b63e5e918188118610e305760443610615a74576004358060a01c615a74576101a052600054600214615a7457600260005533604052611000606052610aa36159de565b60016101a051602052600052604060002054610b1f57600a6101c0527f6e6f7420616374697665000000000000000000000000000000000000000000006101e0526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b60016101a0516020526000526040600020600281019050546101c0526024356101e0526101c051610bb057600e610200527f6e6f7468696e6720746f206275790000000000000000000000000000000000006102205261020050610200518061022001601f826000031636823750506308c379a06101c05260206101e052601f19601f6102005101166044016101dcfd5b6101e051610c1e576013610200527f6e6f7468696e6720746f206275792077697468000000000000000000000000006102205261020050610200518061022001601f826000031636823750506308c379a06101c05260206101e052601f19601f6102005101166044016101dcfd5b6101c0516101e0511115610c35576101c0516101e0525b6101a0516370a082316102205230610240526020610220602461023c845afa610c63573d600060003e3d6000fd5b60203d10615a74576102209050516101e051808202811583838304141715615a7457905090506101c0518015615a7457808204905090506102005261020051610d0c57600f610220527f63616e6e6f7420627579207a65726f00000000000000000000000000000000006102405261022050610220518061024001601f826000031636823750506308c379a06101e052602061020052601f19601f6102205101166044016101fcfd5b6020615a8660003960005160405233606052306080526101e05160a052610d31612d0d565b60016101a051602052600052604060002060028101905080546101e051808203828111615a7457905090508155506011546101e051808203828111615a7457905090506011556012546101e051808201828110615a7457905090506012556101a0517f5e2b8821ad6e0e26207e0cb4d242d07eeb1cbb1cfd853e645bdcd27cc5484f956101c051610220526101c0516101e051808203828111615a745790509050610240526040610220a26101a0516040523360605261020051608052610df6612de9565b6101a0517fe94e7f88819f66c19b097748cb754149f63b1a176ed425dee1f1ee933e6d09b06101e051610220526020610220a26003600055005b63de7aeb418118610e745760243610615a74576004358060a01c615a745761010052336040526001606052610e636159de565b61010051604052610e72614573565b005b63577db3168118610ebd5760243610615a74576004358060a01c615a745761022052336040526002606052610ea76159de565b610220516040526000606052610ebb614787565b005b63fd129e638118610f065760243610615a74576004358060a01c615a745761022052336040526004606052610ef06159de565b610220516040526001606052610f04614787565b005b63b9ddcd688118610ff85760443610615a74576004358060a01c615a745760c052336040526080606052610f386159de565b600160c051602052600052604060002054610fac57601160e0527f696e6163746976652073747261746567790000000000000000000000000000006101005260e05060e0518061010001601f826000031636823750506308c379a060a052602060c052601f19601f60e051011660440160bcfd5b602435600160c05160205260005260406000206003810190505560c051337fb3eef2123fec1523a6bbc90aceb203000154c1a4974335fe06b544c7534d4b8960243560e052602060e0a3005b630aeebf5581186110605760443610615a74576004358060a01c615a745761030052600054600214615a7457600260005533604052604060605261103a6159de565b60206103005161016052602435610180526110566103206149de565b6103206003600055f35b6336a5545081186111405760043610615a7457336040526120006060526110856159de565b602154615a74576001602155601654156110c757600060165560007f777d215db24fb9fee4ded85c66b422abd7162a1caa6ed3ec4c031f6cd29ada52600060c0a25b60006014557fae565aab888bca5e19e25a13db7b0c9144305bf55cb0f3f4d724f730e5acdd62600060c052602060c0a16040601833602052600052604060002054176018336020526000526040600020557f4426aa1fb73e391071491fcfe21a88b5c38a0a0333a1f6e77161470439704cf8600060c0a1005b636e553f65811861119c5760443610615a74576024358060a01c615a745761026052600054600214615a745760026000556020336101a052610260516101c0526004356101e05261119261028061369e565b6102806003600055f35b6394bf804d81186111f85760443610615a74576024358060a01c615a745761028052600054600214615a745760026000556020336101a052610280516101c0526004356101e0526111ee6102a061383f565b6102a06003600055f35b63b460af9481186112175760643610615a7457604036610be0376112aa565b63a318c1a4811861123c5760843610615a7457606435610be0526000610c00526112aa565b63d81a09f681186113585760c43610615a7457606435610be052608435600401600a813511615a7457803580610c0052600081600a8111615a745780156112a557905b8060051b6020850101358060a01c615a74578160051b610c20015260010181811861127f575b505050505b6024358060a01c615a7457610ba0526044358060a01c615a7457610bc052600054600214615a7457600260005560043560a052600260c0526112ed610d80612b45565b610d8051610d6052336105e052610ba05161060052610bc0516106205260043561064052610d605161066052610be05161068052610c0051806106a0528060051b806106c082610c2060045afa505050611348610d80613ab7565b610d80506020610d606003600055f35b63ba087652811861137d5760643610615a7457612710610be0526000610c0052611410565b639f40a7b381186113a25760843610615a7457606435610be0526000610c0052611410565b6306580f2d81186114ba5760c43610615a7457606435610be052608435600401600a813511615a7457803580610c0052600081600a8111615a7457801561140b57905b8060051b6020850101358060a01c615a74578160051b610c2001526001018181186113e5575b505050505b6024358060a01c615a7457610ba0526044358060a01c615a7457610bc052600054600214615a7457600260005560043560a052600160c052611453610d80612a6e565b610d8051610d60526020336105e052610ba05161060052610bc05161062052610d60516106405260043561066052610be05161068052610c0051806106a0528060051b806106c082610c2060045afa5050506114b0610d80613ab7565b610d806003600055f35b63095ea7b381186114fb5760443610615a74576004358060a01c615a745760c05260203360405260c0516060526024356080526114f760e061216b565b60e0f35b63a9059cbb81186115605760443610615a74576004358060a01c615a7457610100526101005130811461153057801515611533565b60005b905015615a745733604052610100516060526024356080526115536122b7565b6001610120526020610120f35b6323b872dd81186115d75760643610615a74576004358060a01c615a74576101e0526024358060a01c615a745761020052610200513081146115a4578015156115a7565b60005b905015615a745760206101e05161018052610200516101a0526044356101c0526115d26102206123a6565b610220f35b6339509351811861161a5760443610615a74576004358060a01c615a745760e05260203360405260e0516060526024356080526116156101006123e5565b610100f35b63a457c2d7811861165d5760443610615a74576004358060a01c615a745760e05260203360405260e051606052602435608052611658610100612479565b610100f35b63d505accf81186116d75760e43610615a74576004358060a01c615a7457610460526024358060a01c615a7457610480526084358060081c615a74576104a05260206104605161018052610480516101a052604060446101c0376104a05161020052604060a4610220376116d26104c06125e7565b6104c0f35b6370a0823181186117545760243610615a74576004358060a01c615a7457608052306080511861173957600e60805160205260005260406000205461171c60a0612981565b60a051808203828111615a74579050905060c052602060c0611752565b600e60805160205260005260406000205460a052602060a05bf35b6318160ddd81186117775760043610615a7457602061177360a06129f3565b60a0f35b6338d52e0f811861179e5760043610615a74576020615a8660003960005160405260206040f35b63313ce56781186117cd5760043610615a74576020615aa66000396000518060081c615a745760405260206040f35b6301e1d11481186117f05760043610615a745760206117ec6040612a55565b6040f35b639aa7df94811861180f5760043610615a745760125460405260206040f35b63fc7b9c18811861182e5760043610615a745760115460405260206040f35b63c6e6f592811861185e5760243610615a7457602060043560a052600160c052611859610160612b45565b610160f35b63ef8b30f7811861188e5760243610615a7457602060043560a052600160c052611889610160612b45565b610160f35b63b3d7f6b981186118be5760243610615a7457602060043560a052600260c0526118b9610140612a6e565b610140f35b6307a2d13a81186118ee5760243610615a7457602060043560a052600160c0526118e9610140612a6e565b610140f35b63402d267d81186119255760243610615a74576004358060a01c615a745760c052602060c05160405261192160e061305d565b60e0f35b63c63d75b6811861197f5760243610615a74576004358060a01c615a745761016052610160516040526119596101a061305d565b6101a0516101805260206101805160a052600160c05261197a6101a0612b45565b6101a0f35b63ce96cb77811861199e5760243610615a745760403661060037611a31565b6385b6875681186119c35760443610615a745760243561060052600061062052611a31565b6365cb67658118611a7e5760843610615a745760243561060052604435600401600a813511615a745780358061062052600081600a8111615a74578015611a2c57905b8060051b6020850101358060a01c615a74578160051b6106400152600101818118611a06575b505050505b6004358060a01c615a74576105e05260206105e0516101405261060051610160526106205180610180528060051b806101a08261064060045afa505050611a7961078061323b565b610780f35b63d905777e8118611aa35760243610615a745761271061060052600061062052611b36565b634abe41378118611ac85760443610615a745760243561060052600061062052611b36565b6334b5fab68118611bd15760843610615a745760243561060052604435600401600a813511615a745780358061062052600081600a8111615a74578015611b3157905b8060051b6020850101358060a01c615a74578160051b6106400152600101818118611b0b575b505050505b6004358060a01c615a74576105e0526105e0516101405261060051610160526106205180610180528060051b806101a08261064060045afa505050611b7c61078061323b565b610780516107c05260026107e0526107c05160a0526107e05160c052611ba36107a0612b45565b6107a051600e6105e05160205260005260406000205480828118828410021890509050610800526020610800f35b630a28a4778118611c015760243610615a7457602060043560a052600260c052611bfc610160612b45565b610160f35b634cdad5068118611c315760243610615a7457602060043560a052600160c052611c2c610140612a6e565b610140f35b63258294108118611cb95760043610615a745760208060805260056040527f332e302e3100000000000000000000000000000000000000000000000000000060605260408160800181518082526020830160208301815181525050508051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506080f35b6366d3ae578118611d1a5760443610615a74576004358060a01c615a74576101205260243560016101205160205260005260406000206002810190505410615a7457602061012051604052602435606052611d15610140613108565b610140f35b630952864e8118611d395760043610615a745760225460405260206040f35b632d6326928118611d585760043610615a745760235460405260206040f35b635141eebb8118611d775760043610615a745760245460405260206040f35b638afca8f08118611d965760043610615a745760255460405260206040f35b633644e5158118611dbb5760043610615a74576020611db661018061250d565b610180f35b632dd310008118611de25760043610615a74576020615ac660003960005160405260206040f35b6339ebf8238118611e375760243610615a74576004358060a01c615a74576040526001604051602052600052604060002080546060526001810154608052600281015460a052600381015460c0525060806060f35b638bf03b9e8118611e645760243610615a7457600435600254811015615a74576003015460405260206040f35b631e56558d8118611e835760043610615a7457600d5460405260206040f35b63dd62ed3e8118611edd5760443610615a74576004358060a01c615a74576040526024358060a01c615a7457606052600f604051602052600052604060002080606051602052600052604060002090505460805260206080f35b633940e9ee8118611efc5760043610615a745760105460405260206040f35b63356d64098118611f1b5760043610615a745760135460405260206040f35b63e46a57978118611f3a5760043610615a745760145460405260206040f35b634fb3ccc58118611f595760043610615a745760155460405260206040f35b6361c2ccf48118611f785760043610615a745760165460405260206040f35b63f5ba68f38118611f975760043610615a745760175460405260206040f35b63993746428118611fd25760243610615a74576004358060a01c615a7457604052601860405160205260005260406000205460605260206060f35b63f3789e45811861200d5760243610615a745760043580600e1c615a7457604052601960405160205260005260406000205460605260206060f35b6379b98917811861202c5760043610615a7457601a5460405260206040f35b639a98f418811861204b5760043610615a7457601b5460405260206040f35b6306fdde0381186120d05760043610615a745760208060405280604001601c5480825260208201600082601f0160051c60028111615a745780156120a257905b80601d01548160051b84015260010181811861208b575b505050508051806020830101601f82600003163682375050601f19601f825160200101169050810190506040f35b6395d89b4181186121285760043610615a745760208060405280604001601f5480825260208201602054815250508051806020830101601f82600003163682375050601f19601f825160200101169050810190506040f35b637ecebe0081186121635760243610615a74576004358060a01c615a7457604052602660405160205260005260406000205460605260206060f35b505b60006000fd5b608051600f60405160205260005260406000208060605160205260005260406000209050556060516040517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560805160a052602060a0a36001815250565b600f60c05160205260005260406000208060e0516020526000526040600020905054610120527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61012051146122b5576101005161012051101561228d576016610140527f696e73756666696369656e7420616c6c6f77616e6365000000000000000000006101605261014050610140518061016001601f826000031636823750506308c379a061010052602061012052601f19601f61014051011660440161011cfd5b60c05160405260e0516060526101005161012051036080526122b061014061216b565b610140505b565b600e60405160205260005260406000205460a05260805160a051101561233457601260c0527f696e73756666696369656e742066756e6473000000000000000000000000000060e05260c05060c0518060e001601f826000031636823750506308c379a0608052602060a052601f19601f60c0510116604401609cfd5b60805160a05103600e604051602052600052604060002055608051600e60605160205260005260406000205401600e6060516020526000526040600020556060516040517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60805160c052602060c0a3565b6101805160c0523360e0526101c051610100526123c16121c9565b610180516040526101a0516060526101c0516080526123de6122b7565b6001815250565b600f6040516020526000526040600020806060516020526000526040600020905054608051808201828110615a74579050905060a05260a051600f60405160205260005260406000208060605160205260005260406000209050556060516040517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560a05160c052602060c0a36001815250565b600f6040516020526000526040600020806060516020526000526040600020905054608051808203828111615a74579050905060a05260a051600f60405160205260005260406000208060605160205260005260406000209050556060516040517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560a05160c052602060c0a36001815250565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8160e00152602081019050600b6040527f596561726e205661756c7400000000000000000000000000000000000000000060605260408051602082012090508160e0015260208101905060056080527f332e302e3100000000000000000000000000000000000000000000000000000060a05260808051602082012090508160e00152602081019050468160e00152602081019050308160e001526020810190508060c05260c09050805160208201209050815250565b6101805161265557600d610260527f696e76616c6964206f776e6572000000000000000000000000000000000000006102805261026050610260518061028001601f826000031636823750506308c379a061022052602061024052601f19601f61026051011660440161023cfd5b426101e05110156126c657600e610260527f7065726d697420657870697265640000000000000000000000000000000000006102805261026050610260518061028001601f826000031636823750506308c379a061022052602061024052601f19601f61026051011660440161023cfd5b60266101805160205260005260406000205461026052600060026102a0527f19010000000000000000000000000000000000000000000000000000000000006102c0526102a080516020820183610400018151815250508083019250505061272f6102e061250d565b6102e05181610400015260208101905060007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9816103200152602081019050610180518161032001526020810190506101a0518161032001526020810190506101c051816103200152602081019050610260518161032001526020810190506101e05181610320015260208101905080610300526103009050805160208201209050816104000152602081019050806103e0526103e090508051602082012090506102805261018051610280516102a052610200516102c052610220516102e05261024051610300526020600060806102a060015afa506000511815612895576011610340527f696e76616c6964207369676e61747572650000000000000000000000000000006103605261034050610340518061036001601f826000031636823750506308c379a061030052602061032052601f19601f61034051011660440161031cfd5b6101c051600f610180516020526000526040600020806101a05160205260005260406000209050556102605160018101818110615a745790506026610180516020526000526040600020556101a051610180517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9256101c0516102a05260206102a0a36001815250565b600e60605160205260005260406000208054604051808203828111615a7457905090508155506040516010540360105560006060517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160805260206080a3565b602354604052600060605242604051116129b457604051156129eb57600e306020526000526040600020546060526129eb565b60245442602554808203828111615a745790509050808202811583838304141715615a74579050905064e8d4a51000810490506060525b606051815250565b601054612a006080612981565b608051808203828111615a745790509050815250565b612a2060c0612981565b60c05160a05260a051612a3257612a53565b426023541115612a4157426025555b60a05160405230606052612a5361291e565b565b601254601154808201828110615a745790509050815250565b60a05119612a7d576001612a82565b60a051155b15612a925760a051815250612b43565b612a9d6101006129f3565b6101005160e05260e051612ab65760a051815250612b43565b60a051612ac4610120612a55565b61012051808202811583838304141715615a745790509050610100526101005160e0518015615a74578082049050905061012052600260c05118612b1d576101005160e0518015615a7457808206905090501515612b20565b60005b15612b3b576101205160018101818110615a74579050610120525b610120518152505b565b60a05119612b54576001612b59565b60a051155b15612b695760a051815250612c39565b612b746101006129f3565b6101005160e052612b86610120612a55565b610120516101005261010051612bb65760e051612bac5760a051815250612c3956612bb6565b6000815250612c39565b60a05160e051808202811583838304141715615a7457905090506101205261012051610100518015615a74578082049050905061014052600260c05118612c135761012051610100518015615a7457808206905090501515612c16565b60005b15612c31576101405160018101818110615a74579050610140525b610140518152505b565b60405163095ea7b360a05260605160c05260805160e052602060a0604460bc6000855af1612c6e573d600060003e3d6000fd5b3d612c8557803b15615a7457600161010052612c9d565b60203d10615a745760a0518060011c615a7457610100525b610100905051612d0b57600f610120527f617070726f76616c206661696c656400000000000000000000000000000000006101405261012050610120518061014001601f826000031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b565b6040516323b872dd60c05260605160e0526080516101005260a05161012052602060c0606460dc6000855af1612d48573d600060003e3d6000fd5b3d612d5f57803b15615a7457600161014052612d77565b60203d10615a745760c0518060011c615a7457610140525b610140905051612de757600f610160527f7472616e73666572206661696c656400000000000000000000000000000000006101805261016050610160518061018001601f826000031636823750506308c379a061012052602061014052601f19601f61016051011660440161013cfd5b565b60405163a9059cbb60a05260605160c05260805160e052602060a0604460bc6000855af1612e1c573d600060003e3d6000fd5b3d612e3357803b15615a7457600161010052612e4b565b60203d10615a745760a0518060011c615a7457610100525b610100905051612eb957600f610120527f7472616e73666572206661696c656400000000000000000000000000000000006101405261012050610120518061014001601f826000031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b565b604051600e60605160205260005260406000205401600e606051602052600052604060002055601054604051808201828110615a74579050905060105560605160007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160805260206080a3565b612f366101006129f3565b6101005160e052612f48610120612a55565b610120516101005260006101205260e051612f695760a0516101205261302c565b60a0516101005111612feb5760a051610100511161302c57600f610140527f616d6f756e7420746f6f206869676800000000000000000000000000000000006101605261014050610140518061016001601f826000031636823750506308c379a061010052602061012052601f19601f61014051011660440161011cfd61302c565b60a05160e051808202811583838304141715615a7457905090506101005160a051808203828111615a7457905090508015615a745780820490509050610120525b6101205161303e57600081525061305b565b6101205160405260c051606052613053612ebb565b610120518152505b565b6040518061306c576001613071565b308118155b905015613082576000815250613106565b601654606052606051156130d05760605163320704ed60805260405160a052602060806024609c845afa6130bb573d600060003e3d6000fd5b60203d10615a74576080905051815250613106565b6130da60a0612a55565b60a05160805260145460a05260a051608051106130fb576000815250613106565b60805160a051038152505b565b60016040516020526000526040600020600281019050546080526040516370a0823160c0523060e052602060c0602460dc845afa61314b573d600060003e3d6000fd5b60203d10615a745760c090505160a0526040516307a2d13a60e05260a05161010052602060e0602460fc845afa613187573d600060003e3d6000fd5b60203d10615a745760e090505160c05260805160c05110156131ac57608051156131af565b60015b156131be576000815250613239565b60605160c051808202811583838304141715615a74579050905060e05260605160e0516080518015615a745780820490509050808203828111615a7457905090506101005260e0516080518015615a74578082069050905015613231576101005160018101818110615a74579050610100525b610100518152505b565b600e6101405160205260005260406000205460a052600160c052613260610300612a6e565b610300516102e052601754610300526103005115613333576103005163c36a0eee61032052606061014051610340526101605161036052806103805280610340016000610180518083528060051b600082600a8111615a745780156132df57905b8060051b6101a001518160051b6020880101526001018181186132c1575b5050820160200191505090508101505060206103206101c461033c845afa61330c573d600060003e3d6000fd5b60203d10615a74576103209050516102e0518082811882841002189050905081525061369c565b60125461032052610320516102e051111561369457610320516103405260006103605260025480610380528060051b600081601f0160051c600a8111615a7457801561339457905b80600301548160051b6103a0015260010181811861337b575b5050505061018051156133aa57600d54156133ad565b60005b156133cf576101805180610380528060051b806103a0826101a060045afa5050505b600061038051600a8111615a7457801561368957905b8060051b6103a001516104e05260016104e05160205260005260406000205461346e576011610500527f696e6163746976652073747261746567790000000000000000000000000000006105205261050050610500518061052001601f826000031636823750506308c379a06104c05260206104e052601f19601f6105005101166044016104dcfd5b6102e05161034051808203828111615a74579050905060016104e05160205260005260406000206002810190505480828118828410021890509050610500526104e051604052610500516060526134c6610540613108565b61054051610520526104e0516307a2d13a6105a0526104e05163d905777e6105605230610580526020610560602461057c845afa613509573d600060003e3d6000fd5b60203d10615a74576105609050516105c05260206105a060246105bc845afa613537573d600060003e3d6000fd5b60203d10615a74576105a0905051610540526105005161052051808203828111615a7457905090506105405110156135b5576105205161054051808202811583838304141715615a745790509050610500518015615a745780820490509050610520526105405161052051808201828110615a745790509050610500525b610500516135c25761367e565b61052051156135d95761270f6101605111156135dc565b60005b15613637576103405161050051808201828110615a74579050905061016051808202811583838304141715615a745790509050612710810490506103605161052051808201828110615a745790509050111561363757613689565b6103405161050051808201828110615a745790509050610340526102e051610340511061366357613689565b6103605161052051808201828110615a745790509050610360525b6001018181186133e5575b5050610340516102e0525b6102e0518152505b565b602154615a74576101c0516040526136b761020061305d565b610200516101e051111561372b576014610220527f657863656564206465706f736974206c696d69740000000000000000000000006102405261022050610220518061024001601f826000031636823750506308c379a06101e052602061020052601f19601f6102205101166044016101fcfd5b6020615a8660003960005160405233606052306080526101e05160a052613750612d0d565b6012546101e051808201828110615a7457905090506012556101e05160a0526101c05160c052613781610220612f2b565b6102205161020052610200516137f7576010610220527f63616e6e6f74206d696e74207a65726f000000000000000000000000000000006102405261022050610220518061024001601f826000031636823750506308c379a06101e052602061020052601f19601f6102205101166044016101fcfd5b6101c0516101a0517fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d76101e0516102205261020051610240526040610220a361020051815250565b602154615a74576101e05160a052600260c05261385d610220612a6e565b6102205161020052610200516138d3576013610220527f63616e6e6f74206465706f736974207a65726f000000000000000000000000006102405261022050610220518061024001601f826000031636823750506308c379a06101e052602061020052601f19601f6102205101166044016101fcfd5b6101c0516040526138e561022061305d565b61022051610200511115613959576014610240527f657863656564206465706f736974206c696d69740000000000000000000000006102605261024050610240518061026001601f826000031636823750506308c379a061020052602061022052601f19601f61024051011660440161021cfd5b6020615a8660003960005160405233606052306080526102005160a05261397e612d0d565b60125461020051808201828110615a7457905090506012556101e0516040526101c0516060526139ac612ebb565b6101c0516101a0517fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d761020051610220526101e051610240526040610220a361020051815250565b604051630a28a47760a05260605160c052602060a0602460bc845afa613a1f573d600060003e3d6000fd5b60203d10615a745760a09050516040516370a0823160e0523061010052602060e0602460fc845afa613a56573d600060003e3d6000fd5b60203d10615a745760e09050518082811882841002189050905060805260405163ba08765260a05260805160c0523060e0523061010052602060a0606460bc6000855af1613aa9573d600060003e3d6000fd5b60203d10615a745760a05050565b61060051613b2557600c610800527f5a45524f204144445245535300000000000000000000000000000000000000006108205261080050610800518061082001601f826000031636823750506308c379a06107c05260206107e052601f19601f6108005101166044016107dcfd5b612710610680511115613b98576008610800527f6d6178206c6f73730000000000000000000000000000000000000000000000006108205261080050610800518061082001601f826000031636823750506308c379a06107c05260206107e052601f19601f6108005101166044016107dcfd5b60175415613c4b57610620516101405261068051610160526106a05180610180528060051b806101a0826106c060045afa505050613bd761080061323b565b61080051610640511115613c4b576015610820527f657863656564207769746864726177206c696d697400000000000000000000006108405261082050610820518061084001601f826000031636823750506308c379a06107e052602061080052601f19601f6108205101166044016107fcfd5b6106605161080052600e610620516020526000526040600020546108205261080051613cd7576013610840527f6e6f2073686172657320746f2072656465656d000000000000000000000000006108605261084050610840518061086001601f826000031636823750506308c379a061080052602061082052601f19601f61084051011660440161081cfd5b61080051610820511015613d4b57601d610840527f696e73756666696369656e742073686172657320746f2072656465656d0000006108605261084050610840518061086001601f826000031636823750506308c379a061080052602061082052601f19601f61084051011660440161081cfd5b610620516105e05114613d76576106205160c0526105e05160e0526106605161010052613d766121c9565b6106405161084052601254610860526108605161084051111561440c5760025480610880528060051b600081601f0160051c600a8111615a74578015613dd157905b80600301548160051b6108a00152600101818118613db8575b505050506106a05115613de757600d5415613dea565b60005b15613e0c576106a05180610880528060051b806108a0826106c060045afa5050505b6011546109e052610860516108405103610a00526000610a20526020615a866000396000516370a08231610a605230610a80526020610a606024610a7c845afa613e5b573d600060003e3d6000fd5b60203d10615a7457610a60905051610a4052600061088051600a8111615a7457801561438e57905b8060051b6108a00151610a60526001610a6051602052600052604060002054613f0c576011610a80527f696e616374697665207374726174656779000000000000000000000000000000610aa052610a8050610a805180610aa001601f826000031636823750506308c379a0610a40526020610a6052601f19601f610a80510116604401610a5cfd5b6001610a6051602052600052604060002060028101905054610a8052610a0051610a805180828118828410021890509050610a2052610a60516307a2d13a610b0052610a605163d905777e610ac05230610ae0526020610ac06024610adc845afa613f7c573d600060003e3d6000fd5b60203d10615a7457610ac0905051610b20526020610b006024610b1c845afa613faa573d600060003e3d6000fd5b60203d10615a7457610b00905051610aa052610a6051604052610a2051606052613fd5610ae0613108565b610ae051610ac052610ac0511561416157610a2051610ac051808203828111615a745790509050610aa051101561406c57610a2051610ac051808203828111615a745790509050610ae052610ac051610aa051808202811583838304141715615a745790509050610ae0518015615a745780820490509050610ac052610aa051610ac051808201828110615a745790509050610a20525b610a2051610ac051808203828111615a745790509050610a205261084051610ac051808203828111615a74579050905061084052610a0051610ac051808203828111615a745790509050610a00526109e051610ac051808203828111615a7457905090506109e052610aa0516140e757610ac05115156140ea565b60005b1561416157610a8051610ac051808203828111615a745790509050610ae052610ae0516001610a6051602052600052604060002060028101905055610a60517f5e2b8821ad6e0e26207e0cb4d242d07eeb1cbb1cfd853e645bdcd27cc5484f95610a8051610b0052610ae051610b20526040610b00a25b610a2051610aa05180828118828410021890509050610a2052610a205161418757614383565b610a6051604052610a205160605261419d6139f4565b6020615a866000396000516370a08231610b005230610b20526020610b006024610b1c845afa6141d2573d600060003e3d6000fd5b60203d10615a7457610b00905051610ae052610ae051610a4051808203828111615a745790509050610b00526000610b2052610a2051610b00511161423157610a2051610b0051101561426b57610b0051610a205103610b205261426b565b610a8051610b00511161426257610a2051610a2051610b005103808201828110615a745790509050610a205261426b565b610a8051610a20525b61086051610a2051610b2051808203828111615a745790509050808201828110615a7457905090506108605261084051610b2051808203828111615a745790509050610840526109e051610a2051808203828111615a7457905090506109e052610a8051610a2051610ac051808201828110615a745790509050808203828111615a745790509050610b4052610b40516001610a6051602052600052604060002060028101905055610a60517f5e2b8821ad6e0e26207e0cb4d242d07eeb1cbb1cfd853e645bdcd27cc5484f95610a8051610b6052610b4051610b80526040610b60a26108605161084051116143605761438e565b610ae051610a4052610a0051610a2051808203828111615a745790509050610a00525b600101818118613e83575b50506108405161086051101561440457601c610a60527f696e73756666696369656e742061737365747320696e207661756c7400000000610a8052610a6050610a605180610a8001601f826000031636823750506308c379a0610a20526020610a4052601f19601f610a60510116604401610a3cfd5b6109e0516011555b61084051610640511161442057600061442a565b61270f6106805111155b156144d4576106405161068051808202811583838304141715615a745790509050612710810490506106405161084051808203828111615a74579050905011156144d457600d610880527f746f6f206d756368206c6f7373000000000000000000000000000000000000006108a0526108805061088051806108a001601f826000031636823750506308c379a061084052602061086052601f19601f61088051011660440161085cfd5b61080051604052610620516060526144ea61291e565b6108605161084051808203828111615a7457905090506012556020615a866000396000516040526106005160605261084051608052614527612de9565b61062051610600516105e0517ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db6108405161088052610800516108a0526040610880a461084051815250565b60405130811461458557801515614588565b60005b90506145eb57601f6080527f73747261746567792063616e6e6f74206265207a65726f20616464726573730060a0526080506080518060a001601f826000031636823750506308c379a06040526020606052601f19601f6080510116604401605cfd5b6020615a866000396000516040516338d52e0f606052602060606004607c845afa61461b573d600060003e3d6000fd5b60203d10615a74576060518060a01c615a745760a05260a0905051181561469957600d60c0527f696e76616c69642061737365740000000000000000000000000000000000000060e05260c05060c0518060e001601f826000031636823750506308c379a0608052602060a052601f19601f60c0510116604401609cfd5b60016040516020526000526040600020541561470c5760176060527f737472617465677920616c72656164792061637469766500000000000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6001604051602052600052604060002042815542600182015560006002820155600060038201555060096002541161475a5760025460098111615a7457600181016002556040518160030155505b60016040517fde8ff765a5c5dad48d27bc9faa99836fb81f3b07c9dc62cfe005475d6b83a2ca60006060a3565b60016040516020526000526040600020546147f95760136080527f7374726174656779206e6f74206163746976650000000000000000000000000060a0526080506080518060a001601f826000031636823750506308c379a06040526020606052601f19601f6080510116604401605cfd5b60006080526001604051602052600052604060002060028101905054156148ea5760605161487e57601160a0527f737472617465677920686173206465627400000000000000000000000000000060c05260a05060a0518060c001601f826000031636823750506308c379a06060526020608052601f19601f60a0510116604401607cfd5b6001604051602052600052604060002060028101905054608052601154608051808203828111615a7457905090506011556040517f7f2ad1d3ba35276f35ef140f83e3e0f17b23064fd710113d3f7a5ab30d267811600060a05260805160c05260803660e03760c060a0a25b600160405160205260005260406000206000815560006001820155600060028201556000600382015550600060a0526000600254600a8111615a7457801561496e57905b80600301546102005260405161020051146149635760a05160098111615a74576001810160a052610200518160051b60c00152505b60010181811861492e575b505060a051806002558060051b600081601f0160051c600a8111615a745780156149ac57905b8060051b60c001518160030155600101818118614994575b5050505060026040517fde8ff765a5c5dad48d27bc9faa99836fb81f3b07c9dc62cfe005475d6b83a2ca6000610200a3565b610180516101a0526001610160516020526000526040600020600281019050546101c05260215415614a115760006101a0525b6101c0516101a05118614a8457601c6101e0527f6e6577206465627420657175616c732063757272656e74206465627400000000610200526101e0506101e0518061020001601f826000031636823750506308c379a06101a05260206101c052601f19601f6101e05101166044016101bcfd5b6101a0516101c05111614e29576001610160516020526000526040600020600381019050546101a0511115614b195760206101e0527f746172676574206465627420686967686572207468616e206d61782064656274610200526101e0506101e0518061020001601f826000031636823750506308c379a06101a05260206101c052601f19601f6101e05101166044016101bcfd5b6101605163402d267d6102005230610220526020610200602461021c845afa614b47573d600060003e3d6000fd5b60203d10615a74576102009050516101e0526101e051614bc7576012610200527f6e6f7468696e6720746f206465706f73697400000000000000000000000000006102205261020050610200518061022001601f826000031636823750506308c379a06101c05260206101e052601f19601f6102005101166044016101dcfd5b6101a0516101c051808203828111615a745790509050610200526101e051610200511115614bf8576101e051610200525b6013546102205260125461024052610220516102405111614c79576013610260527f6e6f2066756e647320746f206465706f736974000000000000000000000000006102805261026050610260518061028001601f826000031636823750506308c379a061022052602061024052601f19601f61026051011660440161023cfd5b6102205161024051036102605261026051610200511115614c9d5761026051610200525b6102005115614e0a576020615a866000396000516040526101605160605261020051608052614cca612c3b565b6020615a866000396000516370a082316102a052306102c05260206102a060246102bc845afa614cff573d600060003e3d6000fd5b60203d10615a74576102a09050516102805261016051636e553f656102a052610200516102c052306102e05260206102a060446102bc6000855af1614d49573d600060003e3d6000fd5b60203d10615a74576102a050506020615a866000396000516370a082316102c052306102e05260206102c060246102dc845afa614d8b573d600060003e3d6000fd5b60203d10615a74576102c09050516102a0526020615a86600039600051604052610160516060526000608052614dbf612c3b565b610280516102a051808203828111615a7457905090506102005260125461020051808203828111615a74579050905060125560115461020051808201828110615a7457905090506011555b6101c05161020051808201828110615a7457905090506101a052615149565b6101a0516101c051036101e052601354610200526012546102205261020051610220516101e051808201828110615a7457905090501015614e88576102205161020051036101e0526101c0516101e0511115614e88576101c0516101e0525b610160516307a2d13a6102a0526101605163d905777e6102605230610280526020610260602461027c845afa614ec3573d600060003e3d6000fd5b60203d10615a74576102609050516102c05260206102a060246102bc845afa614ef1573d600060003e3d6000fd5b60203d10615a74576102a09050516102405261024051614f71576013610260527f6e6f7468696e6720746f207769746864726177000000000000000000000000006102805261026050610260518061028001601f826000031636823750506308c379a061022052602061024052601f19601f61026051011660440161023cfd5b6101e051610240511015614f8857610240516101e0525b610160516040526101e051606052614fa1610280613108565b6102805161026052610260511561501857601e610280527f73747261746567792068617320756e7265616c69736564206c6f7373657300006102a0526102805061028051806102a001601f826000031636823750506308c379a061024052602061026052601f19601f61028051011660440161025cfd5b6020615a866000396000516370a082316102a052306102c05260206102a060246102bc845afa61504d573d600060003e3d6000fd5b60203d10615a74576102a090505161028052610160516040526101e0516060526150756139f4565b6020615a866000396000516370a082316102c052306102e05260206102c060246102dc845afa6150aa573d600060003e3d6000fd5b60203d10615a74576102c09050516102a0526102a05161028051808203828111615a7457905090506101c051808281188284100218905090506102c0526101e0516102c05111156150fe576102c0516101e0525b6012546102c051808201828110615a7457905090506012556011546101e051808203828111615a7457905090506011556101c0516101e051808203828111615a7457905090506101a0525b6101a051600161016051602052600052604060002060028101905055610160517f5e2b8821ad6e0e26207e0cb4d242d07eeb1cbb1cfd853e645bdcd27cc5484f956101c0516101e0526101a0516102005260406101e0a26101a051815250565b60016101a0516020526000526040600020546152255760116101c0527f696e6163746976652073747261746567790000000000000000000000000000006101e0526101c0506101c051806101e001601f826000031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b61522d612a16565b6101a0516370a082316101e052306102005260206101e060246101fc845afa61525b573d600060003e3d6000fd5b60203d10615a74576101e09050516101c0526101a0516307a2d13a610200526101c051610220526020610200602461021c845afa61529e573d600060003e3d6000fd5b60203d10615a74576102009050516101e05260016101a0516020526000526040600020600281019050546102005260403661022037610200516101e051116152f2576101e051610200510361024052615300565b610200516101e05103610220525b608036610260376015546102e0526102e05115615426576102e05163921f8a8f610300526101a05161032052610220516103405261024051610360526040610300606461031c6000855af161535a573d600060003e3d6000fd5b60403d10615a74576103009050805161026052602081015161028052506102605115615426576000610300526020615ac6600039600051635153b199610320526040610320600461033c845afa6153b6573d600060003e3d6000fd5b60403d10615a7457610320518060101c615a745761038052610340518060a01c615a74576103a052610380905080516103005260208101516102c0525060016103005112615426576102605161030051808202811583838304141715615a745790509050612710810490506102a0525b606036610300376102405161026051808201828110615a745790509050156154ee57610300516102405161026051808201828110615a74579050905060a052600260c052615475610360612b45565b61036051808201828110615a7457905090506103005261026051156154ee57610260516102a051808203828111615a74579050905060a052600160c0526154bd610360612b45565b61036051610320526102a051156154ee576102a05160a052600160c0526154e5610360612b45565b61036051610340525b60006103605261028051156155f157610280516020615a866000396000516370a08231610380526102e0516103a0526020610380602461039c845afa615539573d600060003e3d6000fd5b60203d10615a74576103809050516020615a8660003960005163dd62ed3e6103c0526102e0516103e052306104005260206103c060446103dc845afa615584573d600060003e3d6000fd5b60203d10615a74576103c09050518082811882841002189050905080828118828410021890509050610280526020615a866000396000516040526102e051606052306080526102805160a0526155d8612d0d565b60125461028051808201828110615a7457905090506012555b61022051156156415760016101a0516020526000526040600020600281019050805461022051808201828110615a74579050905081555060115461022051808201828110615a7457905090506011555b602254610380526102205161028051808201828110615a7457905090501561566e57610380511515615671565b60005b156156a7576102205161028051808201828110615a74579050905060a0523060c05261569e6103a0612f2b565b6103a051610360525b61024051156156f75760016101a0516020526000526040600020600281019050805461024051808203828111615a74579050905081555060115461024051808203828111615a7457905090506011555b600e3060205260005260406000205461036051808203828111615a7457905090506103a05261030051156157c357610300516103a05161036051808201828110615a7457905090508082811882841002189050905061030052610300516040523060605261576361291e565b6103005161036051808281188284100218905090506103c052610360516103c051808203828111615a745790509050610360526103a051610300516103c051808203828111615a745790509050808203828111615a7457905090506103a0525b61032051156157e257610320516040526102e0516060526157e2612ebb565b610340511561580157610340516040526102c051606052615801612ebb565b6103a05161036051808201828110615a7457905090506103c0526103c051156158fe5760006103e052602354610400524261040051111561586c576103a0516104005142808203828111615a745790509050808202811583838304141715615a7457905090506103e0525b6103e0516103605161038051808202811583838304141715615a745790509050808201828110615a7457905090506103c0518015615a745780820490509050610420526103c05164e8d4a5100081028164e8d4a51000820418615a74579050610420518015615a7457808204905090506024554261042051808201828110615a74579050905060235542602555615904565b60006024555b4260016101a0516020526000526040600020600181019050556101a0517f7f2ad1d3ba35276f35ef140f83e3e0f17b23064fd710113d3f7a5ab30d2678116102205161042052610240516104405260016101a051602052600052604060002060028101905054610460526103405160a052600160c0526159856103e0612a6e565b6103e051610480526103405161032051808201828110615a74579050905060a052600160c0526159b6610400612a6e565b610400516104a052610280516104c05260c0610420a261022051815261024051602082015250565b601860405160205260005260406000205460605116156159ff576001615a11565b60196060516020526000526040600020545b615a7257600b6080527f6e6f7420616c6c6f77656400000000000000000000000000000000000000000060a0526080506080518060a001601f826000031636823750506308c379a06040526020606052601f19601f6080510116604401605cfd5b565b600080fda165767970657283000307000b000000000000000000000000f939e0a03fb07f59a73314e73794be0e57ac1b4e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000e9e8c89c8fc7e8b8f23425688eb68987231178e5
Verified Source Code Partial Match
Compiler: v0.3.7+commit.6020b8bb
EVM: paris
YearnV3Vault.vy 2169 lines
# @version 0.3.7
"""
@title Yearn V3 Vault
@license GNU AGPLv3
@author yearn.finance
@notice
The Yearn VaultV3 is designed as an non-opinionated system to distribute funds of
depositors for a specific `asset` into different opportunities (aka Strategies)
and manage accounting in a robust way.
Depositors receive shares (aka vaults tokens) proportional to their deposit amount.
Vault tokens are yield-bearing and can be redeemed at any time to get back deposit
plus any yield generated.
Addresses that are given different permissioned roles by the `role_manager`
are then able to allocate funds as they best see fit to different strategies
and adjust the strategies and allocations as needed, as well as reporting realized
profits or losses.
Strategies are any ERC-4626 compliant contracts that use the same underlying `asset`
as the vault. The vault provides no assurances as to the safety of any strategy
and it is the responsibility of those that hold the corresponding roles to choose
and fund strategies that best fit their desired specifications.
Those holding vault tokens are able to redeem the tokens for the corresponding
amount of underlying asset based on any reported profits or losses since their
initial deposit.
The vault is built to be customized by the management to be able to fit their
specific desired needs Including the customization of strategies, accountants,
ownership etc.
"""
from vyper.interfaces import ERC20
from vyper.interfaces import ERC20Detailed
# INTERFACES #
interface IStrategy:
def asset() -> address: view
def balanceOf(owner: address) -> uint256: view
def maxDeposit(receiver: address) -> uint256: view
def redeem(shares: uint256, receiver: address, owner: address) -> uint256: nonpayable
def deposit(assets: uint256, receiver: address) -> uint256: nonpayable
def totalAssets() -> (uint256): view
def convertToAssets(shares: uint256) -> uint256: view
def convertToShares(assets: uint256) -> uint256: view
def previewWithdraw(assets: uint256) -> uint256: view
def maxRedeem(owner: address) -> uint256: view
interface IAccountant:
def report(strategy: address, gain: uint256, loss: uint256) -> (uint256, uint256): nonpayable
interface IDepositLimitModule:
def available_deposit_limit(receiver: address) -> uint256: view
interface IWithdrawLimitModule:
def available_withdraw_limit(owner: address, max_loss: uint256, strategies: DynArray[address, MAX_QUEUE]) -> uint256: view
interface IFactory:
def protocol_fee_config() -> (uint16, address): view
# EVENTS #
# ERC4626 EVENTS
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
# ERC20 EVENTS
event Transfer:
sender: indexed(address)
receiver: indexed(address)
value: uint256
event Approval:
owner: indexed(address)
spender: indexed(address)
value: uint256
# STRATEGY EVENTS
event StrategyChanged:
strategy: indexed(address)
change_type: indexed(StrategyChangeType)
event StrategyReported:
strategy: indexed(address)
gain: uint256
loss: uint256
current_debt: uint256
protocol_fees: uint256
total_fees: uint256
total_refunds: uint256
# DEBT MANAGEMENT EVENTS
event DebtUpdated:
strategy: indexed(address)
current_debt: uint256
new_debt: uint256
# ROLE UPDATES
event RoleSet:
account: indexed(address)
role: indexed(Roles)
event RoleStatusChanged:
role: indexed(Roles)
status: indexed(RoleStatusChange)
# STORAGE MANAGEMENT EVENTS
event UpdateRoleManager:
role_manager: indexed(address)
event UpdateAccountant:
accountant: indexed(address)
event UpdateDepositLimitModule:
deposit_limit_module: indexed(address)
event UpdateWithdrawLimitModule:
withdraw_limit_module: indexed(address)
event UpdateDefaultQueue:
new_default_queue: DynArray[address, MAX_QUEUE]
event UpdateUseDefaultQueue:
use_default_queue: bool
event UpdatedMaxDebtForStrategy:
sender: indexed(address)
strategy: indexed(address)
new_debt: uint256
event UpdateDepositLimit:
deposit_limit: uint256
event UpdateMinimumTotalIdle:
minimum_total_idle: uint256
event UpdateProfitMaxUnlockTime:
profit_max_unlock_time: uint256
event DebtPurchased:
strategy: indexed(address)
amount: uint256
event Shutdown:
pass
# STRUCTS #
struct StrategyParams:
# Timestamp when the strategy was added.
activation: uint256
# Timestamp of the strategies last report.
last_report: uint256
# The current assets the strategy holds.
current_debt: uint256
# The max assets the strategy can hold.
max_debt: uint256
# CONSTANTS #
# The max length the withdrawal queue can be.
MAX_QUEUE: constant(uint256) = 10
# 100% in Basis Points.
MAX_BPS: constant(uint256) = 10_000
# Extended for profit locking calculations.
MAX_BPS_EXTENDED: constant(uint256) = 1_000_000_000_000
# The version of this vault.
API_VERSION: constant(String[28]) = "3.0.1"
# ENUMS #
# Each permissioned function has its own Role.
# Roles can be combined in any combination or all kept separate.
# Follows python Enum patterns so the first Enum == 1 and doubles each time.
enum Roles:
ADD_STRATEGY_MANAGER # Can add strategies to the vault.
REVOKE_STRATEGY_MANAGER # Can remove strategies from the vault.
FORCE_REVOKE_MANAGER # Can force remove a strategy causing a loss.
ACCOUNTANT_MANAGER # Can set the accountant that assess fees.
QUEUE_MANAGER # Can set the default withdrawal queue.
REPORTING_MANAGER # Calls report for strategies.
DEBT_MANAGER # Adds and removes debt from strategies.
MAX_DEBT_MANAGER # Can set the max debt for a strategy.
DEPOSIT_LIMIT_MANAGER # Sets deposit limit and module for the vault.
WITHDRAW_LIMIT_MANAGER # Sets the withdraw limit module.
MINIMUM_IDLE_MANAGER # Sets the minimum total idle the vault should keep.
PROFIT_UNLOCK_MANAGER # Sets the profit_max_unlock_time.
DEBT_PURCHASER # Can purchase bad debt from the vault.
EMERGENCY_MANAGER # Can shutdown vault in an emergency.
enum StrategyChangeType:
ADDED
REVOKED
enum Rounding:
ROUND_DOWN
ROUND_UP
enum RoleStatusChange:
OPENED
CLOSED
# IMMUTABLE #
# Underlying token used by the vault.
ASSET: immutable(ERC20)
# Based off the `asset` decimals.
DECIMALS: immutable(uint256)
# Deployer contract used to retrieve the protocol fee config.
FACTORY: public(immutable(address))
# STORAGE #
# HashMap that records all the strategies that are allowed to receive assets from the vault.
strategies: public(HashMap[address, StrategyParams])
# The current default withdrawal queue.
default_queue: public(DynArray[address, MAX_QUEUE])
# Should the vault use the default_queue regardless whats passed in.
use_default_queue: public(bool)
# ERC20 - amount of shares per account
balance_of: HashMap[address, uint256]
# ERC20 - owner -> (spender -> amount)
allowance: public(HashMap[address, HashMap[address, uint256]])
# Total amount of shares that are currently minted including those locked.
# NOTE: To get the ERC20 compliant version user totalSupply().
total_supply: public(uint256)
# Total amount of assets that has been deposited in strategies.
total_debt: uint256
# Current assets held in the vault contract. Replacing balanceOf(this) to avoid price_per_share manipulation.
total_idle: uint256
# Minimum amount of assets that should be kept in the vault contract to allow for fast, cheap redeems.
minimum_total_idle: public(uint256)
# Maximum amount of tokens that the vault can accept. If totalAssets > deposit_limit, deposits will revert.
deposit_limit: public(uint256)
# Contract that charges fees and can give refunds.
accountant: public(address)
# Contract to control the deposit limit.
deposit_limit_module: public(address)
# Contract to control the withdraw limit.
withdraw_limit_module: public(address)
# HashMap mapping addresses to their roles
roles: public(HashMap[address, Roles])
# HashMap mapping roles to their permissioned state. If false, the role is not open to the public.
open_roles: public(HashMap[Roles, bool])
# Address that can add and remove roles to addresses.
role_manager: public(address)
# Temporary variable to store the address of the next role_manager until the role is accepted.
future_role_manager: public(address)
# ERC20 - name of the vaults token.
name: public(String[64])
# ERC20 - symbol of the vaults token.
symbol: public(String[32])
# State of the vault - if set to true, only withdrawals will be available. It can't be reverted.
shutdown: bool
# The amount of time profits will unlock over.
profit_max_unlock_time: uint256
# The timestamp of when the current unlocking period ends.
full_profit_unlock_date: uint256
# The per second rate at which profit will unlock.
profit_unlocking_rate: uint256
# Last timestamp of the most recent profitable report.
last_profit_update: uint256
# `nonces` track `permit` approvals with signature.
nonces: public(HashMap[address, uint256])
DOMAIN_TYPE_HASH: constant(bytes32) = keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)')
PERMIT_TYPE_HASH: constant(bytes32) = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")
# Constructor
@external
def __init__(
asset: ERC20,
name: String[64],
symbol: String[32],
role_manager: address,
profit_max_unlock_time: uint256
):
"""
@notice
The constructor for the vault. Sets the asset, name, symbol, and role manager.
@param asset
The address of the asset that the vault will accept.
@param name
The name of the vault token.
@param symbol
The symbol of the vault token.
@param role_manager
The address that can add and remove roles to addresses
@param profit_max_unlock_time
The amount of time that the profit will be locked for
"""
ASSET = asset
DECIMALS = convert(ERC20Detailed(asset.address).decimals(), uint256)
assert DECIMALS < 256 # dev: see VVE-2020-0001
FACTORY = msg.sender
# Must be less than one year for report cycles
assert profit_max_unlock_time <= 31_556_952 # dev: profit unlock time too long
self.profit_max_unlock_time = profit_max_unlock_time
self.name = name
self.symbol = symbol
self.role_manager = role_manager
## SHARE MANAGEMENT ##
## ERC20 ##
@internal
def _spend_allowance(owner: address, spender: address, amount: uint256):
# Unlimited approval does nothing (saves an SSTORE)
current_allowance: uint256 = self.allowance[owner][spender]
if (current_allowance < max_value(uint256)):
assert current_allowance >= amount, "insufficient allowance"
self._approve(owner, spender, unsafe_sub(current_allowance, amount))
@internal
def _transfer(sender: address, receiver: address, amount: uint256):
sender_balance: uint256 = self.balance_of[sender]
assert sender_balance >= amount, "insufficient funds"
self.balance_of[sender] = unsafe_sub(sender_balance, amount)
self.balance_of[receiver] = unsafe_add(self.balance_of[receiver], amount)
log Transfer(sender, receiver, amount)
@internal
def _transfer_from(sender: address, receiver: address, amount: uint256) -> bool:
self._spend_allowance(sender, msg.sender, amount)
self._transfer(sender, receiver, amount)
return True
@internal
def _approve(owner: address, spender: address, amount: uint256) -> bool:
self.allowance[owner][spender] = amount
log Approval(owner, spender, amount)
return True
@internal
def _increase_allowance(owner: address, spender: address, amount: uint256) -> bool:
new_allowance: uint256 = self.allowance[owner][spender] + amount
self.allowance[owner][spender] = new_allowance
log Approval(owner, spender, new_allowance)
return True
@internal
def _decrease_allowance(owner: address, spender: address, amount: uint256) -> bool:
new_allowance: uint256 = self.allowance[owner][spender] - amount
self.allowance[owner][spender] = new_allowance
log Approval(owner, spender, new_allowance)
return True
@internal
def _permit(
owner: address,
spender: address,
amount: uint256,
deadline: uint256,
v: uint8,
r: bytes32,
s: bytes32
) -> bool:
assert owner != empty(address), "invalid owner"
assert deadline >= block.timestamp, "permit expired"
nonce: uint256 = self.nonces[owner]
digest: bytes32 = keccak256(
concat(
b'\x19\x01',
self.domain_separator(),
keccak256(
concat(
PERMIT_TYPE_HASH,
convert(owner, bytes32),
convert(spender, bytes32),
convert(amount, bytes32),
convert(nonce, bytes32),
convert(deadline, bytes32),
)
)
)
)
assert ecrecover(
digest, convert(v, uint256), convert(r, uint256), convert(s, uint256)
) == owner, "invalid signature"
self.allowance[owner][spender] = amount
self.nonces[owner] = nonce + 1
log Approval(owner, spender, amount)
return True
@internal
def _burn_shares(shares: uint256, owner: address):
self.balance_of[owner] -= shares
self.total_supply = unsafe_sub(self.total_supply, shares)
log Transfer(owner, empty(address), shares)
@view
@internal
def _unlocked_shares() -> uint256:
"""
Returns the amount of shares that have been unlocked.
To avoid sudden price_per_share spikes, profits must be processed
through an unlocking period. The mechanism involves shares to be
minted to the vault which are unlocked gradually over time. Shares
that have been locked are gradually unlocked over profit_max_unlock_time.
"""
_full_profit_unlock_date: uint256 = self.full_profit_unlock_date
unlocked_shares: uint256 = 0
if _full_profit_unlock_date > block.timestamp:
# If we have not fully unlocked, we need to calculate how much has been.
unlocked_shares = self.profit_unlocking_rate * (block.timestamp - self.last_profit_update) / MAX_BPS_EXTENDED
elif _full_profit_unlock_date != 0:
# All shares have been unlocked
unlocked_shares = self.balance_of[self]
return unlocked_shares
@view
@internal
def _total_supply() -> uint256:
# Need to account for the shares issued to the vault that have unlocked.
return self.total_supply - self._unlocked_shares()
@internal
def _burn_unlocked_shares():
"""
Burns shares that have been unlocked since last update.
In case the full unlocking period has passed, it stops the unlocking.
"""
# Get the amount of shares that have unlocked
unlocked_shares: uint256 = self._unlocked_shares()
# IF 0 there's nothing to do.
if unlocked_shares == 0:
return
# Only do an SSTORE if necessary
if self.full_profit_unlock_date > block.timestamp:
self.last_profit_update = block.timestamp
# Burn the shares unlocked.
self._burn_shares(unlocked_shares, self)
@view
@internal
def _total_assets() -> uint256:
"""
Total amount of assets that are in the vault and in the strategies.
"""
return self.total_idle + self.total_debt
@view
@internal
def _convert_to_assets(shares: uint256, rounding: Rounding) -> uint256:
"""
assets = shares * (total_assets / total_supply) --- (== price_per_share * shares)
"""
if shares == max_value(uint256) or shares == 0:
return shares
total_supply: uint256 = self._total_supply()
# if total_supply is 0, price_per_share is 1
if total_supply == 0:
return shares
numerator: uint256 = shares * self._total_assets()
amount: uint256 = numerator / total_supply
if rounding == Rounding.ROUND_UP and numerator % total_supply != 0:
amount += 1
return amount
@view
@internal
def _convert_to_shares(assets: uint256, rounding: Rounding) -> uint256:
"""
shares = amount * (total_supply / total_assets) --- (== amount / price_per_share)
"""
if assets == max_value(uint256) or assets == 0:
return assets
total_supply: uint256 = self._total_supply()
total_assets: uint256 = self._total_assets()
if total_assets == 0:
# if total_assets and total_supply is 0, price_per_share is 1
if total_supply == 0:
return assets
else:
# Else if total_supply > 0 price_per_share is 0
return 0
numerator: uint256 = assets * total_supply
shares: uint256 = numerator / total_assets
if rounding == Rounding.ROUND_UP and numerator % total_assets != 0:
shares += 1
return shares
@internal
def _erc20_safe_approve(token: address, spender: address, amount: uint256):
# Used only to approve tokens that are not the type managed by this Vault.
# Used to handle non-compliant tokens like USDT
assert ERC20(token).approve(spender, amount, default_return_value=True), "approval failed"
@internal
def _erc20_safe_transfer_from(token: address, sender: address, receiver: address, amount: uint256):
# Used only to transfer tokens that are not the type managed by this Vault.
# Used to handle non-compliant tokens like USDT
assert ERC20(token).transferFrom(sender, receiver, amount, default_return_value=True), "transfer failed"
@internal
def _erc20_safe_transfer(token: address, receiver: address, amount: uint256):
# Used only to send tokens that are not the type managed by this Vault.
# Used to handle non-compliant tokens like USDT
assert ERC20(token).transfer(receiver, amount, default_return_value=True), "transfer failed"
@internal
def _issue_shares(shares: uint256, recipient: address):
self.balance_of[recipient] = unsafe_add(self.balance_of[recipient], shares)
self.total_supply += shares
log Transfer(empty(address), recipient, shares)
@internal
def _issue_shares_for_amount(amount: uint256, recipient: address) -> uint256:
"""
Issues shares that are worth 'amount' in the underlying token (asset).
WARNING: this takes into account that any new assets have been summed
to total_assets (otherwise pps will go down).
"""
total_supply: uint256 = self._total_supply()
total_assets: uint256 = self._total_assets()
new_shares: uint256 = 0
# If no supply PPS = 1.
if total_supply == 0:
new_shares = amount
elif total_assets > amount:
new_shares = amount * total_supply / (total_assets - amount)
else:
# If total_supply > 0 but amount = totalAssets we want to revert because
# after first deposit, getting here would mean that the rest of the shares
# would be diluted to a price_per_share of 0. Issuing shares would then mean
# either the new depositor or the previous depositors will loose money.
assert total_assets > amount, "amount too high"
# We don't make the function revert
if new_shares == 0:
return 0
self._issue_shares(new_shares, recipient)
return new_shares
## ERC4626 ##
@view
@internal
def _max_deposit(receiver: address) -> uint256:
if receiver in [empty(address), self]:
return 0
# If there is a deposit limit module set use that.
deposit_limit_module: address = self.deposit_limit_module
if deposit_limit_module != empty(address):
return IDepositLimitModule(deposit_limit_module).available_deposit_limit(receiver)
# Else use the standard flow.
_total_assets: uint256 = self._total_assets()
_deposit_limit: uint256 = self.deposit_limit
if (_total_assets >= _deposit_limit):
return 0
return unsafe_sub(_deposit_limit, _total_assets)
@view
@internal
def _max_withdraw(
owner: address,
max_loss: uint256,
strategies: DynArray[address, MAX_QUEUE]
) -> uint256:
"""
@dev Returns the max amount of `asset` an `owner` can withdraw.
This will do a full simulation of the withdraw in order to determine
how much is currently liquid and if the `max_loss` would allow for the
tx to not revert.
This will track any expected loss to check if the tx will revert, but
not account for it in the amount returned since it is unrealised and
therefore will not be accounted for in the conversion rates.
i.e. If we have 100 debt and 10 of unrealised loss, the max we can get
out is 90, but a user of the vault will need to call withdraw with 100
in order to get the full 90 out.
"""
# Get the max amount for the owner if fully liquid.
max_assets: uint256 = self._convert_to_assets(self.balance_of[owner], Rounding.ROUND_DOWN)
# If there is a withdraw limit module use that.
withdraw_limit_module: address = self.withdraw_limit_module
if withdraw_limit_module != empty(address):
return min(
# Use the min between the returned value and the max.
# Means the limit module doesn't need to account for balances or conversions.
IWithdrawLimitModule(withdraw_limit_module).available_withdraw_limit(owner, max_loss, strategies),
max_assets
)
# See if we have enough idle to service the withdraw.
current_idle: uint256 = self.total_idle
if max_assets > current_idle:
# Track how much we can pull.
have: uint256 = current_idle
loss: uint256 = 0
# Cache the default queue.
_strategies: DynArray[address, MAX_QUEUE] = self.default_queue
# If a custom queue was passed, and we don't force the default queue.
if len(strategies) != 0 and not self.use_default_queue:
# Use the custom queue.
_strategies = strategies
for strategy in _strategies:
# Can't use an invalid strategy.
assert self.strategies[strategy].activation != 0, "inactive strategy"
# Get the maximum amount the vault would withdraw from the strategy.
to_withdraw: uint256 = min(
# What we still need for the full withdraw.
max_assets - have,
# The current debt the strategy has.
self.strategies[strategy].current_debt
)
# Get any unrealised loss for the strategy.
unrealised_loss: uint256 = self._assess_share_of_unrealised_losses(strategy, to_withdraw)
# See if any limit is enforced by the strategy.
strategy_limit: uint256 = IStrategy(strategy).convertToAssets(
IStrategy(strategy).maxRedeem(self)
)
# Adjust accordingly if there is a max withdraw limit.
if strategy_limit < to_withdraw - unrealised_loss:
# lower unrealised loss to the proportional to the limit.
unrealised_loss = unrealised_loss * strategy_limit / to_withdraw
# Still count the unrealised loss as withdrawable.
to_withdraw = strategy_limit + unrealised_loss
# If 0 move on to the next strategy.
if to_withdraw == 0:
continue
# If there would be a loss with a non-maximum `max_loss` value.
if unrealised_loss > 0 and max_loss < MAX_BPS:
# Check if the loss is greater than the allowed range.
if loss + unrealised_loss > (have + to_withdraw) * max_loss / MAX_BPS:
# If so use the amounts up till now.
break
# Add to what we can pull.
have += to_withdraw
# If we have all we need break.
if have >= max_assets:
break
# Add any unrealised loss to the total
loss += unrealised_loss
# Update the max after going through the queue.
# In case we broke early or exhausted the queue.
max_assets = have
return max_assets
@internal
def _deposit(sender: address, recipient: address, assets: uint256) -> uint256:
"""
Used for `deposit` calls to transfer the amount of `asset` to the vault,
issue the corresponding shares to the `recipient` and update all needed
vault accounting.
"""
assert self.shutdown == False # dev: shutdown
assert assets <= self._max_deposit(recipient), "exceed deposit limit"
# Transfer the tokens to the vault first.
self._erc20_safe_transfer_from(ASSET.address, msg.sender, self, assets)
# Record the change in total assets.
self.total_idle += assets
# Issue the corresponding shares for assets.
shares: uint256 = self._issue_shares_for_amount(assets, recipient)
assert shares > 0, "cannot mint zero"
log Deposit(sender, recipient, assets, shares)
return shares
@internal
def _mint(sender: address, recipient: address, shares: uint256) -> uint256:
"""
Used for `mint` calls to issue the corresponding shares to the `recipient`,
transfer the amount of `asset` to the vault, and update all needed vault
accounting.
"""
assert self.shutdown == False # dev: shutdown
# Get corresponding amount of assets.
assets: uint256 = self._convert_to_assets(shares, Rounding.ROUND_UP)
assert assets > 0, "cannot deposit zero"
assert assets <= self._max_deposit(recipient), "exceed deposit limit"
# Transfer the tokens to the vault first.
self._erc20_safe_transfer_from(ASSET.address, msg.sender, self, assets)
# Record the change in total assets.
self.total_idle += assets
# Issue the corresponding shares for assets.
self._issue_shares(shares, recipient)
log Deposit(sender, recipient, assets, shares)
return assets
@view
@internal
def _assess_share_of_unrealised_losses(strategy: address, assets_needed: uint256) -> uint256:
"""
Returns the share of losses that a user would take if withdrawing from this strategy
e.g. if the strategy has unrealised losses for 10% of its current debt and the user
wants to withdraw 1000 tokens, the losses that he will take are 100 token
"""
# Minimum of how much debt the debt should be worth.
strategy_current_debt: uint256 = self.strategies[strategy].current_debt
# The actual amount that the debt is currently worth.
vault_shares: uint256 = IStrategy(strategy).balanceOf(self)
strategy_assets: uint256 = IStrategy(strategy).convertToAssets(vault_shares)
# If no losses, return 0
if strategy_assets >= strategy_current_debt or strategy_current_debt == 0:
return 0
# Users will withdraw assets_to_withdraw divided by loss ratio (strategy_assets / strategy_current_debt - 1),
# but will only receive assets_to_withdraw.
# NOTE: If there are unrealised losses, the user will take his share.
numerator: uint256 = assets_needed * strategy_assets
losses_user_share: uint256 = assets_needed - numerator / strategy_current_debt
# Always round up.
if numerator % strategy_current_debt != 0:
losses_user_share += 1
return losses_user_share
@internal
def _withdraw_from_strategy(strategy: address, assets_to_withdraw: uint256):
"""
This takes the amount denominated in asset and performs a {redeem}
with the corresponding amount of shares.
We use {redeem} to natively take on losses without additional non-4626 standard parameters.
"""
# Need to get shares since we use redeem to be able to take on losses.
shares_to_redeem: uint256 = min(
# Use previewWithdraw since it should round up.
IStrategy(strategy).previewWithdraw(assets_to_withdraw),
# And check against our actual balance.
IStrategy(strategy).balanceOf(self)
)
# Redeem the shares.
IStrategy(strategy).redeem(shares_to_redeem, self, self)
@internal
def _redeem(
sender: address,
receiver: address,
owner: address,
assets: uint256,
shares_to_burn: uint256,
max_loss: uint256,
strategies: DynArray[address, MAX_QUEUE]
) -> uint256:
"""
This will attempt to free up the full amount of assets equivalent to
`shares_to_burn` and transfer them to the `receiver`. If the vault does
not have enough idle funds it will go through any strategies provided by
either the withdrawer or the queue_manager to free up enough funds to
service the request.
The vault will attempt to account for any unrealized losses taken on from
strategies since their respective last reports.
Any losses realized during the withdraw from a strategy will be passed on
to the user that is redeeming their vault shares.
"""
assert receiver != empty(address), "ZERO ADDRESS"
assert max_loss <= MAX_BPS, "max loss"
# If there is a withdraw limit module, check the max.
if self.withdraw_limit_module != empty(address):
assert assets <= self._max_withdraw(owner, max_loss, strategies), "exceed withdraw limit"
shares: uint256 = shares_to_burn
shares_balance: uint256 = self.balance_of[owner]
assert shares > 0, "no shares to redeem"
assert shares_balance >= shares, "insufficient shares to redeem"
if sender != owner:
self._spend_allowance(owner, sender, shares_to_burn)
# The amount of the underlying token to withdraw.
requested_assets: uint256 = assets
# load to memory to save gas
curr_total_idle: uint256 = self.total_idle
# If there are not enough assets in the Vault contract, we try to free
# funds from strategies.
if requested_assets > curr_total_idle:
# Cache the default queue.
_strategies: DynArray[address, MAX_QUEUE] = self.default_queue
# If a custom queue was passed, and we don't force the default queue.
if len(strategies) != 0 and not self.use_default_queue:
# Use the custom queue.
_strategies = strategies
# load to memory to save gas
curr_total_debt: uint256 = self.total_debt
# Withdraw from strategies only what idle doesn't cover.
# `assets_needed` is the total amount we need to fill the request.
assets_needed: uint256 = unsafe_sub(requested_assets, curr_total_idle)
# `assets_to_withdraw` is the amount to request from the current strategy.
assets_to_withdraw: uint256 = 0
# To compare against real withdrawals from strategies
previous_balance: uint256 = ASSET.balanceOf(self)
for strategy in _strategies:
# Make sure we have a valid strategy.
assert self.strategies[strategy].activation != 0, "inactive strategy"
# How much should the strategy have.
current_debt: uint256 = self.strategies[strategy].current_debt
# What is the max amount to withdraw from this strategy.
assets_to_withdraw = min(assets_needed, current_debt)
# Cache max_withdraw now for use if unrealized loss > 0
# Use maxRedeem and convert since we use redeem.
max_withdraw: uint256 = IStrategy(strategy).convertToAssets(
IStrategy(strategy).maxRedeem(self)
)
# CHECK FOR UNREALISED LOSSES
# If unrealised losses > 0, then the user will take the proportional share
# and realize it (required to avoid users withdrawing from lossy strategies).
# NOTE: strategies need to manage the fact that realising part of the loss can
# mean the realisation of 100% of the loss!! (i.e. if for withdrawing 10% of the
# strategy it needs to unwind the whole position, generated losses might be bigger)
unrealised_losses_share: uint256 = self._assess_share_of_unrealised_losses(strategy, assets_to_withdraw)
if unrealised_losses_share > 0:
# If max withdraw is limiting the amount to pull, we need to adjust the portion of
# the unrealized loss the user should take.
if max_withdraw < assets_to_withdraw - unrealised_losses_share:
# How much would we want to withdraw
wanted: uint256 = assets_to_withdraw - unrealised_losses_share
# Get the proportion of unrealised comparing what we want vs. what we can get
unrealised_losses_share = unrealised_losses_share * max_withdraw / wanted
# Adjust assets_to_withdraw so all future calculations work correctly
assets_to_withdraw = max_withdraw + unrealised_losses_share
# User now "needs" less assets to be unlocked (as he took some as losses)
assets_to_withdraw -= unrealised_losses_share
requested_assets -= unrealised_losses_share
# NOTE: done here instead of waiting for regular update of these values
# because it's a rare case (so we can save minor amounts of gas)
assets_needed -= unrealised_losses_share
curr_total_debt -= unrealised_losses_share
# If max withdraw is 0 and unrealised loss is still > 0 then the strategy likely
# realized a 100% loss and we will need to realize that loss before moving on.
if max_withdraw == 0 and unrealised_losses_share > 0:
# Adjust the strategy debt accordingly.
new_debt: uint256 = current_debt - unrealised_losses_share
# Update strategies storage
self.strategies[strategy].current_debt = new_debt
# Log the debt update
log DebtUpdated(strategy, current_debt, new_debt)
# Adjust based on the max withdraw of the strategy.
assets_to_withdraw = min(assets_to_withdraw, max_withdraw)
# Can't withdraw 0.
if assets_to_withdraw == 0:
continue
# WITHDRAW FROM STRATEGY
self._withdraw_from_strategy(strategy, assets_to_withdraw)
post_balance: uint256 = ASSET.balanceOf(self)
# Always check withdrawn against the real amounts.
withdrawn: uint256 = post_balance - previous_balance
loss: uint256 = 0
# Check if we redeemed too much.
if withdrawn > assets_to_withdraw:
# Make sure we don't underflow in debt updates.
if withdrawn > current_debt:
# Can't withdraw more than our debt.
assets_to_withdraw = current_debt
else:
# Add the extra to how much we withdrew.
assets_to_withdraw += (unsafe_sub(withdrawn, assets_to_withdraw))
# If we have not received what we expected, we consider the difference a loss.
elif withdrawn < assets_to_withdraw:
loss = unsafe_sub(assets_to_withdraw, withdrawn)
# NOTE: strategy's debt decreases by the full amount but the total idle increases
# by the actual amount only (as the difference is considered lost).
curr_total_idle += (assets_to_withdraw - loss)
requested_assets -= loss
curr_total_debt -= assets_to_withdraw
# Vault will reduce debt because the unrealised loss has been taken by user
new_debt: uint256 = current_debt - (assets_to_withdraw + unrealised_losses_share)
# Update strategies storage
self.strategies[strategy].current_debt = new_debt
# Log the debt update
log DebtUpdated(strategy, current_debt, new_debt)
# Break if we have enough total idle to serve initial request.
if requested_assets <= curr_total_idle:
break
# We update the previous_balance variable here to save gas in next iteration.
previous_balance = post_balance
# Reduce what we still need. Safe to use assets_to_withdraw
# here since it has been checked against requested_assets
assets_needed -= assets_to_withdraw
# If we exhaust the queue and still have insufficient total idle, revert.
assert curr_total_idle >= requested_assets, "insufficient assets in vault"
# Commit memory to storage.
self.total_debt = curr_total_debt
# Check if there is a loss and a non-default value was set.
if assets > requested_assets and max_loss < MAX_BPS:
# Assure the loss is within the allowed range.
assert assets - requested_assets <= assets * max_loss / MAX_BPS, "too much loss"
# First burn the corresponding shares from the redeemer.
self._burn_shares(shares, owner)
# Commit memory to storage.
self.total_idle = curr_total_idle - requested_assets
# Transfer the requested amount to the receiver.
self._erc20_safe_transfer(ASSET.address, receiver, requested_assets)
log Withdraw(sender, receiver, owner, requested_assets, shares)
return requested_assets
## STRATEGY MANAGEMENT ##
@internal
def _add_strategy(new_strategy: address):
assert new_strategy not in [self, empty(address)], "strategy cannot be zero address"
assert IStrategy(new_strategy).asset() == ASSET.address, "invalid asset"
assert self.strategies[new_strategy].activation == 0, "strategy already active"
# Add the new strategy to the mapping.
self.strategies[new_strategy] = StrategyParams({
activation: block.timestamp,
last_report: block.timestamp,
current_debt: 0,
max_debt: 0
})
# If the default queue has space, add the strategy.
if len(self.default_queue) < MAX_QUEUE:
self.default_queue.append(new_strategy)
log StrategyChanged(new_strategy, StrategyChangeType.ADDED)
@internal
def _revoke_strategy(strategy: address, force: bool=False):
assert self.strategies[strategy].activation != 0, "strategy not active"
# If force revoking a strategy, it will cause a loss.
loss: uint256 = 0
if self.strategies[strategy].current_debt != 0:
assert force, "strategy has debt"
# Vault realizes the full loss of outstanding debt.
loss = self.strategies[strategy].current_debt
# Adjust total vault debt.
self.total_debt -= loss
log StrategyReported(strategy, 0, loss, 0, 0, 0, 0)
# Set strategy params all back to 0 (WARNING: it can be re-added).
self.strategies[strategy] = StrategyParams({
activation: 0,
last_report: 0,
current_debt: 0,
max_debt: 0
})
# Remove strategy if it is in the default queue.
new_queue: DynArray[address, MAX_QUEUE] = []
for _strategy in self.default_queue:
# Add all strategies to the new queue besides the one revoked.
if _strategy != strategy:
new_queue.append(_strategy)
# Set the default queue to our updated queue.
self.default_queue = new_queue
log StrategyChanged(strategy, StrategyChangeType.REVOKED)
# DEBT MANAGEMENT #
@internal
def _update_debt(strategy: address, target_debt: uint256) -> uint256:
"""
The vault will re-balance the debt vs target debt. Target debt must be
smaller or equal to strategy's max_debt. This function will compare the
current debt with the target debt and will take funds or deposit new
funds to the strategy.
The strategy can require a maximum amount of funds that it wants to receive
to invest. The strategy can also reject freeing funds if they are locked.
"""
# How much we want the strategy to have.
new_debt: uint256 = target_debt
# How much the strategy currently has.
current_debt: uint256 = self.strategies[strategy].current_debt
# If the vault is shutdown we can only pull funds.
if self.shutdown:
new_debt = 0
assert new_debt != current_debt, "new debt equals current debt"
if current_debt > new_debt:
# Reduce debt.
assets_to_withdraw: uint256 = unsafe_sub(current_debt, new_debt)
# Ensure we always have minimum_total_idle when updating debt.
minimum_total_idle: uint256 = self.minimum_total_idle
total_idle: uint256 = self.total_idle
# Respect minimum total idle in vault
if total_idle + assets_to_withdraw < minimum_total_idle:
assets_to_withdraw = unsafe_sub(minimum_total_idle, total_idle)
# Cant withdraw more than the strategy has.
if assets_to_withdraw > current_debt:
assets_to_withdraw = current_debt
# Check how much we are able to withdraw.
# Use maxRedeem and convert since we use redeem.
withdrawable: uint256 = IStrategy(strategy).convertToAssets(
IStrategy(strategy).maxRedeem(self)
)
assert withdrawable != 0, "nothing to withdraw"
# If insufficient withdrawable, withdraw what we can.
if withdrawable < assets_to_withdraw:
assets_to_withdraw = withdrawable
# If there are unrealised losses we don't let the vault reduce its debt until there is a new report
unrealised_losses_share: uint256 = self._assess_share_of_unrealised_losses(strategy, assets_to_withdraw)
assert unrealised_losses_share == 0, "strategy has unrealised losses"
# Always check the actual amount withdrawn.
pre_balance: uint256 = ASSET.balanceOf(self)
self._withdraw_from_strategy(strategy, assets_to_withdraw)
post_balance: uint256 = ASSET.balanceOf(self)
# making sure we are changing idle according to the real result no matter what.
# We pull funds with {redeem} so there can be losses or rounding differences.
withdrawn: uint256 = min(post_balance - pre_balance, current_debt)
# If we got too much make sure not to increase PPS.
if withdrawn > assets_to_withdraw:
assets_to_withdraw = withdrawn
# Update storage.
self.total_idle += withdrawn # actual amount we got.
# Amount we tried to withdraw in case of losses
self.total_debt -= assets_to_withdraw
new_debt = current_debt - assets_to_withdraw
else:
# We are increasing the strategies debt
# Revert if target_debt cannot be achieved due to configured max_debt for given strategy
assert new_debt <= self.strategies[strategy].max_debt, "target debt higher than max debt"
# Vault is increasing debt with the strategy by sending more funds.
max_deposit: uint256 = IStrategy(strategy).maxDeposit(self)
assert max_deposit != 0, "nothing to deposit"
# Deposit the difference between desired and current.
assets_to_deposit: uint256 = new_debt - current_debt
if assets_to_deposit > max_deposit:
# Deposit as much as possible.
assets_to_deposit = max_deposit
# Ensure we always have minimum_total_idle when updating debt.
minimum_total_idle: uint256 = self.minimum_total_idle
total_idle: uint256 = self.total_idle
assert total_idle > minimum_total_idle, "no funds to deposit"
available_idle: uint256 = unsafe_sub(total_idle, minimum_total_idle)
# If insufficient funds to deposit, transfer only what is free.
if assets_to_deposit > available_idle:
assets_to_deposit = available_idle
# Can't Deposit 0.
if assets_to_deposit > 0:
# Approve the strategy to pull only what we are giving it.
self._erc20_safe_approve(ASSET.address, strategy, assets_to_deposit)
# Always update based on actual amounts deposited.
pre_balance: uint256 = ASSET.balanceOf(self)
IStrategy(strategy).deposit(assets_to_deposit, self)
post_balance: uint256 = ASSET.balanceOf(self)
# Make sure our approval is always back to 0.
self._erc20_safe_approve(ASSET.address, strategy, 0)
# Making sure we are changing according to the real result no
# matter what. This will spend more gas but makes it more robust.
assets_to_deposit = pre_balance - post_balance
# Update storage.
self.total_idle -= assets_to_deposit
self.total_debt += assets_to_deposit
new_debt = current_debt + assets_to_deposit
# Commit memory to storage.
self.strategies[strategy].current_debt = new_debt
log DebtUpdated(strategy, current_debt, new_debt)
return new_debt
## ACCOUNTING MANAGEMENT ##
@internal
def _process_report(strategy: address) -> (uint256, uint256):
"""
Processing a report means comparing the debt that the strategy has taken
with the current amount of funds it is reporting. If the strategy owes
less than it currently has, it means it has had a profit, else (assets < debt)
it has had a loss.
Different strategies might choose different reporting strategies: pessimistic,
only realised P&L, ... The best way to report depends on the strategy.
The profit will be distributed following a smooth curve over the vaults
profit_max_unlock_time seconds. Losses will be taken immediately, first from the
profit buffer (avoiding an impact in pps), then will reduce pps.
Any applicable fees are charged and distributed during the report as well
to the specified recipients.
"""
# Make sure we have a valid strategy.
assert self.strategies[strategy].activation != 0, "inactive strategy"
# Burn shares that have been unlocked since the last update
self._burn_unlocked_shares()
# Vault assesses profits using 4626 compliant interface.
# NOTE: It is important that a strategies `convertToAssets` implementation
# cannot be manipulated or else the vault could report incorrect gains/losses.
strategy_shares: uint256 = IStrategy(strategy).balanceOf(self)
# How much the vaults position is worth.
total_assets: uint256 = IStrategy(strategy).convertToAssets(strategy_shares)
# How much the vault had deposited to the strategy.
current_debt: uint256 = self.strategies[strategy].current_debt
gain: uint256 = 0
loss: uint256 = 0
# Compare reported assets vs. the current debt.
if total_assets > current_debt:
# We have a gain.
gain = unsafe_sub(total_assets, current_debt)
else:
# We have a loss.
loss = unsafe_sub(current_debt, total_assets)
# For Accountant fee assessment.
total_fees: uint256 = 0
total_refunds: uint256 = 0
# For Protocol fee assessment.
protocol_fees: uint256 = 0
protocol_fee_recipient: address = empty(address)
accountant: address = self.accountant
# If accountant is not set, fees and refunds remain unchanged.
if accountant != empty(address):
total_fees, total_refunds = IAccountant(accountant).report(strategy, gain, loss)
# Protocol fees will be 0 if accountant fees are 0.
if total_fees > 0:
protocol_fee_bps: uint16 = 0
# Get the config for this vault.
protocol_fee_bps, protocol_fee_recipient = IFactory(FACTORY).protocol_fee_config()
if(protocol_fee_bps > 0):
# Protocol fees are a percent of the fees the accountant is charging.
protocol_fees = total_fees * convert(protocol_fee_bps, uint256) / MAX_BPS
# `shares_to_burn` is derived from amounts that would reduce the vaults PPS.
# NOTE: this needs to be done before any pps changes
shares_to_burn: uint256 = 0
accountant_fees_shares: uint256 = 0
protocol_fees_shares: uint256 = 0
# Only need to burn shares if there is a loss or fees.
if loss + total_fees > 0:
# The amount of shares we will want to burn to offset losses and fees.
shares_to_burn += self._convert_to_shares(loss + total_fees, Rounding.ROUND_UP)
# Vault calculates the amount of shares to mint as fees before changing totalAssets / totalSupply.
if total_fees > 0:
# Accountant fees are total fees - protocol fees.
accountant_fees_shares = self._convert_to_shares(total_fees - protocol_fees, Rounding.ROUND_DOWN)
if protocol_fees > 0:
protocol_fees_shares = self._convert_to_shares(protocol_fees, Rounding.ROUND_DOWN)
# Shares to lock is any amounts that would otherwise increase the vaults PPS.
newly_locked_shares: uint256 = 0
if total_refunds > 0:
# Make sure we have enough approval and enough asset to pull.
total_refunds = min(total_refunds, min(ASSET.balanceOf(accountant), ASSET.allowance(accountant, self)))
# Transfer the refunded amount of asset to the vault.
self._erc20_safe_transfer_from(ASSET.address, accountant, self, total_refunds)
# Update storage to increase total assets.
self.total_idle += total_refunds
# Record any reported gains.
if gain > 0:
# NOTE: this will increase total_assets
self.strategies[strategy].current_debt += gain
self.total_debt += gain
profit_max_unlock_time: uint256 = self.profit_max_unlock_time
# Mint anything we are locking to the vault.
if gain + total_refunds > 0 and profit_max_unlock_time != 0:
newly_locked_shares = self._issue_shares_for_amount(gain + total_refunds, self)
# Strategy is reporting a loss
if loss > 0:
self.strategies[strategy].current_debt -= loss
self.total_debt -= loss
# NOTE: should be precise (no new unlocked shares due to above's burn of shares)
# newly_locked_shares have alread...
// [truncated — 79627 bytes total]
Read Contract
DOMAIN_SEPARATOR 0x3644e515 → bytes32
FACTORY 0x2dd31000 → address
accountant 0x4fb3ccc5 → address
allowance 0xdd62ed3e → uint256
apiVersion 0x25829410 → string
assess_share_of_unrealised_losses 0x66d3ae57 → uint256
asset 0x38d52e0f → address
balanceOf 0x70a08231 → uint256
convertToAssets 0x07a2d13a → uint256
convertToShares 0xc6e6f592 → uint256
decimals 0x313ce567 → uint8
default_queue 0x8bf03b9e → address
deposit_limit 0xe46a5797 → uint256
deposit_limit_module 0x61c2ccf4 → address
fullProfitUnlockDate 0x2d632692 → uint256
future_role_manager 0x9a98f418 → address
get_default_queue 0xa9bbf1cc → address[]
isShutdown 0xbf86d690 → bool
lastProfitUpdate 0x8afca8f0 → uint256
maxDeposit 0x402d267d → uint256
maxMint 0xc63d75b6 → uint256
maxRedeem 0xd905777e → uint256
maxRedeem 0x4abe4137 → uint256
maxRedeem 0x34b5fab6 → uint256
maxWithdraw 0xce96cb77 → uint256
maxWithdraw 0x85b68756 → uint256
maxWithdraw 0x65cb6765 → uint256
minimum_total_idle 0x356d6409 → uint256
name 0x06fdde03 → string
nonces 0x7ecebe00 → uint256
open_roles 0xf3789e45 → bool
previewDeposit 0xef8b30f7 → uint256
previewMint 0xb3d7f6b9 → uint256
previewRedeem 0x4cdad506 → uint256
previewWithdraw 0x0a28a477 → uint256
pricePerShare 0x99530b06 → uint256
profitMaxUnlockTime 0x0952864e → uint256
profitUnlockingRate 0x5141eebb → uint256
role_manager 0x79b98917 → address
roles 0x99374642 → uint256
strategies 0x39ebf823 → tuple
symbol 0x95d89b41 → string
totalAssets 0x01e1d114 → uint256
totalDebt 0xfc7b9c18 → uint256
totalIdle 0x9aa7df94 → uint256
totalSupply 0x18160ddd → uint256
total_supply 0x3940e9ee → uint256
unlockedShares 0xd9a0e97a → uint256
use_default_queue 0x1e56558d → bool
withdraw_limit_module 0xf5ba68f3 → address
Write Contract 37 functions
These functions modify contract state and require a wallet transaction to execute.
accept_role_manager 0xf776bf1f
No parameters
add_role 0xa97cefa2
address account
uint256 role
add_strategy 0xde7aeb41
address new_strategy
approve 0x095ea7b3
address spender
uint256 amount
returns: bool
buy_debt 0xe5e91818
address strategy
uint256 amount
close_open_role 0xd52fe498
uint256 role
decreaseAllowance 0xa457c2d7
address spender
uint256 amount
returns: bool
deposit 0x6e553f65
uint256 assets
address receiver
returns: uint256
force_revoke_strategy 0xfd129e63
address strategy
increaseAllowance 0x39509351
address spender
uint256 amount
returns: bool
mint 0x94bf804d
uint256 shares
address receiver
returns: uint256
permit 0xd505accf
address owner
address spender
uint256 amount
uint256 deadline
uint8 v
bytes32 r
bytes32 s
returns: bool
process_report 0x6ec2b8d4
address strategy
returns: uint256, uint256
redeem 0xba087652
uint256 shares
address receiver
address owner
returns: uint256
redeem 0x9f40a7b3
uint256 shares
address receiver
address owner
uint256 max_loss
returns: uint256
redeem 0x06580f2d
uint256 shares
address receiver
address owner
uint256 max_loss
address[] strategies
returns: uint256
remove_role 0xe2bf56dd
address account
uint256 role
revoke_strategy 0x577db316
address strategy
setProfitMaxUnlockTime 0xdf69b22a
uint256 new_profit_max_unlock_time
set_accountant 0x71da8a8d
address new_accountant
set_default_queue 0x2d9caa4e
address[] new_default_queue
set_deposit_limit 0x6fe01d1e
uint256 deposit_limit
set_deposit_limit_module 0xbb435466
address deposit_limit_module
set_minimum_total_idle 0xbdd81c01
uint256 minimum_total_idle
set_open_role 0x0b10dd80
uint256 role
set_role 0x2cf7fd85
address account
uint256 role
set_use_default_queue 0x29c8a33b
bool use_default_queue
set_withdraw_limit_module 0x7b675894
address withdraw_limit_module
shutdown_vault 0x36a55450
No parameters
transfer 0xa9059cbb
address receiver
uint256 amount
returns: bool
transferFrom 0x23b872dd
address sender
address receiver
uint256 amount
returns: bool
transfer_role_manager 0xef54cefd
address role_manager
update_debt 0x0aeebf55
address strategy
uint256 target_debt
returns: uint256
update_max_debt_for_strategy 0xb9ddcd68
address strategy
uint256 new_max_debt
withdraw 0xb460af94
uint256 assets
address receiver
address owner
returns: uint256
withdraw 0xa318c1a4
uint256 assets
address receiver
address owner
uint256 max_loss
returns: uint256
withdraw 0xd81a09f6
uint256 assets
address receiver
address owner
uint256 max_loss
address[] strategies
returns: uint256
Recent Transactions
No transactions found for this address