Address Contract Partially Verified
Address
0x671a912C10bba0CFA74Cfc2d6Fba9BA1ed9530B2
Balance
0 ETH
Nonce
1
Code Size
21325 bytes
Creator
0xa1160494...D35A at tx 0x78b4dc71...e5b4b7
Indexed Transactions
0
Contract Bytecode
21325 bytes
0x600436101561000d57613ebb565b600035601c52600051341561002157600080fd5b6383b4358981141561003c57336102205233610240526100b6565b63a5b81fdf81141561006d57336102405260a43560a01c1561005d57600080fd5b602060a4610220376000506100b6565b63538baeab8114156100b15760a43560a01c1561008957600080fd5b602060a46102203760c43560a01c156100a157600080fd5b602060c4610240376000506100b6565b610714565b60043560a01c156100c657600080fd5b60243560a01c156100d657600080fd5b60443560a01c156100e657600080fd5b606060643560040161014037604060643560040135111561010657600080fd5b60406084356004016101c037602060843560040135111561012657600080fd5b6012541561013357600080fd5b60043560065560006102a0526102a0805160208201209050610140805160208201209050141561027a576000606061034060046395d89b416102e0526102fc6004355afa61018057600080fd5b603f3d1161018d57600080fd5b6015610340610340510151106101a257600080fd5b60005061036060148060208461040001018260208501600060045af150508051820191505060076103a0527f20795661756c74000000000000000000000000000000000000000000000000006103c0526103a060078060208461040001018260208501600060045af15050805182019150508061040052610400905080600060c052602060c020602082510161012060006002818352015b8261012051602002111561024d5761026f565b61012051602002850151610120518501555b815160010180835281141561023a575b5050505050506102d5565b61014080600060c052602060c020602082510161012060006003818352015b826101205160200211156102ac576102ce565b61012051602002850151610120518501555b8151600101808352811415610299575b5050505050505b60006102a0526102a08051602082012090506101c0805160208201209050141561041657600060026102e0527f7976000000000000000000000000000000000000000000000000000000000000610300526102e060028060208461040001018260208501600060045af150508051820191505060606103a060046395d89b416103405261035c6004355afa61036957600080fd5b603f3d1161037657600080fd5b60156103a06103a05101511061038b57600080fd5b6000506103c060148060208461040001018260208501600060045af15050805182019150508061040052610400905080600160c052602060c020602082510161012060006002818352015b826101205160200211156103e95761040b565b61012051602002850151610120518501555b81516001018083528114156103d6575b505050505050610471565b6101c080600160c052602060c020602082510161012060006002818352015b826101205160200211156104485761046a565b61012051602002850151610120518501555b8151600101808352811415610435575b5050505050505b60206102e0600463313ce5676102805261029c6004355afa61049257600080fd5b601f3d1161049f57600080fd5b6000506102e051610260526102605160025561010061026051106104c257600080fd5b602435600755602435610280527f8d55d160c0009eb3d739442df0a3ca089ed64378bfac017e7ddad463f9815b876020610280a16102405160085561024051610280527fff54978127edd34aec0f9061fb3b155fbe0ededdfa881ee3e0d541d3a1eef4386020610280a1604435601555604435610280527fdf3c41a916aecbf42361a147f8348c242662c3ce20ecef30e826b80642477a3d6020610280a16102205160095561022051610280527f837b9ad138a0a1839a9637afce5306a5c13e23eb63365686843a5319a243609c6020610280a16103e86017556103e861028052610280516102a0527f0810a1c261ca2c0cd86a0152c51c43ba9dc329639d2349f98140891b2ea798eb60206102a0a160c860165560c861028052610280516102a0527f7a7883b0074f96e2c7fab65eb25abf624c488761a5db889e3bb84855dcc6daaf60206102a0a142601155426012556529d635a8e00060145560007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f602082610660010152602081019050600b610540527f596561726e205661756c74000000000000000000000000000000000000000000610560526105408051602082012090506020826106600101526020810190506005610600527f302e342e3200000000000000000000000000000000000000000000000000000061062052610600805160208201209050602082610660010152602081019050466020826106600101526020810190503060208261066001015260208101905080610660526106609050805160208201209050601955005b63258294108114156107a9576005610140527f302e342e32000000000000000000000000000000000000000000000000000000610160526101408051602001806101e08284600060045af161076857600080fd5b50506101e0518061020001818260206001820306601f820103905003368237505060206101c05260406101e0510160206001820306601f82010390506101c0f35b63c47f002781141561083f57604a60043560040161014037602a6004356004013511156107d557600080fd5b60075433146107e357600080fd5b61014080600060c052602060c020602082510161012060006003818352015b8261012051602002111561081557610837565b61012051602002850151610120518501555b8151600101808352811415610802575b505050505050005b63b84c82468114156108d557603460043560040161014037601460043560040135111561086b57600080fd5b600754331461087957600080fd5b61014080600160c052602060c020602082510161012060006002818352015b826101205160200211156108ab576108cd565b61012051602002850151610120518501555b8151600101808352811415610898575b505050505050005b63ab033ea98114156109075760043560a01c156108f157600080fd5b60075433146108ff57600080fd5b600435600a55005b63238efcbc81141561095357600a54331461092157600080fd5b3360075533610140527f8d55d160c0009eb3d739442df0a3ca089ed64378bfac017e7ddad463f9815b876020610140a1005b63d4a22bde8114156109b35760043560a01c1561096f57600080fd5b600754331461097d57600080fd5b600435600855600435610140527fff54978127edd34aec0f9061fb3b155fbe0ededdfa881ee3e0d541d3a1eef4386020610140a1005b63ec38a862811415610a725760043560a01c156109cf57600080fd5b60075433146109dd57600080fd5b306101605260006101805260006101405261014061012060006002818352015b6101205160200261016001516004351415610a1b5760018352610a2b565b81516001018083528114156109fd575b5050506101405115610a3c57600080fd5b600435601555600435610140527fdf3c41a916aecbf42361a147f8348c242662c3ce20ecef30e826b80642477a3d6020610140a1005b637a550365811415610aab576007543314610a8c57600080fd5b670de0b6b3a76400006004351115610aa357600080fd5b600435601455005b63bdc8144b811415610afb576007543314610ac557600080fd5b600435600e55600435610140527fae565aab888bca5e19e25a13db7b0c9144305bf55cb0f3f4d724f730e5acdd626020610140a1005b6370897b23811415610b5c576007543314610b1557600080fd5b6113886004351115610b2657600080fd5b600435601755600435610140527f0810a1c261ca2c0cd86a0152c51c43ba9dc329639d2349f98140891b2ea798eb6020610140a1005b63fe56e232811415610bbd576007543314610b7657600080fd5b6127106004351115610b8757600080fd5b600435601655600435610140527f7a7883b0074f96e2c7fab65eb25abf624c488761a5db889e3bb84855dcc6daaf6020610140a1005b638a0dac4a811415610c6e5760043560a01c15610bd957600080fd5b600954610160526007546101805260006101405261014061012060006002818352015b610120516020026101600151331415610c185760018352610c28565b8151600101808352811415610bfc575b50505061014051610c3857600080fd5b600435600955600435610140527f837b9ad138a0a1839a9637afce5306a5c13e23eb63365686843a5319a243609c6020610140a1005b6314c64402811415610d3a5760043560011c15610c8a57600080fd5b60043515610cf657600954610160526007546101805260006101405261014061012060006002818352015b610120516020026101600151331415610cd15760018352610ce1565b8151600101808352811415610cb5575b50505061014051610cf157600080fd5b610d04565b6007543314610d0457600080fd5b600435600d55600435610140527fba40372a3a724dca3c57156128ef1e896724b65b37a17f190b1ad5de68f3a4f36020610140a1005b63941484158114156110c0576000610120525b610120516004013560a01c15610d6257600080fd5b6020610120510161012052610280610120511015610d7f57610d4d565b600854610160526007546101805260006101405261014061012060006002818352015b610120516020026101600151331415610dbe5760018352610dce565b8151600101808352811415610da2575b50505061014051610dde57600080fd5b61028036610140376103c060006014818352015b6103c05160148110610e0357600080fd5b600c60c052602060c02001546101406103c05160148110610e2357600080fd5b602002015260046103c05160148110610e3b57600080fd5b60200201351515610e6e576101406103c05160148110610e5a57600080fd5b602002015115610e6957600080fd5b610ffc565b60006101406103c05160148110610e8457600080fd5b602002015118610e9357600080fd5b60006001600b60046103c05160148110610eac57600080fd5b602002013560e05260c052604060c02060c052602060c020015411610ed057600080fd5b60006103e05261040060006014818352015b60046104005160148110610ef557600080fd5b60200201351515610f0b5760016103e052610fa7565b6101406104005160148110610f1f57600080fd5b602002015160046103c05160148110610f3757600080fd5b60200201351415610f495760016103e0525b6103c05161040051111515610f5d57610f97565b60046104005160148110610f7057600080fd5b602002013560046103c05160148110610f8857600080fd5b602002013518610f9757600080fd5b8151600101808352811415610ee2575b50506103e051610fb657600080fd5b60046103c05160148110610fc957600080fd5b60200201356103c05160148110610fdf57600080fd5b600c60c052602060c02001555b8151600101808352811415610df2575b50506004356103c0526024356103e05260443561040052606435610420526084356104405260a4356104605260c4356104805260e4356104a052610104356104c052610124356104e0526101443561050052610164356105205261018435610540526101a435610560526101c435610580526101e4356105a052610204356105c052610224356105e052610244356106005261026435610620527f695ac3ac73f08f2002284ffe563cefe798ee2878a5e04219522e2e99eb89d1686102806103c0a1005b63a9059cbb8114156111125760043560a01c156110dc57600080fd5b336101405260043561016052602435610180526101805161016051610140516006580161420c565b600050600160005260206000f35b6323b872dd8114156112475760043560a01c1561112e57600080fd5b60243560a01c1561113e57600080fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600460043560e05260c052604060c0203360e05260c052604060c02054101561120f57600460043560e05260c052604060c0203360e05260c052604060c02054604435808210156111af57600080fd5b808203905090506101405261014051600460043560e05260c052604060c0203360e05260c052604060c020556101405161016052336004357f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9256020610160a35b6004356101405260243561016052604435610180526101805161016051610140516006580161420c565b600050600160005260206000f35b63095ea7b38114156112c05760043560a01c1561126357600080fd5b60243560043360e05260c052604060c02060043560e05260c052604060c0205560243561014052600435337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9256020610140a3600160005260206000f35b633950935181141561136d5760043560a01c156112dc57600080fd5b60043360e05260c052604060c02060043560e05260c052604060c020805460243581818301101561130c57600080fd5b8082019050905081555060043360e05260c052604060c02060043560e05260c052604060c0205461014052600435337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9256020610140a3600160005260206000f35b63a457c2d78114156114185760043560a01c1561138957600080fd5b60043360e05260c052604060c02060043560e05260c052604060c0208054602435808210156113b757600080fd5b8082039050905081555060043360e05260c052604060c02060043560e05260c052604060c0205461014052600435337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9256020610140a3600160005260206000f35b639fd5a6cf8114156118155760043560a01c1561143457600080fd5b60243560a01c1561144457600080fd5b606160843560040161014037604160843560040135111561146457600080fd5b60006004351861147357600080fd5b606435151561148357600161148a565b4260643510155b61149357600080fd5b601860043560e05260c052604060c020546101e05260006002610520527f19010000000000000000000000000000000000000000000000000000000000006105405261052060028060208461078001018260208501600060045af150508051820191505060195460208261078001015260208101905060007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c96020826106800101526020810190506004356020826106800101526020810190506024356020826106800101526020810190506044356020826106800101526020810190506101e0516020826106800101526020810190506064356020826106800101526020810190508061068052610680905080516020820120905060208261078001015260208101905080610780526107809050805160208201209050610200526000602060208206610300016101405182840111156115ed57600080fd5b6041806103208260206020880688030161014001600060045af150508181528090509050905080602001516000825180602090131561162b57600080fd5b809190121561163957600080fd5b806020036101000a82049050905090506102205260206020602082066103200161014051828401111561166b57600080fd5b6041806103408260206020880688030161014001600060045af15050818152809050905090508060200151600082518060209013156116a957600080fd5b80919012156116b757600080fd5b806020036101000a8204905090509050610240526040600160208206610340016101405182840111156116e957600080fd5b6041806103608260206020880688030161014001600060045af150508181528090509050905080602001516000825180602090131561172757600080fd5b809190121561173557600080fd5b806020036101000a8204905090509050610260526004356102005161028052610260516102a052610220516102c052610240516102e052602060c0608061028060015afa5060c0511461178757600080fd5b604435600460043560e05260c052604060c02060243560e05260c052604060c020556101e05160018181830110156117be57600080fd5b80820190509050601860043560e05260c052604060c02055604435610280526024356004357f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9256020610280a3600160005260206000f35b6301e1d11481141561183b5760065801614317565b610140526101405160005260206000f35b63d0e30db0811415611876577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101405233610160526118d0565b63b6b55f2581141561189757336101605260206004610140376000506118d0565b636e553f658114156118cb57602060046101403760243560a01c156118bb57600080fd5b60206024610160376000506118d0565b611b2e565b601a54156118dd57600080fd5b6001601a55600d54156118ef57600080fd5b306101a05260006101c05260006101805261018061012060006002818352015b610120516020026101a0015161016051141561192e576001835261193e565b815160010180835281141561190f575b505050610180511561194f57600080fd5b61014051610180527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610180511415611a1957600e5461014051610160516101805160065801614317565b6101a0526101805261016052610140526101a051808210156119bb57600080fd5b80820390509050602061024060246370a082316101c052336101e0526101dc6006545afa6119e857600080fd5b601f3d116119f557600080fd5b6000506102405180821115611a0a5780611a0c565b815b9050905061018052611a6a565b600e5461014051610160516101805160065801614317565b6101a0526101805261016052610140526101a05161018051818183011015611a5857600080fd5b808201905090501115611a6a57600080fd5b60006101805111611a7a57600080fd5b6101405161016051610180516101a051610160516101c052610180516101e0526101e0516101c0516006580161443d565b610240526101a052610180526101605261014052610240516101a0526101405161016051610180516101a0516006546101c052336101e0523061020052610180516102205261022051610200516101e0516101c0516006580161405b565b6101a0526101805261016052610140526000506101a0516000526000601a5560206000f35b6375de2902811415611c8c5760206101e060246370a0823161016052306101805261017c6006545afa611b6057600080fd5b601f3d11611b6d57600080fd5b6000506101e051610200526101405161016051610180516101a0516101c0516101e05161020051610200516102205261022051600658016146ca565b61028052610200526101e0526101c0526101a052610180526101605261014052610280516101405261018060006014818352015b61018051600c60c052602060c020015461016052610160511515611c0057611c7d565b61014080516101405161016051610180516006600b6101605160e05260c052604060c02060c052602060c02001546101a0526101a051600658016146ca565b6102005261018052610160526101405261020051818183011015611c6257600080fd5b808201905090508152505b8151600101808352811415611bdd575b50506101405160005260206000f35b633ccfd60b811415611ccd577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610140523361016052600161018052611d6e565b632e1a7d4d811415611cf45733610160526001610180526020600461014037600050611d6e565b62f714ce811415611d2d57600161018052602060046101403760243560a01c15611d1d57600080fd5b6020602461016037600050611d6e565b63e63697c8811415611d6957602060046101403760243560a01c15611d5157600080fd5b60206024610160376020604461018037600050611d6e565b612383565b601a5415611d7b57600080fd5b6001601a55610140516101a052612710610180511115611d9a57600080fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101a0511415611dd95760033360e05260c052604060c020546101a0525b60033360e05260c052604060c020546101a0511115611df757600080fd5b60006101a05111611e0757600080fd5b6101405161016051610180516101a0516101c0516101a0516101e0526101e051600658016145f4565b610240526101c0526101a052610180526101605261014052610240516101c05260006101e052602061028060246370a0823161020052306102205261021c6006545afa611e7c57600080fd5b601f3d11611e8957600080fd5b600050610280516101c0511115612240576102c060006014818352015b6102c051600c60c052602060c02001546102a0526102a0511515611ec95761214e565b602061038060246370a0823161030052306103205261031c6006545afa611eef57600080fd5b601f3d11611efc57600080fd5b600050610380516102e0526102e0516101c051111515611f1b5761214e565b6101c0516102e05180821015611f3057600080fd5b8082039050905061030052610300516006600b6102a05160e05260c052604060c02060c052602060c020015480821115611f6a5780611f6c565b815b9050905061030052610300511515611f835761213e565b60206103c06024632e1a7d4d61034052610300516103605261035c60006102a0515af1611faf57600080fd5b601f3d11611fbc57600080fd5b6000506103c0516103205260206103e060246370a0823161036052306103805261037c6006545afa611fed57600080fd5b601f3d11611ffa57600080fd5b6000506103e0516102e0518082101561201257600080fd5b808203905090506103405260006103205111156120e5576101c08051610320518082101561203f57600080fd5b808203905090508152506101e080516103205181818301101561206157600080fd5b80820190509050815250610140610360525b6103605151602061036051016103605261036061036051101561209557612073565b6102a05161038052610320516103a0526103a0516103805160065801614777565b610340610360525b61036051526020610360510361036052610140610360511015156120e1576120be565b6000505b6006600b6102a05160e05260c052604060c02060c052602060c020018054610340518082101561211457600080fd5b8082039050905081555060108054610340518082101561213357600080fd5b808203905090508155505b8151600101808352811415611ea6575b5050602061034060246370a082316102c052306102e0526102dc6006545afa61217657600080fd5b601f3d1161218357600080fd5b600050610340516102a0526102a0516101c0511115612240576102a0516101c0526101405161016051610180516101a0516101c0516101e05161020051610220516102405161026051610280516102a0516101c0516101e0518181830110156121eb57600080fd5b808201905090506102c0526102c051600658016146ca565b610320526102a05261028052610260526102405261022052610200526101e0526101c0526101a052610180526101605261014052610320516101a0525b610180516101c0516101e05181818301101561225b57600080fd5b80820190509050808202821582848304141761227657600080fd5b80905090509050612710808204905090506101e051111561229657600080fd5b600580546101a051808210156122ab57600080fd5b8082039050905081555060033360e05260c052604060c02080546101a051808210156122d657600080fd5b808203905090508155506101a051610200526000337fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6020610200a36101405161016051610180516101a0516101c0516101e0516006546102005261016051610220526101c0516102405261024051610220516102005160065801613ec1565b6101e0526101c0526101a0526101805261016052610140526000506101c0516000526000601a5560206000f35b6399530b068114156123c657604e6002541061239e57600080fd5b600254600a0a6101405261014051600658016145f4565b6101a0526101a05160005260206000f35b6314b4e26e8114156125f45760043560a01c156123e257600080fd5b6013600c60c052602060c0200154156123fa57600080fd5b600d541561240757600080fd5b600754331461241557600080fd5b60006004351861242457600080fd5b6001600b60043560e05260c052604060c02060c052602060c02001541561244a57600080fd5b60206101a0600463fbfa77cf6101405261015c6004355afa61246b57600080fd5b601f3d1161247857600080fd5b6000506101a051301461248a57600080fd5b60206101a06004631f1fcd516101405261015c6004355afa6124ab57600080fd5b601f3d116124b857600080fd5b6000506101a051600654146124cc57600080fd5b612710600f546024358181830110156124e457600080fd5b8082019050905011156124f657600080fd5b606435604435111561250757600080fd5b611388608435111561251857600080fd5b600b60043560e05260c052604060c02060c052602060c0206084358155426001820155602435600282015560443560038201556064356004820155426005820155600060068201556000600782015560006008820155506024356101405260443561016052606435610180526084356101a0526004357f5a6abd2af9fe6c0554fa08649e2d86e4393ff19dc304d072d38d295c9291d4dc6080610140a2600f80546024358181830110156125cb57600080fd5b808201905090508155506004356013600c60c052602060c02001556006580161491f565b600050005b637c6a4f248114156127515760043560a01c1561261057600080fd5b600854610160526007546101805260006101405261014061012060006002818352015b61012051602002610160015133141561264f576001835261265f565b8151600101808352811415612633575b5050506101405161266f57600080fd5b60006001600b60043560e05260c052604060c02060c052602060c02001541161269757600080fd5b600f80546002600b60043560e05260c052604060c02060c052602060c0200154808210156126c457600080fd5b808203905090508155506024356002600b60043560e05260c052604060c02060c052602060c0200155600f805460243581818301101561270357600080fd5b80820190509050815550612710600f54111561271e57600080fd5b602435610140526004357fbda9398315c83ccef012bcaa318a2ff7b680f36429d36597bd4bc25ac11ead596020610140a2005b63e722befe8114156128705760043560a01c1561276d57600080fd5b600854610160526007546101805260006101405261014061012060006002818352015b6101205160200261016001513314156127ac57600183526127bc565b8151600101808352811415612790575b505050610140516127cc57600080fd5b60006001600b60043560e05260c052604060c02060c052602060c0200154116127f457600080fd5b6024356004600b60043560e05260c052604060c02060c052602060c0200154101561281e57600080fd5b6024356003600b60043560e05260c052604060c02060c052602060c0200155602435610140526004357f0b728ad785976532c4aaadde09b1cba5f262a7090e83c62d2377bc405678b29c6020610140a2005b634757a15681141561298f5760043560a01c1561288c57600080fd5b600854610160526007546101805260006101405261014061012060006002818352015b6101205160200261016001513314156128cb57600183526128db565b81516001018083528114156128af575b505050610140516128eb57600080fd5b60006001600b60043560e05260c052604060c02060c052602060c02001541161291357600080fd5b6024356003600b60043560e05260c052604060c02060c052602060c0200154111561293d57600080fd5b6024356004600b60043560e05260c052604060c02060c052602060c0200155602435610140526004357f1796a8e0760e2de5b72e7bf64fccb7666c48ceab94cb6cae7cb7eff4b6f641ab6020610140a2005b63d0194ed6811415612a415760043560a01c156129ab57600080fd5b60075433146129b957600080fd5b61138860243511156129ca57600080fd5b60006001600b60043560e05260c052604060c02060c052602060c0200154116129f257600080fd5b602435600b60043560e05260c052604060c02060c052602060c02055602435610140526004357fe57488a65fa53066d4c25bac90db47dda4e5de3025ac12bf76ff07211cf7f39e6020610140a2005b636cb56d19811415612d595760043560a01c15612a5d57600080fd5b60243560a01c15612a6d57600080fd5b6007543314612a7b57600080fd5b600060243518612a8a57600080fd5b60006001600b60043560e05260c052604060c02060c052602060c020015411612ab257600080fd5b6001600b60243560e05260c052604060c02060c052602060c020015415612ad857600080fd5b610140600b60043560e05260c052604060c0208060c052602060c02054825260018160c052602060c0200154826020015260028160c052602060c0200154826040015260038160c052602060c0200154826060015260048160c052602060c0200154826080015260058160c052602060c02001548260a0015260068160c052602060c02001548260c0015260078160c052602060c02001548260e0015260088160c052602060c020015482610100015250506101405161016051610180516101a0516101c0516101e051610200516102205161024051600435610260526102605160065801614a02565b6102405261022052610200526101e0526101c0526101a052610180526101605261014052600050600f805461018051818183011015612c0057600080fd5b8082019050905081555060006006600b60043560e05260c052604060c02060c052602060c0200155600b60243560e05260c052604060c02060c052602060c0206101405181556101e05160018201556101805160028201556101a05160038201556101c05160048201556101e05160058201556102005160068201556000600782015560006008820155506004353b612c9857600080fd5b60006000602463ce5494bb610260526024356102805261027c60006004355af1612cc157600080fd5b6024356004357f100b69bb6b504e1252e36b375233158edee64d071b399e2f81473a695fd1b02160006000a361026060006014818352015b6004356102605160148110612d0d57600080fd5b600c60c052602060c02001541415612d45576024356102605160148110612d3357600080fd5b600c60c052602060c020015560006000f35b8151600101808352811415612cf9575b5050005b63a0e4af9a811415612d6f573361014052612da0565b63bb994d48811415612d9b5760043560a01c15612d8b57600080fd5b6020600461014037600050612da0565b612e52565b61014051610180526007546101a0526009546101c05260006101605261016061012060006003818352015b610120516020026101800151331415612de75760018352612df7565b8151600101808352811415612dcb575b50505061016051612e0757600080fd5b60006002600b6101405160e05260c052604060c02060c052602060c020015418612e3057600080fd5b6101405161014051610160526101605160065801614a02565b61014052600050005b63f76e4caa811415612fce5760043560a01c15612e6e57600080fd5b600854610160526007546101805260006101405261014061012060006002818352015b610120516020026101600151331415612ead5760018352612ebd565b8151600101808352811415612e91575b50505061014051612ecd57600080fd5b60006001600b60043560e05260c052604060c02060c052602060c020015411612ef557600080fd5b60006101405261018060006014818352015b61018051600c60c052602060c020015461016052610160511515612f2a57612f6c565b6004356101605118612f3b57600080fd5b61014080516001818183011015612f5157600080fd5b808201905090508152505b8151600101808352811415612f07575b505060146101405110612f7e57600080fd5b6004356013600c60c052602060c0200155610140516006580161491f565b610140526000506004357fa8727d412c6fa1e2497d6d6f275e2d9fe4d9318d5b793632e60ad9d38ee8f1fa60006000a2005b63b22439f58114156130f55760043560a01c15612fea57600080fd5b600854610160526007546101805260006101405261014061012060006002818352015b6101205160200261016001513314156130295760018352613039565b815160010180835281141561300d575b5050506101405161304957600080fd5b61014060006014818352015b600435610140516014811061306957600080fd5b600c60c052602060c020015414156130dd576000610140516014811061308e57600080fd5b600c60c052602060c0200155610140516006580161491f565b610140526000506004357f8e1ec3c16d6a67ea8effe2ac7adef9c2de0bc0dc47c49cdf18f6a8b0048085be60006000a260006000f35b8151600101808352811415613055575b505060006000fd5b63bf3759b581141561310b57336101405261313c565b63bdcf36bb8114156131375760043560a01c1561312757600080fd5b602060046101403760005061313c565b61316a565b6101405161014051610160526101605160065801614a91565b6101c052610140526101c05160005260206000f35b63112c1f9b8114156131805733610140526131b1565b63d76480138114156131ac5760043560a01c1561319c57600080fd5b60206004610140376000506131b1565b6131df565b6101405161014051610160526101605160065801614bc2565b6101c052610140526101c05160005260206000f35b63153c27c481141561324f5760065801614317565b6101405261014051600e54111561324257600e546101405160065801614317565b6101605261014052610160518082101561322e57600080fd5b8082039050905060005260206000f361324d565b600060005260206000f35b005b63d3406abd811415613265573361014052613296565b6333586b678114156132915760043560a01c1561328157600080fd5b6020600461014037600050613296565b6132c4565b6101405161014051610160526101605160065801614e1d565b6101c052610140526101c05160005260206000f35b63a1d9bafc81141561387d5760006001600b3360e05260c052604060c02060c052602060c0200154116132f657600080fd5b60043560443581818301101561330b57600080fd5b8082019050905060206101c060246370a0823161014052336101605261015c6006545afa61333857600080fd5b601f3d1161334557600080fd5b6000506101c051101561335757600080fd5b6000602435111561338357336101405260243561016052610160516101405160065801614777565b6000505b61014051336101605260043561018052610180516101605160065801614f70565b6101e052610140526101e051610140526007600b3360e05260c052604060c02060c052602060c0200180546004358181830110156133e157600080fd5b80820190509050815550610140516101605133610180526101805160065801614bc2565b6101e05261016052610140526101e05161016052610140516101605161018051336101a0526101a05160065801614a91565b61020052610180526101605261014052610200516101805260443561018051808211156134645780613466565b815b905090506101a05260006101a05111156134f0576006600b3360e05260c052604060c02060c052602060c0200180546101a051808210156134a657600080fd5b80820390509050815550601080546101a051808210156134c557600080fd5b8082039050905081555061018080516101a051808210156134e557600080fd5b808203905090508152505b6000610160511115613556576006600b3360e05260c052604060c02060c052602060c0200180546101605181818301101561352a57600080fd5b80820190509050815550601080546101605181818301101561354b57600080fd5b808201905090508155505b6004356101a05181818301101561356c57600080fd5b808201905090506101c052610160516101c05110156135f6576101405161016051610180516101a0516101c0516006546101e0523361020052610160516101c051808210156135ba57600080fd5b808203905090506102205261022051610200516101e05160065801613ec1565b6101c0526101a05261018052610160526101405260005061367a565b610160516101c051111561367a576101405161016051610180516101a0516101c0516006546101e052336102005230610220526101c051610160518082101561363e57600080fd5b80820390509050610240526102405161022051610200516101e0516006580161405b565b6101c0526101a0526101805261016052610140526000505b6101405161016051610180516101a0516101c0516101e0516006580161437a565b610200526101e0526101c0526101a052610180526101605261014052610200516004358181830110156136cd57600080fd5b8082019050905061014051808210156136e557600080fd5b808203905090506101e0526024356101e0511115613720576101e0516024358082101561371157600080fd5b80820390509050601355613726565b60006013555b426005600b3360e05260c052604060c02060c052602060c02001554260115560406004610200376101a051610240526007600b3360e05260c052604060c02060c052602060c0200154610260526008600b3360e05260c052604060c02060c052602060c0200154610280526006600b3360e05260c052604060c02060c052602060c02001546102a052610160516102c0526002600b3360e05260c052604060c02060c052602060c02001546102e052337f67f96d2854a335a4cadb49f84fd3ca6f990744ddb3feceeb4b349d2d53d32ad3610100610200a26002600b3360e05260c052604060c02060c052602060c02001541515613825576001613829565b600d545b1561386e576020610260600463efbb5cb06102005261021c335afa61384d57600080fd5b601f3d1161385a57600080fd5b6000506102605160005260206000f361387b565b6101805160005260206000f35b005b6301681a628114156138b3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610140526138d4565b636ea056a98114156138cf5760206024610140376000506138d4565b6139b4565b60043560a01c156138e457600080fd5b60075433146138f257600080fd5b6006546004351861390257600080fd5b61014051610160527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61016051141561397457602061020060246370a0823161018052306101a05261019c6004355afa61395b57600080fd5b601f3d1161396857600080fd5b60005061020051610160525b6101405161016051600435610180526007546101a052610160516101c0526101c0516101a0516101805160065801613ec1565b6101605261014052600050005b6306fdde03811415613a595760008060c052602060c020610180602082540161012060006003818352015b826101205160200211156139f257613a14565b61012051850154610120516020028501525b81516001018083528114156139df575b50505050505061018051806101a001818260206001820306601f82010390500336823750506020610160526040610180510160206001820306601f8201039050610160f35b6395d89b41811415613afe5760018060c052602060c020610180602082540161012060006002818352015b82610120516020021115613a9757613ab9565b61012051850154610120516020028501525b8151600101808352811415613a84575b50505050505061018051806101a001818260206001820306601f82010390500336823750506020610160526040610180510160206001820306601f8201039050610160f35b63313ce567811415613b165760025460005260206000f35b6370a08231811415613b4c5760043560a01c15613b3257600080fd5b600360043560e05260c052604060c0205460005260206000f35b63dd62ed3e811415613ba05760043560a01c15613b6857600080fd5b60243560a01c15613b7857600080fd5b600460043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f35b6318160ddd811415613bb85760055460005260206000f35b63fc0c546a811415613bd05760065460005260206000f35b635aa6e675811415613be85760075460005260206000f35b6388a8d602811415613c005760085460005260206000f35b63452a9320811415613c185760095460005260206000f35b6339ebf823811415613d325760043560a01c15613c3457600080fd5b600b60043560e05260c052604060c0206101408080808460c052602060c0205481525050602081019050808060018560c052602060c020015481525050602081019050808060028560c052602060c020015481525050602081019050808060038560c052602060c020015481525050602081019050808060048560c052602060c020015481525050602081019050808060058560c052602060c020015481525050602081019050808060068560c052602060c020015481525050602081019050808060078560c052602060c020015481525050602081019050808060088560c052602060c0200154815250506101209050905060c05260c051610140f35b63c822adda811415613d635760043560148110613d4e57600080fd5b600c60c052602060c020015460005260206000f35b633403c2fc811415613d7b57600d5460005260206000f35b63ecf70858811415613d9357600e5460005260206000f35b63cea55f57811415613dab57600f5460005260206000f35b63fc7b9c18811415613dc35760105460005260206000f35b63c3535b52811415613ddb5760115460005260206000f35b633629c8de811415613df35760125460005260206000f35b6344b81396811415613e0b5760135460005260206000f35b6342232716811415613e235760145460005260206000f35b639ec5a894811415613e3b5760155460005260206000f35b63a6f7f5d6811415613e535760165460005260206000f35b6387788782811415613e6b5760175460005260206000f35b637ecebe00811415613ea15760043560a01c15613e8757600080fd5b601860043560e05260c052604060c0205460005260206000f35b633644e515811415613eb95760195460005260206000f35b505b60006000fd5b6101a05261014052610160526101805260006004610220527fa9059cbb000000000000000000000000000000000000000000000000000000006102405261022060048060208461028001018260208501600060045af15050805182019150506101605160208261028001015260208101905061018051602082610280010152602081019050806102805261028090508051602001806103208284600060045af1613f6a57600080fd5b505060206103e0610320516103406000610140515af1613f8957600080fd5b60203d80821115613f9a5780613f9c565b815b905090506103c0526103c08051602001806101c08284600060045af1613fc157600080fd5b505060006101c0511115614055576101c0806020015160008251806020901315613fea57600080fd5b8091901215613ff857600080fd5b806020036101000a820490509050905015151515614055576308c379a0610220526020610240526010610260527f5472616e73666572206661696c656421000000000000000000000000000000006102805261026050606461023cfd5b6101a051565b6101c0526101405261016052610180526101a05260006004610240527f23b872dd00000000000000000000000000000000000000000000000000000000610260526102406004806020846102a001018260208501600060045af1505080518201915050610160516020826102a0010152602081019050610180516020826102a00101526020810190506101a0516020826102a0010152602081019050806102a0526102a090508051602001806103608284600060045af161411b57600080fd5b50506020610440610360516103806000610140515af161413a57600080fd5b60203d8082111561414b578061414d565b815b90509050610420526104208051602001806101e08284600060045af161417257600080fd5b505060006101e0511115614206576101e080602001516000825180602090131561419b57600080fd5b80919012156141a957600080fd5b806020036101000a820490509050905015151515614206576308c379a0610240526020610260526010610280527f5472616e73666572206661696c656421000000000000000000000000000000006102a05261028050606461025cfd5b6101c051565b6101a052610140526101605261018052306101e05260006102005260006101c0526101c061012060006002818352015b610120516020026101e0015161016051141561425b576001835261426b565b815160010180835281141561423c575b5050506101c0511561427c57600080fd5b60036101405160e05260c052604060c020805461018051808210156142a057600080fd5b8082039050905081555060036101605160e05260c052604060c0208054610180518181830110156142d057600080fd5b80820190509050815550610180516101c05261016051610140517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60206101c0a36101a051565b6101405260206101e060246370a0823161016052306101805261017c6006545afa61434157600080fd5b601f3d1161434e57600080fd5b6000506101e05160105481818301101561436757600080fd5b8082019050905060005260005161014051565b61014052426011548082101561438f57600080fd5b8082039050905060145480820282158284830414176143ad57600080fd5b8090509050905061016052670de0b6b3a764000061016051101561442d576013546101805261018051610160516101805180820282158284830414176143f257600080fd5b80905090509050670de0b6b3a7640000808204905090508082101561441657600080fd5b80820390509050600052600051610140515661443b565b600060005260005161014051565b005b61018052610140526101605260006101a0526005546101c05260006101c0511115614545576101405161016051610180516101a0516101c0516101e05160065801614317565b610200526101e0526101c0526101a052610180526101605261014052610200516101405161016051610180516101a0516101c0516101e051610200516006580161437a565b61022052610200526101e0526101c0526101a05261018052610160526101405261022051808210156144f957600080fd5b808203905090506101e052610160516101c051808202821582848304141761452057600080fd5b809050905090506101e051808061453657600080fd5b8204905090506101a05261454e565b610160516101a0525b60006101a0511861455e57600080fd5b6101c0516101a05181818301101561457557600080fd5b8082019050905060055560036101405160e05260c052604060c02080546101a0518181830110156145a557600080fd5b808201905090508155506101a0516101e0526101405160007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60206101e0a36101a05160005260005161018051565b61016052610140526005541515614615576101405160005260005161016051565b61014051610160516101805160065801614317565b6101a0526101805261016052610140526101a0516101405161016051610180516101a0516006580161437a565b6101c0526101a0526101805261016052610140526101c0518082101561467c57600080fd5b8082039050905061018052610140516101805180820282158284830414176146a357600080fd5b8090509050905060055480806146b857600080fd5b82049050905060005260005161016051565b61016052610140526000610140516101605160065801614317565b6101805261016052610140526101805111156147675761014051600554808202821582848304141761471657600080fd5b8090509050905061014051610160516101805160065801614317565b6101a0526101805261016052610140526101a051808061475157600080fd5b8204905090506000526000516101605156614775565b600060005260005161016051565b005b6101805261014052610160526006600b6101405160e05260c052604060c02060c052602060c02001546101a052610160516101a05110156147b757600080fd5b6000600f5418156148865761016051600f5480820282158284830414176147dd57600080fd5b8090509050905060105480806147f257600080fd5b8204905090506002600b6101405160e05260c052604060c02060c052602060c0200154808211156148235780614825565b815b905090506101c0526002600b6101405160e05260c052604060c02060c052602060c0200180546101c0518082101561485c57600080fd5b80820390509050815550600f80546101c0518082101561487b57600080fd5b808203905090508155505b6008600b6101405160e05260c052604060c02060c052602060c020018054610160518181830110156148b757600080fd5b808201905090508155506101a05161016051808210156148d657600080fd5b808203905090506006600b6101405160e05260c052604060c02060c052602060c020015560108054610160518082101561490f57600080fd5b8082039050905081555061018051565b6101405260006101605261018060006014818352015b610180516014811061494657600080fd5b600c60c052602060c02001546101a0526101a0511515614985576101608051600181818301101561497657600080fd5b808201905090508152506149ea565b60006101605111156149ea576101a0516101805161016051808210156149aa57600080fd5b80820390509050601481106149be57600080fd5b600c60c052602060c0200155600061018051601481106149dd57600080fd5b600c60c052602060c02001555b8151600101808352811415614935575b505061014051565b6101605261014052600f80546002600b6101405160e05260c052604060c02060c052602060c020015480821015614a3857600080fd5b8082039050905081555060006002600b6101405160e05260c052604060c02060c052602060c0200155610140517f4201c688d84c01154d321afa0c72f1bffe9eef53005c9de9d035074e71e9b32a60006000a261016051565b6101605261014052600f541515614acb576006600b6101405160e05260c052604060c02060c052602060c020015460005260005161016051565b6002600b6101405160e05260c052604060c02060c052602060c020015461014051610160516101805160065801614317565b6101a0526101805261016052610140526101a0518082028215828483041417614b2557600080fd5b8090509050905061271080820490509050610180526006600b6101405160e05260c052604060c02060c052602060c02001546101a052600d5415614b77576101a0516000526000516101605156614bc0565b610180516101a051111515614b985760006000526000516101605156614bc0565b6101a0516101805180821015614bad57600080fd5b8082039050905060005260005161016051565b005b6101605261014052600d5415614be057600060005260005161016051565b61014051610160516101805160065801614317565b6101a0526101805261016052610140526101a05161018052600f54610180518082028215828483041417614c2857600080fd5b80905090509050612710808204905090506101a0526010546101c0526002600b6101405160e05260c052604060c02060c052602060c0200154610180518082028215828483041417614c7957600080fd5b80905090509050612710808204905090506101e0526006600b6101405160e05260c052604060c02060c052602060c0200154610200526003600b6101405160e05260c052604060c02060c052602060c0200154610220526004600b6101405160e05260c052604060c02060c052602060c020015461024052610200516101e051111515614d07576001614d12565b6101c0516101a05111155b15614d2557600060005260005161016051565b6101e0516102005180821015614d3a57600080fd5b8082039050905061026052610260516101a0516101c05180821015614d5e57600080fd5b8082039050905080821115614d735780614d75565b815b905090506102605261026051602061030060246370a0823161028052306102a05261029c6006545afa614da757600080fd5b601f3d11614db457600080fd5b6000506103005180821115614dc95780614dcb565b815b905090506102605261022051610260511015614df35760006000526000516101605156614e1b565b610260516102405180821115614e095780614e0b565b815b9050905060005260005161016051565b005b61016052610140526005600b6101405160e05260c052604060c02060c052602060c020015461018052426101805180821015614e5857600080fd5b808203905090506101a052610180516001600b6101405160e05260c052604060c02060c052602060c020015480821015614e9157600080fd5b808203905090506101c05260006101a0511115614ef75760006101c0511115614eef5760206102c060046322f3e2d46102605261027c610140515afa614ed657600080fd5b601f3d11614ee357600080fd5b6000506102c051614ef2565b60005b614efa565b60005b15614f60576007600b6101405160e05260c052604060c02060c052602060c02001546101a0518082028215828483041417614f3457600080fd5b809050905090506101c0518080614f4a57600080fd5b8204905090506000526000516101605156614f6e565b600060005260005161016051565b005b610180526101405261016052426005600b6101405160e05260c052604060c02060c052602060c020015480821015614fa757600080fd5b808203905090506101a05260006101a05118614fc257600080fd5b610160511515614fda57600060005260005161018051565b6006600b6101405160e05260c052604060c02060c052602060c020015460206102406004638e6350e26101e0526101fc610140515afa61501957600080fd5b601f3d1161502657600080fd5b600050610240518082101561503a57600080fd5b808203905090506101a051808202821582848304141761505957600080fd5b80905090509050601654808202821582848304141761507757600080fd5b80905090509050612710808204905090506301e18558808204905090506101c05261016051600b6101405160e05260c052604060c02060c052602060c0205480820282158284830414176150ca57600080fd5b80905090509050612710808204905090506101e0526101605160175480820282158284830414176150fa57600080fd5b809050905090506127108082049050905061020052610200516101e05181818301101561512657600080fd5b808201905090506101c05181818301101561514057600080fd5b8082019050905061022052610160516102205111156151625761016051610220525b600061022051111561533d576101405161016051610180516101a0516101c0516101e0516102005161022051610240513061026052610220516102805261028051610260516006580161443d565b6102e0526102405261022052610200526101e0526101c0526101a0526101805261016052610140526102e0516102405260006101e05111156152a6576101e05161024051808202821582848304141761520857600080fd5b8090509050905061022051808061521e57600080fd5b820490509050610260526101405161016051610180516101a0516101c0516101e051610200516102205161024051610260513061028052610140516102a052610260516102c0526102c0516102a051610280516006580161420c565b610260526102405261022052610200526101e0526101c0526101a0526101805261016052610140526000505b600060033060e05260c052604060c02054111561533d576101405161016051610180516101a0516101c0516101e05161020051610220516102405130610260526015546102805260033060e05260c052604060c020546102a0526102a05161028051610260516006580161420c565b6102405261022052610200526101e0526101c0526101a0526101805261016052610140526000505b610220516000526000516101805156
Verified Source Code Partial Match
Compiler: v0.2.12+commit.2c6842c
Vyper_contract.vy 1775 lines
# @version 0.2.12
"""
@title Yearn Token Vault
@license GNU AGPLv3
@author yearn.finance
@notice
Yearn Token Vault. Holds an underlying token, and allows users to interact
with the Yearn ecosystem through Strategies connected to the Vault.
Vaults are not limited to a single Strategy, they can have as many Strategies
as can be designed (however the withdrawal queue is capped at 20.)
Deposited funds are moved into the most impactful strategy that has not
already reached its limit for assets under management, regardless of which
Strategy a user's funds end up in, they receive their portion of yields
generated across all Strategies.
When a user withdraws, if there are no funds sitting undeployed in the
Vault, the Vault withdraws funds from Strategies in the order of least
impact. (Funds are taken from the Strategy that will disturb everyone's
gains the least, then the next least, etc.) In order to achieve this, the
withdrawal queue's order must be properly set and managed by the community
(through governance).
Vault Strategies are parameterized to pursue the highest risk-adjusted yield.
There is an "Emergency Shutdown" mode. When the Vault is put into emergency
shutdown, assets will be recalled from the Strategies as quickly as is
practical (given on-chain conditions), minimizing loss. Deposits are
halted, new Strategies may not be added, and each Strategy exits with the
minimum possible damage to position, while opening up deposits to be
withdrawn by users. There are no restrictions on withdrawals above what is
expected under Normal Operation.
For further details, please refer to the specification:
https://github.com/iearn-finance/yearn-vaults/blob/master/SPECIFICATION.md
"""
API_VERSION: constant(String[28]) = "0.4.2"
from vyper.interfaces import ERC20
implements: ERC20
interface DetailedERC20:
def name() -> String[42]: view
def symbol() -> String[20]: view
def decimals() -> uint256: view
interface Strategy:
def want() -> address: view
def vault() -> address: view
def isActive() -> bool: view
def delegatedAssets() -> uint256: view
def estimatedTotalAssets() -> uint256: view
def withdraw(_amount: uint256) -> uint256: nonpayable
def migrate(_newStrategy: address): nonpayable
event Transfer:
sender: indexed(address)
receiver: indexed(address)
value: uint256
event Approval:
owner: indexed(address)
spender: indexed(address)
value: uint256
name: public(String[64])
symbol: public(String[32])
decimals: public(uint256)
balanceOf: public(HashMap[address, uint256])
allowance: public(HashMap[address, HashMap[address, uint256]])
totalSupply: public(uint256)
token: public(ERC20)
governance: public(address)
management: public(address)
guardian: public(address)
pendingGovernance: address
struct StrategyParams:
performanceFee: uint256 # Strategist's fee (basis points)
activation: uint256 # Activation block.timestamp
debtRatio: uint256 # Maximum borrow amount (in BPS of total assets)
minDebtPerHarvest: uint256 # Lower limit on the increase of debt since last harvest
maxDebtPerHarvest: uint256 # Upper limit on the increase of debt since last harvest
lastReport: uint256 # block.timestamp of the last time a report occured
totalDebt: uint256 # Total outstanding debt that Strategy has
totalGain: uint256 # Total returns that Strategy has realized for Vault
totalLoss: uint256 # Total losses that Strategy has realized for Vault
event StrategyAdded:
strategy: indexed(address)
debtRatio: uint256 # Maximum borrow amount (in BPS of total assets)
minDebtPerHarvest: uint256 # Lower limit on the increase of debt since last harvest
maxDebtPerHarvest: uint256 # Upper limit on the increase of debt since last harvest
performanceFee: uint256 # Strategist's fee (basis points)
event StrategyReported:
strategy: indexed(address)
gain: uint256
loss: uint256
debtPaid: uint256
totalGain: uint256
totalLoss: uint256
totalDebt: uint256
debtAdded: uint256
debtRatio: uint256
event UpdateGovernance:
governance: address # New active governance
event UpdateManagement:
management: address # New active manager
event UpdateRewards:
rewards: address # New active rewards recipient
event UpdateDepositLimit:
depositLimit: uint256 # New active deposit limit
event UpdatePerformanceFee:
performanceFee: uint256 # New active performance fee
event UpdateManagementFee:
managementFee: uint256 # New active management fee
event UpdateGuardian:
guardian: address # Address of the active guardian
event EmergencyShutdown:
active: bool # New emergency shutdown state (if false, normal operation enabled)
event UpdateWithdrawalQueue:
queue: address[MAXIMUM_STRATEGIES] # New active withdrawal queue
event StrategyUpdateDebtRatio:
strategy: indexed(address) # Address of the strategy for the debt ratio adjustment
debtRatio: uint256 # The new debt limit for the strategy (in BPS of total assets)
event StrategyUpdateMinDebtPerHarvest:
strategy: indexed(address) # Address of the strategy for the rate limit adjustment
minDebtPerHarvest: uint256 # Lower limit on the increase of debt since last harvest
event StrategyUpdateMaxDebtPerHarvest:
strategy: indexed(address) # Address of the strategy for the rate limit adjustment
maxDebtPerHarvest: uint256 # Upper limit on the increase of debt since last harvest
event StrategyUpdatePerformanceFee:
strategy: indexed(address) # Address of the strategy for the performance fee adjustment
performanceFee: uint256 # The new performance fee for the strategy
event StrategyMigrated:
oldVersion: indexed(address) # Old version of the strategy to be migrated
newVersion: indexed(address) # New version of the strategy
event StrategyRevoked:
strategy: indexed(address) # Address of the strategy that is revoked
event StrategyRemovedFromQueue:
strategy: indexed(address) # Address of the strategy that is removed from the withdrawal queue
event StrategyAddedToQueue:
strategy: indexed(address) # Address of the strategy that is added to the withdrawal queue
# NOTE: Track the total for overhead targeting purposes
strategies: public(HashMap[address, StrategyParams])
MAXIMUM_STRATEGIES: constant(uint256) = 20
DEGRADATION_COEFFICIENT: constant(uint256) = 10 ** 18
# Ordering that `withdraw` uses to determine which strategies to pull funds from
# NOTE: Does *NOT* have to match the ordering of all the current strategies that
# exist, but it is recommended that it does or else withdrawal depth is
# limited to only those inside the queue.
# NOTE: Ordering is determined by governance, and should be balanced according
# to risk, slippage, and/or volatility. Can also be ordered to increase the
# withdrawal speed of a particular Strategy.
# NOTE: The first time a ZERO_ADDRESS is encountered, it stops withdrawing
withdrawalQueue: public(address[MAXIMUM_STRATEGIES])
emergencyShutdown: public(bool)
depositLimit: public(uint256) # Limit for totalAssets the Vault can hold
debtRatio: public(uint256) # Debt ratio for the Vault across all strategies (in BPS, <= 10k)
totalDebt: public(uint256) # Amount of tokens that all strategies have borrowed
lastReport: public(uint256) # block.timestamp of last report
activation: public(uint256) # block.timestamp of contract deployment
lockedProfit: public(uint256) # how much profit is locked and cant be withdrawn
lockedProfitDegradation: public(uint256) # rate per block of degradation. DEGRADATION_COEFFICIENT is 100% per block
rewards: public(address) # Rewards contract where Governance fees are sent to
# Governance Fee for management of Vault (given to `rewards`)
managementFee: public(uint256)
# Governance Fee for performance of Vault (given to `rewards`)
performanceFee: public(uint256)
MAX_BPS: constant(uint256) = 10_000 # 100%, or 10k basis points
# NOTE: A four-century period will be missing 3 of its 100 Julian leap years, leaving 97.
# So the average year has 365 + 97/400 = 365.2425 days
# ERROR(Julian): -0.0078
# ERROR(Gregorian): -0.0003
SECS_PER_YEAR: constant(uint256) = 31_556_952 # 365.2425 days
# `nonces` track `permit` approvals with signature.
nonces: public(HashMap[address, uint256])
DOMAIN_SEPARATOR: public(bytes32)
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)")
@external
def initialize(
token: address,
governance: address,
rewards: address,
nameOverride: String[64],
symbolOverride: String[32],
guardian: address = msg.sender,
management: address = msg.sender,
):
"""
@notice
Initializes the Vault, this is called only once, when the contract is
deployed.
The performance fee is set to 10% of yield, per Strategy.
The management fee is set to 2%, per year.
The initial deposit limit is set to 0 (deposits disabled); it must be
updated after initialization.
@dev
If `nameOverride` is not specified, the name will be 'yearn'
combined with the name of `token`.
If `symbolOverride` is not specified, the symbol will be 'yv'
combined with the symbol of `token`.
The token used by the vault should not change balances outside transfers and
it must transfer the exact amount requested. Fee on transfer and rebasing are not supported.
@param token The token that may be deposited into this Vault.
@param governance The address authorized for governance interactions.
@param rewards The address to distribute rewards to.
@param management The address of the vault manager.
@param nameOverride Specify a custom Vault name. Leave empty for default choice.
@param symbolOverride Specify a custom Vault symbol name. Leave empty for default choice.
@param guardian The address authorized for guardian interactions. Defaults to caller.
"""
assert self.activation == 0 # dev: no devops199
self.token = ERC20(token)
if nameOverride == "":
self.name = concat(DetailedERC20(token).symbol(), " yVault")
else:
self.name = nameOverride
if symbolOverride == "":
self.symbol = concat("yv", DetailedERC20(token).symbol())
else:
self.symbol = symbolOverride
decimals: uint256 = DetailedERC20(token).decimals()
self.decimals = decimals
assert decimals < 256 # dev: see VVE-2020-0001
self.governance = governance
log UpdateGovernance(governance)
self.management = management
log UpdateManagement(management)
self.rewards = rewards
log UpdateRewards(rewards)
self.guardian = guardian
log UpdateGuardian(guardian)
self.performanceFee = 1000 # 10% of yield (per Strategy)
log UpdatePerformanceFee(convert(1000, uint256))
self.managementFee = 200 # 2% per year
log UpdateManagementFee(convert(200, uint256))
self.lastReport = block.timestamp
self.activation = block.timestamp
self.lockedProfitDegradation = convert(DEGRADATION_COEFFICIENT * 46 / 10 ** 6 , uint256) # 6 hours in blocks
# EIP-712
self.DOMAIN_SEPARATOR = keccak256(
concat(
DOMAIN_TYPE_HASH,
keccak256(convert("Yearn Vault", Bytes[11])),
keccak256(convert(API_VERSION, Bytes[28])),
convert(chain.id, bytes32),
convert(self, bytes32)
)
)
@pure
@external
def apiVersion() -> String[28]:
"""
@notice
Used to track the deployed version of this contract. In practice you
can use this version number to compare with Yearn's GitHub and
determine which version of the source matches this deployed contract.
@dev
All strategies must have an `apiVersion()` that matches the Vault's
`API_VERSION`.
@return API_VERSION which holds the current version of this contract.
"""
return API_VERSION
@external
def setName(name: String[42]):
"""
@notice
Used to change the value of `name`.
This may only be called by governance.
@param name The new name to use.
"""
assert msg.sender == self.governance
self.name = name
@external
def setSymbol(symbol: String[20]):
"""
@notice
Used to change the value of `symbol`.
This may only be called by governance.
@param symbol The new symbol to use.
"""
assert msg.sender == self.governance
self.symbol = symbol
# 2-phase commit for a change in governance
@external
def setGovernance(governance: address):
"""
@notice
Nominate a new address to use as governance.
The change does not go into effect immediately. This function sets a
pending change, and the governance address is not updated until
the proposed governance address has accepted the responsibility.
This may only be called by the current governance address.
@param governance The address requested to take over Vault governance.
"""
assert msg.sender == self.governance
self.pendingGovernance = governance
@external
def acceptGovernance():
"""
@notice
Once a new governance address has been proposed using setGovernance(),
this function may be called by the proposed address to accept the
responsibility of taking over governance for this contract.
This may only be called by the proposed governance address.
@dev
setGovernance() should be called by the existing governance address,
prior to calling this function.
"""
assert msg.sender == self.pendingGovernance
self.governance = msg.sender
log UpdateGovernance(msg.sender)
@external
def setManagement(management: address):
"""
@notice
Changes the management address.
Management is able to make some investment decisions adjusting parameters.
This may only be called by governance.
@param management The address to use for managing.
"""
assert msg.sender == self.governance
self.management = management
log UpdateManagement(management)
@external
def setRewards(rewards: address):
"""
@notice
Changes the rewards address. Any distributed rewards
will cease flowing to the old address and begin flowing
to this address once the change is in effect.
This will not change any Strategy reports in progress, only
new reports made after this change goes into effect.
This may only be called by governance.
@param rewards The address to use for collecting rewards.
"""
assert msg.sender == self.governance
assert not (rewards in [self, ZERO_ADDRESS])
self.rewards = rewards
log UpdateRewards(rewards)
@external
def setLockedProfitDegradation(degradation: uint256):
"""
@notice
Changes the locked profit degradation.
@param degradation The rate of degradation in percent per second scaled to 1e18.
"""
assert msg.sender == self.governance
# Since "degradation" is of type uint256 it can never be less than zero
assert degradation <= DEGRADATION_COEFFICIENT
self.lockedProfitDegradation = degradation
@external
def setDepositLimit(limit: uint256):
"""
@notice
Changes the maximum amount of tokens that can be deposited in this Vault.
Note, this is not how much may be deposited by a single depositor,
but the maximum amount that may be deposited across all depositors.
This may only be called by governance.
@param limit The new deposit limit to use.
"""
assert msg.sender == self.governance
self.depositLimit = limit
log UpdateDepositLimit(limit)
@external
def setPerformanceFee(fee: uint256):
"""
@notice
Used to change the value of `performanceFee`.
Should set this value below the maximum strategist performance fee.
This may only be called by governance.
@param fee The new performance fee to use.
"""
assert msg.sender == self.governance
assert fee <= MAX_BPS / 2
self.performanceFee = fee
log UpdatePerformanceFee(fee)
@external
def setManagementFee(fee: uint256):
"""
@notice
Used to change the value of `managementFee`.
This may only be called by governance.
@param fee The new management fee to use.
"""
assert msg.sender == self.governance
assert fee <= MAX_BPS
self.managementFee = fee
log UpdateManagementFee(fee)
@external
def setGuardian(guardian: address):
"""
@notice
Used to change the address of `guardian`.
This may only be called by governance or the existing guardian.
@param guardian The new guardian address to use.
"""
assert msg.sender in [self.guardian, self.governance]
self.guardian = guardian
log UpdateGuardian(guardian)
@external
def setEmergencyShutdown(active: bool):
"""
@notice
Activates or deactivates Vault mode where all Strategies go into full
withdrawal.
During Emergency Shutdown:
1. No Users may deposit into the Vault (but may withdraw as usual.)
2. Governance may not add new Strategies.
3. Each Strategy must pay back their debt as quickly as reasonable to
minimally affect their position.
4. Only Governance may undo Emergency Shutdown.
See contract level note for further details.
This may only be called by governance or the guardian.
@param active
If true, the Vault goes into Emergency Shutdown. If false, the Vault
goes back into Normal Operation.
"""
if active:
assert msg.sender in [self.guardian, self.governance]
else:
assert msg.sender == self.governance
self.emergencyShutdown = active
log EmergencyShutdown(active)
@external
def setWithdrawalQueue(queue: address[MAXIMUM_STRATEGIES]):
"""
@notice
Updates the withdrawalQueue to match the addresses and order specified
by `queue`.
There can be fewer strategies than the maximum, as well as fewer than
the total number of strategies active in the vault. `withdrawalQueue`
will be updated in a gas-efficient manner, assuming the input is well-
ordered with 0x0 only at the end.
This may only be called by governance or management.
@dev
This is order sensitive, specify the addresses in the order in which
funds should be withdrawn (so `queue`[0] is the first Strategy withdrawn
from, `queue`[1] is the second, etc.)
This means that the least impactful Strategy (the Strategy that will have
its core positions impacted the least by having funds removed) should be
at `queue`[0], then the next least impactful at `queue`[1], and so on.
@param queue
The array of addresses to use as the new withdrawal queue. This is
order sensitive.
"""
assert msg.sender in [self.management, self.governance]
# HACK: Temporary until Vyper adds support for Dynamic arrays
old_queue: address[MAXIMUM_STRATEGIES] = empty(address[MAXIMUM_STRATEGIES])
for i in range(MAXIMUM_STRATEGIES):
old_queue[i] = self.withdrawalQueue[i]
if queue[i] == ZERO_ADDRESS:
# NOTE: Cannot use this method to remove entries from the queue
assert old_queue[i] == ZERO_ADDRESS
break
# NOTE: Cannot use this method to add more entries to the queue
assert old_queue[i] != ZERO_ADDRESS
assert self.strategies[queue[i]].activation > 0
existsInOldQueue: bool = False
for j in range(MAXIMUM_STRATEGIES):
if queue[j] == ZERO_ADDRESS:
existsInOldQueue = True
break
if queue[i] == old_queue[j]:
# NOTE: Ensure that every entry in queue prior to reordering exists now
existsInOldQueue = True
if j <= i:
# NOTE: This will only check for duplicate entries in queue after `i`
continue
assert queue[i] != queue[j] # dev: do not add duplicate strategies
assert existsInOldQueue # dev: do not add new strategies
self.withdrawalQueue[i] = queue[i]
log UpdateWithdrawalQueue(queue)
@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.
# HACK: Used to handle non-compliant tokens like USDT
response: Bytes[32] = raw_call(
token,
concat(
method_id("transfer(address,uint256)"),
convert(receiver, bytes32),
convert(amount, bytes32),
),
max_outsize=32,
)
if len(response) > 0:
assert convert(response, bool), "Transfer failed!"
@internal
def erc20_safe_transferFrom(token: address, sender: address, receiver: address, amount: uint256):
# Used only to send tokens that are not the type managed by this Vault.
# HACK: Used to handle non-compliant tokens like USDT
response: Bytes[32] = raw_call(
token,
concat(
method_id("transferFrom(address,address,uint256)"),
convert(sender, bytes32),
convert(receiver, bytes32),
convert(amount, bytes32),
),
max_outsize=32,
)
if len(response) > 0:
assert convert(response, bool), "Transfer failed!"
@internal
def _transfer(sender: address, receiver: address, amount: uint256):
# See note on `transfer()`.
# Protect people from accidentally sending their shares to bad places
assert receiver not in [self, ZERO_ADDRESS]
self.balanceOf[sender] -= amount
self.balanceOf[receiver] += amount
log Transfer(sender, receiver, amount)
@external
def transfer(receiver: address, amount: uint256) -> bool:
"""
@notice
Transfers shares from the caller's address to `receiver`. This function
will always return true, unless the user is attempting to transfer
shares to this contract's address, or to 0x0.
@param receiver
The address shares are being transferred to. Must not be this contract's
address, must not be 0x0.
@param amount The quantity of shares to transfer.
@return
True if transfer is sent to an address other than this contract's or
0x0, otherwise the transaction will fail.
"""
self._transfer(msg.sender, receiver, amount)
return True
@external
def transferFrom(sender: address, receiver: address, amount: uint256) -> bool:
"""
@notice
Transfers `amount` shares from `sender` to `receiver`. This operation will
always return true, unless the user is attempting to transfer shares
to this contract's address, or to 0x0.
Unless the caller has given this contract unlimited approval,
transfering shares will decrement the caller's `allowance` by `amount`.
@param sender The address shares are being transferred from.
@param receiver
The address shares are being transferred to. Must not be this contract's
address, must not be 0x0.
@param amount The quantity of shares to transfer.
@return
True if transfer is sent to an address other than this contract's or
0x0, otherwise the transaction will fail.
"""
# Unlimited approval (saves an SSTORE)
if (self.allowance[sender][msg.sender] < MAX_UINT256):
allowance: uint256 = self.allowance[sender][msg.sender] - amount
self.allowance[sender][msg.sender] = allowance
# NOTE: Allows log filters to have a full accounting of allowance changes
log Approval(sender, msg.sender, allowance)
self._transfer(sender, receiver, amount)
return True
@external
def approve(spender: address, amount: uint256) -> bool:
"""
@dev Approve the passed address to spend the specified amount of tokens on behalf of
`msg.sender`. Beware that changing an allowance with this method brings the risk
that someone may use both the old and the new allowance by unfortunate transaction
ordering. See https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
@param spender The address which will spend the funds.
@param amount The amount of tokens to be spent.
"""
self.allowance[msg.sender][spender] = amount
log Approval(msg.sender, spender, amount)
return True
@external
def increaseAllowance(spender: address, amount: uint256) -> bool:
"""
@dev Increase the allowance of the passed address to spend the total amount of tokens
on behalf of msg.sender. This method mitigates the risk that someone may use both
the old and the new allowance by unfortunate transaction ordering.
See https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
@param spender The address which will spend the funds.
@param amount The amount of tokens to increase the allowance by.
"""
self.allowance[msg.sender][spender] += amount
log Approval(msg.sender, spender, self.allowance[msg.sender][spender])
return True
@external
def decreaseAllowance(spender: address, amount: uint256) -> bool:
"""
@dev Decrease the allowance of the passed address to spend the total amount of tokens
on behalf of msg.sender. This method mitigates the risk that someone may use both
the old and the new allowance by unfortunate transaction ordering.
See https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
@param spender The address which will spend the funds.
@param amount The amount of tokens to decrease the allowance by.
"""
self.allowance[msg.sender][spender] -= amount
log Approval(msg.sender, spender, self.allowance[msg.sender][spender])
return True
@external
def permit(owner: address, spender: address, amount: uint256, expiry: uint256, signature: Bytes[65]) -> bool:
"""
@notice
Approves spender by owner's signature to expend owner's tokens.
See https://eips.ethereum.org/EIPS/eip-2612.
@param owner The address which is a source of funds and has signed the Permit.
@param spender The address which is allowed to spend the funds.
@param amount The amount of tokens to be spent.
@param expiry The timestamp after which the Permit is no longer valid.
@param signature A valid secp256k1 signature of Permit by owner encoded as r, s, v.
@return True, if transaction completes successfully
"""
assert owner != ZERO_ADDRESS # dev: invalid owner
assert expiry == 0 or expiry >= block.timestamp # dev: 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(expiry, bytes32),
)
)
)
)
# NOTE: signature is packed as r, s, v
r: uint256 = convert(slice(signature, 0, 32), uint256)
s: uint256 = convert(slice(signature, 32, 32), uint256)
v: uint256 = convert(slice(signature, 64, 1), uint256)
assert ecrecover(digest, v, r, s) == owner # dev: invalid signature
self.allowance[owner][spender] = amount
self.nonces[owner] = nonce + 1
log Approval(owner, spender, amount)
return True
@view
@internal
def _totalAssets() -> uint256:
# See note on `totalAssets()`.
return self.token.balanceOf(self) + self.totalDebt
@view
@external
def totalAssets() -> uint256:
"""
@notice
Returns the total quantity of all assets under control of this
Vault, whether they're loaned out to a Strategy, or currently held in
the Vault.
@return The total assets under control of this Vault.
"""
return self._totalAssets()
@view
@internal
def _calculateLockedProfit() -> uint256:
lockedFundsRatio: uint256 = (block.timestamp - self.lastReport) * self.lockedProfitDegradation
if(lockedFundsRatio < DEGRADATION_COEFFICIENT):
lockedProfit: uint256 = self.lockedProfit
return lockedProfit - (
lockedFundsRatio
* lockedProfit
/ DEGRADATION_COEFFICIENT
)
else:
return 0
@internal
def _issueSharesForAmount(to: address, amount: uint256) -> uint256:
# Issues `amount` Vault shares to `to`.
# Shares must be issued prior to taking on new collateral, or
# calculation will be wrong. This means that only *trusted* tokens
# (with no capability for exploitative behavior) can be used.
shares: uint256 = 0
# HACK: Saves 2 SLOADs (~200 gas, post-Berlin)
totalSupply: uint256 = self.totalSupply
if totalSupply > 0:
# Mint amount of shares based on what the Vault is managing overall
# NOTE: if sqrt(token.totalSupply()) > 1e39, this could potentially revert
freeFunds: uint256 = self._totalAssets() - self._calculateLockedProfit()
shares = amount * totalSupply / freeFunds # dev: no free funds
else:
# No existing shares, so mint 1:1
shares = amount
assert shares != 0 # dev: division rounding resulted in zero
# Mint new shares
self.totalSupply = totalSupply + shares
self.balanceOf[to] += shares
log Transfer(ZERO_ADDRESS, to, shares)
return shares
@external
@nonreentrant("withdraw")
def deposit(_amount: uint256 = MAX_UINT256, recipient: address = msg.sender) -> uint256:
"""
@notice
Deposits `_amount` `token`, issuing shares to `recipient`. If the
Vault is in Emergency Shutdown, deposits will not be accepted and this
call will fail.
@dev
Measuring quantity of shares to issues is based on the total
outstanding debt that this contract has ("expected value") instead
of the total balance sheet it has ("estimated value") has important
security considerations, and is done intentionally. If this value were
measured against external systems, it could be purposely manipulated by
an attacker to withdraw more assets than they otherwise should be able
to claim by redeeming their shares.
On deposit, this means that shares are issued against the total amount
that the deposited capital can be given in service of the debt that
Strategies assume. If that number were to be lower than the "expected
value" at some future point, depositing shares via this method could
entitle the depositor to *less* than the deposited value once the
"realized value" is updated from further reports by the Strategies
to the Vaults.
Care should be taken by integrators to account for this discrepancy,
by using the view-only methods of this contract (both off-chain and
on-chain) to determine if depositing into the Vault is a "good idea".
@param _amount The quantity of tokens to deposit, defaults to all.
@param recipient
The address to issue the shares in this Vault to. Defaults to the
caller's address.
@return The issued Vault shares.
"""
assert not self.emergencyShutdown # Deposits are locked out
assert recipient not in [self, ZERO_ADDRESS]
amount: uint256 = _amount
# If _amount not specified, transfer the full token balance,
# up to deposit limit
if amount == MAX_UINT256:
amount = min(
self.depositLimit - self._totalAssets(),
self.token.balanceOf(msg.sender),
)
else:
# Ensure deposit limit is respected
assert self._totalAssets() + amount <= self.depositLimit
# Ensure we are depositing something
assert amount > 0
# Issue new shares (needs to be done before taking deposit to be accurate)
# Shares are issued to recipient (may be different from msg.sender)
# See @dev note, above.
shares: uint256 = self._issueSharesForAmount(recipient, amount)
# Tokens are transferred from msg.sender (may be different from _recipient)
self.erc20_safe_transferFrom(self.token.address, msg.sender, self, amount)
return shares # Just in case someone wants them
@view
@internal
def _shareValue(shares: uint256) -> uint256:
# Returns price = 1:1 if vault is empty
if self.totalSupply == 0:
return shares
# Determines the current value of `shares`.
# NOTE: if sqrt(Vault.totalAssets()) >>> 1e39, this could potentially revert
freeFunds: uint256 = self._totalAssets() - self._calculateLockedProfit()
return (
shares
* freeFunds
/ self.totalSupply
)
@view
@internal
def _sharesForAmount(amount: uint256) -> uint256:
# Determines how many shares `amount` of token would receive.
# See dev note on `deposit`.
if self._totalAssets() > 0:
# NOTE: if sqrt(token.totalSupply()) > 1e37, this could potentially revert
return (
amount
* self.totalSupply
/ self._totalAssets()
)
else:
return 0
@view
@external
def maxAvailableShares() -> uint256:
"""
@notice
Determines the maximum quantity of shares this Vault can facilitate a
withdrawal for, factoring in assets currently residing in the Vault,
as well as those deployed to strategies on the Vault's balance sheet.
@dev
Regarding how shares are calculated, see dev note on `deposit`.
If you want to calculated the maximum a user could withdraw up to,
you want to use this function.
Note that the amount provided by this function is the theoretical
maximum possible from withdrawing, the real amount depends on the
realized losses incurred during withdrawal.
@return The total quantity of shares this Vault can provide.
"""
shares: uint256 = self._sharesForAmount(self.token.balanceOf(self))
for strategy in self.withdrawalQueue:
if strategy == ZERO_ADDRESS:
break
shares += self._sharesForAmount(self.strategies[strategy].totalDebt)
return shares
@internal
def _reportLoss(strategy: address, loss: uint256):
# Loss can only be up the amount of debt issued to strategy
totalDebt: uint256 = self.strategies[strategy].totalDebt
assert totalDebt >= loss
# Also, make sure we reduce our trust with the strategy by the amount of loss
if self.debtRatio != 0: # if vault with single strategy that is set to EmergencyOne
# NOTE: The context to this calculation is different than the calculation in `_reportLoss`,
# this calculation intentionally approximates via `totalDebt` to avoid manipulatable results
ratio_change: uint256 = min(
# NOTE: This calculation isn't 100% precise, the adjustment is ~10%-20% more severe due to EVM math
loss * self.debtRatio / self.totalDebt,
self.strategies[strategy].debtRatio,
)
self.strategies[strategy].debtRatio -= ratio_change
self.debtRatio -= ratio_change
# Finally, adjust our strategy's parameters by the loss
self.strategies[strategy].totalLoss += loss
self.strategies[strategy].totalDebt = totalDebt - loss
self.totalDebt -= loss
@external
@nonreentrant("withdraw")
def withdraw(
maxShares: uint256 = MAX_UINT256,
recipient: address = msg.sender,
maxLoss: uint256 = 1, # 0.01% [BPS]
) -> uint256:
"""
@notice
Withdraws the calling account's tokens from this Vault, redeeming
amount `_shares` for an appropriate amount of tokens.
See note on `setWithdrawalQueue` for further details of withdrawal
ordering and behavior.
@dev
Measuring the value of shares is based on the total outstanding debt
that this contract has ("expected value") instead of the total balance
sheet it has ("estimated value") has important security considerations,
and is done intentionally. If this value were measured against external
systems, it could be purposely manipulated by an attacker to withdraw
more assets than they otherwise should be able to claim by redeeming
their shares.
On withdrawal, this means that shares are redeemed against the total
amount that the deposited capital had "realized" since the point it
was deposited, up until the point it was withdrawn. If that number
were to be higher than the "expected value" at some future point,
withdrawing shares via this method could entitle the depositor to
*more* than the expected value once the "realized value" is updated
from further reports by the Strategies to the Vaults.
Under exceptional scenarios, this could cause earlier withdrawals to
earn "more" of the underlying assets than Users might otherwise be
entitled to, if the Vault's estimated value were otherwise measured
through external means, accounting for whatever exceptional scenarios
exist for the Vault (that aren't covered by the Vault's own design.)
In the situation where a large withdrawal happens, it can empty the
vault balance and the strategies in the withdrawal queue.
Strategies not in the withdrawal queue will have to be harvested to
rebalance the funds and make the funds available again to withdraw.
@param maxShares
How many shares to try and redeem for tokens, defaults to all.
@param recipient
The address to issue the shares in this Vault to. Defaults to the
caller's address.
@param maxLoss
The maximum acceptable loss to sustain on withdrawal. Defaults to 0.01%.
@return The quantity of tokens redeemed for `_shares`.
"""
shares: uint256 = maxShares # May reduce this number below
# Max Loss is <=100%, revert otherwise
assert maxLoss <= MAX_BPS
# If _shares not specified, transfer full share balance
if shares == MAX_UINT256:
shares = self.balanceOf[msg.sender]
# Limit to only the shares they own
assert shares <= self.balanceOf[msg.sender]
# Ensure we are withdrawing something
assert shares > 0
# See @dev note, above.
value: uint256 = self._shareValue(shares)
totalLoss: uint256 = 0
if value > self.token.balanceOf(self):
# We need to go get some from our strategies in the withdrawal queue
# NOTE: This performs forced withdrawals from each Strategy. During
# forced withdrawal, a Strategy may realize a loss. That loss
# is reported back to the Vault, and the will affect the amount
# of tokens that the withdrawer receives for their shares. They
# can optionally specify the maximum acceptable loss (in BPS)
# to prevent excessive losses on their withdrawals (which may
# happen in certain edge cases where Strategies realize a loss)
for strategy in self.withdrawalQueue:
if strategy == ZERO_ADDRESS:
break # We've exhausted the queue
vault_balance: uint256 = self.token.balanceOf(self)
if value <= vault_balance:
break # We're done withdrawing
amountNeeded: uint256 = value - vault_balance
# NOTE: Don't withdraw more than the debt so that Strategy can still
# continue to work based on the profits it has
# NOTE: This means that user will lose out on any profits that each
# Strategy in the queue would return on next harvest, benefiting others
amountNeeded = min(amountNeeded, self.strategies[strategy].totalDebt)
if amountNeeded == 0:
continue # Nothing to withdraw from this Strategy, try the next one
# Force withdraw amount from each Strategy in the order set by governance
loss: uint256 = Strategy(strategy).withdraw(amountNeeded)
withdrawn: uint256 = self.token.balanceOf(self) - vault_balance
# NOTE: Withdrawer incurs any losses from liquidation
if loss > 0:
value -= loss
totalLoss += loss
self._reportLoss(strategy, loss)
# Reduce the Strategy's debt by the amount withdrawn ("realized returns")
# NOTE: This doesn't add to returns as it's not earned by "normal means"
self.strategies[strategy].totalDebt -= withdrawn
self.totalDebt -= withdrawn
# NOTE: We have withdrawn everything possible out of the withdrawal queue
# but we still don't have enough to fully pay them back, so adjust
# to the total amount we've freed up through forced withdrawals
vault_balance: uint256 = self.token.balanceOf(self)
if value > vault_balance:
value = vault_balance
# NOTE: Burn # of shares that corresponds to what Vault has on-hand,
# including the losses that were incurred above during withdrawals
shares = self._sharesForAmount(value + totalLoss)
# NOTE: This loss protection is put in place to revert if losses from
# withdrawing are more than what is considered acceptable.
assert totalLoss <= maxLoss * (value + totalLoss) / MAX_BPS
# Burn shares (full value of what is being withdrawn)
self.totalSupply -= shares
self.balanceOf[msg.sender] -= shares
log Transfer(msg.sender, ZERO_ADDRESS, shares)
# Withdraw remaining balance to _recipient (may be different to msg.sender) (minus fee)
self.erc20_safe_transfer(self.token.address, recipient, value)
return value
@view
@external
def pricePerShare() -> uint256:
"""
@notice Gives the price for a single Vault share.
@dev See dev note on `withdraw`.
@return The value of a single share.
"""
return self._shareValue(10 ** self.decimals)
@internal
def _organizeWithdrawalQueue():
# Reorganize `withdrawalQueue` based on premise that if there is an
# empty value between two actual values, then the empty value should be
# replaced by the later value.
# NOTE: Relative ordering of non-zero values is maintained.
offset: uint256 = 0
for idx in range(MAXIMUM_STRATEGIES):
strategy: address = self.withdrawalQueue[idx]
if strategy == ZERO_ADDRESS:
offset += 1 # how many values we need to shift, always `<= idx`
elif offset > 0:
self.withdrawalQueue[idx - offset] = strategy
self.withdrawalQueue[idx] = ZERO_ADDRESS
@external
def addStrategy(
strategy: address,
debtRatio: uint256,
minDebtPerHarvest: uint256,
maxDebtPerHarvest: uint256,
performanceFee: uint256,
):
"""
@notice
Add a Strategy to the Vault.
This may only be called by governance.
@dev
The Strategy will be appended to `withdrawalQueue`, call
`setWithdrawalQueue` to change the order.
@param strategy The address of the Strategy to add.
@param debtRatio
The share of the total assets in the `vault that the `strategy` has access to.
@param minDebtPerHarvest
Lower limit on the increase of debt since last harvest
@param maxDebtPerHarvest
Upper limit on the increase of debt since last harvest
@param performanceFee
The fee the strategist will receive based on this Vault's performance.
"""
# Check if queue is full
assert self.withdrawalQueue[MAXIMUM_STRATEGIES - 1] == ZERO_ADDRESS
# Check calling conditions
assert not self.emergencyShutdown
assert msg.sender == self.governance
# Check strategy configuration
assert strategy != ZERO_ADDRESS
assert self.strategies[strategy].activation == 0
assert self == Strategy(strategy).vault()
assert self.token.address == Strategy(strategy).want()
# Check strategy parameters
assert self.debtRatio + debtRatio <= MAX_BPS
assert minDebtPerHarvest <= maxDebtPerHarvest
assert performanceFee <= MAX_BPS / 2
# Add strategy to approved strategies
self.strategies[strategy] = StrategyParams({
performanceFee: performanceFee,
activation: block.timestamp,
debtRatio: debtRatio,
minDebtPerHarvest: minDebtPerHarvest,
maxDebtPerHarvest: maxDebtPerHarvest,
lastReport: block.timestamp,
totalDebt: 0,
totalGain: 0,
totalLoss: 0,
})
log StrategyAdded(strategy, debtRatio, minDebtPerHarvest, maxDebtPerHarvest, performanceFee)
# Update Vault parameters
self.debtRatio += debtRatio
# Add strategy to the end of the withdrawal queue
self.withdrawalQueue[MAXIMUM_STRATEGIES - 1] = strategy
self._organizeWithdrawalQueue()
@external
def updateStrategyDebtRatio(
strategy: address,
debtRatio: uint256,
):
"""
@notice
Change the quantity of assets `strategy` may manage.
This may be called by governance or management.
@param strategy The Strategy to update.
@param debtRatio The quantity of assets `strategy` may now manage.
"""
assert msg.sender in [self.management, self.governance]
assert self.strategies[strategy].activation > 0
self.debtRatio -= self.strategies[strategy].debtRatio
self.strategies[strategy].debtRatio = debtRatio
self.debtRatio += debtRatio
assert self.debtRatio <= MAX_BPS
log StrategyUpdateDebtRatio(strategy, debtRatio)
@external
def updateStrategyMinDebtPerHarvest(
strategy: address,
minDebtPerHarvest: uint256,
):
"""
@notice
Change the quantity assets per block this Vault may deposit to or
withdraw from `strategy`.
This may only be called by governance or management.
@param strategy The Strategy to update.
@param minDebtPerHarvest
Lower limit on the increase of debt since last harvest
"""
assert msg.sender in [self.management, self.governance]
assert self.strategies[strategy].activation > 0
assert self.strategies[strategy].maxDebtPerHarvest >= minDebtPerHarvest
self.strategies[strategy].minDebtPerHarvest = minDebtPerHarvest
log StrategyUpdateMinDebtPerHarvest(strategy, minDebtPerHarvest)
@external
def updateStrategyMaxDebtPerHarvest(
strategy: address,
maxDebtPerHarvest: uint256,
):
"""
@notice
Change the quantity assets per block this Vault may deposit to or
withdraw from `strategy`.
This may only be called by governance or management.
@param strategy The Strategy to update.
@param maxDebtPerHarvest
Upper limit on the increase of debt since last harvest
"""
assert msg.sender in [self.management, self.governance]
assert self.strategies[strategy].activation > 0
assert self.strategies[strategy].minDebtPerHarvest <= maxDebtPerHarvest
self.strategies[strategy].maxDebtPerHarvest = maxDebtPerHarvest
log StrategyUpdateMaxDebtPerHarvest(strategy, maxDebtPerHarvest)
@external
def updateStrategyPerformanceFee(
strategy: address,
performanceFee: uint256,
):
"""
@notice
Change the fee the strategist will receive based on this Vault's
performance.
This may only be called by governance.
@param strategy The Strategy to update.
@param performanceFee The new fee the strategist will receive.
"""
assert msg.sender == self.governance
assert performanceFee <= MAX_BPS / 2
assert self.strategies[strategy].activation > 0
self.strategies[strategy].performanceFee = performanceFee
log StrategyUpdatePerformanceFee(strategy, performanceFee)
@internal
def _revokeStrategy(strategy: address):
self.debtRatio -= self.strategies[strategy].debtRatio
self.strategies[strategy].debtRatio = 0
log StrategyRevoked(strategy)
@external
def migrateStrategy(oldVersion: address, newVersion: address):
"""
@notice
Migrates a Strategy, including all assets from `oldVersion` to
`newVersion`.
This may only be called by governance.
@dev
Strategy must successfully migrate all capital and positions to new
Strategy, or else this will upset the balance of the Vault.
The new Strategy should be "empty" e.g. have no prior commitments to
this Vault, otherwise it could have issues.
@param oldVersion The existing Strategy to migrate from.
@param newVersion The new Strategy to migrate to.
"""
assert msg.sender == self.governance
assert newVersion != ZERO_ADDRESS
assert self.strategies[oldVersion].activation > 0
assert self.strategies[newVersion].activation == 0
strategy: StrategyParams = self.strategies[oldVersion]
self._revokeStrategy(oldVersion)
# _revokeStrategy will lower the debtRatio
self.debtRatio += strategy.debtRatio
# Debt is migrated to new strategy
self.strategies[oldVersion].totalDebt = 0
self.strategies[newVersion] = StrategyParams({
performanceFee: strategy.performanceFee,
# NOTE: use last report for activation time, so E[R] calc works
activation: strategy.lastReport,
debtRatio: strategy.debtRatio,
minDebtPerHarvest: strategy.minDebtPerHarvest,
maxDebtPerHarvest: strategy.maxDebtPerHarvest,
lastReport: strateg...
// [truncated — 67176 bytes total]
Read Contract
DOMAIN_SEPARATOR 0x3644e515 → bytes32
activation 0x3629c8de → uint256
allowance 0xdd62ed3e → uint256
apiVersion 0x25829410 → string
availableDepositLimit 0x153c27c4 → uint256
balanceOf 0x70a08231 → uint256
creditAvailable 0x112c1f9b → uint256
creditAvailable 0xd7648013 → uint256
debtOutstanding 0xbf3759b5 → uint256
debtOutstanding 0xbdcf36bb → uint256
debtRatio 0xcea55f57 → uint256
decimals 0x313ce567 → uint256
depositLimit 0xecf70858 → uint256
emergencyShutdown 0x3403c2fc → bool
expectedReturn 0xd3406abd → uint256
expectedReturn 0x33586b67 → uint256
governance 0x5aa6e675 → address
guardian 0x452a9320 → address
lastReport 0xc3535b52 → uint256
lockedProfit 0x44b81396 → uint256
lockedProfitDegradation 0x42232716 → uint256
management 0x88a8d602 → address
managementFee 0xa6f7f5d6 → uint256
maxAvailableShares 0x75de2902 → uint256
name 0x06fdde03 → string
nonces 0x7ecebe00 → uint256
performanceFee 0x87788782 → uint256
pricePerShare 0x99530b06 → uint256
rewards 0x9ec5a894 → address
strategies 0x39ebf823 → uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256
symbol 0x95d89b41 → string
token 0xfc0c546a → address
totalAssets 0x01e1d114 → uint256
totalDebt 0xfc7b9c18 → uint256
totalSupply 0x18160ddd → uint256
withdrawalQueue 0xc822adda → address
Write Contract 42 functions
These functions modify contract state and require a wallet transaction to execute.
acceptGovernance 0x238efcbc
No parameters
addStrategy 0x14b4e26e
address strategy
uint256 debtRatio
uint256 minDebtPerHarvest
uint256 maxDebtPerHarvest
uint256 performanceFee
addStrategyToQueue 0xf76e4caa
address strategy
approve 0x095ea7b3
address spender
uint256 amount
returns: bool
decreaseAllowance 0xa457c2d7
address spender
uint256 amount
returns: bool
deposit 0xd0e30db0
No parameters
returns: uint256
deposit 0xb6b55f25
uint256 _amount
returns: uint256
deposit 0x6e553f65
uint256 _amount
address recipient
returns: uint256
increaseAllowance 0x39509351
address spender
uint256 amount
returns: bool
initialize 0x83b43589
address token
address governance
address rewards
string nameOverride
string symbolOverride
initialize 0xa5b81fdf
address token
address governance
address rewards
string nameOverride
string symbolOverride
address guardian
initialize 0x538baeab
address token
address governance
address rewards
string nameOverride
string symbolOverride
address guardian
address management
migrateStrategy 0x6cb56d19
address oldVersion
address newVersion
permit 0x9fd5a6cf
address owner
address spender
uint256 amount
uint256 expiry
bytes signature
returns: bool
removeStrategyFromQueue 0xb22439f5
address strategy
report 0xa1d9bafc
uint256 gain
uint256 loss
uint256 _debtPayment
returns: uint256
revokeStrategy 0xa0e4af9a
No parameters
revokeStrategy 0xbb994d48
address strategy
setDepositLimit 0xbdc8144b
uint256 limit
setEmergencyShutdown 0x14c64402
bool active
setGovernance 0xab033ea9
address governance
setGuardian 0x8a0dac4a
address guardian
setLockedProfitDegradation 0x7a550365
uint256 degradation
setManagement 0xd4a22bde
address management
setManagementFee 0xfe56e232
uint256 fee
setName 0xc47f0027
string name
setPerformanceFee 0x70897b23
uint256 fee
setRewards 0xec38a862
address rewards
setSymbol 0xb84c8246
string symbol
setWithdrawalQueue 0x94148415
address[20] queue
sweep 0x01681a62
address token
sweep 0x6ea056a9
address token
uint256 amount
transfer 0xa9059cbb
address receiver
uint256 amount
returns: bool
transferFrom 0x23b872dd
address sender
address receiver
uint256 amount
returns: bool
updateStrategyDebtRatio 0x7c6a4f24
address strategy
uint256 debtRatio
updateStrategyMaxDebtPerHarvest 0x4757a156
address strategy
uint256 maxDebtPerHarvest
updateStrategyMinDebtPerHarvest 0xe722befe
address strategy
uint256 minDebtPerHarvest
updateStrategyPerformanceFee 0xd0194ed6
address strategy
uint256 performanceFee
withdraw 0x3ccfd60b
No parameters
returns: uint256
withdraw 0x2e1a7d4d
uint256 maxShares
returns: uint256
withdraw 0x00f714ce
uint256 maxShares
address recipient
returns: uint256
withdraw 0xe63697c8
uint256 maxShares
address recipient
uint256 maxLoss
returns: uint256
Token Balances (1)
View Transfers →Recent Transactions
No transactions found for this address