Address Contract Partially Verified
Address
0x5426178799ee0a0181A89b4f57eFddfAb49941Ec
Balance
4.9162 ETH
Nonce
1
Code Size
21789 bytes
Creator
0x0c0e5f2f...4963 at tx 0xf8a1b6c8...0b316d
Indexed Transactions
0
Contract Bytecode
21789 bytes
0x6003361161000c576129bd565b5f3560e01c635b41b9088118610033576084361061534c575f610aa05233610ac052610091565b63394747c5811861005f5760a4361061534c576084358060011c61534c57610aa05233610ac052610091565b63ce7d650381186100dd5760c4361061534c576084358060011c61534c57610aa05260a4358060a01c61534c57610ac0525b5f5460021461534c5760025f556020336105e05234610600526080600461062037610aa0516106a052610ac0516106c0526040366106e0376100d4610ae0613cbd565b610ae060035f55f35b6365b2489b81186100fa576084361061534c5733610aa05261011d565b63e2ad025a81186101675760a4361061534c576084358060a01c61534c57610aa0525b5f5460021461534c5760025f556020336105e0523461060052608060046106203760016106a052610aa0516106c0526040366106e03761015e610ac0613cbd565b610ac060035f55f35b634515cef38118610189576084361061534c575f6105e05233610600526101e7565b632b6e993a81186101b55760a4361061534c576084358060011c61534c576105e05233610600526101e7565b635cecb5f781186109a75760c4361061534c576084358060011c61534c576105e05260a4358060a01c61534c57610600525b5f5460021461534c5760025f556101ff610660612d41565b61066080516106205260208101516106405250600b5461066052600c5461068052600d546106a052610120366106c03760043560243580820182811061534c579050905060443580820182811061534c57905090501561534c5760015460405261026a610840612e9a565b61084080516107e05260208101516108005260408101516108205250600354610840526108405160405261029f6108a0612ed6565b6108a080516108605260208101516108805250610660516108a052610680516108c0526106a0516108e0525f6003905b8061090052610900516002811161534c5760051b6106600151610900516002811161534c5760051b6004013580820182811061534c57905090506109205261092051610900516002811161534c5760051b610660015261092051610900516002811161534c57600b01556001018181186102cf575050610660516107205261068051610740526106a05161076052610660516107e05180820281158383830414171561534c5790509050610660526108a0516107e05180820281158383830414171561534c57905090506108a052600160028101905b8061090052670de0b6b3a7640000610900516002811161534c5760051b6106600151610900516001810381811161534c5790506001811161534c5760051b610860015180820281158383830414171561534c5790509050610900516002811161534c5760051b6107e0015180820281158383830414171561534c579050905004610900516002811161534c5760051b6106600152670de0b6b3a7640000610900516002811161534c5760051b6108a00151610900516002811161534c5760051b6107e00151610900516001810381811161534c5790506001811161534c5760051b61086001510280820281158383830414171561534c579050905004610900516002811161534c5760051b6108a001526001018181186103a55750505f6003905b8061090052610900516002811161534c5760051b600401351561060457602061535d5f395f516020610900516002811161534c5760051b60400161535d015f395f511861056a576020610900516002811161534c5760051b60400161535d015f395f51604052610900516002811161534c5760051b600401356060525f6080523460a05260403660c03733610100525f610120526105e051610140526105b9612a10565b6020610900516002811161534c5760051b60400161535d015f395f51604052610900516002811161534c5760051b600401356060526080366080373361010052604036610120376105b9612a10565b610900516002811161534c5760051b6106600151610900516002811161534c5760051b6108a0015180820382811161534c5790509050610900516002811161534c5760051b6106c001525b6001018181186104c657505042600a541161062557600e546107c052610690565b602061537d5f395f51637b12e00961090052610620516109205261064051610940526108a051610960526108c051610980526108e0516109a0525f6109c052602061090060c461091c845afa61067d573d5f5f3e3d5ffd5b60203d1061534c576109009050516107c0525b602061537d5f395f51637b12e00961092052610620516109405261064051610960526106605161098052610680516109a0526106a0516109c0525f6109e052602061092060c461093c845afa6106e8573d5f5f3e3d5ffd5b60203d1061534c5761092090505161090052601954610920526107c0511561075257610920516109005180820281158383830414171561534c57905090506107c051801561534c57808204905090506109205180820382811161534c57905090506107805261076d565b6109005160405261076461094061444a565b61094051610780525b610780511561534c576107c0511561088e576106c0516101e0526106e051610200526107005161022052610660516102405261068051610260526106a051610280526107ba610940614537565b610940516107805180820281158383830414171561534c57905090506402540be400810490506001810181811061534c5790506107a052610780516107a05180820382811161534c579050905061078052610920516107805180820182811061534c579050905061092052610600516040526107805160605261083e610940614662565b610940506106205160e0526106405161010052610660516101205261068051610140526106a0516101605261090051610180525f6101a05261088161094061309d565b61094051610840526108d7565b61090051600e55670de0b6b3a7640000601155670de0b6b3a7640000600f55670de0b6b3a764000060105561060051604052610780516060526108d2610940614662565b610940505b606435610780511015610949576008610940527f536c6970706167650000000000000000000000000000000000000000000000006109605261094050610940518061096001601f825f031636823750506308c379a061090052602061092052601f19601f61094051011660440161091cfd5b610600517fe1b60455bd9e33720b547f60e4e0cfbf1252d0f2ee0147d53029945f39fe3c1a60606004610940376107a0516109a052610920516109c052610840516109e05260c0610940a261099c6148a6565b602061078060035f55f35b6317e26cd181186109c9573461534c57602061535d5f395f5160405260206040f35b63ed6c154681186109eb573461534c57602061537d5f395f5160405260206040f35b63c66106578118610a27576024361061534c573461534c5760206004356002811161534c5760051b60400161535d015f395f5160405260206040f35b63c45a01558118610a43573461534c5760025460405260206040f35b636112c7478118610a5f573461534c5760065460405260206040f35b63204fe3d58118610a7b573461534c5760075460405260206040f35b63e89876ff8118610a97573461534c5760085460405260206040f35b63f30cfad58118610ab3573461534c5760095460405260206040f35b63f9ed95978118610acf573461534c57600a5460405260206040f35b634903b0d18118610aff576024361061534c573461534c576004356002811161534c57600b015460405260206040f35b630f529ba28118610b1b573461534c57600e5460405260206040f35b637ba1a74d8118610b37573461534c57600f5460405260206040f35b630b7b594b8118610b53573461534c5760105460405260206040f35b630c46b72a8118610b6f573461534c5760115460405260206040f35b633dd654788118610b8b573461534c5760125460405260206040f35b63e36164058118610ba7573461534c5760145460405260206040f35b634469ed148118610bc6573461534c5764012a05f20060405260206040f35b63405e28f88118610be2573461534c5760165460405260206040f35b6306fdde038118610c3d573461534c576020806040528060400160206153fd5f395f51602082018161541d823950808252508051806020830101601f825f03163682375050601f19601f825160200101169050810190506040f35b6395d89b418118610c9d573461534c5760208060405280604001602061545d5f395f5160208201602061547d5f395f51815250808252508051806020830101601f825f03163682375050601f19601f825160200101169050810190506040f35b63313ce5678118610cb8573461534c57601260405260206040f35b6354fd4d508118610d3c573461534c5760208060805260066040527f76322e302e30000000000000000000000000000000000000000000000000000060605260408160800181516020830160208301815181525050808252508051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506080f35b6370a082318118610d7a576024361061534c576004358060a01c61534c576040523461534c5760176040516020525f5260405f205460605260206060f35b63dd62ed3e8118610dd5576044361061534c576004358060a01c61534c576040526024358060a01c61534c576060523461534c5760186040516020525f5260405f20806060516020525f5260405f2090505460805260206080f35b6318160ddd8118610df1573461534c5760195460405260206040f35b637ecebe008118610e2f576024361061534c576004358060a01c61534c576040523461534c57601a6040516020525f5260405f205460605260206060f35b63bfa0b1338118610e51573461534c5760206154dd5f395f5160405260206040f35b63dd96994f8118610ef357610104361061534c576084358060011c61534c57610aa05260a4358060a01c61534c57610ac05260c4358060a01c61534c57610ae0523461534c575f5460021461534c5760025f5560e4351561534c576020610ac0516105e0525f610600526080600461062037610aa0516106a052610ae0516106c052336106e05260e43561070052610eea610b00613cbd565b610b0060035f55f35b63ecb586a58118610f1b576084361061534c575f610400523361042052600161044052610fca565b63fce647368118610f4d5760a4361061534c576084358060011c61534c57610400523361042052600161044052610fca565b631da3d2388118610f895760c4361061534c576084358060011c61534c576104005260a4358060a01c61534c5761042052600161044052610fca565b635cd3478081186112ab5760e4361061534c576084358060011c61534c576104005260a4358060a01c61534c576104205260c4358060011c61534c57610440525b3461534c575f5460021461534c5760025f5560043561046052600b5461048052600c546104a052600d546104c0526060366104e0376104405115611010576110106148a6565b601954610540523360405260043560605261102c610560614c09565b61056050610540516104605118611091575f6003905b8061056052610560516002811161534c5760051b6104800151610560516002811161534c5760051b6104e001525f610560516002811161534c57600b01556001018181186110425750506111a8565b610460516001810381811161534c579050610460525f6003905b8061056052610560516002811161534c5760051b61048001516104605180820281158383830414171561534c579050905061054051801561534c5780820490509050610560516002811161534c5760051b6104e00152610560516002811161534c5760051b60240135610560516002811161534c5760051b6104e001511061534c57610560516002811161534c5760051b6104800151610560516002811161534c5760051b6104e0015180820382811161534c5790509050610560516002811161534c57600b0155610560516002811161534c5760051b6104e00151610560516002811161534c5760051b61048001526001018181186110ab5750505b600e54610560526105605161054051610560516104605180820281158383830414171561534c57905090500480820382811161534c5790509050600e555f6003905b80610580526020610580516002811161534c5760051b60400161535d015f395f51604052610580516002811161534c5760051b6104e00151606052610400516080526104205160a05261123b612c4a565b6001018181186111ea575050337fd6cc314a0b1e3b2579f8e64248e82434072e8271290eef8ad0886709304195f561048051610580526104a0516105a0526104c0516105c0526105405160043580820382811161534c57905090506105e0526080610580a260606104e060035f55f35b63f1dc3cc981186112cd576064361061534c575f61066052336106805261132b565b638f15b6b581186112f9576084361061534c576064358060011c61534c5761066052336106805261132b565b6307329bcd81186115545760a4361061534c576064358060011c61534c57610660526084358060a01c61534c57610680525b3461534c575f5460021461534c5760025f556113486106e0612d41565b6106e080516106a05260208101516106c0525060e0366106e03761136a6148a6565b6106a0516101e0526106c05161020052604060046102203742600a5411610260526113966107c0614c7b565b6107c080516106e052602081015161070052604081018051610740526020810151610760526040810151610780525060a08101516107a052506044356106e05110156114415760086107c0527f536c6970706167650000000000000000000000000000000000000000000000006107e0526107c0506107c051806107e001601f825f031636823750506308c379a06107805260206107a052601f19601f6107c051011660440161079cfd5b6024356002811161534c57600b0180546106e05180820382811161534c57905090508155503360405260043560605261147b6107c0614c09565b6107c05060206024356002811161534c5760051b60400161535d015f395f516040526106e051606052610660516080526106805160a0526114ba612c4a565b6106a05160e0526106c0516101005261074051610120526107605161014052610780516101605261070051610180525f6101a0526114f96107e061309d565b6107e0516107c052337fe200e24d4a4c7cd367dd9befe394dc8a14e6d58c88ff5e2f512d65a9e0aa9c5c604060046107e0376106e051610820526107a051610840526107c0516108605260a06107e0a260206106e060035f55f35b63c93f49e8811861157f573461534c575f5460021461534c5760025f556115796148a6565b60035f55005b6323b872dd811861164e576064361061534c576004358060a01c61534c5760c0526024358060a01c61534c5760e0523461534c57601860c0516020525f5260405f2080336020525f5260405f20905054610100527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61010051146116275760c051604052336060526101005160443580820382811161534c57905090506080526116276151c1565b60c05160405260e051606052604435608052611641615216565b6001610120526020610120f35b63a9059cbb8118611697576044361061534c576004358060a01c61534c5760c0523461534c573360405260c05160605260243560805261168c615216565b600160e052602060e0f35b63095ea7b381186116e0576044361061534c576004358060a01c61534c5760c0523461534c573360405260c0516060526024356080526116d56151c1565b600160e052602060e0f35b63395093518118611795576044361061534c576004358060a01c61534c5760c0523461534c576018336020525f5260405f208060c0516020525f5260405f2090505460e05260243560e051016101005260e051610100511015611763577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610100525b60e0516101005114611788573360405260c051606052610100516080526117886151c1565b6001610120526020610120f35b63a457c2d7811861182a576044361061534c576004358060a01c61534c5760c0523461534c576018336020525f5260405f208060c0516020525f5260405f2090505460e05260243560e05103610100526101005160e05110156117f8575f610100525b60e051610100511461181d573360405260c0516060526101005160805261181d6151c1565b6001610120526020610120f35b63d505accf81186119e75760e4361061534c576004358060a01c61534c57610120526024358060a01c61534c57610140526084358060081c61534c57610160523461534c57610120511561534c57606435421161534c57601a610120516020525f5260405f2054610180525f60026101c0527f19010000000000000000000000000000000000000000000000000000000000006101e0526101c08051602082018361032001815181525050808301925050506118e76102006152ad565b610200518161032001526020810190507f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c961024052610120516102605261014051610280526044356102a052610180516102c0526064356102e05260c061022052610220805160208201209050816103200152602081019050806103005261030090508051602082012090506101a052610120516101a0516101c052610160516101e052604060a46102003760205f60806101c060015afa505f511861534c5760016101805101601a610120516020525f5260405f205561012051604052610140516060526044356080526119da6151c1565b60016101c05260206101c0f35b63cab4d3db8118611a37573461534c57602060025463cab4d3db604052602060406004605c845afa611a1b573d5f5f3e3d5ffd5b60203d1061534c576040518060a01c61534c5760805260809050f35b633883e1198118611ae2576084361061534c576064358060011c61534c576040523461534c5760025463e31593d8608052602060806004609c845afa611a7f573d5f5f3e3d5ffd5b60203d1061534c576080518060a01c61534c5760c05260c09050516060526020606051638585c4b16080526060600460a0376040516101005230610120526020608060a4609c845afa611ad4573d5f5f3e3d5ffd5b60203d1061534c5760809050f35b63556d6e9f8118611b77576064361061534c573461534c5760025463e31593d8606052602060606004607c845afa611b1c573d5f5f3e3d5ffd5b60203d1061534c576060518060a01c61534c5760a05260a09050516040526020604051633bb1f8c1606052606060046080373060e052602060606084607c845afa611b69573d5f5f3e3d5ffd5b60203d1061534c5760609050f35b6337ed3a7a8118611c0c576064361061534c573461534c5760025463e31593d8606052602060606004607c845afa611bb1573d5f5f3e3d5ffd5b60203d1061534c576060518060a01c61534c5760a05260a090505160405260206040516399bf0b76606052606060046080373060e052602060606084607c845afa611bfe573d5f5f3e3d5ffd5b60203d1061534c5760609050f35b6354f0f7d58118611ce1573461534c575f5460021461534c57600454604052611c36610120612ed6565b610120805160e052602081015161010052506011546003810281600382041861534c579050602061537d5f395f5163f42c56c26101205260e0516101005180820281158383830414171561534c5790509050610140526020610120602461013c845afa611ca5573d5f5f3e3d5ffd5b60203d1061534c5761012090505180820281158383830414171561534c579050905069d3c21bcecceda100000081049050610160526020610160f35b63bb7b8b808118611d48573461534c575f5460021461534c57600e54604052611d0b61016061444a565b61016051670de0b6b3a7640000810281670de0b6b3a764000082041861534c579050601954801561534c5780820490509050610180526020610180f35b63687276538118611f72576024361061534c573461534c575f5460021461534c57600454604052611d7a610100612ed6565b6101006004356001811161534c5760051b810190505160e052600354604052611da4610120612ed6565b6101206004356001811161534c5760051b8101905051610100526006546101205242610120511015611f6b57600554604052611de1610160612ed6565b6101606004356001811161534c5760051b810190505161014052601254604052611e0c610180612e9a565b6101806040810190505161016052602061537d5f395f516381d18d876101a052426101205180820382811161534c5790509050670de0b6b3a7640000810281670de0b6b3a764000082041861534c57905061016051801561534c57808204905090508060ff1c61534c577f8000000000000000000000000000000000000000000000000000000000000000811461534c575f036101c05260206101a060246101bc845afa611ebc573d5f5f3e3d5ffd5b60203d1061534c576101a09050516101805261014051610100518060011b818160011c1861534c579050808281188284100218905090506101805180670de0b6b3a764000003670de0b6b3a7640000811161534c57905080820281158383830414171561534c579050905060e0516101805180820281158383830414171561534c579050905080820182811061534c5790509050670de0b6b3a7640000810490506101a05260206101a0611f70565b602060e05bf35b63591890178118611fb2576024361061534c573461534c576020600554604052611f9c60e0612ed6565b60e06004356001811161534c5760051b81019050f35b63a3f7cdd58118611ff2576024361061534c573461534c576020600354604052611fdc60e0612ed6565b60e06004356001811161534c5760051b81019050f35b63ddca3f438118612050573461534c57602061200f6101e0614780565b6101e080516102605260208101516102805260408101516102a0525061026051606052610280516080526102a05160a05261204b610240612f37565b610240f35b634fb08c5e81186120d1576044361061534c573461534c576020612075610660612d41565b61066080516107605260208101516107805250604060046107a03742600a54116107e052610760516101e05261078051610200526107a051610220526107c051610240526107e051610260526120cc6106a0614c7b565b6106a0f35b63cde699fa811861210b5760c4361061534c573461534c576020606060046101e0376060606461024037612106610340614537565b610340f35b63f446c1d0811861212d573461534c576020612128610120612d41565b610120f35b63b13739298118612155573461534c57602061214a610120612d41565b610120602081019050f35b6392526c0c811861217b573461534c5760206014546040526121776060612e9a565b6060f35b63ee8de67581186121a7573461534c57602060145460405261219d6060612e9a565b6060602081019050f35b6372d4f0e281186121d3573461534c5760206014546040526121c96060612e9a565b6060604081019050f35b6349fe9e7781186121f9573461534c5760206012546040526121f56060612e9a565b6060f35b63083812e58118612225573461534c57602060125460405261221b6060612e9a565b6060602081019050f35b6309c3da6a8118612270573461534c576012546040526122456060612e9a565b6060604081019050516102b68102816102b682041861534c5790506103e88104905060c052602060c0f35b633620604b8118612296573461534c5760606001546040526122926060612e9a565b6060f35b63572e562581186122c7576064361061534c573461534c576020606060046060376122c26101e0612f37565b6101e0f35b633644e51581186122e9573461534c5760206122e46101206152ad565b610120f35b635e248072811861252a576064361061534c573461534c5760025463f851a440610120526020610120600461013c845afa612326573d5f5f3e3d5ffd5b60203d1061534c57610120518060a01c61534c5761016052610160905051331861534c576008546201517f810181811061534c57905042111561534c574262015180810181811061534c5790506001810381811161534c579050604435111561534c57612394610160612d41565b610160805161012052602081015161014052506101205160801b6101605261014051610160511761016052610a8c6004351061534c57631017df806004351161534c576402540be4006024351061534c5766b1a2bc2ec500006024351161534c57600435670de0b6b3a7640000810281670de0b6b3a764000082041861534c57905061012051801561534c578082049050905061018052678ac7230489e80000610180511161534c5767016345785d8a0000610180511061534c57602435670de0b6b3a7640000810281670de0b6b3a764000082041861534c57905061014051801561534c578082049050905061018052678ac7230489e80000610180511161534c5767016345785d8a0000610180511061534c57610160516007554260085560043560801b6101a0526024356101a051176101a052604435600a556101a0516009557fe35f0559b0642164e286b30df2077ec3a05426617a25db7578fd20ba39a6cd05610120516101c0526004356101e05261014051610200526024356102205242610240526044356102605260c06101c0a1005b63244c7c2e811861260d573461534c5760025463f851a440610120526020610120600461013c845afa61255f573d5f5f3e3d5ffd5b60203d1061534c57610120518060a01c61534c5761016052610160905051331861534c5761258e610160612d41565b610160805161012052602081015161014052506101205160801b610160526101405161016051176101605261016051600755610160516009554260085542600a557f5f0e7fba3d100c9e19446e1c92fe436f0a9a22fe99669360e4fdd6d3de2fc2846101205161018052610140516101a052426101c0526060610180a1005b634711a4f881186128675760c4361061534c573461534c5760025463f851a44060a052602060a0600460bc845afa612647573d5f5f3e3d5ffd5b60203d1061534c5760a0518060a01c61534c5760e05260e0905051331861534c5760165461534c57426203f480810181811061534c57905060a05260a0516016556060600460c0376014546040526126a0610180612e9a565b610180805161012052602081015161014052604081015161016052506402540be40060e05111156126d7576101405160e0526126e4565b6207a12060e0511061534c575b6402540be40160c051106126fa576101205160c0525b60e05160c0511161534c57670de0b6b3a763ffff61010051111561272557610160516101005261272f565b610100511561534c575b60c05160405260e0516060526101005160805261274d6101806151ab565b61018051601555606060646101803760125460405261276d610240612e9a565b61024080516101e05260208101516102005260408101516102205250670de0b6b3a764000161018051106127a4576101e051610180525b670de0b6b3a76400016101a051106127bf57610200516101a0525b620d505d6101c05111156127da57610220516101c0526127e6565b60576101c0511061534c575b610180516040526101a0516060526101c0516080526128066102406151ab565b6102405160135560a0517fec36b92a482408f90e07357ca20c8cfaca85affe765903cb242e377fafb166af60c0516102405260e051610260526101005161028052610180516102a0526101a0516102c0526101c0516102e05260c0610240a2005b632a7dd7cd8118612962573461534c575f5460021461534c5760025f55601654421061534c576016541561534c575f6016556015546060526060516014556013546080526080516012556080516040526128c2610100612e9a565b610100805160a052602081015160c052604081015160e052506060516040526128ec610160612e9a565b610160805161010052602081015161012052604081015161014052507fa32137411fc7c20db359079cd84af0e2cad58cd7a182a8a5e23e08e554e88bf061010051610160526101205161018052610140516101a05260a0516101c05260c0516101e05260e0516102005260c0610160a160035f55005b63226840fb81186129bb573461534c5760025463f851a440604052602060406004605c845afa612994573d5f5f3e3d5ffd5b60203d1061534c576040518060a01c61534c576080526080905051331861534c575f601655005b505b3415612a0e57602061535d5f395f515f6040525f6003905b60208160051b60400161535d015f395f5183186129f6576001604052612a01565b6001018181186129d5575b505060405190501561534c575b005b61014051612a1e575f612a2d565b602061535d5f395f5160405118155b612c3c5760a05161534c5760e051612ab9576040516323b872dd610160526101005161018052306101a0526060516101c0526020610160606461017c5f855af1612a79573d5f5f3e3d5ffd5b3d612a9057803b1561534c5760016101e052612aa9565b60203d1061534c57610160518060011c61534c576101e0525b6101e09050511561534c57612bec565b6040516370a0823161018052306101a0526020610180602461019c845afa612ae3573d5f5f3e3d5ffd5b60203d1061534c57610180905051610160525f60e0516101805261018080516101c05260046101a0526101a09050805160208201836102c001815181525050808301925050506101005161020052610120516102205260405161024052606051610260526080516102805260a06101e0526101e0805160208201836102c0018281848460045afa50505080830192505050806102a0526102a050505f5f6102a0516102c05f60c0515af1612b99573d5f5f3e3d5ffd5b6060516040516370a0823161018052306101a0526020610180602461019c845afa612bc6573d5f5f3e3d5ffd5b60203d1061534c576101809050516101605180820382811161534c57905090501861534c575b602061535d5f395f5160405118612c4857602061535d5f395f51632e1a7d4d6101605260605161018052803b1561534c575f610160602461017c5f855af1612c36573d5f5f3e3d5ffd5b50612c48565b60605160a0511861534c575b565b608051612c57575f612c66565b602061535d5f395f5160405118155b612d1d57602061535d5f395f5160405118612cae57602061535d5f395f5163d0e30db060c052803b1561534c575f60c0600460dc606051855af1612cac573d5f5f3e3d5ffd5b505b60405163a9059cbb60c05260a05160e05260605161010052602060c0604460dc5f855af1612cde573d5f5f3e3d5ffd5b3d612cf557803b1561534c57600161012052612d0d565b60203d1061534c5760c0518060011c61534c57610120525b6101209050511561534c57612d3f565b5f60c05260c0505f5f60c05160e060605160a0515af1612d3f573d5f5f3e3d5ffd5b565b600a546040526009546060526fffffffffffffffffffffffffffffffff6060511660805260605160801c60a052604051421015612e8a5760075460c05260085460e05260405160e05180820382811161534c57905090506040524260e05180820382811161534c579050905060e05260405160e05180820382811161534c57905090506101005260c05160801c6101005180820281158383830414171561534c579050905060a05160e05180820281158383830414171561534c579050905080820182811061534c5790509050604051801561534c578082049050905060a0526fffffffffffffffffffffffffffffffff60c051166101005180820281158383830414171561534c579050905060805160e05180820281158383830414171561534c579050905080820182811061534c5790509050604051801561534c57808204905090506080525b60a0518152608051602082015250565b67ffffffffffffffff60405160801c16815267ffffffffffffffff60405160401c16602082015267ffffffffffffffff60405116604082015250565b60403660603760405160a0525f6002905b8060c0526fffffffffffffffffffffffffffffffff60a0511660c0516001811161534c5760051b6060015260a05160801c60a052600101818118612ee75750506060518152608051602082015250565b601454604052612f48610120612e9a565b610120805160c052602081015160e05260408101516101005250602061537d5f395f5163fa18042d61014052606051610160526080516101805260a0516101a052610100516101c0526020610140608461015c845afa612faa573d5f5f3e3d5ffd5b60203d1061534c5761014090505161012052670de0b6b3a764000060c0516101205180820281158383830414171561534c579050905060e0516101205180670de0b6b3a764000003670de0b6b3a7640000811161534c57905080820281158383830414171561534c579050905080820182811061534c579050905004815250565b6040366080375f6002905b8060c05260805160801b60805260c051806001036001811161534c5790506001811161534c5760051b6040015160a0526ffffffffffffffffffffffffffffffffe60a0511161534c5760805160a05117608052600101818118613036575050608051815250565b6012546040526130ae610220612e9a565b61022080516101c05260208101516101e052604081015161020052506004546040526130db610260612ed6565b610260805161022052602081015161024052506005546040526130ff6102a0612ed6565b6102a0805161026052602081015161028052506003546102a0526102a05160405261312b610300612ed6565b61030080516102c05260208101516102e0525060195461030052600f546103205260115461034052600654610360524261036051101561331957602061537d5f395f516381d18d876103a05261020051426103605180820382811161534c5790509050670de0b6b3a7640000810281670de0b6b3a764000082041861534c579050048060ff1c61534c577f8000000000000000000000000000000000000000000000000000000000000000811461534c575f036103c05260206103a060246103bc845afa6131fb573d5f5f3e3d5ffd5b60203d1061534c576103a0905051610380525f6002905b806103a052670de0b6b3a76400006103a0516001811161534c5760051b61026001516103a0516001811161534c5760051b6102c001518060011b818160011c1861534c579050808281188284100218905090506103805180670de0b6b3a764000003670de0b6b3a7640000811161534c57905080820281158383830414171561534c57905090506103a0516001811161534c5760051b61022001516103805180820281158383830414171561534c579050905080820182811061534c5790509050046103a0516001811161534c5760051b6102200152600101818118613212575050610220516040526102405160605261330d6103a061302b565b6103a051600455426006555b61018051610380526101805161339657602061537d5f395f51637b12e0096103a05260e0516103c052610100516103e0526101205161040052610140516104205261016051610440526101a0516104605260206103a060c46103bc845afa613383573d5f5f3e3d5ffd5b60203d1061534c576103a0905051610380525b602061537d5f395f5163754b76b36103a052610120516103c052610140516103e0526101605161040052610380516104205260e05161044052610100516104605260406103a060c46103bc845afa6133f0573d5f5f3e3d5ffd5b60403d1061534c576103a09050805161026052602081015161028052505f6002905b806103a052670de0b6b3a76400006103a0516001811161534c5760051b61026001516103a0516001811161534c5760051b6102c0015180820281158383830414171561534c5790509050046103a0516001811161534c5760051b610260015260010181811861341257505061026051604052610280516060526134966103a061302b565b6103a0516005556060366103a037600361038051046103a0525f6002905b806104005261038051670de0b6b3a7640000810281670de0b6b3a764000082041861534c579050610400516001811161534c5760051b6102c001516003810281600382041861534c579050801561534c5780820490509050610400516001810181811061534c5790506002811161534c5760051b6103a001526001018181186134b4575050670de0b6b3a764000061040052670de0b6b3a764000061042052610340511561368957602061537d5f395f5163bad1dc26610460526103a051610480526103c0516104a0526103e0516104c0526020610460606461047c845afa61359f573d5f5f3e3d5ffd5b60203d1061534c576104609050516104405261044051670de0b6b3a7640000810281670de0b6b3a764000082041861534c57905061030051801561534c57808204905090506104205261034051610320516104205180820281158383830414171561534c5790509050046104005242600a54101561368957610340516104205111613689576004610460527f4c6f7373000000000000000000000000000000000000000000000000000000006104805261046050610460518061048001601f825f031636823750506308c379a061042052602061044052601f19601f61046051011660440161043cfd5b61040051600f55610400516101c0518060011b818160011c1861534c57905080820182811061534c5790509050610420518060011b818160011c1861534c579050670de0b6b3a7640000810381811161534c5790501115613ca557604036610440375f6002905b8061048052610480516001811161534c5760051b6102c00151610480516001811161534c5760051b6102200151670de0b6b3a7640000810281670de0b6b3a764000082041861534c5790500461046052670de0b6b3a764000161046051101561376a5761046051670de0b6b3a7640000036104605261377d565b670de0b6b3a76400006104605103610460525b610460516fffffffffffffffffffffffffffffffff811161534c576002810a90506104405101610440526001018181186136f0575050610440518060b57101000000000000000000000000000000000082106137e0578160801c91508060401b90505b690100000000000000000082106137fe578160401c91508060201b90505b650100000000008210613818578160201c91508060101b90505b63010000008210613830578160101c91508060081b90505b620100008201810260121c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c90508083048082811882841002189050905090509050610440526101e05160056104405104808281188284110218905090506104805261048051610440511115613ca5576040366104a0375f6002905b806104e052610440516104e0516001811161534c5760051b6102c0015161048051610440510380820281158383830414171561534c5790509050610480516104e0516001811161534c5760051b610220015180820281158383830414171561534c579050905080820182811061534c5790509050046104e0516001811161534c5760051b6104a001526001018181186138d1575050610120516103a052610140516103c052610160516103e0525f6002905b806104e0526104e0516001811161534c5760051b6102c001516104e0516001810181811061534c5790506002811161534c5760051b61012001516104e0516001811161534c5760051b6104a0015180820281158383830414171561534c5790509050046104e0516001810181811061534c5790506002811161534c5760051b6103a00152600101818118613983575050602061537d5f395f51637b12e0096105005260e0516105205261010051610540526103a051610560526103c051610580526103e0516105a0525f6105c052602061050060c461051c845afa613a6a573d5f5f3e3d5ffd5b60203d1061534c576105009050516104e0525f6003905b8061050052610500516002811161534c5760051b6103a00151670de0b6b3a7640000810281670de0b6b3a764000082041861534c5790506104e051801561534c578082049050905061052052662386f26fc10000610520511015613ae5575f613af6565b68056bc75e2d631000006105205111155b1561534c57600101818118613a815750506104e0516003810490506103a0525f6002905b80610500526104e051670de0b6b3a7640000810281670de0b6b3a764000082041861534c579050610500516001811161534c5760051b6104a001516003810281600382041861534c579050801561534c5780820490509050610500516001810181811061534c5790506002811161534c5760051b6103a00152600101818118613b1a57505061030051602061537d5f395f5163bad1dc26610500526103a051610520526103c051610540526103e051610560526020610500606461051c845afa613be6573d5f5f3e3d5ffd5b60203d1061534c57610500905051670de0b6b3a7640000810281670de0b6b3a764000082041861534c5790500461034052670de0b6b3a7640001610340511015613c30575f613c5e565b61040051610340518060011b818160011c1861534c579050670de0b6b3a7640000810381811161534c579050115b15613ca5576104a0516040526104c051606052613c7c61050061302b565b610500516102a0526104e051600e55610340516011556102a0516003556102a051815250613cbb565b61038051600e55610420516011556102a0518152505b565b61064051610620511461534c57610660511561534c57613cde610760612d41565b61076080516107205260208101516107405250600b5461076052600c5461078052600d546107a052600154604052613d17610820612e9a565b61082080516107c05260208101516107e052604081015161080052505f61082052610640516002811161534c5760051b610760015161084052610620516002811161534c5760051b610760015161086052610860516106605180820182811061534c5790509050610620516002811161534c5760051b6107600152610620516002811161534c5760051b6107600151610620516002811161534c57600b01556003546108805261088051604052613dcf6108e0612ed6565b6108e080516108a05260208101516108c05250610760516107c05180820281158383830414171561534c579050905061076052600160028101905b806108e052670de0b6b3a76400006108e0516002811161534c5760051b61076001516108e0516001810381811161534c5790506001811161534c5760051b6108a0015180820281158383830414171561534c57905090506108e0516002811161534c5760051b6107c0015180820281158383830414171561534c5790509050046108e0516002811161534c5760051b6107600152600101818118613e0a575050610620516002811161534c5760051b6107c001516108e052600a546109005242610900511115613ff757610860516108e05180820281158383830414171561534c5790509050610860526106205115613f4557670de0b6b3a764000061086051610620516001810381811161534c5790506001811161534c5760051b6108a0015180820281158383830414171561534c579050905004610860525b610620516002811161534c5760051b61076001516109205261086051610620516002811161534c5760051b6107600152602061537d5f395f51637b12e0096109405261072051610960526107405161098052610760516109a052610780516109c0526107a0516109e0525f610a0052602061094060c461095c845afa613fcd573d5f5f3e3d5ffd5b60203d1061534c57610940905051600e5561092051610620516002811161534c5760051b61076001525b600e5461092052610640516002811161534c5760051b6107c0015161094052602061537d5f395f51634a2ab3be6109a052610720516109c052610740516109e05261076051610a005261078051610a20526107a051610a405261092051610a605261064051610a805260406109a060e46109bc845afa614079573d5f5f3e3d5ffd5b60403d1061534c576109a0905080516109605260208101516109805250610640516002811161534c5760051b61076001516109605180820382811161534c579050905061082052610640516002811161534c5760051b6107600180516108205180820382811161534c5790509050815250610820516001810381811161534c57905061082052610640511561415d5761082051670de0b6b3a7640000810281670de0b6b3a764000082041861534c579050610640516001810381811161534c5790506001811161534c5760051b6108a00151801561534c5780820490509050610820525b6108205161094051801561534c5780820490509050610820526402540be40061076051606052610780516080526107a05160a05261419c6109c0612f37565b6109c0516108205180820281158383830414171561534c5790509050046109a052610820516109a05180820382811161534c5790509050610820526106805161082051101561424a5760086109c0527f536c6970706167650000000000000000000000000000000000000000000000006109e0526109c0506109c051806109e001601f825f031636823750506308c379a06109805260206109a052601f19601f6109c051011660440161099cfd5b610840516108205180820382811161534c57905090506108405261084051610640516002811161534c57600b0155610840516109405180820281158383830414171561534c57905090506108405261064051156142e957670de0b6b3a764000061084051610640516001810381811161534c5790506001811161534c5760051b6108a0015180820281158383830414171561534c579050905004610840525b61084051610640516002811161534c5760051b61076001526020610620516002811161534c5760051b60400161535d015f395f5160405261066051606052610820516080526106005160a0526106e05160c0526107005160e0526105e051610100526106c051610120526106a05161014052614363612a10565b6020610640516002811161534c5760051b60400161535d015f395f51604052610820516060526106a0516080526106c05160a05261439f612c4a565b6107205160e0526107405161010052610760516101205261078051610140526107a051610160525f61018052610980516101a0526143de6109c061309d565b6109c051610880526105e0517f143f1f8e861fbdeddd5b46e844b7d3ac7b86a122f36e8c463859ee6811b1f29c610620516109c052610660516109e05261064051610a005261082051610a20526109a051610a405261088051610a605260c06109c0a261082051815250565b60603660603760405160038104905060605260035460c052600160028101905b8060e052604051670de0b6b3a7640000810281670de0b6b3a764000082041861534c5790506fffffffffffffffffffffffffffffffff60c051166003810281600382041861534c579050801561534c578082049050905060e0516002811161534c5760051b6060015260c05160801c60c05260010181811861446a575050602061537d5f395f5163bad1dc2660e052606051610100526080516101205260a05161014052602060e0606460fc845afa614525573d5f5f3e3d5ffd5b60203d1061534c5760e0905051815250565b600361024051606052610260516080526102805160a0526145596102c0612f37565b6102c0510260031c6102a0525f6102c0525f6003905b8060051b6101e001516102e0526102c0516102e05180820182811061534c57905090506102c05260010181811861456f57505060036102c051046102e0525f610300525f6003905b8060051b6101e00151610320526102e05161032051116145f55761030051610320516102e0510380820182811061534c579050905061030052614615565b610300516102e051610320510380820182811061534c5790509050610300525b6001018181186145b75750506102a0516103005180820281158383830414171561534c57905090506102c051801561534c5780820490509050620186a0810181811061534c579050815250565b60195460605180820182811061534c579050905060195560176040516020525f5260405f20805460605180820182811061534c57905090508155506040515f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60605160805260206080a36001815250565b60195460805260805160605180820281158383830414171561534c5790509050670de0b6b3a76400008104905060a05260a051156147785760805160a05180820182811061534c579050905060195560176040516020525f5260405f20805460a05180820182811061534c57905090508155506040515f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60a05160c052602060c0a35b60a051815250565b600b54606052600c54608052600d5460a05260035460c0526001546040526147a9610140612e9a565b610140805160e0526020810151610100526040810151610120525060605160e05180820281158383830414171561534c5790509050606052600160028101905b80610140526fffffffffffffffffffffffffffffffff60c05116610140516002811161534c5760051b60e0015180820281158383830414171561534c579050905061016052610140516002811161534c5760051b606001516101605180820281158383830414171561534c5790509050670de0b6b3a764000081049050610140516002811161534c5760051b6060015260c05160801c60c0526001018181186147e95750506060518152608051602082015260a051604082015250565b6148b16101e0612d41565b6101e080516101a05260208101516101c05250600f546101e0526010546102005260195461022052610200516101e05111156148fb57670de0b6b3a763ffff6102205111156148fe565b60015b1561490857614c07565b5f6003905b8061024052602061535d5f395f516020610240516002811161534c5760051b60400161535d015f395f51186149525747610240516002811161534c57600b01556149b4565b6020610240516002811161534c5760051b60400161535d015f395f516370a082316102605230610280526020610260602461027c845afa614995573d5f5f3e3d5ffd5b60203d1061534c57610260905051610240516002811161534c57600b01555b60010181811861490d575050601154610240526404a817c800610200516101e0510364012a05f20081028164012a05f20082041861534c579050046102605260025463cab4d3db6102a05260206102a060046102bc845afa614a18573d5f5f3e3d5ffd5b60203d1061534c576102a0518060a01c61534c576102e0526102e0905051610280526102805115614a4e57610260511515614a50565b5f5b15614b385761024051670de0b6b3a7640000810281670de0b6b3a764000082041861534c579050610240516102605180820382811161534c5790509050801561534c5780820490509050670de0b6b3a7640000810381811161534c5790506102a052610280516040526102a051606052614acb6102e06146d4565b6102e0516102c0526101e051610260518060011b818160011c1861534c57905080820382811161534c57905090506101e0526101e051600f55610280517f6059a38198b1dc42b3791087d1ff0fbd72b3179553c25f678cd246f52ffaaf596102c0516102e05260206102e0a25b602061537d5f395f51637b12e009610320526101a051610340526101c05161036052614b656102c0614780565b6102c080516103805260208101516103a05260408101516103c052505f6103e052602061032060c461033c845afa614b9f573d5f5f3e3d5ffd5b60203d1061534c576103209050516102a0526102a051600e556102a051604052614bca6102c061444a565b6102c051670de0b6b3a7640000810281670de0b6b3a764000082041861534c579050601954801561534c57808204905090506011556101e0516010555b565b60195460605180820382811161534c579050905060195560176040516020525f5260405f20805460605180820382811161534c57905090508155505f6040517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60605160805260206080a36001815250565b6019546102805261028051610220511161534c576002610240511161534c57600b546102a052600c546102c052600d546102e052600154604052614cc0610360612e9a565b6103608051610300526020810151610320526040810151610340525061030051610360526103205161038052610340516103a0525f6103c05261030051670de0b6b3a7640000810281670de0b6b3a764000082041861534c5790506103e05260035461040052610360516102a05180820281158383830414171561534c579050905061036052600160028101905b80610420526fffffffffffffffffffffffffffffffff610400511661044052610420516102405118614dab5761044051610240516002811161534c5760051b610360015180820281158383830414171561534c57905090506103e0525b670de0b6b3a7640000610420516002811161534c5760051b6103600151610420516002811161534c5760051b6102a0015180820281158383830414171561534c57905090506104405180820281158383830414171561534c579050905004610420516002811161534c5760051b61036001526104005160801c61040052600101818118614d4e57505061026051614e4857600e546103c052614eb3565b602061537d5f395f51637b12e009610420526101e0516104405261020051610460526103605161048052610380516104a0526103a0516104c0525f6104e052602061042060c461043c845afa614ea0573d5f5f3e3d5ffd5b60203d1061534c576104209050516103c0525b6103c05161042052610360516104405261038051610460526103a05161048052610240516002811161534c5760051b61036001516003810281600382041861534c5790506102205180820281158383830414171561534c579050905061028051801561534c57808204905090506104a052601454604052614f356104e0612e9a565b6104e0602081019050516104c052610240516002811161534c5760051b61044001516104a0511015614fb457610240516002811161534c5760051b6104400180516104a05180820382811161534c579050905081525061044051606052610460516080526104805160a052614fab6104e0612f37565b6104e0516104c0525b61028051610220516104205180820281158383830414171561534c5790509050046104e0526104c0516104e05180820281158383830414171561534c57905090506404a817c800810490506001810181811061534c57905061050052610500516003810281600382041861534c579050610240516002811161534c5760051b6102a0015180820281158383830414171561534c579050905061042051801561534c578082049050905061052052610420516104e0516105005180820382811161534c579050905080820382811161534c579050905061042052602061537d5f395f51634a2ab3be610560526101e05161058052610200516105a052610360516105c052610380516105e0526103a0516106005261042051610620526102405161064052604061056060e461057c845afa6150f0573d5f5f3e3d5ffd5b60403d1061534c5761056090505161054052610240516002811161534c5760051b61036001516105405180820382811161534c5790509050670de0b6b3a7640000810281670de0b6b3a764000082041861534c5790506103e051801561534c57808204905090506105605261054051610240516002811161534c5760051b6103600152610560518152610420516020820152604081016103605181526103805160208201526103a0516040820152506105205160a082015250565b60805160605160401b60405160801b1717815250565b60805160186040516020525f5260405f20806060516020525f5260405f209050556060516040517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560805160a052602060a0a3565b6060513081146152285780151561522a565b5f5b90501561534c5760176040516020525f5260405f20805460805180820382811161534c579050905081555060176060516020525f5260405f20805460805180820182811061534c57905090508155506060516040517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60805160a052602060a0a3565b60206154bd5f395f51461461533d577fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac56472606052602061549d5f395f516080527fd61c1033330c368dfc371f5b1e7133f4794e104642e5a3c87aba7a6a3441c8ff60a0524660c0523060e05260206154dd5f395f516101005260c0604052604080516020820120905081525061534a565b60206154fd5f395f518152505b565b5f80fda165767970657283000309000b000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000cbff3004a20dbfe2731543aa38599a526e0fd6ee000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000041d5d79431a913c4ae7d69a668ecdfe5ff9dfb68000000000000000000000000000000000000000000000000000000000000000c54726963727970746f494e5600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e6372765553444357455448494e560000000000000000000000000000000000003c54a4740e24c1809181820faa59774175f899d6014e92375714a31761836a370000000000000000000000000000000000000000000000000000000000000001e91fe7fcabbd0b445881e823e9f568a08b90cadda81163b7b161cccd44c17dc2f4d1060237db771a559ecbf6488f8de63b7bd4a28fe4d981140dac1f0bcff0c5
Verified Source Code Partial Match
Compiler: v0.3.9+commit.66b96705
EVM: shanghai
CurveTricryptoOptimizedWETH.vy 2156 lines
# @version 0.3.9
"""
@title CurveTricryptoOptimizedWETH
@author Curve.Fi
@license Copyright (c) Curve.Fi, 2020-2023 - all rights reserved
@notice A Curve AMM pool for 3 unpegged assets (e.g. ETH, BTC, USD).
@dev All prices in the AMM are with respect to the first token in the pool.
"""
from vyper.interfaces import ERC20
implements: ERC20 # <--------------------- AMM contract is also the LP token.
# --------------------------------- Interfaces -------------------------------
interface Math:
def geometric_mean(_x: uint256[N_COINS]) -> uint256: view
def wad_exp(_power: int256) -> uint256: view
def cbrt(x: uint256) -> uint256: view
def reduction_coefficient(
x: uint256[N_COINS], fee_gamma: uint256
) -> uint256: view
def newton_D(
ANN: uint256,
gamma: uint256,
x_unsorted: uint256[N_COINS],
K0_prev: uint256
) -> uint256: view
def get_y(
ANN: uint256,
gamma: uint256,
x: uint256[N_COINS],
D: uint256,
i: uint256,
) -> uint256[2]: view
def get_p(
_xp: uint256[N_COINS], _D: uint256, _A_gamma: uint256[2],
) -> uint256[N_COINS-1]: view
interface WETH:
def deposit(): payable
def withdraw(_amount: uint256): nonpayable
interface Factory:
def admin() -> address: view
def fee_receiver() -> address: view
def views_implementation() -> address: view
interface Views:
def calc_token_amount(
amounts: uint256[N_COINS], deposit: bool, swap: address
) -> uint256: view
def get_dy(
i: uint256, j: uint256, dx: uint256, swap: address
) -> uint256: view
def get_dx(
i: uint256, j: uint256, dy: uint256, swap: address
) -> uint256: view
# ------------------------------- Events -------------------------------------
event Transfer:
sender: indexed(address)
receiver: indexed(address)
value: uint256
event Approval:
owner: indexed(address)
spender: indexed(address)
value: uint256
event TokenExchange:
buyer: indexed(address)
sold_id: uint256
tokens_sold: uint256
bought_id: uint256
tokens_bought: uint256
fee: uint256
packed_price_scale: uint256
event AddLiquidity:
provider: indexed(address)
token_amounts: uint256[N_COINS]
fee: uint256
token_supply: uint256
packed_price_scale: uint256
event RemoveLiquidity:
provider: indexed(address)
token_amounts: uint256[N_COINS]
token_supply: uint256
event RemoveLiquidityOne:
provider: indexed(address)
token_amount: uint256
coin_index: uint256
coin_amount: uint256
approx_fee: uint256
packed_price_scale: uint256
event CommitNewParameters:
deadline: indexed(uint256)
mid_fee: uint256
out_fee: uint256
fee_gamma: uint256
allowed_extra_profit: uint256
adjustment_step: uint256
ma_time: uint256
event NewParameters:
mid_fee: uint256
out_fee: uint256
fee_gamma: uint256
allowed_extra_profit: uint256
adjustment_step: uint256
ma_time: uint256
event RampAgamma:
initial_A: uint256
future_A: uint256
initial_gamma: uint256
future_gamma: uint256
initial_time: uint256
future_time: uint256
event StopRampA:
current_A: uint256
current_gamma: uint256
time: uint256
event ClaimAdminFee:
admin: indexed(address)
tokens: uint256
# ----------------------- Storage/State Variables ----------------------------
WETH20: public(immutable(address))
N_COINS: constant(uint256) = 3
PRECISION: constant(uint256) = 10**18 # <------- The precision to convert to.
A_MULTIPLIER: constant(uint256) = 10000
packed_precisions: uint256
MATH: public(immutable(Math))
coins: public(immutable(address[N_COINS]))
factory: public(address)
price_scale_packed: uint256 # <------------------------ Internal price scale.
price_oracle_packed: uint256 # <------- Price target given by moving average.
last_prices_packed: uint256
last_prices_timestamp: public(uint256)
initial_A_gamma: public(uint256)
initial_A_gamma_time: public(uint256)
future_A_gamma: public(uint256)
future_A_gamma_time: public(uint256) # <------ Time when ramping is finished.
# This value is 0 (default) when pool is first deployed, and only gets
# populated by block.timestamp + future_time in `ramp_A_gamma` when the
# ramping process is initiated. After ramping is finished
# (i.e. self.future_A_gamma_time < block.timestamp), the variable is left
# and not set to 0.
balances: public(uint256[N_COINS])
D: public(uint256)
xcp_profit: public(uint256)
xcp_profit_a: public(uint256) # <--- Full profit at last claim of admin fees.
virtual_price: public(uint256) # <------ Cached (fast to read) virtual price.
# The cached `virtual_price` is also used internally.
# -------------- Params that affect how price_scale get adjusted -------------
packed_rebalancing_params: public(uint256) # <---------- Contains rebalancing
# parameters allowed_extra_profit, adjustment_step, and ma_time.
future_packed_rebalancing_params: uint256
# ---------------- Fee params that determine dynamic fees --------------------
packed_fee_params: public(uint256) # <---- Packs mid_fee, out_fee, fee_gamma.
future_packed_fee_params: uint256
ADMIN_FEE: public(constant(uint256)) = 5 * 10**9 # <----- 50% of earned fees.
MIN_FEE: constant(uint256) = 5 * 10**5 # <-------------------------- 0.5 BPS.
MAX_FEE: constant(uint256) = 10 * 10**9
NOISE_FEE: constant(uint256) = 10**5 # <---------------------------- 0.1 BPS.
# ----------------------- Admin params ---------------------------------------
admin_actions_deadline: public(uint256)
ADMIN_ACTIONS_DELAY: constant(uint256) = 3 * 86400
MIN_RAMP_TIME: constant(uint256) = 86400
MIN_A: constant(uint256) = N_COINS**N_COINS * A_MULTIPLIER / 100
MAX_A: constant(uint256) = 1000 * A_MULTIPLIER * N_COINS**N_COINS
MAX_A_CHANGE: constant(uint256) = 10
MIN_GAMMA: constant(uint256) = 10**10
MAX_GAMMA: constant(uint256) = 5 * 10**16
PRICE_SIZE: constant(uint128) = 256 / (N_COINS - 1)
PRICE_MASK: constant(uint256) = 2**PRICE_SIZE - 1
# ----------------------- ERC20 Specific vars --------------------------------
name: public(immutable(String[64]))
symbol: public(immutable(String[32]))
decimals: public(constant(uint8)) = 18
version: public(constant(String[8])) = "v2.0.0"
balanceOf: public(HashMap[address, uint256])
allowance: public(HashMap[address, HashMap[address, uint256]])
totalSupply: public(uint256)
nonces: public(HashMap[address, uint256])
EIP712_TYPEHASH: constant(bytes32) = keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)"
)
EIP2612_TYPEHASH: constant(bytes32) = keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
)
VERSION_HASH: constant(bytes32) = keccak256(version)
NAME_HASH: immutable(bytes32)
CACHED_CHAIN_ID: immutable(uint256)
salt: public(immutable(bytes32))
CACHED_DOMAIN_SEPARATOR: immutable(bytes32)
# ----------------------- Contract -------------------------------------------
@external
def __init__(
_name: String[64],
_symbol: String[32],
_coins: address[N_COINS],
_math: address,
_weth: address,
_salt: bytes32,
packed_precisions: uint256,
packed_A_gamma: uint256,
packed_fee_params: uint256,
packed_rebalancing_params: uint256,
packed_prices: uint256,
):
WETH20 = _weth
MATH = Math(_math)
self.factory = msg.sender
name = _name
symbol = _symbol
coins = _coins
self.packed_precisions = packed_precisions # <------- Precisions of coins
# are calculated as 10**(18 - coin.decimals()).
self.initial_A_gamma = packed_A_gamma # <------------------- A and gamma.
self.future_A_gamma = packed_A_gamma
self.packed_rebalancing_params = packed_rebalancing_params # <-- Contains
# rebalancing params: allowed_extra_profit, adjustment_step,
# and ma_exp_time.
self.packed_fee_params = packed_fee_params # <-------------- Contains Fee
# params: mid_fee, out_fee and fee_gamma.
self.price_scale_packed = packed_prices
self.price_oracle_packed = packed_prices
self.last_prices_packed = packed_prices
self.last_prices_timestamp = block.timestamp
self.xcp_profit_a = 10**18
# Cache DOMAIN_SEPARATOR. If chain.id is not CACHED_CHAIN_ID, then
# DOMAIN_SEPARATOR will be re-calculated each time `permit` is called.
# Otherwise, it will always use CACHED_DOMAIN_SEPARATOR.
# see: `_domain_separator()` for its implementation.
NAME_HASH = keccak256(name)
salt = _salt
CACHED_CHAIN_ID = chain.id
CACHED_DOMAIN_SEPARATOR = keccak256(
_abi_encode(
EIP712_TYPEHASH,
NAME_HASH,
VERSION_HASH,
chain.id,
self,
salt,
)
)
log Transfer(empty(address), self, 0) # <------- Fire empty transfer from
# 0x0 to self for indexers to catch.
# ------------------- Token transfers in and out of the AMM ------------------
@payable
@external
def __default__():
if msg.value > 0:
assert WETH20 in coins
@internal
def _transfer_in(
_coin: address,
dx: uint256,
dy: uint256,
mvalue: uint256,
callbacker: address,
callback_sig: bytes32,
sender: address,
receiver: address,
use_eth: bool
):
"""
@notice Transfers `_coin` from `sender` to `self` and calls `callback_sig`
if it is not empty.
@dev The callback sig must have the following args:
sender: address
receiver: address
coin: address
dx: uint256
dy: uint256
@params _coin address of the coin to transfer in.
@params dx amount of `_coin` to transfer into the pool.
@params dy amount of `_coin` to transfer out of the pool.
@params mvalue msg.value if the transfer is ETH, 0 otherwise.
@params callbacker address to call `callback_sig` on.
@params callback_sig signature of the callback function.
@params sender address to transfer `_coin` from.
@params receiver address to transfer `_coin` to.
@params use_eth True if the transfer is ETH, False otherwise.
"""
if use_eth and _coin == WETH20:
assert mvalue == dx # dev: incorrect eth amount
else:
assert mvalue == 0 # dev: nonzero eth amount
if callback_sig == empty(bytes32):
assert ERC20(_coin).transferFrom(
sender, self, dx, default_return_value=True
)
else:
# --------- This part of the _transfer_in logic is only accessible
# by _exchange.
# First call callback logic and then check if pool
# gets dx amounts of _coins[i], revert otherwise.
b: uint256 = ERC20(_coin).balanceOf(self)
raw_call(
callbacker,
concat(
slice(callback_sig, 0, 4),
_abi_encode(sender, receiver, _coin, dx, dy)
)
)
assert ERC20(_coin).balanceOf(self) - b == dx # dev: callback didn't give us coins
# ^------ note: dx cannot
# be 0, so the contract MUST receive some _coin.
if _coin == WETH20:
WETH(WETH20).withdraw(dx) # <--------- if WETH was transferred in
# previous step and `not use_eth`, withdraw WETH to ETH.
@internal
def _transfer_out(
_coin: address, _amount: uint256, use_eth: bool, receiver: address
):
"""
@notice Transfer a single token from the pool to receiver.
@dev This function is called by `remove_liquidity` and
`remove_liquidity_one` and `_exchange` methods.
@params _coin Address of the token to transfer out
@params _amount Amount of token to transfer out
@params use_eth Whether to transfer ETH or not
@params receiver Address to send the tokens to
"""
if use_eth and _coin == WETH20:
raw_call(receiver, b"", value=_amount)
else:
if _coin == WETH20:
WETH(WETH20).deposit(value=_amount)
assert ERC20(_coin).transfer(
receiver, _amount, default_return_value=True
)
# -------------------------- AMM Main Functions ------------------------------
@payable
@external
@nonreentrant("lock")
def exchange(
i: uint256,
j: uint256,
dx: uint256,
min_dy: uint256,
use_eth: bool = False,
receiver: address = msg.sender
) -> uint256:
"""
@notice Exchange using wrapped native token by default
@param i Index value for the input coin
@param j Index value for the output coin
@param dx Amount of input coin being swapped in
@param min_dy Minimum amount of output coin to receive
@param use_eth True if the input coin is native token, False otherwise
@param receiver Address to send the output coin to. Default is msg.sender
@return uint256 Amount of tokens at index j received by the `receiver
"""
return self._exchange(
msg.sender,
msg.value,
i,
j,
dx,
min_dy,
use_eth,
receiver,
empty(address),
empty(bytes32)
)
@payable
@external
@nonreentrant('lock')
def exchange_underlying(
i: uint256,
j: uint256,
dx: uint256,
min_dy: uint256,
receiver: address = msg.sender
) -> uint256:
"""
@notice Exchange using native token transfers.
@param i Index value for the input coin
@param j Index value for the output coin
@param dx Amount of input coin being swapped in
@param min_dy Minimum amount of output coin to receive
@param receiver Address to send the output coin to. Default is msg.sender
@return uint256 Amount of tokens at index j received by the `receiver
"""
return self._exchange(
msg.sender,
msg.value,
i,
j,
dx,
min_dy,
True,
receiver,
empty(address),
empty(bytes32)
)
@external
@nonreentrant('lock')
def exchange_extended(
i: uint256,
j: uint256,
dx: uint256,
min_dy: uint256,
use_eth: bool,
sender: address,
receiver: address,
cb: bytes32
) -> uint256:
"""
@notice Exchange with callback method.
@dev This method does not allow swapping in native token, but does allow
swaps that transfer out native token from the pool.
@dev Does not allow flashloans
@dev One use-case is to reduce the number of redundant ERC20 token
transfers in zaps.
@param i Index value for the input coin
@param j Index value for the output coin
@param dx Amount of input coin being swapped in
@param min_dy Minimum amount of output coin to receive
@param use_eth True if output is native token, False otherwise
@param sender Address to transfer input coin from
@param receiver Address to send the output coin to
@param cb Callback signature
@return uint256 Amount of tokens at index j received by the `receiver`
"""
assert cb != empty(bytes32) # dev: No callback specified
return self._exchange(
sender, 0, i, j, dx, min_dy, use_eth, receiver, msg.sender, cb
) # callbacker should never be self ------------------^
@payable
@external
@nonreentrant("lock")
def add_liquidity(
amounts: uint256[N_COINS],
min_mint_amount: uint256,
use_eth: bool = False,
receiver: address = msg.sender
) -> uint256:
"""
@notice Adds liquidity into the pool.
@param amounts Amounts of each coin to add.
@param min_mint_amount Minimum amount of LP to mint.
@param use_eth True if native token is being added to the pool.
@param receiver Address to send the LP tokens to. Default is msg.sender
@return uint256 Amount of LP tokens received by the `receiver
"""
A_gamma: uint256[2] = self._A_gamma()
xp: uint256[N_COINS] = self.balances
amountsp: uint256[N_COINS] = empty(uint256[N_COINS])
xx: uint256[N_COINS] = empty(uint256[N_COINS])
d_token: uint256 = 0
d_token_fee: uint256 = 0
old_D: uint256 = 0
assert amounts[0] + amounts[1] + amounts[2] > 0 # dev: no coins to add
# --------------------- Get prices, balances -----------------------------
precisions: uint256[N_COINS] = self._unpack(self.packed_precisions)
packed_price_scale: uint256 = self.price_scale_packed
price_scale: uint256[N_COINS-1] = self._unpack_prices(packed_price_scale)
# -------------------------------------- Update balances and calculate xp.
xp_old: uint256[N_COINS] = xp
for i in range(N_COINS):
bal: uint256 = xp[i] + amounts[i]
xp[i] = bal
self.balances[i] = bal
xx = xp
xp[0] *= precisions[0]
xp_old[0] *= precisions[0]
for i in range(1, N_COINS):
xp[i] = unsafe_div(xp[i] * price_scale[i-1] * precisions[i], PRECISION)
xp_old[i] = unsafe_div(
xp_old[i] * unsafe_mul(price_scale[i-1], precisions[i]),
PRECISION
)
# ---------------- transferFrom token into the pool ----------------------
for i in range(N_COINS):
if amounts[i] > 0:
if coins[i] == WETH20:
self._transfer_in(
coins[i],
amounts[i],
0, # <-----------------------------------
msg.value, # | No callbacks
empty(address), # <----------------------| for
empty(bytes32), # <----------------------| add_liquidity.
msg.sender, # |
empty(address), # <-----------------------
use_eth
)
else:
self._transfer_in(
coins[i],
amounts[i],
0,
0, # <----------------- mvalue = 0 if coin is not WETH20.
empty(address),
empty(bytes32),
msg.sender,
empty(address),
False # <-------- use_eth is False if coin is not WETH20.
)
amountsp[i] = xp[i] - xp_old[i]
# -------------------- Calculate LP tokens to mint -----------------------
if self.future_A_gamma_time > block.timestamp: # <--- A_gamma is ramping.
# ----- Recalculate the invariant if A or gamma are undergoing a ramp.
old_D = MATH.newton_D(A_gamma[0], A_gamma[1], xp_old, 0)
else:
old_D = self.D
D: uint256 = MATH.newton_D(A_gamma[0], A_gamma[1], xp, 0)
token_supply: uint256 = self.totalSupply
if old_D > 0:
d_token = token_supply * D / old_D - token_supply
else:
d_token = self.get_xcp(D) # <------------------------- Making initial
# virtual price equal to 1.
assert d_token > 0 # dev: nothing minted
if old_D > 0:
d_token_fee = (
self._calc_token_fee(amountsp, xp) * d_token / 10**10 + 1
)
d_token -= d_token_fee
token_supply += d_token
self.mint(receiver, d_token)
packed_price_scale = self.tweak_price(A_gamma, xp, D, 0)
else:
self.D = D
self.virtual_price = 10**18
self.xcp_profit = 10**18
self.xcp_profit_a = 10**18
self.mint(receiver, d_token)
assert d_token >= min_mint_amount, "Slippage"
log AddLiquidity(
receiver, amounts, d_token_fee, token_supply, packed_price_scale
)
self._claim_admin_fees() # <--------------------------- Claim admin fees.
return d_token
@external
@nonreentrant("lock")
def remove_liquidity(
_amount: uint256,
min_amounts: uint256[N_COINS],
use_eth: bool = False,
receiver: address = msg.sender,
claim_admin_fees: bool = True,
) -> uint256[N_COINS]:
"""
@notice This withdrawal method is very safe, does no complex math since
tokens are withdrawn in balanced proportions. No fees are charged.
@param _amount Amount of LP tokens to burn
@param min_amounts Minimum amounts of tokens to withdraw
@param use_eth Whether to withdraw ETH or not
@param receiver Address to send the withdrawn tokens to
@param claim_admin_fees If True, call self._claim_admin_fees(). Default is True.
@return uint256[3] Amount of pool tokens received by the `receiver`
"""
amount: uint256 = _amount
balances: uint256[N_COINS] = self.balances
d_balances: uint256[N_COINS] = empty(uint256[N_COINS])
if claim_admin_fees:
self._claim_admin_fees() # <------ We claim fees so that the DAO gets
# paid before withdrawal. In emergency cases, set it to False.
# -------------------------------------------------------- Burn LP tokens.
total_supply: uint256 = self.totalSupply # <------ Get totalSupply before
self.burnFrom(msg.sender, _amount) # ---- reducing it with self.burnFrom.
# There are two cases for withdrawing tokens from the pool.
# Case 1. Withdrawal does not empty the pool.
# In this situation, D is adjusted proportional to the amount of
# LP tokens burnt. ERC20 tokens transferred is proportional
# to : (AMM balance * LP tokens in) / LP token total supply
# Case 2. Withdrawal empties the pool.
# In this situation, all tokens are withdrawn and the invariant
# is reset.
if amount == total_supply: # <----------------------------------- Case 2.
for i in range(N_COINS):
d_balances[i] = balances[i]
self.balances[i] = 0 # <------------------------- Empty the pool.
else: # <-------------------------------------------------------- Case 1.
amount -= 1 # <---- To prevent rounding errors, favor LPs a tiny bit.
for i in range(N_COINS):
d_balances[i] = balances[i] * amount / total_supply
assert d_balances[i] >= min_amounts[i]
self.balances[i] = balances[i] - d_balances[i]
balances[i] = d_balances[i] # <-- Now it's the amounts going out.
D: uint256 = self.D
self.D = D - unsafe_div(D * amount, total_supply) # <----------- Reduce D
# proportional to the amount of tokens leaving. Since withdrawals are
# balanced, this is a simple subtraction. If amount == total_supply,
# D will be 0.
# ---------------------------------- Transfers ---------------------------
for i in range(N_COINS):
self._transfer_out(coins[i], d_balances[i], use_eth, receiver)
log RemoveLiquidity(msg.sender, balances, total_supply - _amount)
return d_balances
@external
@nonreentrant("lock")
def remove_liquidity_one_coin(
token_amount: uint256,
i: uint256,
min_amount: uint256,
use_eth: bool = False,
receiver: address = msg.sender
) -> uint256:
"""
@notice Withdraw liquidity in a single token.
Involves fees (lower than swap fees).
@dev This operation also involves an admin fee claim.
@param token_amount Amount of LP tokens to burn
@param i Index of the token to withdraw
@param min_amount Minimum amount of token to withdraw.
@param use_eth Whether to withdraw ETH or not
@param receiver Address to send the withdrawn tokens to
@return Amount of tokens at index i received by the `receiver`
"""
A_gamma: uint256[2] = self._A_gamma()
dy: uint256 = 0
D: uint256 = 0
p: uint256 = 0
xp: uint256[N_COINS] = empty(uint256[N_COINS])
approx_fee: uint256 = 0
# ---------------------------- Claim admin fees before removing liquidity.
self._claim_admin_fees()
# ------------------------------------------------------------------------
dy, D, xp, approx_fee = self._calc_withdraw_one_coin(
A_gamma,
token_amount,
i,
(self.future_A_gamma_time > block.timestamp), # <------- During ramps
) # we need to update D.
assert dy >= min_amount, "Slippage"
# ------------------------- Transfers ------------------------------------
self.balances[i] -= dy
self.burnFrom(msg.sender, token_amount)
self._transfer_out(coins[i], dy, use_eth, receiver)
packed_price_scale: uint256 = self.tweak_price(A_gamma, xp, D, 0)
# Safe to use D from _calc_withdraw_one_coin here ---^
log RemoveLiquidityOne(
msg.sender, token_amount, i, dy, approx_fee, packed_price_scale
)
return dy
@external
@nonreentrant("lock")
def claim_admin_fees():
"""
@notice Claim admin fees. Callable by anyone.
"""
self._claim_admin_fees()
# -------------------------- Packing functions -------------------------------
@internal
@view
def _pack(x: uint256[3]) -> uint256:
"""
@notice Packs 3 integers with values <= 10**18 into a uint256
@param x The uint256[3] to pack
@return uint256 Integer with packed values
"""
return (x[0] << 128) | (x[1] << 64) | x[2]
@internal
@view
def _unpack(_packed: uint256) -> uint256[3]:
"""
@notice Unpacks a uint256 into 3 integers (values must be <= 10**18)
@param val The uint256 to unpack
@return uint256[3] A list of length 3 with unpacked integers
"""
return [
(_packed >> 128) & 18446744073709551615,
(_packed >> 64) & 18446744073709551615,
_packed & 18446744073709551615,
]
@internal
@view
def _pack_prices(prices_to_pack: uint256[N_COINS-1]) -> uint256:
"""
@notice Packs N_COINS-1 prices into a uint256.
@param prices_to_pack The prices to pack
@return uint256 An integer that packs prices
"""
packed_prices: uint256 = 0
p: uint256 = 0
for k in range(N_COINS - 1):
packed_prices = packed_prices << PRICE_SIZE
p = prices_to_pack[N_COINS - 2 - k]
assert p < PRICE_MASK
packed_prices = p | packed_prices
return packed_prices
@internal
@view
def _unpack_prices(_packed_prices: uint256) -> uint256[2]:
"""
@notice Unpacks N_COINS-1 prices from a uint256.
@param _packed_prices The packed prices
@return uint256[2] Unpacked prices
"""
unpacked_prices: uint256[N_COINS-1] = empty(uint256[N_COINS-1])
packed_prices: uint256 = _packed_prices
for k in range(N_COINS - 1):
unpacked_prices[k] = packed_prices & PRICE_MASK
packed_prices = packed_prices >> PRICE_SIZE
return unpacked_prices
# ---------------------- AMM Internal Functions -------------------------------
@internal
def _exchange(
sender: address,
mvalue: uint256,
i: uint256,
j: uint256,
dx: uint256,
min_dy: uint256,
use_eth: bool,
receiver: address,
callbacker: address,
callback_sig: bytes32
) -> uint256:
assert i != j # dev: coin index out of range
assert dx > 0 # dev: do not exchange 0 coins
A_gamma: uint256[2] = self._A_gamma()
xp: uint256[N_COINS] = self.balances
precisions: uint256[N_COINS] = self._unpack(self.packed_precisions)
dy: uint256 = 0
y: uint256 = xp[j] # <----------------- if j > N_COINS, this will revert.
x0: uint256 = xp[i] # <--------------- if i > N_COINS, this will revert.
xp[i] = x0 + dx
self.balances[i] = xp[i]
packed_price_scale: uint256 = self.price_scale_packed
price_scale: uint256[N_COINS - 1] = self._unpack_prices(
packed_price_scale
)
xp[0] *= precisions[0]
for k in range(1, N_COINS):
xp[k] = unsafe_div(
xp[k] * price_scale[k - 1] * precisions[k],
PRECISION
) # <-------- Safu to do unsafe_div here since PRECISION is not zero.
prec_i: uint256 = precisions[i]
# ----------- Update invariant if A, gamma are undergoing ramps ---------
t: uint256 = self.future_A_gamma_time
if t > block.timestamp:
x0 *= prec_i
if i > 0:
x0 = unsafe_div(x0 * price_scale[i - 1], PRECISION)
x1: uint256 = xp[i] # <------------------ Back up old value in xp ...
xp[i] = x0 # |
self.D = MATH.newton_D(A_gamma[0], A_gamma[1], xp, 0) # |
xp[i] = x1 # <-------------------------------------- ... and restore.
# ----------------------- Calculate dy and fees --------------------------
D: uint256 = self.D
prec_j: uint256 = precisions[j]
y_out: uint256[2] = MATH.get_y(A_gamma[0], A_gamma[1], xp, D, j)
dy = xp[j] - y_out[0]
xp[j] -= dy
dy -= 1
if j > 0:
dy = dy * PRECISION / price_scale[j - 1]
dy /= prec_j
fee: uint256 = unsafe_div(self._fee(xp) * dy, 10**10)
dy -= fee # <--------------------- Subtract fee from the outgoing amount.
assert dy >= min_dy, "Slippage"
y -= dy
self.balances[j] = y # <----------- Update pool balance of outgoing coin.
y *= prec_j
if j > 0:
y = unsafe_div(y * price_scale[j - 1], PRECISION)
xp[j] = y # <------------------------------------------------- Update xp.
# ---------------------- Do Transfers in and out -------------------------
########################## TRANSFER IN <-------
self._transfer_in(
coins[i], dx, dy, mvalue,
callbacker, callback_sig, # <-------- Callback method is called here.
sender, receiver, use_eth,
)
########################## -------> TRANSFER OUT
self._transfer_out(coins[j], dy, use_eth, receiver)
# ------ Tweak price_scale with good initial guess for newton_D ----------
packed_price_scale = self.tweak_price(A_gamma, xp, 0, y_out[1])
log TokenExchange(sender, i, dx, j, dy, fee, packed_price_scale)
return dy
@internal
def tweak_price(
A_gamma: uint256[2],
_xp: uint256[N_COINS],
new_D: uint256,
K0_prev: uint256 = 0,
) -> uint256:
"""
@notice Tweaks price_oracle, last_price and conditionally adjusts
price_scale. This is called whenever there is an unbalanced
liquidity operation: _exchange, add_liquidity, or
remove_liquidity_one_coin.
@dev Contains main liquidity rebalancing logic, by tweaking `price_scale`.
@param A_gamma Array of A and gamma parameters.
@param _xp Array of current balances.
@param new_D New D value.
@param K0_prev Initial guess for `newton_D`.
"""
# ---------------------------- Read storage ------------------------------
rebalancing_params: uint256[3] = self._unpack(
self.packed_rebalancing_params
) # <---------- Contains: allowed_extra_profit, adjustment_step, ma_time.
price_oracle: uint256[N_COINS - 1] = self._unpack_prices(
self.price_oracle_packed
)
last_prices: uint256[N_COINS - 1] = self._unpack_prices(
self.last_prices_packed
)
packed_price_scale: uint256 = self.price_scale_packed
price_scale: uint256[N_COINS - 1] = self._unpack_prices(
packed_price_scale
)
total_supply: uint256 = self.totalSupply
old_xcp_profit: uint256 = self.xcp_profit
old_virtual_price: uint256 = self.virtual_price
last_prices_timestamp: uint256 = self.last_prices_timestamp
# ----------------------- Update MA if needed ----------------------------
if last_prices_timestamp < block.timestamp:
# The moving average price oracle is calculated using the last_price
# of the trade at the previous block, and the price oracle logged
# before that trade. This can happen only once per block.
# ------------------ Calculate moving average params -----------------
alpha: uint256 = MATH.wad_exp(
-convert(
unsafe_div(
(block.timestamp - last_prices_timestamp) * 10**18,
rebalancing_params[2] # <----------------------- ma_time.
),
int256,
)
)
for k in range(N_COINS - 1):
# ----------------- We cap state price that goes into the EMA with
# 2 x price_scale.
price_oracle[k] = unsafe_div(
min(last_prices[k], 2 * price_scale[k]) * (10**18 - alpha) +
price_oracle[k] * alpha, # ^-------- Cap spot price into EMA.
10**18
)
self.price_oracle_packed = self._pack_prices(price_oracle)
self.last_prices_timestamp = block.timestamp # <---- Store timestamp.
# price_oracle is used further on to calculate its vector
# distance from price_scale. This distance is used to calculate
# the amount of adjustment to be done to the price_scale.
# ------------------ If new_D is set to 0, calculate it ------------------
D_unadjusted: uint256 = new_D
if new_D == 0: # <--------------------------- _exchange sets new_D to 0.
D_unadjusted = MATH.newton_D(A_gamma[0], A_gamma[1], _xp, K0_prev)
# ----------------------- Calculate last_prices --------------------------
last_prices = MATH.get_p(_xp, D_unadjusted, A_gamma)
for k in range(N_COINS - 1):
last_prices[k] = unsafe_div(last_prices[k] * price_scale[k], 10**18)
self.last_prices_packed = self._pack_prices(last_prices)
# ---------- Update profit numbers without price adjustment first --------
xp: uint256[N_COINS] = empty(uint256[N_COINS])
xp[0] = unsafe_div(D_unadjusted, N_COINS)
for k in range(N_COINS - 1):
xp[k + 1] = D_unadjusted * 10**18 / (N_COINS * price_scale[k])
# ------------------------- Update xcp_profit ----------------------------
xcp_profit: uint256 = 10**18
virtual_price: uint256 = 10**18
if old_virtual_price > 0:
xcp: uint256 = MATH.geometric_mean(xp)
virtual_price = 10**18 * xcp / total_supply
xcp_profit = unsafe_div(
old_xcp_profit * virtual_price,
old_virtual_price
) # <---------------- Safu to do unsafe_div as old_virtual_price > 0.
# If A and gamma are not undergoing ramps (t < block.timestamp),
# ensure new virtual_price is not less than old virtual_price,
# else the pool suffers a loss.
if self.future_A_gamma_time < block.timestamp:
assert virtual_price > old_virtual_price, "Loss"
self.xcp_profit = xcp_profit
# ------------ Rebalance liquidity if there's enough profits to adjust it:
if virtual_price * 2 - 10**18 > xcp_profit + 2 * rebalancing_params[0]:
# allowed_extra_profit --------^
# ------------------- Get adjustment step ----------------------------
# Calculate the vector distance between price_scale and
# price_oracle.
norm: uint256 = 0
ratio: uint256 = 0
for k in range(N_COINS - 1):
ratio = unsafe_div(price_oracle[k] * 10**18, price_scale[k])
# unsafe_div because we did safediv before ----^
if ratio > 10**18:
ratio = unsafe_sub(ratio, 10**18)
else:
ratio = unsafe_sub(10**18, ratio)
norm = unsafe_add(norm, ratio**2)
norm = isqrt(norm) # <-------------------- isqrt is not in base 1e18.
adjustment_step: uint256 = max(
rebalancing_params[1], unsafe_div(norm, 5)
) # ^------------------------------------- adjustment_step.
if norm > adjustment_step: # <---------- We only adjust prices if the
# vector distance between price_oracle and price_scale is
# large enough. This check ensures that no rebalancing
# occurs if the distance is low i.e. the pool prices are
# pegged to the oracle prices.
# ------------------------------------- Calculate new price scale.
p_new: uint256[N_COINS - 1] = empty(uint256[N_COINS - 1])
for k in range(N_COINS - 1):
p_new[k] = unsafe_div(
price_scale[k] * unsafe_sub(norm, adjustment_step)
+ adjustment_step * price_oracle[k],
norm
) # <- norm is non-zero and gt adjustment_step; unsafe = safe
# ---------------- Update stale xp (using price_scale) with p_new.
xp = _xp
for k in range(N_COINS - 1):
xp[k + 1] = unsafe_div(_xp[k + 1] * p_new[k], price_scale[k])
# unsafe_div because we did safediv before ----^
# ------------------------------------------ Update D with new xp.
D: uint256 = MATH.newton_D(A_gamma[0], A_gamma[1], xp, 0)
for k in range(N_COINS):
frac: uint256 = xp[k] * 10**18 / D # <----- Check validity of
assert (frac > 10**16 - 1) and (frac < 10**20 + 1) # p_new.
xp[0] = D / N_COINS
for k in range(N_COINS - 1):
xp[k + 1] = D * 10**18 / (N_COINS * p_new[k]) # <---- Convert
# xp to real prices.
# ---------- Calculate new virtual_price using new xp and D. Reuse
# `old_virtual_price` (but it has new virtual_price).
old_virtual_price = unsafe_div(
10**18 * MATH.geometric_mean(xp), total_supply
) # <----- unsafe_div because we did safediv before (if vp>1e18)
# ---------------------------- Proceed if we've got enough profit.
if (
old_virtual_price > 10**18 and
2 * old_virtual_price - 10**18 > xcp_profit
):
packed_price_scale = self._pack_prices(p_new)
self.D = D
self.virtual_price = old_virtual_price
self.price_scale_packed = packed_price_scale
return packed_price_scale
# --------- price_scale was not adjusted. Update the profit counter and D.
self.D = D_unadjusted
self.virtual_price = virtual_price
return packed_price_scale
@internal
def _claim_admin_fees():
"""
@notice Claims admin fees and sends it to fee_receiver set in the factory.
"""
A_gamma: uint256[2] = self._A_gamma()
xcp_profit: uint256 = self.xcp_profit # <---------- Current pool profits.
xcp_profit_a: uint256 = self.xcp_profit_a # <- Profits at previous claim.
total_supply: uint256 = self.totalSupply
# Do not claim admin fees if:
# 1. insufficient profits accrued since last claim, and
# 2. there are less than 10**18 (or 1 unit of) lp tokens, else it can lead
# to manipulated virtual prices.
if xcp_profit <= xcp_profit_a or total_supply < 10**18:
return
# Claim tokens belonging to the admin here. This is done by 'gulping'
# pool tokens that have accrued as fees, but not accounted in pool's
# `self.balances` yet: pool balances only account for incoming and
# outgoing tokens excluding fees. Following 'gulps' fees:
for i in range(N_COINS):
if coins[i] == WETH20:
self.balances[i] = self.balance
else:
self.balances[i] = ERC20(coins[i]).balanceOf(self)
# If the pool has made no profits, `xcp_profit == xcp_profit_a`
# and the pool gulps nothing in the previous step.
vprice: uint256 = self.virtual_price
# Admin fees are calculated as follows.
# 1. Calculate accrued profit since last claim. `xcp_profit`
# is the current profits. `xcp_profit_a` is the profits
# at the previous claim.
# 2. Take out admin's share, which is hardcoded at 5 * 10**9.
# (50% => half of 100% => 10**10 / 2 => 5 * 10**9).
# 3. Since half of the profits go to rebalancing the pool, we
# are left with half; so divide by 2.
fees: uint256 = unsafe_div(
unsafe_sub(xcp_profit, xcp_profit_a) * ADMIN_FEE, 2 * 10**10
)
# ------------------------------ Claim admin fees by minting admin's share
# of the pool in LP tokens.
receiver: address = Factory(self.factory).fee_receiver()
if receiver != empty(address) and fees > 0:
frac: uint256 = vprice * 10**18 / (vprice - fees) - 10**18
claimed: uint256 = self.mint_relative(receiver, frac)
xcp_profit -= fees * 2
self.xcp_profit = xcp_profit
log ClaimAdminFee(receiver, claimed)
# ------------------------------------------- Recalculate D b/c we gulped.
D: uint256 = MATH.newton_D(A_gamma[0], A_gamma[1], self.xp(), 0)
self.D = D
# ------------------- Recalculate virtual_price following admin fee claim.
# In this instance we do not check if current virtual price is greater
# than old virtual price, since the claim process can result
# in a small decrease in pool's value.
self.virtual_price = 10**18 * self.get_xcp(D) / self.totalSupply
self.xcp_profit_a = xcp_profit # <------------ Cache last claimed profit.
@internal
@view
def xp() -> uint256[N_COINS]:
result: uint256[N_COINS] = self.balances
packed_prices: uint256 = self.price_scale_packed
precisions: uint256[N_COINS] = self._unpack(self.packed_precisions)
result[0] *= precisions[0]
for i in range(1, N_COINS):
p: uint256 = (packed_prices & PRICE_MASK) * precisions[i]
result[i] = result[i] * p / PRECISION
packed_prices = packed_prices >> PRICE_SIZE
return result
@view
@internal
def _A_gamma() -> uint256[2]:
t1: uint256 = self.future_A_gamma_time
A_gamma_1: uint256 = self.future_A_gamma
gamma1: uint256 = A_gamma_1 & 2**128 - 1
A1: uint256 = A_gamma_1 >> 128
if block.timestamp < t1:
# --------------- Handle ramping up and down of A --------------------
A_gamma_0: uint256 = self.initial_A_gamma
t0: uint256 = self.initial_A_gamma_time
t1 -= t0
t0 = block.timestamp - t0
t2: uint256 = t1 - t0
A1 = ((A_gamma_0 >> 128) * t2 + A1 * t0) / t1
gamma1 = ((A_gamma_0 & 2**128 - 1) * t2 + gamma1 * t0) / t1
return [A1, gamma1]
@internal
@view
def _fee(xp: uint256[N_COINS]) -> uint256:
fee_params: uint256[3] = self._unpack(self.packed_fee_params)
f: uint256 = MATH.reduction_coefficient(xp, fee_params[2])
return unsafe_div(
fee_params[0] * f + fee_params[1] * (10**18 - f),
10**18
)
@internal
@view
def get_xcp(D: uint256) -> uint256:
x: uint256[N_COINS] = empty(uint256[N_COINS])
x[0] = D / N_COINS
packed_prices: uint256 = self.price_scale_packed # <-- No precisions here
# because we don't switch to "real" units.
for i in range(1, N_COINS):
x[i] = D * 10**18 / (N_COINS * (packed_prices & PRICE_MASK))
packed_prices = packed_prices >> PRICE_SIZE
return MATH.geometric_mean(x)
@view
@internal
def _calc_token_fee(amounts: uint256[N_COINS], xp: uint256[N_COINS]) -> uint256:
# fee = sum(amounts_i - avg(amounts)) * fee' / sum(amounts)
fee: uint256 = unsafe_div(
unsafe_mul(self._fee(xp), N_COINS),
unsafe_mul(4, unsafe_sub(N_COINS, 1))
)
S: uint256 = 0
for _x in amounts:
S += _x
avg: uint256 = unsafe_div(S, N_COINS)
Sdiff: uint256 = 0
for _x in amounts:
if _x > avg:
Sdiff += unsafe_sub(_x, avg)
else:
Sdiff += unsafe_sub(avg, _x)
return fee * Sdiff / S + NOISE_FEE
@internal
@view
def _calc_withdraw_one_coin(
A_gamma: uint256[2],
token_amount: uint256,
i: uint256,
update_D: bool,
) -> (uint256, uint256, uint256[N_COINS], uint256):
token_supply: uint256 = self.totalSupply
assert token_amount <= token_supply # dev: token amount more than supply
assert i < N_COINS # dev: coin out of range
xx: uint256[N_COINS] = self.balances
precisions: uint256[N_COINS] = self._unpack(self.packed_precisions)
xp: uint256[N_COINS] = precisions
D0: uint256 = 0
# -------------------------- Calculate D0 and xp -------------------------
price_scale_i: uint256 = PRECISION * precisions[0]
packed_prices: uint256 = self.price_scale_packed
xp[0] *= xx[0]
for k in range(1, N_COINS):
p: uint256 = (packed_prices & PRICE_MASK)
if i == k:
price_scale_i = p * xp[i]
xp[k] = unsafe_div(xp[k] * xx[k] * p, PRECISION)
packed_prices = packed_prices >> PRICE_SIZE
if update_D: # <-------------- D is updated if pool is undergoing a ramp.
D0 = MATH.newton_D(A_gamma[0], A_gamma[1], xp, 0)
else:
D0 = self.D
D: uint256 = D0
# -------------------------------- Fee Calc ------------------------------
# Charge fees on D. Roughly calculate xp[i] after withdrawal and use that
# to calculate fee. Precision is not paramount here: we just want a
# behavior where the higher the imbalance caused the more fee the AMM
# charges.
# xp is adjusted assuming xp[0] ~= xp[1] ~= x[2], which is usually not the
# case. We charge self._fee(xp), where xp is an imprecise adjustment post
# withdrawal in one coin. If the withdraw is too large: charge max fee by
# default. This is because the fee calculation will otherwise underflow.
xp_imprecise: uint256[N_COINS] = xp
xp_correction: uint256 = xp[i] * N_COINS * token_amount / token_supply
fee: uint256 = self._unpack(self.packed_fee_params)[1] # <- self.out_fee.
if xp_correction < xp_imprecise[i]:
xp_imprecise[i] -= xp_correction
fee = self._fee(xp_imprecise)
dD: uint256 = unsafe_div(token_amount * D, token_supply)
D_fee: uint256 = fee * dD / (2 * 10**10) + 1 # <------- Actual fee on D.
# --------- Calculate `approx_fee` (assuming balanced state) in ith token.
# -------------------------------- We only need this for fee in the event.
approx_fee: uint256 = N_COINS * D_fee * xx[i] / D
# ------------------------------------------------------------------------
D -= (dD - D_fee) # <----------------------------------- Charge fee on D.
# --------------------------------- Calculate `y_out`` with `(D - D_fee)`.
y: uint256 = MATH.get_y(A_gamma[0], A_gamma[1], xp, D, i)[0]
dy: uint256 = (xp[i] - y) * PRECISION / price_scale_i
xp[i] = y
return dy, D, xp, approx_fee
# ------------------------ ERC20 functions -----------------------------------
@internal
def _approve(_owner: address, _spender: address, _value: uint256):
self.allowance[_owner][_spender] = _value
log Approval(_owner, _spender, _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)
@view
@internal
def _domain_separator() -> bytes32:
if chain.id != CACHED_CHAIN_ID:
return keccak256(
_abi_encode(
EIP712_TYPEHASH,
NAME_HASH,
VERSION_HASH,
chain.id,
self,
salt,
)
)
return CACHED_DOMAIN_SEPARATOR
@external
def transferFrom(_from: address, _to: address, _value: uint256) -> bool:
"""
@dev Transfer tokens from one address to another.
@param _from address The address which you want to send tokens from
@param _to address The address which you want to transfer to
@param _value uint256 the amount of tokens to be transferred
@return bool True on successul transfer. Reverts otherwise.
"""
_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:
"""
@dev Transfer token for a specified address
@param _to The address to transfer to.
@param _value The amount to be transferred.
@return bool True on successful transfer. Reverts otherwise.
"""
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.
@return bool Success
"""
self._approve(msg.sender, _spender, _value)
return True
@external
def increaseAllowan...
// [truncated — 70613 bytes total]
Read Contract
A 0xf446c1d0 → uint256
ADMIN_FEE 0x4469ed14 → uint256
D 0x0f529ba2 → uint256
DOMAIN_SEPARATOR 0x3644e515 → bytes32
MATH 0xed6c1546 → address
WETH20 0x17e26cd1 → address
adjustment_step 0x083812e5 → uint256
admin_actions_deadline 0x405e28f8 → uint256
allowance 0xdd62ed3e → uint256
allowed_extra_profit 0x49fe9e77 → uint256
balanceOf 0x70a08231 → uint256
balances 0x4903b0d1 → uint256
calc_token_amount 0x3883e119 → uint256
calc_token_fee 0xcde699fa → uint256
calc_withdraw_one_coin 0x4fb08c5e → uint256
coins 0xc6610657 → address
decimals 0x313ce567 → uint8
factory 0xc45a0155 → address
fee 0xddca3f43 → uint256
fee_calc 0x572e5625 → uint256
fee_gamma 0x72d4f0e2 → uint256
fee_receiver 0xcab4d3db → address
future_A_gamma 0xf30cfad5 → uint256
future_A_gamma_time 0xf9ed9597 → uint256
gamma 0xb1373929 → uint256
get_dx 0x37ed3a7a → uint256
get_dy 0x556d6e9f → uint256
get_virtual_price 0xbb7b8b80 → uint256
initial_A_gamma 0x204fe3d5 → uint256
initial_A_gamma_time 0xe89876ff → uint256
last_prices 0x59189017 → uint256
last_prices_timestamp 0x6112c747 → uint256
lp_price 0x54f0f7d5 → uint256
ma_time 0x09c3da6a → uint256
mid_fee 0x92526c0c → uint256
name 0x06fdde03 → string
nonces 0x7ecebe00 → uint256
out_fee 0xee8de675 → uint256
packed_fee_params 0xe3616405 → uint256
packed_rebalancing_params 0x3dd65478 → uint256
precisions 0x3620604b → uint256[3]
price_oracle 0x68727653 → uint256
price_scale 0xa3f7cdd5 → uint256
salt 0xbfa0b133 → bytes32
symbol 0x95d89b41 → string
totalSupply 0x18160ddd → uint256
version 0x54fd4d50 → string
virtual_price 0x0c46b72a → uint256
xcp_profit 0x7ba1a74d → uint256
xcp_profit_a 0x0b7b594b → uint256
Write Contract 28 functions
These functions modify contract state and require a wallet transaction to execute.
add_liquidity 0x4515cef3
uint256[3] amounts
uint256 min_mint_amount
returns: uint256
add_liquidity 0x2b6e993a
uint256[3] amounts
uint256 min_mint_amount
bool use_eth
returns: uint256
add_liquidity 0x5cecb5f7
uint256[3] amounts
uint256 min_mint_amount
bool use_eth
address receiver
returns: uint256
apply_new_parameters 0x2a7dd7cd
No parameters
approve 0x095ea7b3
address _spender
uint256 _value
returns: bool
claim_admin_fees 0xc93f49e8
No parameters
commit_new_parameters 0x4711a4f8
uint256 _new_mid_fee
uint256 _new_out_fee
uint256 _new_fee_gamma
uint256 _new_allowed_extra_profit
uint256 _new_adjustment_step
uint256 _new_ma_time
decreaseAllowance 0xa457c2d7
address _spender
uint256 _sub_value
returns: bool
exchange 0x5b41b908
uint256 i
uint256 j
uint256 dx
uint256 min_dy
returns: uint256
exchange 0x394747c5
uint256 i
uint256 j
uint256 dx
uint256 min_dy
bool use_eth
returns: uint256
exchange 0xce7d6503
uint256 i
uint256 j
uint256 dx
uint256 min_dy
bool use_eth
address receiver
returns: uint256
exchange_extended 0xdd96994f
uint256 i
uint256 j
uint256 dx
uint256 min_dy
bool use_eth
address sender
address receiver
bytes32 cb
returns: uint256
exchange_underlying 0x65b2489b
uint256 i
uint256 j
uint256 dx
uint256 min_dy
returns: uint256
exchange_underlying 0xe2ad025a
uint256 i
uint256 j
uint256 dx
uint256 min_dy
address receiver
returns: uint256
increaseAllowance 0x39509351
address _spender
uint256 _add_value
returns: bool
permit 0xd505accf
address _owner
address _spender
uint256 _value
uint256 _deadline
uint8 _v
bytes32 _r
bytes32 _s
returns: bool
ramp_A_gamma 0x5e248072
uint256 future_A
uint256 future_gamma
uint256 future_time
remove_liquidity 0xecb586a5
uint256 _amount
uint256[3] min_amounts
returns: uint256[3]
remove_liquidity 0xfce64736
uint256 _amount
uint256[3] min_amounts
bool use_eth
returns: uint256[3]
remove_liquidity 0x1da3d238
uint256 _amount
uint256[3] min_amounts
bool use_eth
address receiver
returns: uint256[3]
remove_liquidity 0x5cd34780
uint256 _amount
uint256[3] min_amounts
bool use_eth
address receiver
bool claim_admin_fees
returns: uint256[3]
remove_liquidity_one_coin 0xf1dc3cc9
uint256 token_amount
uint256 i
uint256 min_amount
returns: uint256
remove_liquidity_one_coin 0x8f15b6b5
uint256 token_amount
uint256 i
uint256 min_amount
bool use_eth
returns: uint256
remove_liquidity_one_coin 0x07329bcd
uint256 token_amount
uint256 i
uint256 min_amount
bool use_eth
address receiver
returns: uint256
revert_new_parameters 0x226840fb
No parameters
stop_ramp_A_gamma 0x244c7c2e
No parameters
transfer 0xa9059cbb
address _to
uint256 _value
returns: bool
transferFrom 0x23b872dd
address _from
address _to
uint256 _value
returns: bool
Token Balances (2)
View Transfers →Recent Transactions
No transactions found for this address