Forkchoice Ethereum Mainnet

Address Contract Partially Verified

Address 0xc014F34D5Ba10B6799d76b0F5ACdEEe577805085
Balance 0 ETH
Nonce 1
Code Size 10161 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

10161 bytes
0x5f3560e01c60026027820660011b61276301601e395f51565b63765337b68118610034573461275f5760015460405260206040f35b63c63d75b681186100815760243610341761275f576004358060a01c61275f576040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60605260206060f35b637bde82f281186121535760443610341761275f576024358060a01c61275f576101a052336101c0526102a556612153565b632621db2f81186100cf573461275f5760025460405260206040f35b6306fdde03811861014a573461275f57602080604052806040016020600754015f81601f0160051c6003811161275f57801561011e57905b80600701548160051b850152600101818118610107575b5050508051806020830101601f825f03163682375050601f19601f825160200101169050810190506040f35b63a980497e8118612153573461275f575f5460021461275f576005546331dc3ca860e052602060e0600460fc845afa610185573d5f5f3e3d5ffd5b60203d1061275f5760e090505160c05260c0516101ad575f60e052602060e061022f5661022f565b600454632c4e722e60e052602060e0600460fc845afa6101cf573d5f5f3e3d5ffd5b60203d1061275f5760e09050516301e133808102816301e1338082041861275f57905060c05180820281158383830414171561275f57905090506102146101206122e8565b61012051801561275f57808204905090506101405260206101405bf3612153565b6386fc88d38118612153573461275f5760035460405260206040f3612153565b632a9439458118610271573461275f5760045460405260206040f35b63ba08765281186121535760643610341761275f576024358060a01c61275f576101a0526044358060a01c61275f576101c0525b5f5460021461275f5760025f55336101c0511461033257600d6101c0516020525f5260405f2080336020525f5260405f209050546101e0527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101e05114610332576101c051604052336060526101e05160043580820382811161275f5790509050608052610332612606565b61033d6102006122e8565b610200516101e05260043560c052600160e0526101e0516101005261036361022061249a565b610220516102005261270f6101e0516102005180820382811161275f57905090501161040657600f54600435186103a1576101e05161020052610406565b6010610220527f4e656564206d6f726520617373657473000000000000000000000000000000006102405261022050610220518061024001601f825f031636823750506308c379a06101e052602061020052601f19601f6102205101166044016101fcfd5b6101c05160405260043560605261041b61265b565b600554610220526001546323b872dd6102405261022051610260526101a05161028052610200516102a0526020610240606461025c5f855af1610460573d5f5f3e3d5ffd5b3d61047757803b1561275f5760016102c052610490565b60203d1061275f57610240518060011c61275f576102c0525b6102c09050511561275f57610220516369c6804e61024052803b1561275f575f610240600461025c5f855af16104c8573d5f5f3e3d5ffd5b506101c0516101a051337ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db6102005161024052600435610260526040610240a4602061020060035f55f3612153565b63f77c47918118610533573461275f5760055460405260206040f35b63d905777e81186121535760243610341761275f576004358060a01c61275f576101a0525f5460021461275f576001546370a082316101c0526005546101e05260206101c060246101dc845afa61058c573d5f5f3e3d5ffd5b60203d1061275f576101c090505160c0525f60e0527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610100526105d161020061239b565b61020051600e6101a0516020525f5260405f205480828118828410021890509050610220526020610220f3612153565b63c45a0155811861061d573461275f5760065460405260206040f35b63313ce5678118610638573461275f57601260405260206040f35b634cdad50681186121535760243610341761275f575f5460021461275f57600f546106775760043561275f575f6101a05260206101a061070356610703565b60043560c052600160e0527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610100526106b26101c061249a565b6101c0516101a0526001546370a082316101c0526005546101e05260206101c060246101dc845afa6106e6573d5f5f3e3d5ffd5b60203d1061275f576101c09050516101a0511161275f5760206101a05bf3612153565b6395d89b418118610784573461275f57602080604052806040016020600a54015f81601f0160051c6003811161275f57801561075857905b80600a01548160051b850152600101818118610741575b5050508051806020830101601f825f03163682375050601f19601f825160200101169050810190506040f35b6343687bba8118612153576101443610341761275f576004358060a01c61275f57610100526024358060a01c61275f57610120526044358060a01c61275f57610140526064358060a01c61275f576101605260c4358060a01c61275f576101805260e4358060a01c61275f576101a05260015461275f5761014051600155610160516002556101805160035560026084351015610821575f61082a565b61271060843511155b6108935760076101c0527f57726f6e672041000000000000000000000000000000000000000000000000006101e0526101c0506101c051806101e001601f825f031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b67016345785d8a000060a435111561090a57600c6101c0527f46656520746f6f206869676800000000000000000000000000000000000000006101e0526101c0506101c051806101e001601f825f031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b620f424060a435101561097c57600b6101c0527f46656520746f6f206c6f770000000000000000000000000000000000000000006101e0526101c0506101c051806101e001601f825f031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b662386f26fc100006101243510156109f357601c6101c0527f4c69717569646174696f6e20646973636f756e7420746f6f206c6f77000000006101e0526101c0506101c051806101e001601f825f031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b6706f05b59d3b20000610104351115610a6b5760166101c0527f4c6f616e20646973636f756e7420746f6f2068696768000000000000000000006101e0526101c0506101c051806101e001601f825f031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b610124356101043511610b025760276101c0527f6e656564206c6f616e5f646973636f756e743e6c69717569646174696f6e5f646101e0527f6973636f756e7400000000000000000000000000000000000000000000000000610200526101c0506101c051806101e001601f825f031636823750506308c379a06101805260206101a052601f19601f6101c051011660440161019cfd5b6101805163a035b1fe6101e05260206101e060046101fc845afa610b28573d5f5f3e3d5ffd5b60203d1061275f576101e09050516101c0526101c0511561275f576101c0516101805163ceb7f7596101e05260206101e060046101fc5f855af1610b6e573d5f5f3e3d5ffd5b60203d1061275f576101e09050511861275f57608435670de0b6b3a7640000810281670de0b6b3a764000082041861275f5790506084356001810381811161275f579050801561275f57808204905090506101e0526101405163313ce567610220526020610220600461023c845afa610be9573d5f5f3e3d5ffd5b60203d1061275f57610220905051806012036012811161275f579050604d811161275f5780600a0a90506102005261010051610140516102a0526102a05161040052610200516102c0526102c05161042052610160516102e0526102e051610440526101605163313ce567610240526020610240600461025c845afa610c71573d5f5f3e3d5ffd5b60203d1061275f57610240905051806012036012811161275f579050604d811161275f5780600a0a90506103005261030051610460526084356103205261032051610480526101e051670de0b6b3a7640000810281670de0b6b3a764000082041861275f5790508060b5710100000000000000000000000000000000008210610d01578160801c91508060401b90505b69010000000000000000008210610d1f578160401c91508060201b90505b650100000000008210610d39578160201c91508060101b90505b63010000008210610d51578160101c91508060081b90505b620100008201810260121c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808304808281188284100218905090509050905061034052610340516104a0526101e051604052610dd6610280612157565b6102805161036052610360516104c0526101c05161038052610380516104e05260a4356103a0526103a051610500525f6103c0526103c05161052052610180516103e0526103e051610540526101606003823b03596001821261275f5781600382863c81810183818561040060045afa5050828201815ff0801561275f57905090509050905061022052610120515f6102605261026051610300526101a051610280526102805161032052610104356102a0526102a05161034052610124356102c0526102c05161036052610220516102e0526102e0516103805260a06003823b03596001821261275f5781600382863c81810183818561030060045afa5050828201815ff0801561275f579050905090509050610240526102205163e9333fab610260526102405161028052803b1561275f575f610260602461027c5f855af1610f23573d5f5f3e3d5ffd5b5061022051600455610240516005553360065561020051601055610140516395d89b416102a05260606102a060046102bc845afa610f63573d5f5f3e3d5ffd5b60403d1061275f576102a0516102a001602081511161275f57805161032052602081015161034052506103209050805161026052602081015161028052505f60106102a0527f4375727665205661756c7420666f7220000000000000000000000000000000006102c0526102a080516020820183610300018151815250508083019250505061026051816103000161028051815250808201915050806102e0526102e0905060208151015f81601f0160051c6003811161275f57801561103c57905b8060051b8401518160070155600101818118611025575b505050505f60026102a0527f63760000000000000000000000000000000000000000000000000000000000006102c0526102a080516020820183610300018151815250508083019250505061026051816103000161028051815250808201915050806102e0526102e0905060208151015f81601f0160051c6003811161275f5780156110db57905b8060051b84015181600a01556001018181186110c4575b50505050610240516102a052610220516102c05260406102a0f3612153565b63dd62ed3e81186111525760443610341761275f576004358060a01c61275f576040526024358060a01c61275f57606052600d6040516020525f5260405f20806060516020525f5260405f2090505460805260206080f35b6338d52e0f811861116e573461275f5760015460405260206040f35b6328c0620381186121535760243610341761275f576004358060011c61275f5760c0525b5f5460021461275f57600f5460e05260e0516111c25766038d7ea4c680006101005260206101006112a6566112a6565b601054610100526111d46101406122e8565b610140516101005180820281158383830414171561275f57905090506001810181811061275f579050670de0b6b3a7640000810281670de0b6b3a764000082041861275f5790506101205260e0516103e8810181811061275f579050610140525f6101605260c05161127d57610120516101405180820182811061275f57905090506001810381811161275f57905061014051801561275f578082049050905061016052611297565b6101205161014051801561275f5780820490509050610160525b610160511561275f5760206101605bf3612153565b6370a0823181186121535760243610341761275f576004358060a01c61275f57604052600e6040516020525f5260405f205460605260206060f3612153565b6318160ddd8118612153573461275f57600f5460405260206040f3612153565b63bac4daa28118611372573461275f575f5460021461275f57600454632c4e722e604052602060406004605c845afa611346573d5f5f3e3d5ffd5b60203d1061275f5760409050516301e133808102816301e1338082041861275f57905060805260206080f35b63b3d7f6b981186121535760243610341761275f575f5460021461275f57602060043560c0525f60e0527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610100526113cc6101a061249a565b6101a0f3612153565b6301e1d11481186113fe573461275f575f5460021461275f5760206113fa60c06122e8565b60c0f35b63402d267d811861144b5760243610341761275f576004358060a01c61275f576040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60605260206060f35b63f851a4408118612153573461275f57602060065463f851a440604052602060406004605c845afa61147f573d5f5f3e3d5ffd5b60203d1061275f576040518060a01c61275f5760805260809050f3612153565b6399530b0681186114b9573461275f57600160c052611192565b6394bf804d81186116ad5760443610341761275f576024358060a01c61275f576101a0525b5f5460021461275f5760025f556005546101c0526114fd6102006122e8565b610200516101e05260043560c0525f60e0526101e0516101005261152261022061249a565b61022051610200526127106101e0516102005180820182811061275f579050905010156115ae576010610220527f4e656564206d6f726520617373657473000000000000000000000000000000006102405261022050610220518061024001601f825f031636823750506308c379a06101e052602061020052601f19601f6102205101166044016101fcfd5b6001546323b872dd6102205233610240526101c0516102605261020051610280526020610220606461023c5f855af16115e9573d5f5f3e3d5ffd5b3d61160057803b1561275f5760016102a052611619565b60203d1061275f57610220518060011c61275f576102a0525b6102a09050511561275f576101a051604052600435606052611639612599565b6101c0516369c6804e61022052803b1561275f575f610220600461023c5f855af1611666573d5f5f3e3d5ffd5b506101a051337fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d76102005161022052600435610240526040610220a3602061020060035f55f35b632e1a7d4d81186121535760243610341761275f57336101a052336101c052611b3a56612153565b63c6e6f59281186117355760243610341761275f575f5460021461275f57602060043560c052600160e0527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610100526117306101a061239b565b6101a0f35b63ce96cb7781186121535760243610341761275f576004358060a01c61275f576101a0525f5460021461275f57600e6101a0516020525f5260405f205460c052600160e0527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610100526117aa6101c061249a565b6101c0516001546370a082316101e0526005546102005260206101e060246101fc845afa6117da573d5f5f3e3d5ffd5b60203d1061275f576101e090505180828118828410021890509050610220526020610220f3612153565b6307a2d13a81186121535760243610341761275f575f5460021461275f57602060043560c052600160e0527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101005261185f6101a061249a565b6101a0f3612153565b63ef8b30f781186121535760243610341761275f575f5460021461275f57602060043560c052600160e0527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610100526118c36101a061239b565b6101a0f3612153565b63b6b55f2581186121535760243610341761275f57336101a05261191456612153565b636e553f6581186121535760443610341761275f576024358060a01c61275f576101a0525b5f5460021461275f5760025f556005546101c0526119336102006122e8565b610200516101e0526127106101e05160043580820182811061275f579050905010156119be576010610200527f4e656564206d6f726520617373657473000000000000000000000000000000006102205261020050610200518061022001601f825f031636823750506308c379a06101c05260206101e052601f19601f6102005101166044016101dcfd5b60043560c052600160e0526101e051610100526119dc61022061239b565b61022051610200526001546323b872dd6102205233610240526101c05161026052600435610280526020610220606461023c5f855af1611a1e573d5f5f3e3d5ffd5b3d611a3557803b1561275f5760016102a052611a4e565b60203d1061275f57610220518060011c61275f576102a0525b6102a09050511561275f576101a05160405261020051606052611a6f612599565b6101c0516369c6804e61022052803b1561275f575f610220600461023c5f855af1611a9c573d5f5f3e3d5ffd5b506101a051337fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d76004356102205261020051610240526040610220a3602061020060035f55f3612153565b63a0712d688118611b065760243610341761275f57336101a0526114de565b63b460af9481186121535760643610341761275f576024358060a01c61275f576101a0526044358060a01c61275f576101c0525b5f5460021461275f5760025f55611b526102006122e8565b610200516101e0526127106101e05160043580820382811161275f57905090501015611b86576004356101e0511815611b89565b60015b611bf2576010610200527f4e656564206d6f726520617373657473000000000000000000000000000000006102205261020050610200518061022001601f825f031636823750506308c379a06101c05260206101e052601f19601f6102005101166044016101dcfd5b60043560c0525f60e0526101e05161010052611c0f61022061239b565b6102205161020052336101c05114611c9857600d6101c0516020525f5260405f2080336020525f5260405f20905054610220527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102205114611c98576101c05160405233606052610220516102005180820382811161275f5790509050608052611c98612606565b600554610220526101c05160405261020051606052611cb561265b565b6001546323b872dd6102405261022051610260526101a051610280526004356102a0526020610240606461025c5f855af1611cf2573d5f5f3e3d5ffd5b3d611d0957803b1561275f5760016102c052611d22565b60203d1061275f57610240518060011c61275f576102c0525b6102c09050511561275f57610220516369c6804e61024052803b1561275f575f610240600461025c5f855af1611d5a573d5f5f3e3d5ffd5b506101c0516101a051337ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db6004356102405261020051610260526040610240a4602061020060035f55f3612153565b630a28a47781186121535760243610341761275f575f5460021461275f576001546370a082316101a0526005546101c05260206101a060246101bc845afa611df3573d5f5f3e3d5ffd5b60203d1061275f576101a09050516004351161275f57602060043560c0525f60e0527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61010052611e456101a061239b565b6101a0f3612153565b62f714ce81186121535760443610341761275f576024358060a01c61275f576101a052336101c052611b3a56612153565b63db006a7581186121535760243610341761275f57336101a052336101c0526102a556612153565b6323b872dd81186121535760643610341761275f576004358060a01c61275f5760c0526024358060a01c61275f5760e052600d60c0516020525f5260405f2080336020525f5260405f20905054610100527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101005114611f4c5760c051604052336060526101005160443580820382811161275f5790509050608052611f4c612606565b60c05160405260e051606052604435608052611f666126c8565b6001610120526020610120f3612153565b63a9059cbb81186121535760443610341761275f576004358060a01c61275f5760c0523360405260c051606052602435608052611fb26126c8565b600160e052602060e0f3612153565b63095ea7b381186121535760443610341761275f576004358060a01c61275f5760c0523360405260c051606052602435608052611ffc612606565b600160e052602060e0f3612153565b633950935181186121535760443610341761275f576004358060a01c61275f5760c052600d336020525f5260405f208060c0516020525f5260405f2090505460e05260243560e051016101005260e05161010051101561208b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610100525b60e05161010051146120b0573360405260c051606052610100516080526120b0612606565b6001610120526020610120f3612153565b63a457c2d781186121535760443610341761275f576004358060a01c61275f5760c052600d336020525f5260405f208060c0516020525f5260405f2090505460e05260243560e05103610100526101005160e0511015612121575f610100525b60e0516101005114612146573360405260c05160605261010051608052612146612606565b6001610120526020610120f35b5f5ffd5b6040516060525f6080525f6008905b8060a05260a051806007036007811161275f57905060ff811161275f578060020a905060c05260c05160ff811161275f578060020a905060e05260e051670de0b6b3a7640000810281670de0b6b3a764000082041861275f579050606051106122155760605160e051801561275f578082049050905060605260805160c051670de0b6b3a7640000810281670de0b6b3a764000082041861275f57905080820182811061275f57905090506080525b600101818118612166575050670de0b6b3a764000060a0525f603b905b8060c052671bc16d674ec800006060511061226b5760805160a05180820182811061275f57905090506080526060518060011c90506060525b60605160605180820281158383830414171561275f5790509050670de0b6b3a76400008104905060605260a0518060011c905060a052600101818118612232575050608051670de0b6b3a7640000810281670de0b6b3a764000082041861275f5790506714057b7ef7678100810490508060ff1c61275f57815250565b60055463d0c581bf604052602060406004605c845afa61230a573d5f5f3e3d5ffd5b60203d1061275f576040518060011c61275f57608052608050506001546370a08231604052600554606052602060406024605c845afa61234c573d5f5f3e3d5ffd5b60203d1061275f5760409050516005546331dc3ca8608052602060806004609c845afa61237b573d5f5f3e3d5ffd5b60203d1061275f57608090505180820182811061275f5790509050815250565b610100516101205261012051196123c0576123b76101406122e8565b61014051610120525b60105461014052600f546103e8810181811061275f57905060c05180820281158383830414171561275f57905090506101405180820281158383830414171561275f579050905061016052610120516101405180820281158383830414171561275f57905090506001810181811061275f5790506101805260e05161247f57610160516101805180820182811061275f57905090506001810381811161275f57905061018051801561275f578082049050905081525061249856612498565b6101605161018051801561275f57808204905090508152505b565b610100516101205261012051196124bf576124b66101406122e8565b61014051610120525b6010546101405260c051610120516101405180820281158383830414171561275f57905090506001810181811061275f57905080820281158383830414171561275f579050905061016052600f546103e8810181811061275f5790506101405180820281158383830414171561275f57905090506101805260e05161257e57610160516101805180820182811061275f57905090506001810381811161275f57905061018051801561275f578082049050905081525061259756612597565b6101605161018051801561275f57808204905090508152505b565b600e6040516020525f5260405f20805460605180820182811061275f5790509050815550600f5460605180820182811061275f5790509050600f556040515f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60605160805260206080a3565b608051600d6040516020525f5260405f20806060516020525f5260405f209050556060516040517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560805160a052602060a0a3565b600e6040516020525f5260405f20805460605180820382811161275f5790509050815550600f5460605180820382811161275f5790509050600f555f6040517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60605160805260206080a3565b6060513081146126da578015156126dc565b5f5b90501561275f57600e6040516020525f5260405f20805460805180820382811161275f5790509050815550600e6060516020525f5260405f20805460805180820182811061275f57905090508155506060516040517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60805160a052602060a0a3565b5f80fd215318042153215312ac215310fa1f7721531da900b3200b130b149f1ea716d51e7f215318cc21531ae7070918681fc1215312eb21530601025513d50018215318ef20c121531e4e215302350517

Verified Source Code Partial Match

Compiler: v0.3.10+commit.91361694
Vault.vy 665 lines
# @version 0.3.10
"""
@title Vault
@notice ERC4626+ Vault for lending with crvUSD using LLAMMA algorithm
@author Curve.Fi
@license Copyright (c) Curve.Fi, 2020-2024 - all rights reserved
"""
from vyper.interfaces import ERC20 as ERC20Spec
from vyper.interfaces import ERC20Detailed


implements: ERC20Spec
implements: ERC20Detailed


interface ERC20:
    def transferFrom(_from: address, _to: address, _value: uint256) -> bool: nonpayable
    def transfer(_to: address, _value: uint256) -> bool: nonpayable
    def decimals() -> uint256: view
    def balanceOf(_from: address) -> uint256: view
    def symbol() -> String[32]: view
    def name() -> String[64]: view

interface AMM:
    def set_admin(_admin: address): nonpayable
    def rate() -> uint256: view

interface Controller:
    def total_debt() -> uint256: view
    def minted() -> uint256: view
    def redeemed() -> uint256: view
    def monetary_policy() -> address: view
    def check_lock() -> bool: view
    def save_rate(): nonpayable

interface PriceOracle:
    def price() -> uint256: view
    def price_w() -> uint256: nonpayable

interface Factory:
    def admin() -> address: view


# ERC20 events

event Approval:
    owner: indexed(address)
    spender: indexed(address)
    value: uint256

event Transfer:
    sender: indexed(address)
    receiver: indexed(address)
    value: uint256

# 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


# Limits
MIN_A: constant(uint256) = 2
MAX_A: constant(uint256) = 10000
MIN_FEE: constant(uint256) = 10**6  # 1e-12, still needs to be above 0
MAX_FEE: constant(uint256) = 10**17  # 10%
MAX_LOAN_DISCOUNT: constant(uint256) = 5 * 10**17
MIN_LIQUIDATION_DISCOUNT: constant(uint256) = 10**16
ADMIN_FEE: constant(uint256) = 0

# These are virtual shares from method proposed by OpenZeppelin
# see: https://blog.openzeppelin.com/a-novel-defense-against-erc4626-inflation-attacks
# and
# https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/ERC4626.sol
DEAD_SHARES: constant(uint256) = 1000
MIN_ASSETS: constant(uint256) = 10000

borrowed_token: public(ERC20)
collateral_token: public(ERC20)

price_oracle: public(PriceOracle)
amm: public(AMM)
controller: public(Controller)
factory: public(Factory)


# ERC20 publics

decimals: public(constant(uint8)) = 18
name: public(String[64])
symbol: public(String[34])

NAME_PREFIX: constant(String[16]) = 'Curve Vault for '
SYMBOL_PREFIX: constant(String[2]) = 'cv'

allowance: public(HashMap[address, HashMap[address, uint256]])
balanceOf: public(HashMap[address, uint256])
totalSupply: public(uint256)

precision: uint256


@external
def __init__():
    """
    @notice Template for Vault implementation
    """
    # The contract is made a "normal" template (not blueprint) so that we can get contract address before init
    # This is needed if we want to create a rehypothecation dual-market with two vaults
    # where vaults are collaterals of each other
    self.borrowed_token = ERC20(0x0000000000000000000000000000000000000001)


@internal
@pure
def ln_int(_x: uint256) -> int256:
    """
    @notice Logarithm ln() function based on log2. Not very gas-efficient but brief
    """
    # adapted from: https://medium.com/coinmonks/9aef8515136e
    # and vyper log implementation
    # This can be much more optimal but that's not important here
    x: uint256 = _x
    res: uint256 = 0
    for i in range(8):
        t: uint256 = 2**(7 - i)
        p: uint256 = 2**t
        if x >= p * 10**18:
            x /= p
            res += t * 10**18
    d: uint256 = 10**18
    for i in range(59):  # 18 decimals: math.log2(10**10) == 59.7
        if (x >= 2 * 10**18):
            res += d
            x /= 2
        x = x * x / 10**18
        d /= 2
    # Now res = log2(x)
    # ln(x) = log2(x) / log2(e)
    return convert(res * 10**18 / 1442695040888963328, int256)


@external
def initialize(
        amm_impl: address,
        controller_impl: address,
        borrowed_token: ERC20,
        collateral_token: ERC20,
        A: uint256,
        fee: uint256,
        price_oracle: PriceOracle,  # Factory makes from template if needed, deploying with a from_pool()
        monetary_policy: address,  # Standard monetary policy set in factory
        loan_discount: uint256,
        liquidation_discount: uint256
    ) -> (address, address):
    """
    @notice Initializer for vaults
    @param amm_impl AMM implementation (blueprint)
    @param controller_impl Controller implementation (blueprint)
    @param borrowed_token Token which is being borrowed
    @param collateral_token Token used for collateral
    @param A Amplification coefficient: band size is ~1/A
    @param fee Fee for swaps in AMM (for ETH markets found to be 0.6%)
    @param price_oracle Already initialized price oracle
    @param monetary_policy Already initialized monetary policy
    @param loan_discount Maximum discount. LTV = sqrt(((A - 1) / A) ** 4) - loan_discount
    @param liquidation_discount Liquidation discount. LT = sqrt(((A - 1) / A) ** 4) - liquidation_discount
    """
    assert self.borrowed_token.address == empty(address)

    self.borrowed_token = borrowed_token
    self.collateral_token = collateral_token
    self.price_oracle = price_oracle

    assert A >= MIN_A and A <= MAX_A, "Wrong A"
    assert fee <= MAX_FEE, "Fee too high"
    assert fee >= MIN_FEE, "Fee too low"
    assert liquidation_discount >= MIN_LIQUIDATION_DISCOUNT, "Liquidation discount too low"
    assert loan_discount <= MAX_LOAN_DISCOUNT, "Loan discount too high"
    assert loan_discount > liquidation_discount, "need loan_discount>liquidation_discount"

    p: uint256 = price_oracle.price()  # This also validates price oracle ABI
    assert p > 0
    assert price_oracle.price_w() == p
    A_ratio: uint256 = 10**18 * A / (A - 1)

    borrowed_precision: uint256 = 10**(18 - borrowed_token.decimals())

    amm: address = create_from_blueprint(
        amm_impl,
        borrowed_token.address, borrowed_precision,
        collateral_token.address, 10**(18 - collateral_token.decimals()),
        A, isqrt(A_ratio * 10**18), self.ln_int(A_ratio),
        p, fee, ADMIN_FEE, price_oracle.address,
        code_offset=3)
    controller: address = create_from_blueprint(
        controller_impl,
        empty(address), monetary_policy, loan_discount, liquidation_discount, amm,
        code_offset=3)
    AMM(amm).set_admin(controller)

    self.amm = AMM(amm)
    self.controller = Controller(controller)
    self.factory = Factory(msg.sender)

    # ERC20 set up
    self.precision = borrowed_precision
    borrowed_symbol: String[32] = borrowed_token.symbol()
    self.name = concat(NAME_PREFIX, borrowed_symbol)
    # Symbol must be String[32], but we do String[34]. It doesn't affect contracts which read it (they will truncate)
    # However this will be changed as soon as Vyper can *properly* manipulate strings
    self.symbol = concat(SYMBOL_PREFIX, borrowed_symbol)

    # No events because it's the only market we would ever create in this contract

    return controller, amm


@external
@view
@nonreentrant('lock')
def borrow_apr() -> uint256:
    """
    @notice Borrow APR (annualized and 1e18-based)
    """
    return self.amm.rate() * (365 * 86400)


@external
@view
@nonreentrant('lock')
def lend_apr() -> uint256:
    """
    @notice Lending APR (annualized and 1e18-based)
    """
    debt: uint256 = self.controller.total_debt()
    if debt == 0:
        return 0
    else:
        return self.amm.rate() * (365 * 86400) * debt / self._total_assets()


@external
@view
def asset() -> ERC20:
    """
    @notice Asset which is the same as borrowed_token
    """
    return self.borrowed_token


@internal
@view
def _total_assets() -> uint256:
    # admin fee should be accounted for here when enabled
    self.controller.check_lock()
    return self.borrowed_token.balanceOf(self.controller.address) + self.controller.total_debt()


@external
@view
@nonreentrant('lock')
def totalAssets() -> uint256:
    """
    @notice Total assets which can be lent out or be in reserve
    """
    return self._total_assets()


@internal
@view
def _convert_to_shares(assets: uint256, is_floor: bool = True,
                       _total_assets: uint256 = max_value(uint256)) -> uint256:
    total_assets: uint256 = _total_assets
    if total_assets == max_value(uint256):
        total_assets = self._total_assets()
    precision: uint256 = self.precision
    numerator: uint256 = (self.totalSupply + DEAD_SHARES) * assets * precision
    denominator: uint256 = (total_assets * precision + 1)
    if is_floor:
        return numerator / denominator
    else:
        return (numerator + denominator - 1) / denominator


@internal
@view
def _convert_to_assets(shares: uint256, is_floor: bool = True,
                       _total_assets: uint256 = max_value(uint256)) -> uint256:
    total_assets: uint256 = _total_assets
    if total_assets == max_value(uint256):
        total_assets = self._total_assets()
    precision: uint256 = self.precision
    numerator: uint256 = shares * (total_assets * precision + 1)
    denominator: uint256 = (self.totalSupply + DEAD_SHARES) * precision
    if is_floor:
        return numerator / denominator
    else:
        return (numerator + denominator - 1) / denominator


@external
@view
@nonreentrant('lock')
def pricePerShare(is_floor: bool = True) -> uint256:
    """
    @notice Method which shows how much one pool share costs in asset tokens if they are normalized to 18 decimals
    """
    supply: uint256 = self.totalSupply
    if supply == 0:
        return 10**18 / DEAD_SHARES
    else:
        precision: uint256 = self.precision
        numerator: uint256 = 10**18 * (self._total_assets() * precision + 1)
        denominator: uint256 = (supply + DEAD_SHARES)
        pps: uint256 = 0
        if is_floor:
            pps = numerator / denominator
        else:
            pps = (numerator + denominator - 1) / denominator
        assert pps > 0
        return pps


@external
@view
@nonreentrant('lock')
def convertToShares(assets: uint256) -> uint256:
    """
    @notice Returns the amount of shares which the Vault would exchange for the given amount of shares provided
    """
    return self._convert_to_shares(assets)


@external
@view
@nonreentrant('lock')
def convertToAssets(shares: uint256) -> uint256:
    """
    @notice Returns the amount of assets that the Vault would exchange for the amount of shares provided
    """
    return self._convert_to_assets(shares)


@external
@view
def maxDeposit(receiver: address) -> uint256:
    """
    @notice Maximum amount of assets which a given user can deposit (inf)
    """
    return max_value(uint256)


@external
@view
@nonreentrant('lock')
def previewDeposit(assets: uint256) -> uint256:
    """
    @notice Returns the amount of shares which can be obtained upon depositing assets
    """
    return self._convert_to_shares(assets)


@external
@nonreentrant('lock')
def deposit(assets: uint256, receiver: address = msg.sender) -> uint256:
    """
    @notice Deposit assets in return for whatever number of shares corresponds to the current conditions
    @param assets Amount of assets to deposit
    @param receiver Receiver of the shares who is optional. If not specified - receiver is the sender
    """
    controller: Controller = self.controller
    total_assets: uint256 = self._total_assets()
    assert total_assets + assets >= MIN_ASSETS, "Need more assets"
    to_mint: uint256 = self._convert_to_shares(assets, True, total_assets)
    assert self.borrowed_token.transferFrom(msg.sender, controller.address, assets, default_return_value=True)
    self._mint(receiver, to_mint)
    controller.save_rate()
    log Deposit(msg.sender, receiver, assets, to_mint)
    return to_mint


@external
@view
def maxMint(receiver: address) -> uint256:
    """
    @notice Return maximum amount of shares which a given user can mint (inf)
    """
    return max_value(uint256)


@external
@view
@nonreentrant('lock')
def previewMint(shares: uint256) -> uint256:
    """
    @notice Calculate the amount of assets which is needed to exactly mint the given amount of shares
    """
    return self._convert_to_assets(shares, False)


@external
@nonreentrant('lock')
def mint(shares: uint256, receiver: address = msg.sender) -> uint256:
    """
    @notice Mint given amount of shares taking whatever number of assets it requires
    @param shares Number of sharess to mint
    @param receiver Optional receiver for the shares. If not specified - it's the sender
    """
    controller: Controller = self.controller
    total_assets: uint256 = self._total_assets()
    assets: uint256 = self._convert_to_assets(shares, False, total_assets)
    assert total_assets + assets >= MIN_ASSETS, "Need more assets"
    assert self.borrowed_token.transferFrom(msg.sender, controller.address, assets, default_return_value=True)
    self._mint(receiver, shares)
    controller.save_rate()
    log Deposit(msg.sender, receiver, assets, shares)
    return assets


@external
@view
@nonreentrant('lock')
def maxWithdraw(owner: address) -> uint256:
    """
    @notice Maximum amount of assets which a given user can withdraw. Aware of both user's balance and available liquidity
    """
    return min(
        self._convert_to_assets(self.balanceOf[owner]),
        self.borrowed_token.balanceOf(self.controller.address))


@external
@view
@nonreentrant('lock')
def previewWithdraw(assets: uint256) -> uint256:
    """
    @notice Calculate number of shares which gets burned when withdrawing given amount of asset
    """
    assert assets <= self.borrowed_token.balanceOf(self.controller.address)
    return self._convert_to_shares(assets, False)


@external
@nonreentrant('lock')
def withdraw(assets: uint256, receiver: address = msg.sender, owner: address = msg.sender) -> uint256:
    """
    @notice Withdraw given amount of asset and burn the corresponding amount of vault shares
    @param assets Amount of assets to withdraw
    @param receiver Receiver of the assets (optional, sender if not specified)
    @param owner Owner who's shares the caller takes. Only can take those if owner gave the approval to the sender. Optional
    """
    total_assets: uint256 = self._total_assets()
    assert total_assets - assets >= MIN_ASSETS or total_assets == assets, "Need more assets"
    shares: uint256 = self._convert_to_shares(assets, False, total_assets)
    if owner != msg.sender:
        allowance: uint256 = self.allowance[owner][msg.sender]
        if allowance != max_value(uint256):
            self._approve(owner, msg.sender, allowance - shares)

    controller: Controller = self.controller
    self._burn(owner, shares)
    assert self.borrowed_token.transferFrom(controller.address, receiver, assets, default_return_value=True)
    controller.save_rate()
    log Withdraw(msg.sender, receiver, owner, assets, shares)
    return shares


@external
@view
@nonreentrant('lock')
def maxRedeem(owner: address) -> uint256:
    """
    @notice Calculate maximum amount of shares which a given user can redeem
    """
    return min(
        self._convert_to_shares(self.borrowed_token.balanceOf(self.controller.address), False),
        self.balanceOf[owner])


@external
@view
@nonreentrant('lock')
def previewRedeem(shares: uint256) -> uint256:
    """
    @notice Calculate the amount of assets which can be obtained by redeeming the given amount of shares
    """
    if self.totalSupply == 0:
        assert shares == 0
        return 0

    else:
        assets_to_redeem: uint256 = self._convert_to_assets(shares)
        assert assets_to_redeem <= self.borrowed_token.balanceOf(self.controller.address)
        return assets_to_redeem


@external
@nonreentrant('lock')
def redeem(shares: uint256, receiver: address = msg.sender, owner: address = msg.sender) -> uint256:
    """
    @notice Burn given amount of shares and give corresponding assets to the user
    @param shares Amount of shares to burn
    @param receiver Optional receiver of the assets
    @param owner Optional owner of the shares. Can only redeem if owner gave approval to the sender
    """
    if owner != msg.sender:
        allowance: uint256 = self.allowance[owner][msg.sender]
        if allowance != max_value(uint256):
            self._approve(owner, msg.sender, allowance - shares)

    total_assets: uint256 = self._total_assets()
    assets_to_redeem: uint256 = self._convert_to_assets(shares, True, total_assets)
    if total_assets - assets_to_redeem < MIN_ASSETS:
        if shares == self.totalSupply:
            # This is the last withdrawal, so we can take everything
            assets_to_redeem = total_assets
        else:
            raise "Need more assets"
    self._burn(owner, shares)
    controller: Controller = self.controller
    assert self.borrowed_token.transferFrom(controller.address, receiver, assets_to_redeem, default_return_value=True)
    controller.save_rate()
    log Withdraw(msg.sender, receiver, owner, assets_to_redeem, shares)
    return assets_to_redeem


# ERC20 methods

@internal
def _approve(_owner: address, _spender: address, _value: uint256):
    self.allowance[_owner][_spender] = _value

    log Approval(_owner, _spender, _value)


@internal
def _burn(_from: address, _value: uint256):
    self.balanceOf[_from] -= _value
    self.totalSupply -= _value

    log Transfer(_from, empty(address), _value)


@internal
def _mint(_to: address, _value: uint256):
    self.balanceOf[_to] += _value
    self.totalSupply += _value

    log Transfer(empty(address), _to, _value)


@internal
def _transfer(_from: address, _to: address, _value: uint256):
    assert _to not in [self, empty(address)]

    self.balanceOf[_from] -= _value
    self.balanceOf[_to] += _value

    log Transfer(_from, _to, _value)


@external
def transferFrom(_from: address, _to: address, _value: uint256) -> bool:
    """
    @notice Transfer tokens from one account to another.
    @dev The caller needs to have an allowance from account `_from` greater than or
        equal to the value being transferred. An allowance equal to the uint256 type's
        maximum, is considered infinite and does not decrease.
    @param _from The account which tokens will be spent from.
    @param _to The account which tokens will be sent to.
    @param _value The amount of tokens to be transferred.
    """
    allowance: uint256 = self.allowance[_from][msg.sender]
    if allowance != max_value(uint256):
        self._approve(_from, msg.sender, allowance - _value)

    self._transfer(_from, _to, _value)
    return True


@external
def transfer(_to: address, _value: uint256) -> bool:
    """
    @notice Transfer tokens to `_to`.
    @param _to The account to transfer tokens to.
    @param _value The amount of tokens to transfer.
    """
    self._transfer(msg.sender, _to, _value)
    return True


@external
def approve(_spender: address, _value: uint256) -> bool:
    """
    @notice Allow `_spender` to transfer up to `_value` amount of tokens from the caller's account.
    @dev Non-zero to non-zero approvals are allowed, but should be used cautiously. The methods
        increaseAllowance + decreaseAllowance are available to prevent any front-running that
        may occur.
    @param _spender The account permitted to spend up to `_value` amount of caller's funds.
    @param _value The amount of tokens `_spender` is allowed to spend.
    """
    self._approve(msg.sender, _spender, _value)
    return True


@external
def increaseAllowance(_spender: address, _add_value: uint256) -> bool:
    """
    @notice Increase the allowance granted to `_spender`.
    @dev This function will never overflow, and instead will bound
        allowance to MAX_UINT256. This has the potential to grant an
        infinite approval.
    @param _spender The account to increase the allowance of.
    @param _add_value The amount to increase the allowance by.
    """
    cached_allowance: uint256 = self.allowance[msg.sender][_spender]
    allowance: uint256 = unsafe_add(cached_allowance, _add_value)

    # check for an overflow
    if allowance < cached_allowance:
        allowance = max_value(uint256)

    if allowance != cached_allowance:
        self._approve(msg.sender, _spender, allowance)

    return True


@external
def decreaseAllowance(_spender: address, _sub_value: uint256) -> bool:
    """
    @notice Decrease the allowance granted to `_spender`.
    @dev This function will never underflow, and instead will bound
        allowance to 0.
    @param _spender The account to decrease the allowance of.
    @param _sub_value The amount to decrease the allowance by.
    """
    cached_allowance: uint256 = self.allowance[msg.sender][_spender]
    allowance: uint256 = unsafe_sub(cached_allowance, _sub_value)

    # check for an underflow
    if cached_allowance < allowance:
        allowance = 0

    if allowance != cached_allowance:
        self._approve(msg.sender, _spender, allowance)

    return True


@external
@view
def admin() -> address:
    return self.factory.admin()

Read Contract

admin 0xf851a440 → address
allowance 0xdd62ed3e → uint256
amm 0x2a943945 → address
asset 0x38d52e0f → address
balanceOf 0x70a08231 → uint256
borrow_apr 0xbac4daa2 → uint256
borrowed_token 0x765337b6 → address
collateral_token 0x2621db2f → address
controller 0xf77c4791 → address
convertToAssets 0x07a2d13a → uint256
convertToShares 0xc6e6f592 → uint256
decimals 0x313ce567 → uint8
factory 0xc45a0155 → address
lend_apr 0xa980497e → uint256
maxDeposit 0x402d267d → uint256
maxMint 0xc63d75b6 → uint256
maxRedeem 0xd905777e → uint256
maxWithdraw 0xce96cb77 → uint256
name 0x06fdde03 → string
previewDeposit 0xef8b30f7 → uint256
previewMint 0xb3d7f6b9 → uint256
previewRedeem 0x4cdad506 → uint256
previewWithdraw 0x0a28a477 → uint256
pricePerShare 0x99530b06 → uint256
pricePerShare 0x28c06203 → uint256
price_oracle 0x86fc88d3 → address
symbol 0x95d89b41 → string
totalAssets 0x01e1d114 → uint256
totalSupply 0x18160ddd → uint256

Write Contract 16 functions

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

approve 0x095ea7b3
address _spender
uint256 _value
returns: bool
decreaseAllowance 0xa457c2d7
address _spender
uint256 _sub_value
returns: bool
deposit 0xb6b55f25
uint256 assets
returns: uint256
deposit 0x6e553f65
uint256 assets
address receiver
returns: uint256
increaseAllowance 0x39509351
address _spender
uint256 _add_value
returns: bool
initialize 0x43687bba
address amm_impl
address controller_impl
address borrowed_token
address collateral_token
uint256 A
uint256 fee
address price_oracle
address monetary_policy
uint256 loan_discount
uint256 liquidation_discount
returns: address, address
mint 0xa0712d68
uint256 shares
returns: uint256
mint 0x94bf804d
uint256 shares
address receiver
returns: uint256
redeem 0xdb006a75
uint256 shares
returns: uint256
redeem 0x7bde82f2
uint256 shares
address receiver
returns: uint256
redeem 0xba087652
uint256 shares
address receiver
address owner
returns: uint256
transfer 0xa9059cbb
address _to
uint256 _value
returns: bool
transferFrom 0x23b872dd
address _from
address _to
uint256 _value
returns: bool
withdraw 0x2e1a7d4d
uint256 assets
returns: uint256
withdraw 0x00f714ce
uint256 assets
address receiver
returns: uint256
withdraw 0xb460af94
uint256 assets
address receiver
address owner
returns: uint256

Recent Transactions

No transactions found for this address