Address Contract Verified
Address
0x78190e4c7C7B2c2C3b0562F1f155a1FC2F5160CA
Balance
0 ETH
Nonce
1
Code Size
24400 bytes
Creator
0x4630cDE3...C552 at tx 0x7f1bfe5a...1f886f
Indexed Transactions
0
Contract Bytecode
24400 bytes
0x6080604052600436106103bb575f3560e01c80637fb668c4116101f2578063c579d75311610112578063c579d75314610e0e578063c7c5c4a714610e2d578063c82c94bf14610e4c578063c98f413414610e86578063ca36c04a14610eb1578063ca7d907314610ed0578063cd88674014610f07578063cfdc148f14610f26578063d1f6346214610f5a578063d30f629214610f79578063d3573a3314610f98578063d6745e7814610fb7578063d816248814610fd6578063d91c1b5014610fde578063e65bcf9814610ff1578063eabad60a14611035578063eb470ebf14611054578063ee97f7f314611088578063ef55aa08146110a6578063f26f1ea6146110c5578063fa83f4ce146110e4575f80fd5b80637fb668c414610b1e57806381cc49a314610b3d57806386b47ce114610b8157806386c5cb9d14610ba05780638ba8d15e14610ba8578063901accb814610bd3578063951e435d14610bf25780639785d0e714610c3657806399080e7014610c555780639d0f545014610c745780639f61557e14610ca2578063a4c6a7d514610cc1578063aa5d03dd14610ce0578063aced8d7414610d17578063b5ed298a14610d36578063c0e6d40714610d55578063c1919dd914610d68578063c2e77e4414610db1578063c3f4f45c14610dd0578063c5619dfe14610def575f80fd5b80633fec6386116102dd5780633fec6386146107e357806340ee5d731461080257806349622c49146108395780634969b6c1146108a95780634e71e0c8146108d757806352228054146108eb5780635295bd461461090a57806352d7220e1461094b57806362aa126d1461096a578063655ac9651461098957806365d57877146109a85780636c2b34a8146109c75780636f4330c1146109fd578063715018a614610a1c57806377cfd4a514610a305780637844a19914610a4f5780637b1f847c14610a6e5780637c854ec714610a995780637cc97da514610acc5780637eb823c814610aff575f80fd5b8061153614610415578063019dbb631461048057806302daa233146104b0578063040141e5146104cf57806307ed50001461050f5780630f9f234d1461056f578063115e84231461058e57806312d8947a146105ad57806313f7642c146105ce5780631d0f9fe7146105ed5780631f0ae5dc146106245780632256b4911461067e57806322d7fd021461069d578063251671ac146106bc578063276152c1146106f25780632a145e25146107115780632ab88d1c14610752578063335956fd146107865780633d007263146107a55780633dda0c63146107c4575f80fd5b36610411576103c8611103565b6001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21633036103fa57005b5f5461040f906001600160a01b03163461115e565b005b5f80fd5b348015610420575f80fd5b5061045961042f366004615888565b600d6020525f9081526040902080546001820154600283015460039093015460ff90921692909184565b60408051941515855260208501939093529183015260608201526080015b60405180910390f35b34801561048b575f80fd5b506001546104a090600160a01b900460ff1681565b6040519015158152602001610477565b3480156104bb575f80fd5b5061040f6104ca3660046158b0565b611217565b3480156104da575f80fd5b506105027f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6040516104779190615913565b34801561051a575f80fd5b5061054f610529366004615888565b600e6020525f908152604090208054600182015460028301546003909301549192909184565b604080519485526020850193909352918301526060820152608001610477565b34801561057a575f80fd5b50600354610502906001600160a01b031681565b348015610599575f80fd5b506105026105a8366004615927565b6113a4565b6105c06105bb366004615947565b6113e0565b604051908152602001610477565b3480156105d9575f80fd5b506105c06105e836600461595e565b611541565b3480156105f8575f80fd5b506105c0610607366004615888565b6001600160a01b03165f9081526010602052604090206001015490565b34801561062f575f80fd5b5061066761063e366004615988565b600b60209081525f92835260408084209091529082529020805460019091015460ff9091169082565b604080519215158352602083019190915201610477565b348015610689575f80fd5b50610502610698366004615927565b61155b565b3480156106a8575f80fd5b506105c06106b73660046159b6565b61158f565b3480156106c7575f80fd5b506105c06106d6366004615988565b600960209081525f928352604080842090915290825290205481565b3480156106fd575f80fd5b5061040f61070c366004615a14565b611791565b34801561071c575f80fd5b506105c061072b366004615988565b5f9182526009602090815260408084206001600160a01b0393909316845291905290205490565b34801561075d575f80fd5b506105c061076c366004615888565b6001600160a01b03165f908152600e602052604090205490565b348015610791575f80fd5b506105c06107a0366004615a2e565b6117a5565b3480156107b0575f80fd5b506105c06107bf366004615a2e565b6117fd565b3480156107cf575f80fd5b5061040f6107de36600461595e565b61183d565b3480156107ee575f80fd5b5061040f6107fd366004615888565b611853565b34801561080d575f80fd5b506105c061081c366004615888565b6001600160a01b03165f9081526010602052604090206002015490565b348015610844575f80fd5b50610881610853366004615888565b600c6020525f9081526040902080546001820154600283015460038401546004909401549293919290919085565b604080519586526020860194909452928401919091526060830152608082015260a001610477565b3480156108b4575f80fd5b506104a06108c3366004615888565b60146020525f908152604090205460ff1681565b3480156108e2575f80fd5b5061040f6118da565b3480156108f6575f80fd5b5061040f610905366004615888565b6118f5565b348015610915575f80fd5b506105c0610924366004615988565b5f918252600a602090815260408084206001600160a01b0393909316845291905290205490565b348015610956575f80fd5b5061040f610965366004615a2e565b611a44565b348015610975575f80fd5b50610502610984366004615927565b611a8b565b348015610994575f80fd5b5061040f6109a3366004615a2e565b611aaa565b3480156109b3575f80fd5b506105c06109c236600461595e565b611ae7565b3480156109d2575f80fd5b506105c06109e1366004615988565b600a60209081525f928352604080842090915290825290205481565b348015610a08575f80fd5b50610502610a17366004615927565b611af2565b348015610a27575f80fd5b5061040f611b0b565b348015610a3b575f80fd5b506105c0610a4a366004615a2e565b611b57565b348015610a5a575f80fd5b5061040f610a6936600461595e565b611ba4565b348015610a79575f80fd5b506105c0610a88366004615947565b5f9081526008602052604090205490565b348015610aa4575f80fd5b506105027f000000000000000000000000bec57d7ba1fef3f2352cd529c3b40cf2c499952981565b348015610ad7575f80fd5b506105027f000000000000000000000000896fc8ffc11cda80cf40c373afa9a22d6e05f2d381565b348015610b0a575f80fd5b5061040f610b19366004615a63565b611bca565b348015610b29575f80fd5b506105c0610b38366004615aa8565b611bd6565b348015610b48575f80fd5b50610459610b57366004615888565b60106020525f9081526040902080546001820154600283015460039093015460ff90921692909184565b348015610b8c575f80fd5b506105c0610b9b36600461595e565b611d75565b61040f611dd8565b348015610bb3575f80fd5b506105c0610bc2366004615947565b5f9081526007602052604090205490565b348015610bde575f80fd5b5061040f610bed366004615988565b611de3565b348015610bfd575f80fd5b506105c0610c0c366004615988565b5f918252600b602090815260408084206001600160a01b0393909316845291905290206001015490565b348015610c41575f80fd5b5061040f610c50366004615b14565b611eaf565b348015610c60575f80fd5b506105c0610c6f366004615927565b611ee1565b348015610c7f575f80fd5b506104a0610c8e366004615947565b60126020525f908152604090205460ff1681565b348015610cad575f80fd5b506105c0610cbc366004615927565b611f7f565b348015610ccc575f80fd5b506105c0610cdb366004615a2e565b611fe8565b348015610ceb575f80fd5b506105c0610cfa366004615888565b6001600160a01b03165f908152600e602052604090206002015490565b348015610d22575f80fd5b506105c0610d31366004615a2e565b612020565b348015610d41575f80fd5b5061040f610d50366004615888565b612056565b61040f610d63366004615947565b6120d0565b348015610d73575f80fd5b50610da2610d82366004615888565b600f6020525f908152604090208054600182015460029092015490919083565b60405161047793929190615b40565b348015610dbc575f80fd5b506105c0610dcb366004615a2e565b61216c565b348015610ddb575f80fd5b5061040f610dea366004615b56565b6121a2565b348015610dfa575f80fd5b5061040f610e09366004615ba1565b612229565b348015610e19575f80fd5b506105c0610e28366004615a2e565b612288565b348015610e38575f80fd5b506105c0610e47366004615a2e565b6122bd565b348015610e57575f80fd5b50610da2610e66366004615888565b60116020525f908152604090208054600182015460029092015490919083565b348015610e91575f80fd5b506105c0610ea0366004615888565b60066020525f908152604090205481565b348015610ebc575f80fd5b506105c0610ecb366004615bd3565b6122e6565b348015610edb575f80fd5b506105c0610eea366004615888565b6001600160a01b03165f908152600f602052604090206001015490565b348015610f12575f80fd5b5061040f610f21366004615927565b612339565b348015610f31575f80fd5b506105c0610f40366004615888565b6001600160a01b03165f908152600f602052604090205490565b348015610f65575f80fd5b5061040f610f74366004615c12565b6123be565b348015610f84575f80fd5b506105c0610f93366004615a2e565b6123f6565b348015610fa3575f80fd5b50600154610502906001600160a01b031681565b348015610fc2575f80fd5b5061040f610fd1366004615c4a565b612422565b6105c06124f0565b6105c0610fec366004615947565b612544565b348015610ffc575f80fd5b506104a061100b366004615988565b5f918252600b602090815260408084206001600160a01b0393909316845291905290205460ff1690565b348015611040575f80fd5b5061040f61104f366004615988565b61258b565b34801561105f575f80fd5b506105c061106e366004615888565b6001600160a01b03165f9081526011602052604090205490565b348015611093575f80fd5b505f54610502906001600160a01b031681565b3480156110b1575f80fd5b506105c06110c0366004615bd3565b612595565b3480156110d0575f80fd5b5061040f6110df366004615988565b6125dd565b3480156110ef575f80fd5b506105c06110fe366004615927565b612681565b60018054600160a01b900460ff161515900361113257604051634a7f394f60e01b815260040160405180910390fd5b61113a6126ff565b151560010361115c57604051634a7f394f60e01b815260040160405180910390fd5b565b8047101561117f5760405163617ab12d60e11b815260040160405180910390fd5b6001805460ff60a01b1916600160a01b1790556040515f906001600160a01b0384169083908381818185875af1925050503d805f81146111da576040519150601f19603f3d011682016040523d82523d5f602084013e6111df565b606091505b50506001805460ff60a01b1916905590508015155f036112125760405163120086e360e11b815260040160405180910390fd5b505050565b61121f61276f565b6001600160a01b0386165f9081526013602052604090205460ff16151560010361125c57604051634a7f394f60e01b815260040160405180910390fd5b6001600160a01b0386165f908152601360209081526040808320805460ff1990811686151517909155600d90925290912080549091168315151781556112b4856112af662386f26fc1000061012c615c81565b61279b565b6112ca846112af662386f26fc100006064615c81565b6112d4848661279b565b5f6112df87876127bc565b90505f6112ec88876127bc565b90505f6112f98284612831565b90505f611306838561284a565b905061131a8a670de0b6b3a764000061279b565b6040805160a081018252828152602080820194855281830196875260608201958652608082019c8d526001600160a01b03909d165f908152600c8e528281209151825593516001808301919091559551600280830191909155945160038201559a516004909b019a909a5584840155600f9099529690972090960154959094019490945550505050565b5f8281526008602052604081208054839081106113c3576113c3615c98565b5f918252602090912001546001600160a01b031690505b92915050565b5f7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25f8061140d83612857565b5f8781526009602090815260408083206001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2168452909152902054919350915061145d81612898565b5f6114887f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc283611d75565b90505f6114b67f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2345f6122e6565b90506114c181612898565b5f34838111156114e1573484900391506114db8282615cac565b90508492505b61150e338b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc284876128b8565b6115178161291b565b811561152757611527338361115e565b50909650505050611539838383612974565b505050919050565b5f61155461154d612988565b84846123f6565b9392505050565b6007602052815f5260405f208181548110611574575f80fd5b5f918252602090912001546001600160a01b03169150829050565b5f835f8061159c83612857565b91509150855f806115ac83612857565b915091506115b8615808565b8c815260208082018d9052336040808401919091526001600160a01b038d811660608501528c8116608085015260c084018c905260035482516332b98a6960e11b8152925191169263657314d292600480820193918290030181865afa158015611624573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116489190615cbf565b60e082015260035460408051635878441b60e01b815290516001600160a01b0390921691635878441b916004808201926020929091908290030181865afa158015611695573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116b99190615cbf565b6101008201526116ca8d8b8d612a16565b6101408301526101208201526116e08b8a611d75565b60a08201526116ef8d33612a3d565b6116f98d8d612a89565b600354604051630701c45360e21b8152600481018f90526001600160a01b038d81166024830152604482018c905290911690631c07114c906064015f6040518083038186803b15801561174a575f80fd5b505afa15801561175c573d5f803e3d5ffd5b5050505061176981612b7b565b975050611777838383612974565b505050611785838383612974565b50505095945050505050565b61179961276f565b6117a281612e01565b50565b5f825f806117b283612857565b915091505f6117c287875f6122e6565b90506117cd81612898565b6117da33898989856128b8565b6117e6873330896132d0565b93506117f3838383612974565b5050509392505050565b5f825f8061180a83612857565b915091505f6118198787611d75565b905061182481612898565b611831338989848a6128b8565b6117e6873330846132d0565b61184f611848612988565b8383611a44565b5050565b805f8061185f83612857565b6040805160018082528183019092529294509092505f91906020808301908036833701905050905084815f8151811061189a5761189a615c98565b6001600160a01b0392909216602092830291909101820152604080515f815291820190526118c8908261333b565b506118d4838383612974565b50505050565b6118e261334d565b5f80546001600160a01b03191633179055565b6118fd61276f565b6003546001600160a01b03161561192757604051634a7f394f60e01b815260040160405180910390fd5b600380546001600160a01b0319166001600160a01b03831690811790915560408051633a89899b60e21b8152905163ea26266c916004808201926020929091908290030181865afa15801561197e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119a29190615cd6565b600480546001600160a01b0319166001600160a01b039283161781556003546040805163730e695d60e01b81529051919093169263730e695d92818101926020929091908290030181865afa1580156119fd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a219190615cd6565b600280546001600160a01b0319166001600160a01b039290921691909117905550565b815f80611a5083612857565b91509150611a603387878761337a565b611a6c338787876133ab565b611a78853330876132d0565b611a83838383612974565b505050505050565b5f8281526007602052604081208054839081106113c3576113c3615c98565b815f80611ab683612857565b9150915085611ac733888888613408565b611ad286338761342a565b611adb81613449565b50611a83838383612974565b5f6115548383613487565b6008602052815f5260405f208181548110611574575f80fd5b611b1361276f565b5f80546001600160a01b0319908116825560018054909116905560405133917f6172baf984ea013d88b784409f46655b96ba7f2ff91bca1ac9bcd27b113e6eb091a2565b5f825f80611b6483612857565b91509150865f611b77338a8a8a5f6134c7565b9050611b8281612898565b611b8d88338961342a565b9450611b9881613449565b506117f3838383612974565b611bac6134e4565b6001600160a01b039091165f908152600e6020526040902060030155565b6118d484848484613511565b5f845f80611be383612857565b91509150865f80611bf383612857565b91509150611bff615808565b8e815260208082018f90526001600160a01b03808f1660408085019190915260a084018d90528e821660608501528d8216608085015260c084018c905260035481516374f517a360e11b8152915192169263e9ea2f46926004808401938290030181865afa158015611c73573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c979190615cbf565b60e082015260035460408051638cd6840360e01b815290516001600160a01b0390921691638cd68403916004808201926020929091908290030181865afa158015611ce4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d089190615cbf565b61010082015280516020820151611d2091339161364e565b611d36815f015182608001518360600151612a16565b610140830152610120820152611d4b81612b7b565b975050611d59838383612974565b505050611d67838383612974565b505050979650505050505050565b6001600160a01b0382165f908152601060205260408120600101548190611d9c9084615c81565b6001600160a01b0385165f90815260106020526040902060020154909150611dc48183615cf1565b611dcf906001615d10565b95945050505050565b61115c610d63612988565b805f80611def83612857565b91509150611dfd8533613741565b5f80611e0a87875f612a16565b5f898152600b602090815260408083206001600160a01b03808d168552925291829020805460ff191660011790556003549151637c2114c960e01b81529395509193501690637c2114c990611e65908a908a90600401615d23565b5f6040518083038186803b158015611e7b575f80fd5b505afa158015611e8d573d5f803e3d5ffd5b50505050611e9b828261333b565b5050611ea8838383612974565b5050505050565b611eb761276f565b6001600160a01b03919091165f908152601460205260409020805460ff1916911515919091179055565b5f7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25f80611f0e83612857565b91509150855f611f4133897f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28a5f6134c7565b9050611f4c81612898565b611f558761379b565b611f5f338861115e565b9450611f6a81613449565b50611f76838383612974565b50505092915050565b5f7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25f80611fac83612857565b9150915085611fbb8733613741565b5f611f41887f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2895f61380c565b5f611ff161382a565b825f80611ffd83612857565b91509150865f61200f88886001612595565b9050611b82338a8a8a856001613855565b5f61202961382a565b825f8061203583612857565b91509150865f612049338a8a8a60016139c5565b9050611b8d88338361342a565b61205e61276f565b6001600160a01b0381166120855760405163f2365b5b60e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b03831690811790915560405133907f322fd6444c59daffa82e4689b7685b6fafc6109a1eff8a6ca10c5a8e3206cda1905f90a350565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25f806120fc83612857565b9150915061212c33857f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc23461337a565b6121353461291b565b61216133857f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2346133ab565b6118d4838383612974565b5f825f8061217983612857565b91509150865f61218c338a8a8a5f6139c5565b905061219781612898565b611b8d88338361342a565b6121aa61276f565b6121b382612e01565b6003546001600160a01b031663c1766f256121d46040850160208601615888565b6121de8480615d3a565b846020016040518463ffffffff1660e01b815260040161220093929190615dc8565b5f604051808303815f87803b158015612217575f80fd5b505af1158015611a83573d5f803e3d5ffd5b61223161276f565b8015612252576001600160a01b0383165f9081526006602052604090208190555b8115612276576001600160a01b0383165f908152600f602052604090206002018290555b61121282670de0b6b3a764000061279b565b5f61229161382a565b825f8061229d83612857565b91509150865f6122b0898989600161380c565b9050611b8d88338961342a565b5f825f806122ca83612857565b91509150866122d98833613741565b5f611b778989895f61380c565b6001600160a01b0383165f9081526010602052604081206002015461233190612310908590615c81565b6001600160a01b0386165f90815260106020526040902060010154846139fe565b949350505050565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25f8061236583612857565b915091508461239633877f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc288613408565b61239f8561379b565b6123a9338661115e565b6123b281613449565b50611ea8838383612974565b6123c66134e4565b835f806123d283612857565b915091506123e286888787613a39565b6123ed838383612974565b50505050505050565b5f825f8061240383612857565b915091505f61241433898989613a94565b90506117e6873330896132d0565b61242b33613b3e565b600354604051635454018560e01b81526004810184905261249e916001600160a01b0316906354540185906024015b602060405180830381865afa158015612475573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124999190615cbf565b613b7a565b6003546040516312ad379b60e21b8152600481018490526124d1916001600160a01b031690634ab4de6c9060240161245a565b5f91825260126020526040909120805460ff1916911515919091179055565b5f7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25f8061251d83612857565b9150915061253161252c612988565b613b99565b935061253e838383612974565b50505090565b5f7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25f8061257183612857565b9150915061257e85613b99565b9350611539838383612974565b61184f8282612a3d565b6001600160a01b0383165f908152600f6020526040812060010154612331906125bf908590615c81565b6001600160a01b0386165f908152600f6020526040902054846139fe565b805f806125e983612857565b60035460405163dd998e9f60e01b81529294509092506001600160a01b03169063dd998e9f9061262190889033908990600401615e82565b5f6040518083038186803b158015612637575f80fd5b505afa158015612649573d5f803e3d5ffd5b5050505f868152600b602090815260408083206001600160a01b03891684529091529020805460ff1916905550611ea8838383612974565b5f7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25f806126ae83612857565b91509150855f6126e133897f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28a5f6139c5565b90506126ec81612898565b6126f58161379b565b611f5f338261115e565b60025460408051631786ef6d60e01b815290515f926001600160a01b031691631786ef6d9160048083019260209291908290030181865afa158015612746573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061276a9190615ea1565b905090565b5f546001600160a01b0316330361278257565b604051635a7617f960e11b815260040160405180910390fd5b8082111561184f57604051634a7f394f60e01b815260040160405180910390fd5b5f612814826127d3670de0b6b3a764000080615c81565b6127dd9086615c81565b6127e79190615cf1565b60046127fb670de0b6b3a764000080615c81565b6128059190615cf1565b61280f9190615d10565b613bd2565b6128276002670de0b6b3a7640000615cf1565b6115549190615d10565b5f6249d4006128408385615cac565b6115549190615cf1565b5f60026128408385615d10565b5f80612861611103565b61286a83613d46565b61287383613d58565b15156001036128855761288583613d89565b61288e83613e20565b9094909350915050565b805f036117a25760405163ba3b5b5960e01b815260040160405180910390fd5b6128c484848484613a39565b83836001600160a01b0316866001600160a01b03167f7f41b0c3b993c6789242222b015eb52f8ed30b46935194737c07c7abb5742f5e85854260405161290c93929190615b40565b60405180910390a45050505050565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b158015612217575f80fd5b61297d83613ed1565b611212838383613ee3565b60405163acd0503b60e01b81525f906001600160a01b037f000000000000000000000000bec57d7ba1fef3f2352cd529c3b40cf2c4999529169063acd0503b906129d6903390600401615913565b6020604051808303815f875af11580156129f2573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061276a9190615cbf565b606080612a2560078686613f26565b612a3160088786613f26565b91509150935093915050565b612a4681613f91565b1515600103612a53575050565b5f8281526012602052604081205460ff1615159003612a70575050565b6040516363e936b960e11b815260040160405180910390fd5b5f8181526012602052604090205460ff161515600103612abc5760405163f508bb9360e01b815260040160405180910390fd5b818103612adc576040516387e9041360e01b815260040160405180910390fd5b7f000000000000000000000000bec57d7ba1fef3f2352cd529c3b40cf2c49995296001600160a01b0316635d96f7486040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b38573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b5c9190615cbf565b811061184f576040516387e9041360e01b815260040160405180910390fd5b5f612b898260a00151612898565b600480548351604051631e1b300760e11b8152928301526001600160a01b031690633c36600e906024015f604051808303815f87803b158015612bca575f80fd5b505af1158015612bdc573d5f803e3d5ffd5b505060035484516080860151606087015160a0880151604051630e8f811d60e41b81525f97506001600160a01b039586169650633c5da0c2957f000000000000000000000000896fc8ffc11cda80cf40c373afa9a22d6e05f2d3169263e8f811d092612c4a92600401615ebc565b602060405180830381865afa158015612c65573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c899190615cbf565b8760e001518861010001516040518663ffffffff1660e01b8152600401612cdb9594939291909485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b602060405180830381865afa158015612cf6573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d1a9190615cbf565b9050612d2e81670de0b6b3a764000061279b565b612d49835f015184606001518560a001518660c00151613a39565b612d60835f01518460200151856080015184613fc4565b600480548551604051631e1b300760e11b8152928301529193506001600160a01b0390911690633c36600e906024015f604051808303815f87803b158015612da6575f80fd5b505af1158015612db8573d5f803e3d5ffd5b50505050612dd083610120015184610140015161333b565b612de883606001518460400151308660a001516132d0565b612dfb836080015184604001518461342a565b50919050565b612e3f60115f612e176040850160208601615888565b6001600160a01b03166001600160a01b031681526020019081526020015f205f01545f61279b565b5f612e506040830160208401615888565b6001600160a01b031603612e775760405163e6c4247b60e01b815260040160405180910390fd5b612e8d8160400135670de0b6b3a764000061279b565b612ea760608201356112af662386f26fc100006055615c81565b5f612ec86040830135612ec3662386f26fc1000061012c615c81565b6127bc565b90505f612ee56040840135612ec3662386f26fc100006064615c81565b90505f612ef28284612831565b9050608084013560065f612f0c6040880160208901615888565b6001600160a01b03166001600160a01b031681526020019081526020015f208190555060405180608001604052805f81526020015f81526020015f8152602001662386f26fc100006014612f609190615c81565b9052600e5f612f756040880160208901615888565b6001600160a01b0316815260208082019290925260409081015f90812084518155928401516001840155908301516002830155606090920151600390910155612fbe838561284a565b90506040518060a001604052808281526020018381526020018581526020018481526020018660400135815250600c5f8760200160208101906130019190615888565b6001600160a01b0316815260208082019290925260409081015f20835181558383015160018201558382015160028201556060840151600382015560809384015160049091015580519283019052819061305d90880188615ed5565b151581526020016103e881526020016103e881526020015f81525060105f87602001602081019061308e9190615888565b6001600160a01b0316815260208082019290925260409081015f9081208451815460ff19169015151781558484015160018201558483015160028201556060948501516003909101558151608081018352818152808401869052808301829052938401819052600d92909161310891908a01908a01615888565b6001600160a01b0316815260208082019290925260409081015f9081208451815460ff1916901515178155848401516001820155848301516002820155606094850151600390910155815180850183526103e8808252818501529389013584830152600f92909161317e91908a01908a01615888565b6001600160a01b03166001600160a01b031681526020019081526020015f205f820151815f0155602082015181600101556040820151816002015590505060405180606001604052804281526020014281526020014281525060115f8760200160208101906131ed9190615888565b6001600160a01b03908116825260208083019390935260409182015f2084518155848401516001820155938201516002909401939093556004549092169163c2bedd0a9161323f918901908901615888565b6040518263ffffffff1660e01b815260040161325b9190615913565b5f604051808303815f87803b158015613272575f80fd5b505af1158015613284573d5f803e3d5ffd5b505050505f6132a486602001602081019061329f9190615888565b6140f2565b90508015611a8357611a836132bf6040880160208901615888565b5f546001600160a01b03168361342a565b6040516001600160a01b0380851660248301528316604482015260648101829052611ea89085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261415f565b61334482614213565b61184f81614213565b6001546001600160a01b0316330361336157565b6040516379543eaf60e11b815260040160405180910390fd5b61338683858484613511565b613393600a8484846142a5565b61339d82826142df565b6118d4838360166007614312565b816001600160a01b031683856001600160a01b03167f493e7cdf01e4ed7630de4e602e5b95da2515b85276cdc3bfaa6b18d84fcd4d8b84426040516133fa929190918252602082015260400190565b60405180910390a450505050565b6134128385613741565b61341e848484846143b3565b6118d48484848461447e565b6118d48363a9059cbb60e01b8484604051602401613304929190615ebc565b600254613461908290600160a01b900460ff166144cd565b600254600160a01b900460ff1615156001036117a2576002805460ff60a01b1916905550565b6001600160a01b0382165f908152600f6020526040812060018181015491549091906134b39085615c81565b6134bd9190615cf1565b6115549190615cac565b5f6134d485338686614505565b9050611dcf868686868587613855565b6004546001600160a01b031633036134f857565b6040516348f5c3ed60e01b815260040160405180910390fd5b604051636bc4c0f760e11b81526001600160a01b037f000000000000000000000000896fc8ffc11cda80cf40c373afa9a22d6e05f2d3169063d78981ee9061355d908590600401615913565b602060405180830381865afa158015613578573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061359c9190615ea1565b15156001036135be57604051630625e47160e11b815260040160405180910390fd5b6135c8848461451c565b6135d28484612a3d565b60035460405163038d737960e11b81526001600160a01b039091169063071ae6f2906136049085908590600401615ebc565b602060405180830381865afa15801561361f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136439190615ea1565b506118d482826145e9565b61365783613b3e565b5f8281526012602052604081205460ff161515900361368957604051630539fff360e51b815260040160405180910390fd5b6136938282612a89565b604051631697425b60e21b81526001600160a01b037f000000000000000000000000bec57d7ba1fef3f2352cd529c3b40cf2c49995291690635a5d096c906136e19085908790600401615d23565b602060405180830381865afa1580156136fc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137209190615ea1565b15155f03611212576040516348f5c3ed60e01b815260040160405180910390fd5b60035460405163729e035f60e11b81526001600160a01b039091169063e53c06be906137739085908590600401615d23565b5f6040518083038186803b158015613789575f80fd5b505afa158015611a83573d5f803e3d5ffd5b604051632e1a7d4d60e01b8152600481018290527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d906024015f604051808303815f87803b1580156137fa575f80fd5b505af1158015611ea8573d5f803e3d5ffd5b5f8061381a858560016122e6565b9050611dcf338787878588614661565b6002546001600160a01b0316331461115c576040516348f5c3ed60e01b815260040160405180910390fd5b5f8061386287875f612a16565b600354604051634b41268960e01b81529294509092506001600160a01b031690634b4126899061389a908a908c908b90600401615e82565b602060405180830381865afa1580156138b5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906138d99190615ea1565b60028054911515600160a01b0260ff60a01b19909216919091179055613901878787876147ca565b82151560010361396057856001600160a01b031687896001600160a01b03167f7d6726117009e10fa13f77dc73efe20fa41c8a07d6857a035988e647e01a075a88884260405161395393929190615b40565b60405180910390a46139b1565b856001600160a01b031687896001600160a01b03167fc66aaaac03ae801ceea0787537ef653b38da54f2dbeab4e08a6a61b9c73c78618888426040516139a893929190615b40565b60405180910390a45b6139bb828261333b565b5050505050505050565b5f81151581036139d9576139d98587613741565b5f6139e48585613487565b90506139f4878787848888613855565b9695505050505050565b5f600182151514613a24576001613a158486615cf1565b613a1f9190615cac565b612331565b613a2e8385615cf1565b612331906001615d10565b613a4d8383836147f361481a61484461486e565b613a5a6009858584614898565b5f8481526009602090815260408083206001600160a01b03871684529091529020546118d4576118d48484610a886113a46148c75f614935565b5f80613aa184845f612595565b9050613aac81612898565b613ab885878686613511565b613ac3858583614b10565b613ad78484836147f3614b4e614b7561486e565b613ae5858560166007614312565b836001600160a01b031685876001600160a01b03167f1e97b612c4a205592622401b7af208efaf898f721133c276e9d11ff69f6061fb868542604051613b2d93929190615b40565b60405180910390a495945050505050565b6001600160a01b0381165f9081526014602052604081205460ff16151590036117a257604051634a7f394f60e01b815260040160405180910390fd5b80156117a25760405163405cb76960e01b815260040160405180910390fd5b5f80613bc733847f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc234613a94565b90506113da3461291b565b5f815f03613be157505f919050565b816001600160801b8210613bfa5760809190911c9060401b5b600160401b8210613c105760409190911c9060201b5b600160201b8210613c265760209190911c9060101b5b620100008210613c3b5760109190911c9060081b5b6101008210613c4f5760089190911c9060041b5b60108210613c625760049190911c9060021b5b60088210613c6e5760011b5b6001613c7a8286615cf1565b613c849083615d10565b901c90506001613c948286615cf1565b613c9e9083615d10565b901c90506001613cae8286615cf1565b613cb89083615d10565b901c90506001613cc88286615cf1565b613cd29083615d10565b901c90506001613ce28286615cf1565b613cec9083615d10565b901c90506001613cfc8286615cf1565b613d069083615d10565b901c90506001613d168286615cf1565b613d209083615d10565b901c90505f613d2f8286615cf1565b9050808210613d3e5780611dcf565b509392505050565b613d4f81614b9f565b6117a281614c33565b6001600160a01b0381165f90815260116020526040812060010154612a3090613d819042615cac565b101592915050565b6001600160a01b0381165f908152600f6020908152604080832060010154600d909252909120600201548110613df457613dc38282614e2e565b6001600160a01b03919091165f908152600d6020908152604080832060030193909355601190522042600190910155565b613dfe8282614e61565b1515600114613e1657613e118282614eb5565b613dc3565b613dc38282614f18565b6001600160a01b0381165f908152601060205260408120600281015460019091015482918291613e5990670de0b6b3a764000090615c81565b613e639190615cf1565b9050613e8d600a613e7d670de0b6b3a76400006005615c81565b613e879190615cf1565b8261279b565b6001600160a01b0384165f908152600f6020526040902060018101549054613ebe90670de0b6b3a764000090615c81565b613ec89190615cf1565b94909350915050565b613eda81614f51565b6117a281614f78565b5f80613eee85613e20565b915091505f613efc86615021565b9050613f08858461279b565b613f12838261279b565b613f1c848261279b565b611a83828561279b565b5f82815260208481526040808320805482518185028101850190935280835260609493830182828015613f8057602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311613f62575b505050505090506123318382615092565b6001600160a01b0381165f9081526014602052604081205460ff161515600103613fbd57506001919050565b505f919050565b5f848152600a602090815260408083206001600160a01b038616845290915281205415613ff957613ff68584846150f4565b90505b5f858152600b602090815260408083206001600160a01b038716845290915290205460ff161515600114612331575f858152600b602090815260408083206001600160a01b03871680855290835281842060010154898552600a84528285209185529252822054801580159061406e57505f82115b156140815761407e82878761514f565b92505b5f831180156140905750808311155b156140c0576140a2600a898886614898565b6140ac8684615176565b6140b68385615d10565b9350505050612331565b815f036140cf57505050612331565b836140dc898989896151a0565b6140e69190615d10565b98975050505050505050565b6040516370a0823160e01b81525f906001600160a01b038316906370a0823190614120903090600401615913565b602060405180830381865afa15801561413b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113da9190615cbf565b5f805f846001600160a01b03168460405161417a9190615ef0565b5f604051808303815f865af19150503d805f81146141b3576040519150601f19603f3d011682016040523d82523d5f602084013e6141b8565b606091505b50915091505f81515f14806141dc5750818060200190518101906141dc9190615ea1565b90508215155f036141eb575f80fd5b8280156141f55750805b80156139f457505f866001600160a01b03163b119695505050505050565b80515f905b808210156112125760035483516001600160a01b039091169063eb288a9b9085908590811061424957614249615c98565b60200260200101516040518263ffffffff1660e01b815260040161426d9190615913565b5f604051808303815f87803b158015614284575f80fd5b505af1158015614296573d5f803e3d5ffd5b50505050816001019150614218565b5f838152602085815260408083206001600160a01b0386168452909152812080548392906142d4908490615d10565b909155505050505050565b6001600160a01b0382165f908152600e602052604081206002018054839290614309908490615d10565b90915550505050565b5f61431d8585615292565b5f8181526020859052604090205490915060ff16151560010361434057506118d4565b5f818152602084815260408083208054600160ff199091168117909155888452858352908320805491820181558084529183200180546001600160a01b0319166001600160a01b038816179055908690525460081015611ea857604051633a4733d960e11b815260040160405180910390fd5b5f806143c085855f612a16565b600354604051630e3d3ddf60e41b81529294509092506001600160a01b03169063e3d3ddf0906143f89088908a908990600401615e82565b602060405180830381865afa158015614413573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906144379190615ea1565b60028054911515600160a01b0260ff60a01b19909216919091179055614460600a868686614898565b61446a8484615176565b61447485856152da565b611a83828261333b565b816001600160a01b031683856001600160a01b03167f9a20046940513705440ed12d8a6c4d21d3b6fe465b4645bf838df04815130f3884426040516133fa929190918252602082015260400190565b600354604051621f2f7b60e91b81526004810184905282151560248201526001600160a01b0390911690633e5ef60090604401613773565b5f6145108585613741565b611dcf83836001612595565b6002546001600160a01b0390811690821603614536575050565b604051631697425b60e21b81526001600160a01b037f000000000000000000000000bec57d7ba1fef3f2352cd529c3b40cf2c49995291690635a5d096c906145849085908590600401615d23565b602060405180830381865afa15801561459f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906145c39190615ea1565b15156001036145d0575050565b604051634a7f394f60e01b815260040160405180910390fd5b6001600160a01b0382165f908152600f6020908152604080832054600e909252822060020154839161461a91615d10565b6146249190615d10565b6001600160a01b0384165f90815260066020526040902054109050600181900361121257604051634a7f394f60e01b815260040160405180910390fd5b5f8061466e875f88612a16565b600354604051630bc6de8560e01b81529294509092506001600160a01b031690630bc6de85906146a6908a908c908b90600401615e82565b602060405180830381865afa1580156146c1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906146e59190615ea1565b60028054911515600160a01b0260ff60a01b1990921691909117905561471586868661531061533a61536161486e565b61472260098888876142a5565b614730878760156008614312565b82151560010361478257856001600160a01b031687896001600160a01b03167ff62e181fe3d3a65c23588c6efd1b23808a1779dd621a984f4dc563759d1d3c0b88884260405161395393929190615b40565b856001600160a01b031687896001600160a01b03167f79f28dd1050dd16be59fc6358a6c5b7608afce58aff46e66652e3c2f81afedf38888426040516139a893929190615b40565b6147de83838361533a61538b6153b261486e565b6147e98484836153dc565b6118d484846152da565b6001600160a01b0382165f908152600e602052604081208054839290614309908490615d10565b6001600160a01b0382165f9081526010602052604081206001018054839290614309908490615cac565b6001600160a01b0382165f9081526010602052604081206002018054839290614309908490615cac565b61487c86868563ffffffff16565b61488a86868463ffffffff16565b611a8386858363ffffffff16565b5f838152602085815260408083206001600160a01b0386168452909152812080548392906142d4908490615cac565b5f8281526008602052604090208054806148e3576148e3615f06565b5f8281526020812082015f1990810180546001600160a01b03191690559091019091556015816149138585615292565b815260208101919091526040015f20805460ff19169115159190911790555050565b5f614943878663ffffffff16565b9050806001036149d7575f60018315151461497d5760155f6149658a8a615292565b815260208101919091526040015f205460ff1661499e565b60165f61498a8a8a615292565b815260208101919091526040015f205460ff165b90508015155f036149c2576040516341f2a4a360e01b815260040160405180910390fd5b6149d088888663ffffffff16565b5050611a83565b5f806149e4600184615cac565b90505b828260ff161015614b0557808260ff1603614a0f57614a0a89898763ffffffff16565b614b05565b876001600160a01b0316614a2a8a8460ff168963ffffffff16565b6001600160a01b031614614a43578160010191506149e7565b5f614a528a838963ffffffff16565b9050600185151514614aab575f8a8152600860205260409020805482919060ff8616908110614a8357614a83615c98565b5f91825260209091200180546001600160a01b0319166001600160a01b038316179055614af4565b5f8a8152600760205260409020805482919060ff8616908110614ad057614ad0615c98565b5f91825260209091200180546001600160a01b0319166001600160a01b0383161790555b50614b038a8a8863ffffffff16565b505b505050505050505050565b5f838152600b602090815260408083206001600160a01b038616845290915281206001018054839290614b44908490615d10565b9091555050505050565b6001600160a01b0382165f908152600f602052604081208054839290614309908490615d10565b6001600160a01b0382165f908152600f602052604081206001018054839290614309908490615d10565b6001600160a01b0381165f908152600f6020526040902060010154614bc390612898565b5f614bcd826140f2565b6001600160a01b0383165f908152600e60205260409020805460029091015491925090614bfb838383615410565b15614c065750505050565b81810183035f614c1586615426565b905080821115614c2957611a838682615498565b611a838683615498565b6001600160a01b0381165f90815260056020908152604080832054601083528184206001015460119093529083205442939290614c709085615cac565b6001600160a01b0386165f90815260106020526040902060030154614c959190615c81565b614c9f9190615c81565b614ca99190615d10565b9050614cc16301e13380670de0b6b3a7640000615c81565b811015614cec576001600160a01b0383165f90815260056020526040902081905561121283836154ac565b6001600160a01b0383165f908152600560205260408120819055614d1c6301e13380670de0b6b3a7640000615c81565b614d269083615cf1565b6001600160a01b0385165f908152600e602052604081206003015491925090670de0b6b3a764000090614d599084615c81565b614d639190615cf1565b9050614d6f8583615310565b614d798583614b4e565b805f03614d8a57611ea885856154ac565b6001600160a01b0385165f908152600f6020526040812054614dad908390615cac565b6001600160a01b0387165f908152600f6020526040902060010154614dd29084615c81565b614ddc9190615cf1565b9050805f03614def57611a8386866154ac565b614e1a7f00000000000000000000000000000000000000000000000000000000000000008783614b10565b614e248682614b75565b611a8386866154ac565b614e3882826154c7565b506001600160a01b03165f908152600c6020908152604080832054600d90925290912060010155565b6001600160a01b0382165f908152600d6020526040812060020154670de0b6b3a764000090614e98662386f26fc10000604b615c81565b614ea29190615c81565b614eac9190615cf1565b90911092915050565b6001600160a01b0382165f908152600d6020526040902060030154670de0b6b3a764000090614eec662386f26fc10000605a615c81565b614ef69190615c81565b614f009190615cf1565b8110614f0f5761184f826154e5565b61184f82615516565b6001600160a01b0382165f908152600d6020526040902060010154614f3e908390615555565b614f4882826154c7565b61184f82615570565b614f5a81615598565b6001600160a01b039091165f908152600e6020526040902060010155565b6001600160a01b0381165f908152600c6020908152604080832054600e9092528220600101549091614faa8284615cac565b614fb49084615c81565b6001600160a01b0385165f908152600c602052604090206004015490915081908390614fe990670de0b6b3a764000090615c81565b614ff39190615c81565b614ffd9190615cf1565b6001600160a01b039094165f90815260106020526040902060030193909355505050565b6001600160a01b0381165f9081526011602052604081206002015481906150489042615cac565b9050670de0b6b3a76400006150616301e1338082615c81565b615073670de0b6b3a764000080615c81565b61507e90600a615c81565b6150889190615cf1565b6128279083615c81565b80515f9081905b80821015611ea8578382815181106150b3576150b3615c98565b60200260200101519250816001019150846001600160a01b0316836001600160a01b03160315615099576150e683613d46565b6150ef83613ed1565b615099565b5f838152600a602090815260408083206001600160a01b038616845290915281205481906151229084615c81565b9050615136670de0b6b3a764000082615cf1565b9150615145600a868685614898565b613d3e8483615176565b5f61233183670de0b6b3a76400006151678786615c81565b6151719190615cf1565b613487565b6001600160a01b0382165f908152600e602052604081206002018054839290614309908490615cac565b5f848152600b602090815260408083206001600160a01b038616845290915281206001015481906151d19084615c81565b90505f6151e6670de0b6b3a764000083615cf1565b6151f1906001615d10565b90505f6151fe8683613487565b6001600160a01b0387165f908152600e60205260409020549091508082116152375761522c898884866147ca565b509250612331915050565b5f61524488836001612595565b90505f6152518286615cac565b905061525f8b8a85856147ca565b61526a8b8a836153dc565b6152758a8a83614b10565b6152838a8a60166007614312565b50909998505050505050505050565b5f82826040516020016152bc92919091825260601b6001600160601b031916602082015260340190565b60405160208183030381529060405280519060200120905092915050565b815f036152e5575050565b6152ef82826155fa565b15155f036152fb575050565b61184f8282610bc2611a8b6156506001614935565b6001600160a01b0382165f9081526010602052604081206001018054839290614309908490615d10565b6001600160a01b0382165f908152600e602052604081208054839290614309908490615cac565b6001600160a01b0382165f9081526010602052604081206002018054839290614309908490615d10565b6001600160a01b0382165f908152600f602052604081208054839290614309908490615cac565b6001600160a01b0382165f908152600f602052604081206001018054839290614309908490615cac565b5f838152600b602090815260408083206001600160a01b038616845290915281206001018054839290614b44908490615cac565b5f8361541c8484615d10565b1015949350505050565b6001600160a01b0381165f90815260116020526040812054819061544a9042615cac565b90506154626301e13380670de0b6b3a7640000615c81565b6001600160a01b0384165f908152600f6020526040902054670de0b6b3a76400009061548e9084615c81565b6128409190615c81565b6154a28282614b4e565b61184f82826147f3565b6001600160a01b039091165f90815260116020526040902055565b6001600160a01b039091165f908152600d6020526040902060020155565b6001600160a01b0381165f908152600d602052604090205460ff1661550d576117a28161569c565b6117a281615760565b6001600160a01b0381165f908152600d602052604090205460ff166155435761553e81615760565b61554c565b61554c8161569c565b6117a281615570565b6001600160a01b039091165f908152600c6020526040902055565b6001600160a01b03165f908152600d60205260409020805460ff81161560ff19909116179055565b6001600160a01b0381165f908152600e6020908152604080832054600f9092528220548082106155cb57505f9392505050565b806155de83670de0b6b3a7640000615c81565b6155e89190615cf1565b61233190670de0b6b3a7640000615cac565b5f828152600b602090815260408083206001600160a01b03851684529091528120600101541580156115545750505f918252600a602090815260408084206001600160a01b039390931684529190529020541590565b5f82815260076020526040902080548061566c5761566c615f06565b5f8281526020812082015f1990810180546001600160a01b03191690559091019091556016816149138585615292565b6001600160a01b0381165f908152600c602090815260408083206002015460119092528220600101549091906156d29042615cac565b6001600160a01b0384165f908152600c60205260409020600101546156f79190615c81565b6001600160a01b0384165f908152600c602052604081205491925090821061571f575f615742565b6001600160a01b0384165f908152600c6020526040902054615742908390615cac565b90505f8382106157525781615754565b835b9050611ea88582615555565b6001600160a01b0381165f818152600c60209081526040808320815160a08101835281548152600180830154828601526002830154828501526003830154606083015260049092015460808201529484526011909252822001546157c49042615cac565b82602001516157d39190615c81565b82519091505f906157e49083615d10565b90505f836060015182116157f85781615754565b506060830151611ea88582615555565b6040518061016001604052805f81526020015f81526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f81526020015f815260200160608152602001606081525090565b6001600160a01b03811681146117a2575f80fd5b5f60208284031215615898575f80fd5b813561155481615874565b80151581146117a2575f80fd5b5f805f805f8060c087890312156158c5575f80fd5b86356158d081615874565b955060208701359450604087013593506060870135925060808701356158f5816158a3565b915060a0870135615905816158a3565b809150509295509295509295565b6001600160a01b0391909116815260200190565b5f8060408385031215615938575f80fd5b50508035926020909101359150565b5f60208284031215615957575f80fd5b5035919050565b5f806040838503121561596f575f80fd5b823561597a81615874565b946020939093013593505050565b5f8060408385031215615999575f80fd5b8235915060208301356159ab81615874565b809150509250929050565b5f805f805f60a086880312156159ca575f80fd5b853594506020860135935060408601356159e381615874565b925060608601356159f381615874565b949793965091946080013592915050565b5f60a08284031215612dfb575f80fd5b5f60a08284031215615a24575f80fd5b6115548383615a04565b5f805f60608486031215615a40575f80fd5b833592506020840135615a5281615874565b929592945050506040919091013590565b5f805f8060808587031215615a76575f80fd5b843593506020850135615a8881615874565b92506040850135615a9881615874565b9396929550929360600135925050565b5f805f805f805f60e0888a031215615abe575f80fd5b87359650602088013595506040880135615ad781615874565b94506060880135615ae781615874565b93506080880135615af781615874565b9699959850939692959460a0840135945060c09093013592915050565b5f8060408385031215615b25575f80fd5b8235615b3081615874565b915060208301356159ab816158a3565b9283526020830191909152604082015260600190565b5f8060c08385031215615b67575f80fd5b615b718484615a04565b915060a08301356001600160401b03811115615b8b575f80fd5b615b9785828601615a04565b9150509250929050565b5f805f60608486031215615bb3575f80fd5b8335615bbe81615874565b95602085013595506040909401359392505050565b5f805f60608486031215615be5575f80fd5b8335615bf081615874565b9250602084013591506040840135615c07816158a3565b809150509250925092565b5f805f8060808587031215615c25575f80fd5b8435615c3081615874565b966020860135965060408601359560600135945092505050565b5f8060408385031215615c5b575f80fd5b8235915060208301356159ab816158a3565b634e487b7160e01b5f52601160045260245ffd5b80820281158282048414176113da576113da615c6d565b634e487b7160e01b5f52603260045260245ffd5b818103818111156113da576113da615c6d565b5f60208284031215615ccf575f80fd5b5051919050565b5f60208284031215615ce6575f80fd5b815161155481615874565b5f82615d0b57634e487b7160e01b5f52601260045260245ffd5b500490565b808201808211156113da576113da615c6d565b9182526001600160a01b0316602082015260400190565b5f8235607e19833603018112615d4e575f80fd5b9190910192915050565b5f808335601e19843603018112615d6d575f80fd5b83016020810192503590506001600160401b03811115615d8b575f80fd5b803603821315615d99575f80fd5b9250929050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6001600160a01b03848116825260c060208301525f908435615de981615874565b811660c08401526020850135615dfe81615874565b1660e0830152615e116040850185615d58565b6080610100850152615e2861014085018284615da0565b915050615e386060860186615d58565b84830360bf1901610120860152615e50838284615da0565b9350505050823560408301526020830135606083015260408301356080830152606083013560a0830152949350505050565b9283526001600160a01b03918216602084015216604082015260600190565b5f60208284031215615eb1575f80fd5b8151611554816158a3565b6001600160a01b03929092168252602082015260400190565b5f60208284031215615ee5575f80fd5b8135611554816158a3565b5f82518060208501845e5f920191825250919050565b634e487b7160e01b5f52603160045260245ffdfea26469706673582212205f448112bf73daf76aff9f47cc74572b8b31b83bab24cbd2857b3f721619625464736f6c63430008190033
Verified Source Code Full Match
Compiler: v0.8.25+commit.b61c2a91
EVM: cancun
Optimization: Yes (20 runs)
WiseCore.sol 686 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
import "./MainHelper.sol";
import "./TransferHub/TransferHelper.sol";
abstract contract WiseCore is MainHelper, TransferHelper {
/**
* @dev Wrapper function combining pool
* preparations for borrow and collaterals.
* Bypassed when called by powerFarms.
*/
function _prepareAssociatedTokens(
uint256 _nftId,
address _poolTokenLend,
address _poolTokenBorrow
)
internal
returns (
address[] memory,
address[] memory
)
{
return (
_preparationTokens(
positionLendTokenData,
_nftId,
_poolTokenLend
),
_preparationTokens(
positionBorrowTokenData,
_nftId,
_poolTokenBorrow
)
);
}
/**
* @dev Core function combining withdraw
* logic and security checks.
*/
function _coreWithdrawToken(
address _caller,
uint256 _nftId,
address _poolToken,
uint256 _amount,
uint256 _shares,
bool _onBehalf
)
internal
{
(
address[] memory lendTokens,
address[] memory borrowTokens
) = _prepareAssociatedTokens(
_nftId,
_poolToken,
ZERO_ADDRESS
);
powerFarmCheck = WISE_SECURITY.checksWithdraw(
_nftId,
_caller,
_poolToken
);
_coreWithdrawBare(
_nftId,
_poolToken,
_amount,
_shares
);
if (_onBehalf == true) {
emit FundsWithdrawnOnBehalf(
_caller,
_nftId,
_poolToken,
_amount,
_shares,
block.timestamp
);
} else {
emit FundsWithdrawn(
_caller,
_nftId,
_poolToken,
_amount,
_shares,
block.timestamp
);
}
_curveSecurityChecks(
lendTokens,
borrowTokens
);
}
/**
* @dev Internal function combining deposit
* logic, security checks and event emit.
*/
function _handleDeposit(
address _caller,
uint256 _nftId,
address _poolToken,
uint256 _amount
)
internal
returns (uint256)
{
uint256 shareAmount = calculateLendingShares(
{
_poolToken: _poolToken,
_amount: _amount,
_maxSharePrice: false
}
);
_validateNonZero(
shareAmount
);
_checkDeposit(
_nftId,
_caller,
_poolToken,
_amount
);
_increasePositionLendingDeposit(
_nftId,
_poolToken,
shareAmount
);
_updatePoolStorage(
_poolToken,
_amount,
shareAmount,
_increaseTotalPool,
_increasePseudoTotalPool,
_increaseTotalDepositShares
);
_addPositionTokenData(
_nftId,
_poolToken,
hashMapPositionLending,
positionLendTokenData
);
emit FundsDeposited(
_caller,
_nftId,
_poolToken,
_amount,
shareAmount,
block.timestamp
);
return shareAmount;
}
/**
* @dev External wrapper for
* {_checkPositionLocked}.
*/
function checkPositionLocked(
uint256 _nftId,
address _caller
)
external
view
{
_checkPositionLocked(
_nftId,
_caller
);
}
/**
* @dev Checks if a postion is locked
* for powerFarms. Get skipped when
* aaveHub or a powerFarm itself is
* the {msg.sender}.
*/
function _checkPositionLocked(
uint256 _nftId,
address _caller
)
internal
view
{
if (_byPassCase(_caller) == true) {
return;
}
if (positionLocked[_nftId] == false) {
return;
}
revert PositionLocked();
}
/**
* @dev External wrapper for
* {_checkDeposit}.
*/
function checkDeposit(
uint256 _nftId,
address _caller,
address _poolToken,
uint256 _amount
)
external
view
{
_checkDeposit(
_nftId,
_caller,
_poolToken,
_amount
);
}
/**
* @dev Internal function including
* security checks for deposit logic.
*/
function _checkDeposit(
uint256 _nftId,
address _caller,
address _poolToken,
uint256 _amount
)
internal
view
{
if (WISE_ORACLE.chainLinkIsDead(_poolToken) == true) {
revert DeadOracle();
}
_checkAllowDeposit(
_nftId,
_caller
);
_checkPositionLocked(
_nftId,
_caller
);
WISE_SECURITY.checkPoolWithMinDeposit(
_poolToken,
_amount
);
_checkMaxDepositValue(
_poolToken,
_amount
);
}
function _checkAllowDeposit(
uint256 _nftId,
address _caller
)
internal
view
{
if (_caller == AAVE_HUB_ADDRESS) {
return;
}
if (POSITION_NFT.isOwner(_nftId, _caller) == true) {
return;
}
revert InvalidAction();
}
/**
* @dev Internal function checking
* if the deposit amount for the
* pool token is reached.
*/
function _checkMaxDepositValue(
address _poolToken,
uint256 _amount
)
private
view
{
bool state = maxDepositValueToken[_poolToken]
< globalPoolData[_poolToken].totalBareToken
+ lendingPoolData[_poolToken].pseudoTotalPool
+ _amount;
if (state == true) {
revert InvalidAction();
}
}
/**
* @dev Low level core function combining
* pure withdraw math (without security
* checks).
*/
function _coreWithdrawBare(
uint256 _nftId,
address _poolToken,
uint256 _amount,
uint256 _shares
)
private
{
_updatePoolStorage(
_poolToken,
_amount,
_shares,
_decreaseTotalPool,
_decreasePseudoTotalPool,
_decreaseTotalDepositShares
);
_decreaseLendingShares(
_nftId,
_poolToken,
_shares
);
_removeEmptyLendingData(
_nftId,
_poolToken
);
}
/**
* @dev Core function combining borrow
* logic with security checks.
*/
function _coreBorrowTokens(
address _caller,
uint256 _nftId,
address _poolToken,
uint256 _amount,
uint256 _shares,
bool _onBehalf
)
internal
{
(
address[] memory lendTokens,
address[] memory borrowTokens
) = _prepareAssociatedTokens(
_nftId,
ZERO_ADDRESS,
_poolToken
);
powerFarmCheck = WISE_SECURITY.checksBorrow(
_nftId,
_caller,
_poolToken
);
_updatePoolStorage(
_poolToken,
_amount,
_shares,
_increasePseudoTotalBorrowAmount,
_decreaseTotalPool,
_increaseTotalBorrowShares
);
_increaseMappingValue(
userBorrowShares,
_nftId,
_poolToken,
_shares
);
_addPositionTokenData(
_nftId,
_poolToken,
hashMapPositionBorrow,
positionBorrowTokenData
);
if (_onBehalf == true) {
emit FundsBorrowedOnBehalf(
_caller,
_nftId,
_poolToken,
_amount,
_shares,
block.timestamp
);
} else {
emit FundsBorrowed(
_caller,
_nftId,
_poolToken,
_amount,
_shares,
block.timestamp
);
}
_curveSecurityChecks(
lendTokens,
borrowTokens
);
}
/**
* @dev Internal math function for liquidation logic
* caluclating amount to withdraw from pure
* collateral for liquidation.
*/
function _withdrawPureCollateralLiquidation(
uint256 _nftId,
address _poolToken,
uint256 _percentLiquidation
)
private
returns (uint256 transferAmount)
{
uint256 product = _percentLiquidation
* pureCollateralAmount[_nftId][_poolToken];
transferAmount = product / PRECISION_FACTOR_E18;
_decreasePositionMappingValue(
pureCollateralAmount,
_nftId,
_poolToken,
transferAmount
);
_decreaseTotalBareToken(
_poolToken,
transferAmount
);
}
/**
* @dev Internal math function for liquidation logic
* which checks if pool has enough token to pay out
* liquidator. If not, liquidator get corresponding
* shares for later withdraw.
*/
function _withdrawOrAllocateSharesLiquidation(
uint256 _nftId,
uint256 _nftIdLiquidator,
address _poolToken,
uint256 _percentWishCollateral
)
private
returns (uint256)
{
uint256 product = _percentWishCollateral
* userLendingData[_nftId][_poolToken].shares;
uint256 cashoutShares = product / PRECISION_FACTOR_E18 + 1;
uint256 withdrawAmount = _cashoutAmount(
_poolToken,
cashoutShares
);
uint256 totalPoolToken = globalPoolData[_poolToken].totalPool;
if (withdrawAmount <= totalPoolToken) {
_coreWithdrawBare(
_nftId,
_poolToken,
withdrawAmount,
cashoutShares
);
return withdrawAmount;
}
uint256 totalPoolInShares = calculateLendingShares(
{
_poolToken: _poolToken,
_amount: totalPoolToken,
_maxSharePrice: true
}
);
uint256 shareDifference = cashoutShares
- totalPoolInShares;
_coreWithdrawBare(
_nftId,
_poolToken,
totalPoolToken,
totalPoolInShares
);
_decreaseLendingShares(
_nftId,
_poolToken,
shareDifference
);
_increasePositionLendingDeposit(
_nftIdLiquidator,
_poolToken,
shareDifference
);
_addPositionTokenData(
_nftIdLiquidator,
_poolToken,
hashMapPositionLending,
positionLendTokenData
);
return totalPoolToken;
}
/**
* @dev Internal math function combining functionallity
* of {_withdrawPureCollateralLiquidation} and
* {_withdrawOrAllocateSharesLiquidation}.
*/
function _calculateReceiveAmount(
uint256 _nftId,
uint256 _nftIdLiquidator,
address _receiveTokens,
uint256 _removePercentage
)
private
returns (uint256 receiveAmount)
{
if (pureCollateralAmount[_nftId][_receiveTokens] > 0) {
receiveAmount = _withdrawPureCollateralLiquidation(
_nftId,
_receiveTokens,
_removePercentage
);
}
if (userLendingData[_nftId][_receiveTokens].unCollateralized == true) {
return receiveAmount;
}
uint256 potentialPureExtraCashout;
uint256 userShares = userLendingData[_nftId][_receiveTokens].shares;
uint256 pureCollateral = pureCollateralAmount[_nftId][_receiveTokens];
if (pureCollateral > 0 && userShares > 0) {
potentialPureExtraCashout = _calculatePotentialPureExtraCashout(
userShares,
_receiveTokens,
_removePercentage
);
}
if (potentialPureExtraCashout > 0 && potentialPureExtraCashout <= pureCollateral) {
_decreasePositionMappingValue(
pureCollateralAmount,
_nftId,
_receiveTokens,
potentialPureExtraCashout
);
_decreaseTotalBareToken(
_receiveTokens,
potentialPureExtraCashout
);
return receiveAmount + potentialPureExtraCashout;
}
if (userShares == 0) {
return receiveAmount;
}
return _withdrawOrAllocateSharesLiquidation(
_nftId,
_nftIdLiquidator,
_receiveTokens,
_removePercentage
) + receiveAmount;
}
function _calculatePotentialPureExtraCashout(
uint256 _userShares,
address _poolToken,
uint256 _removePercentage
)
private
view
returns (uint256)
{
return _cashoutAmount(
_poolToken,
_removePercentage
* _userShares
/ PRECISION_FACTOR_E18
);
}
/**
* @dev Core liquidation function for
* security checks and liquidation math.
*/
function _coreLiquidation(
CoreLiquidationStruct memory _data
)
internal
returns (uint256 receiveAmount)
{
_validateNonZero(
_data.paybackAmount
);
FEE_MANAGER.updatePositionCurrentBadDebt(
_data.nftId
);
uint256 collateralPercentage = WISE_SECURITY.calculateWishPercentage(
_data.nftId,
_data.tokenToRecieve,
WISE_ORACLE.getTokensInETH(
_data.tokenToPayback,
_data.paybackAmount
),
_data.maxFeeETH,
_data.baseRewardLiquidation
);
_validateParameter(
collateralPercentage,
PRECISION_FACTOR_E18
);
_corePayback(
_data.nftId,
_data.tokenToPayback,
_data.paybackAmount,
_data.shareAmountToPay
);
receiveAmount = _calculateReceiveAmount(
_data.nftId,
_data.nftIdLiquidator,
_data.tokenToRecieve,
collateralPercentage
);
FEE_MANAGER.updatePositionCurrentBadDebt(
_data.nftId
);
_curveSecurityChecks(
_data.lendTokens,
_data.borrowTokens
);
_safeTransferFrom(
_data.tokenToPayback,
_data.caller,
address(this),
_data.paybackAmount
);
_safeTransfer(
_data.tokenToRecieve,
_data.caller,
receiveAmount
);
}
}
Babylonian.sol 56 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
library Babylonian {
function sqrt(
uint256 x
)
internal
pure
returns (uint256)
{
if (x == 0) return 0;
uint256 xx = x;
uint256 r = 1;
if (xx >= 0x100000000000000000000000000000000) {
xx >>= 128;
r <<= 64;
}
if (xx >= 0x10000000000000000) {
xx >>= 64;
r <<= 32;
}
if (xx >= 0x100000000) {
xx >>= 32;
r <<= 16;
}
if (xx >= 0x10000) {
xx >>= 16;
r <<= 8;
}
if (xx >= 0x100) {
xx >>= 8;
r <<= 4;
}
if (xx >= 0x10) {
xx >>= 4;
r <<= 2;
}
if (xx >= 0x8) {
r <<= 1;
}
r = (r + (x / r)) >> 1;
r = (r + (x / r)) >> 1;
r = (r + (x / r)) >> 1;
r = (r + (x / r)) >> 1;
r = (r + (x / r)) >> 1;
r = (r + (x / r)) >> 1;
r = (r + (x / r)) >> 1;
uint256 r1 = x / r;
return (r < r1 ? r : r1);
}
}
MainHelper.sol 1228 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
import "./WiseLowLevelHelper.sol";
abstract contract MainHelper is WiseLowLevelHelper {
/**
* @dev Helper function to convert {_amount}
* of a certain pool with {_poolToken}
* into lending shares. Includes devison
* by zero and share security checks.
* Needs latest pseudo amount for accurate
* result.
*/
function calculateLendingShares(
address _poolToken,
uint256 _amount,
bool _maxSharePrice
)
public
view
returns (uint256)
{
return _calculateShares(
lendingPoolData[_poolToken].totalDepositShares * _amount,
lendingPoolData[_poolToken].pseudoTotalPool,
_maxSharePrice
);
}
function _calculateShares(
uint256 _product,
uint256 _pseudo,
bool _maxSharePrice
)
private
pure
returns (uint256)
{
return _maxSharePrice == true
? _product / _pseudo + 1
: _product / _pseudo - 1;
}
/**
* @dev Helper function to convert {_amount}
* of a certain pool with {_poolToken}
* into borrow shares. Includes devison
* by zero and share security checks.
* Needs latest pseudo amount for accurate
* result.
*/
function calculateBorrowShares(
address _poolToken,
uint256 _amount,
bool _maxSharePrice
)
public
view
returns (uint256)
{
return _calculateShares(
borrowPoolData[_poolToken].totalBorrowShares * _amount,
borrowPoolData[_poolToken].pseudoTotalBorrowAmount,
_maxSharePrice
);
}
/**
* @dev Helper function to convert {_shares}
* of a certain pool with {_poolToken}
* into lending token. Includes devison
* by zero and share security checks.
* Needs latest pseudo amount for accurate
* result.
*/
function cashoutAmount(
address _poolToken,
uint256 _shares
)
external
view
returns (uint256)
{
return _cashoutAmount(
_poolToken,
_shares
);
}
function _cashoutAmount(
address _poolToken,
uint256 _shares
)
internal
view
returns (uint256)
{
return _shares
* lendingPoolData[_poolToken].pseudoTotalPool
/ lendingPoolData[_poolToken].totalDepositShares - 1;
}
/**
* @dev Helper function to convert {_shares}
* of a certain pool with {_poolToken}
* into borrow token. Includes devison
* by zero and share security checks.
* Needs latest pseudo amount for accurate
* result.
*/
function paybackAmount(
address _poolToken,
uint256 _shares
)
public
view
returns (uint256)
{
uint256 product = _shares
* borrowPoolData[_poolToken].pseudoTotalBorrowAmount;
uint256 totalBorrowShares = borrowPoolData[_poolToken].totalBorrowShares;
return product / totalBorrowShares + 1;
}
/**
* @dev Internal helper combining one
* security check with lending share
* calculation for withdraw.
*/
function _preparationsWithdraw(
uint256 _nftId,
address _caller,
address _poolToken,
uint256 _amount
)
internal
view
returns (uint256)
{
_checkOwnerPosition(
_nftId,
_caller
);
return calculateLendingShares(
{
_poolToken: _poolToken,
_amount: _amount,
_maxSharePrice: true
}
);
}
/**
* @dev Internal helper calculating {_poolToken}
* utilization. Includes math underflow check.
*/
function _getValueUtilization(
address _poolToken
)
private
view
returns (uint256)
{
uint256 totalPool = globalPoolData[_poolToken].totalPool;
uint256 pseudoPool = lendingPoolData[_poolToken].pseudoTotalPool;
if (totalPool >= pseudoPool) {
return 0;
}
return PRECISION_FACTOR_E18 - (PRECISION_FACTOR_E18
* totalPool
/ pseudoPool
);
}
/**
* @dev Internal helper function setting new pool
* utilization by calling {_getValueUtilization}.
*/
function _updateUtilization(
address _poolToken
)
private
{
globalPoolData[_poolToken].utilization = _getValueUtilization(
_poolToken
);
}
/**
* @dev Internal helper function checking if
* cleanup gathered new token to save into
* pool variables.
*/
function _checkCleanUp(
uint256 _amountContract,
uint256 _totalPool,
uint256 _bareAmount
)
private
pure
returns (bool)
{
return _bareAmount + _totalPool >= _amountContract;
}
/**
* @dev Wrapper for isolation pool check.
*/
function _onlyIsolationPool(
address _poolAddress
)
internal
view
{
if (verifiedIsolationPool[_poolAddress] == false) {
revert InvalidAction();
}
}
/**
* @dev Internal helper function checking if
* user inputs are safe.
*/
function _validateIsolationPoolLiquidation(
address _caller,
uint256 _nftId,
uint256 _nftIdLiquidator
)
internal
view
{
_onlyIsolationPool(
_caller
);
if (positionLocked[_nftId] == false) {
revert NotPowerFarm();
}
_checkLiquidatorNft(
_nftId,
_nftIdLiquidator
);
if (POSITION_NFT.isOwner(_nftId, _caller) == false) {
revert InvalidCaller();
}
}
function _checkLiquidatorNft(
uint256 _nftId,
uint256 _nftIdLiquidator
)
internal
view
{
if (positionLocked[_nftIdLiquidator] == true) {
revert LiquidatorIsInPowerFarm();
}
if (_nftIdLiquidator == _nftId) {
revert InvalidLiquidator();
}
if (_nftIdLiquidator >= POSITION_NFT.getNextExpectedId()) {
revert InvalidLiquidator();
}
}
function _getBalance(
address _tokenAddress
)
internal
view
returns (uint256)
{
return IERC20(_tokenAddress).balanceOf(
address(this)
);
}
/**
* @dev Internal helper function checking if falsely
* sent token are inside the contract for the pool with
* {_poolToken}. If this is the case it adds those token
* to the pool by increasing pseudo and total amount.
* In context of aToken from aave pools it gathers the
* rebase amount from supply APY of aave pools.
*/
function _cleanUp(
address _poolToken
)
internal
{
_validateNonZero(
lendingPoolData[_poolToken].totalDepositShares
);
uint256 amountContract = _getBalance(
_poolToken
);
uint256 totalPool = globalPoolData[_poolToken].totalPool;
uint256 bareToken = globalPoolData[_poolToken].totalBareToken;
if (_checkCleanUp(amountContract, totalPool, bareToken)) {
return;
}
unchecked {
uint256 difference = amountContract - (
totalPool + bareToken
);
uint256 allowedDifference = _getAllowedDifference(
_poolToken
);
if (difference > allowedDifference) {
_increaseTotalAndPseudoTotalPool(
_poolToken,
allowedDifference
);
return;
}
_increaseTotalAndPseudoTotalPool(
_poolToken,
difference
);
}
}
/**
* @dev Internal helper function calculating
* allowed increase of pseudoTotalPool to
* contain shareprice increase reasoanbly.
*/
function _getAllowedDifference(
address _poolToken
)
private
view
returns (uint256)
{
uint256 timeDifference = block.timestamp
- timestampsPoolData[_poolToken].timeStamp;
return timeDifference
* lendingPoolData[_poolToken].pseudoTotalPool
* PRECISION_FACTOR_E18
/ PRECISION_FACTOR_YEAR;
}
/**
* @dev Internal helper function for
* updating pools and calling {_cleanUp}.
* Also includes re-entrancy guard for
* curve pools security checks.
*/
function _preparePool(
address _poolToken
)
internal
{
_cleanUp(
_poolToken
);
_updatePseudoTotalAmounts(
_poolToken
);
}
/**
* @dev Internal helper function for
* updating all lending tokens of a
* position.
*/
function _preparationTokens(
mapping(uint256 => address[]) storage _userTokenData,
uint256 _nftId,
address _poolToken
)
internal
returns (address[] memory)
{
address[] memory tokens = _userTokenData[
_nftId
];
_prepareTokens(
_poolToken,
tokens
);
return tokens;
}
/**
* @dev Internal helper function for
* updating pseudo amounts of a pool
* inside {tokens} array and sets new
* borrow rates.
*/
function _prepareTokens(
address _poolToken,
address[] memory _tokens
)
private
{
address currentAddress;
uint256 i;
uint256 l = _tokens.length;
while (i < l) {
currentAddress = _tokens[i];
unchecked {
++i;
}
if (currentAddress == _poolToken) {
continue;
}
_preparePool(
currentAddress
);
_newBorrowRate(
currentAddress
);
}
}
/**
* @dev Internal helper function for iterating
* over all tokens which may contain curvePools.
*/
function _curveSecurityChecks(
address[] memory _lendTokens,
address[] memory _borrowTokens
)
internal
{
_whileLoopCurveSecurity(
_lendTokens
);
_whileLoopCurveSecurity(
_borrowTokens
);
}
/**
* @dev Internal helper function for executing while loops
* iterating over all tokens which may contain curvePools.
*/
function _whileLoopCurveSecurity(
address[] memory _tokens
)
private
{
uint256 i;
uint256 l = _tokens.length;
while (i < l) {
WISE_SECURITY.curveSecurityCheck(
_tokens[i]
);
unchecked {
++i;
}
}
}
/**
* @dev Internal helper function
* updating pseudo amounts and
* printing fee shares for the
* feeManager proportional to the
* fee percentage of the pool.
*/
function _updatePseudoTotalAmounts(
address _poolToken
)
private
{
uint256 currentTime = block.timestamp;
uint256 bareIncrease = borrowPoolData[_poolToken].borrowRate
* (currentTime - timestampsPoolData[_poolToken].timeStamp)
* borrowPoolData[_poolToken].pseudoTotalBorrowAmount
+ bufferIncrease[_poolToken];
if (bareIncrease < PRECISION_FACTOR_YEAR) {
bufferIncrease[_poolToken] = bareIncrease;
_setTimeStamp(
_poolToken,
currentTime
);
return;
}
delete bufferIncrease[_poolToken];
uint256 amountInterest = bareIncrease
/ PRECISION_FACTOR_YEAR;
uint256 feeAmount = amountInterest
* globalPoolData[_poolToken].poolFee
/ PRECISION_FACTOR_E18;
_increasePseudoTotalBorrowAmount(
_poolToken,
amountInterest
);
_increasePseudoTotalPool(
_poolToken,
amountInterest
);
if (feeAmount == 0) {
_setTimeStamp(
_poolToken,
currentTime
);
return;
}
uint256 feeShares = feeAmount
* lendingPoolData[_poolToken].totalDepositShares
/ (lendingPoolData[_poolToken].pseudoTotalPool - feeAmount);
if (feeShares == 0) {
_setTimeStamp(
_poolToken,
currentTime
);
return;
}
_increasePositionLendingDeposit(
FEE_MANAGER_NFT,
_poolToken,
feeShares
);
_increaseTotalDepositShares(
_poolToken,
feeShares
);
_setTimeStamp(
_poolToken,
currentTime
);
}
/**
* @dev Internal increas function for
* lending shares of a postion {_nftId}
* and {_poolToken}.
*/
function _increasePositionLendingDeposit(
uint256 _nftId,
address _poolToken,
uint256 _shares
)
internal
{
userLendingData[_nftId][_poolToken].shares += _shares;
}
/**
* @dev Internal decrease function for
* lending shares of a postion {_nftId}
* and {_poolToken}.
*/
function _decreaseLendingShares(
uint256 _nftId,
address _poolToken,
uint256 _shares
)
internal
{
userLendingData[_nftId][_poolToken].shares -= _shares;
}
/**
* @dev Internal helper function adding a new
* {_poolToken} token to {userTokenData} if needed.
* Check is done by using hash maps.
*/
function _addPositionTokenData(
uint256 _nftId,
address _poolToken,
mapping(bytes32 => bool) storage hashMap,
mapping(uint256 => address[]) storage userTokenData
)
internal
{
bytes32 hashData = _getHash(
_nftId,
_poolToken
);
if (hashMap[hashData] == true) {
return;
}
hashMap[hashData] = true;
userTokenData[_nftId].push(
_poolToken
);
if (userTokenData[_nftId].length > MAX_TOTAL_TOKEN_NUMBER) {
revert TooManyTokens();
}
}
/**
* @dev Internal helper calculating
* a hash out of {_nftId} and {_poolToken}
* using keccak256.
*/
function _getHash(
uint256 _nftId,
address _poolToken
)
private
pure
returns (bytes32)
{
return keccak256(
abi.encodePacked(
_nftId,
_poolToken
)
);
}
/**
* @dev Internal helper function deleting an
* entry in {_deleteLastPositionData}.
*/
function _removePositionData(
uint256 _nftId,
address _poolToken,
function(uint256) view returns (uint256) _getPositionTokenLength,
function(uint256, uint256) view returns (address) _getPositionTokenByIndex,
function(uint256, address) internal _deleteLastPositionData,
bool isLending
)
private
{
uint256 length = _getPositionTokenLength(
_nftId
);
if (length == 1) {
bool exists = isLending == true
? hashMapPositionLending[
_getHash(
_nftId,
_poolToken
)
]
: hashMapPositionBorrow[
_getHash(
_nftId,
_poolToken
)
];
if (exists == false) {
revert TokenNotPresent();
}
_deleteLastPositionData(
_nftId,
_poolToken
);
return;
}
uint8 i;
uint256 endPosition = length - 1;
while (i < length) {
if (i == endPosition) {
_deleteLastPositionData(
_nftId,
_poolToken
);
break;
}
if (_getPositionTokenByIndex(_nftId, i) != _poolToken) {
unchecked {
++i;
}
continue;
}
address poolToken = _getPositionTokenByIndex(
_nftId,
endPosition
);
isLending == true
? positionLendTokenData[_nftId][i] = poolToken
: positionBorrowTokenData[_nftId][i] = poolToken;
_deleteLastPositionData(
_nftId,
_poolToken
);
break;
}
}
/**
* @dev Internal helper deleting last entry
* of postion lending data.
*/
function _deleteLastPositionLendingData(
uint256 _nftId,
address _poolToken
)
private
{
positionLendTokenData[_nftId].pop();
hashMapPositionLending[
_getHash(
_nftId,
_poolToken
)
] = false;
}
/**
* @dev Core function combining payback
* logic with security checks.
*/
function _corePayback(
uint256 _nftId,
address _poolToken,
uint256 _amount,
uint256 _shares
)
internal
{
_updatePoolStorage(
_poolToken,
_amount,
_shares,
_increaseTotalPool,
_decreasePseudoTotalBorrowAmount,
_decreaseTotalBorrowShares
);
_decreasePositionMappingValue(
userBorrowShares,
_nftId,
_poolToken,
_shares
);
if (userBorrowShares[_nftId][_poolToken] > 0) {
return;
}
_removePositionData({
_nftId: _nftId,
_poolToken: _poolToken,
_getPositionTokenLength: getPositionBorrowTokenLength,
_getPositionTokenByIndex: getPositionBorrowTokenByIndex,
_deleteLastPositionData: _deleteLastPositionBorrowData,
isLending: false
});
}
/**
* @dev Internal helper deleting last entry
* of postion borrow data.
*/
function _deleteLastPositionBorrowData(
uint256 _nftId,
address _poolToken
)
private
{
positionBorrowTokenData[_nftId].pop();
hashMapPositionBorrow[
_getHash(
_nftId,
_poolToken
)
] = false;
}
/**
* @dev Internal helper function calculating
* returning if a {_poolToken} of a {_nftId}
* is uncollateralized.
*/
function isUncollateralized(
uint256 _nftId,
address _poolToken
)
external
view
returns (bool)
{
return userLendingData[_nftId][_poolToken].unCollateralized;
}
/**
* @dev Internal helper function
* checking if {_nftId} as no
* {_poolToken} left.
*/
function _checkLendingDataEmpty(
uint256 _nftId,
address _poolToken
)
private
view
returns (bool)
{
return userLendingData[_nftId][_poolToken].shares == 0
&& pureCollateralAmount[_nftId][_poolToken] == 0;
}
/**
* @dev Internal helper function
* calculating new borrow rates
* for {_poolToken}. Uses smooth
* functions of the form
* f(x) = a * x /(p(p-x)) with
* p > 1E18 the {pole} and
* a the {mulFactor}.
*/
function _calculateNewBorrowRate(
address _poolToken
)
internal
{
uint256 pole = borrowRatesData[_poolToken].pole;
uint256 utilization = globalPoolData[_poolToken].utilization;
uint256 baseDivider = pole
* (pole - utilization);
borrowPoolData[_poolToken].borrowRate =
borrowRatesData[_poolToken].multiplicativeFactor
* PRECISION_FACTOR_E18
* utilization
/ baseDivider;
}
/**
* @dev Internal helper function
* updating utilization of the pool
* with {_poolToken}, calculating the
* new borrow rate and running LASA if
* the time intervall of three hours has
* passed.
*/
function _newBorrowRate(
address _poolToken
)
internal
{
_updateUtilization(
_poolToken
);
_calculateNewBorrowRate(
_poolToken
);
}
/**
* @dev Internal helper function
* checking if time interval for
* next LASA call has passed.
*/
function _aboveThreshold(
address _poolToken
)
internal
view
returns (bool)
{
return block.timestamp - timestampsPoolData[_poolToken].timeStampScaling >= THREE_HOURS;
}
/**
* @dev function that tries to maximise totalDepositShares of the pool.
* Reacting to negative and positive feedback by changing the resonance
* factor of the pool. Method similar to one parameter monte-carlo methods
*/
function _scalingAlgorithm(
address _poolToken
)
internal
{
uint256 totalShares = lendingPoolData[_poolToken].totalDepositShares;
if (algorithmData[_poolToken].maxValue <= totalShares) {
_newMaxPoolShares(
_poolToken,
totalShares
);
_saveUp(
_poolToken,
totalShares
);
return;
}
_resonanceOutcome(_poolToken, totalShares) == true
? _resetResonanceFactor(_poolToken, totalShares)
: _updateResonanceFactor(_poolToken, totalShares);
_saveUp(
_poolToken,
totalShares
);
}
/**
* @dev Sets the new max value in shares
* and saves the corresponding resonance factor.
*/
function _newMaxPoolShares(
address _poolToken,
uint256 _shareValue
)
private
{
_setMaxValue(
_poolToken,
_shareValue
);
_setBestPole(
_poolToken,
borrowRatesData[_poolToken].pole
);
}
/**
* @dev Internal function setting {previousValue}
* and {timestampScaling} for LASA of pool with
* {_poolToken}.
*/
function _saveUp(
address _poolToken,
uint256 _shareValue
)
private
{
algorithmData[_poolToken].previousValue = _shareValue;
_setTimeStampScaling(
_poolToken,
block.timestamp
);
}
/**
* @dev Returns bool to determine if resonance
* factor needs to be reset to last best value.
*/
function _resonanceOutcome(
address _poolToken,
uint256 _shareValue
)
private
view
returns (bool)
{
return _shareValue < THRESHOLD_RESET_RESONANCE_FACTOR
* algorithmData[_poolToken].maxValue
/ PRECISION_FACTOR_E18;
}
/**
* @dev Resets resonance factor to old best value when system
* evolves into too bad state and sets current totalDepositShares
* amount to new maxPoolShares to exclude eternal loops and that
* unorganic peaks do not set maxPoolShares forever.
*/
function _resetResonanceFactor(
address _poolToken,
uint256 _shareValue
)
private
{
_setPole(
_poolToken,
algorithmData[_poolToken].bestPole
);
_setMaxValue(
_poolToken,
_shareValue
);
_revertDirectionState(
_poolToken
);
}
/**
* @dev Reverts the flag for stepping direction from LASA.
*/
function _revertDirectionState(
address _poolToken
)
private
{
_setIncreasePole(
_poolToken,
!algorithmData[_poolToken].increasePole
);
}
/**
* @dev Function combining all possible stepping scenarios.
* Depending how share values has changed compared to last time.
*/
function _updateResonanceFactor(
address _poolToken,
uint256 _shareValues
)
private
{
_shareValues < THRESHOLD_SWITCH_DIRECTION
* algorithmData[_poolToken].previousValue
/ PRECISION_FACTOR_E18
? _reversedResonanceFactor(_poolToken)
: _changingResonanceFactor(_poolToken);
}
/**
* @dev Does a revert stepping and swaps stepping state in opposite flag.
*/
function _reversedResonanceFactor(
address _poolToken
)
private
{
algorithmData[_poolToken].increasePole
? _decreaseResonanceFactor(_poolToken)
: _increaseResonanceFactor(_poolToken);
_revertDirectionState(
_poolToken
);
}
/**
* @dev Increasing or decresing resonance factor depending on flag value.
*/
function _changingResonanceFactor(
address _poolToken
)
private
{
algorithmData[_poolToken].increasePole
? _increaseResonanceFactor(_poolToken)
: _decreaseResonanceFactor(_poolToken);
}
/**
* @dev stepping function increasing the resonance factor
* depending on the time past in the last time interval.
* Checks if current resonance factor is bigger than max value.
* If this is the case sets current value to maximal value
*/
function _increaseResonanceFactor(
address _poolToken
)
private
{
BorrowRatesEntry memory borrowData = borrowRatesData[
_poolToken
];
uint256 delta = borrowData.deltaPole
* (block.timestamp - timestampsPoolData[_poolToken].timeStampScaling);
uint256 sum = delta
+ borrowData.pole;
uint256 setValue = sum > borrowData.maxPole
? borrowData.maxPole
: sum;
_setPole(
_poolToken,
setValue
);
}
/**
* @dev Stepping function decresing the resonance factor
* depending on the time past in the last time interval.
* Checks if current resonance factor undergoes the min value,
* if this is the case sets current value to minimal value.
*/
function _decreaseResonanceFactor(
address _poolToken
)
private
{
uint256 minValue = borrowRatesData[_poolToken].minPole;
uint256 delta = borrowRatesData[_poolToken].deltaPole
* (block.timestamp - timestampsPoolData[_poolToken].timeStampScaling);
uint256 sub = borrowRatesData[_poolToken].pole > delta
? borrowRatesData[_poolToken].pole - delta
: 0;
uint256 setValue = sub < minValue
? minValue
: sub;
_setPole(
_poolToken,
setValue
);
}
/**
* @dev Internal helper function for removing token address
* from lending data array if all shares are removed. When
* feeManager (nftId = 0) is calling this function is skipped
* to save gas for continues fee accounting.
*/
function _removeEmptyLendingData(
uint256 _nftId,
address _poolToken
)
internal
{
if (_nftId == 0) {
return;
}
if (_checkLendingDataEmpty(_nftId, _poolToken) == false) {
return;
}
_removePositionData({
_nftId: _nftId,
_poolToken: _poolToken,
_getPositionTokenLength: getPositionLendingTokenLength,
_getPositionTokenByIndex: getPositionLendingTokenByIndex,
_deleteLastPositionData: _deleteLastPositionLendingData,
isLending: true
});
}
/**
* @dev Internal helper function grouping several function
* calls into one function for refactoring and code size
* reduction.
*/
function _updatePoolStorage(
address _poolToken,
uint256 _amount,
uint256 _shares,
function(address, uint256) functionAmountA,
function(address, uint256) functionAmountB,
function(address, uint256) functionSharesA
)
internal
{
functionAmountA(
_poolToken,
_amount
);
functionAmountB(
_poolToken,
_amount
);
functionSharesA(
_poolToken,
_shares
);
}
}
PoolManager.sol 314 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
import "./WiseCore.sol";
import "./Babylonian.sol";
abstract contract PoolManager is WiseCore {
using Babylonian for uint256;
struct CreatePool {
bool allowBorrow;
address poolToken;
uint256 poolMulFactor;
uint256 poolCollFactor;
uint256 maxDepositAmount;
}
struct CurvePoolSettings {
CurveSwapStructData curveSecuritySwapsData;
CurveSwapStructToken curveSecuritySwapsToken;
}
function setParamsLASA(
address _poolToken,
uint256 _poolMulFactor,
uint256 _upperBoundMaxRate,
uint256 _lowerBoundMaxRate,
bool _steppingDirection,
bool _isFinal
)
external
onlyMaster
{
if (parametersLocked[_poolToken] == true) {
revert InvalidAction();
}
parametersLocked[_poolToken] = _isFinal;
AlgorithmEntry storage algoData = algorithmData[
_poolToken
];
algoData.increasePole = _steppingDirection;
_validateParameter(
_upperBoundMaxRate,
UPPER_BOUND_MAX_RATE
);
_validateParameter(
_lowerBoundMaxRate,
LOWER_BOUND_MAX_RATE
);
_validateParameter(
_lowerBoundMaxRate,
_upperBoundMaxRate
);
uint256 staticMinPole = _getPoleValue(
_poolMulFactor,
_upperBoundMaxRate
);
uint256 staticMaxPole = _getPoleValue(
_poolMulFactor,
_lowerBoundMaxRate
);
uint256 staticDeltaPole = _getDeltaPole(
staticMaxPole,
staticMinPole
);
uint256 startValuePole = _getStartValue(
staticMaxPole,
staticMinPole
);
_validateParameter(
_poolMulFactor,
PRECISION_FACTOR_E18
);
borrowRatesData[_poolToken] = BorrowRatesEntry(
startValuePole,
staticDeltaPole,
staticMinPole,
staticMaxPole,
_poolMulFactor
);
algoData.bestPole = startValuePole;
algoData.maxValue = lendingPoolData[_poolToken].totalDepositShares;
}
function setPoolParameters(
address _poolToken,
uint256 _collateralFactor,
uint256 _maximumDeposit
)
external
onlyMaster
{
if (_maximumDeposit > 0) {
maxDepositValueToken[_poolToken] = _maximumDeposit;
}
if (_collateralFactor > 0) {
lendingPoolData[_poolToken].collateralFactor = _collateralFactor;
}
_validateParameter(
_collateralFactor,
PRECISION_FACTOR_E18
);
}
/**
* @dev Allow to verify isolation pool.
*/
function setVerifiedIsolationPool(
address _isolationPool,
bool _state
)
external
onlyMaster
{
verifiedIsolationPool[_isolationPool] = _state;
}
function createPool(
CreatePool calldata _params
)
external
onlyMaster
{
_createPool(
_params
);
}
function createCurvePool(
CreatePool calldata _params,
CurvePoolSettings calldata _settings
)
external
onlyMaster
{
_createPool(
_params
);
WISE_SECURITY.prepareCurvePools(
_params.poolToken,
_settings.curveSecuritySwapsData,
_settings.curveSecuritySwapsToken
);
}
function _createPool(
CreatePool calldata _params
)
private
{
_validateParameter(
timestampsPoolData[_params.poolToken].timeStamp,
0
);
if (_params.poolToken == ZERO_ADDRESS) {
revert InvalidAddress();
}
_validateParameter(
_params.poolMulFactor,
PRECISION_FACTOR_E18
);
_validateParameter(
_params.poolCollFactor,
MAX_COLLATERAL_FACTOR
);
// Calculating lower bound for the pole
uint256 staticMinPole = _getPoleValue(
_params.poolMulFactor,
UPPER_BOUND_MAX_RATE
);
// Calculating upper bound for the pole
uint256 staticMaxPole = _getPoleValue(
_params.poolMulFactor,
LOWER_BOUND_MAX_RATE
);
// Calculating fraction for algorithm step
uint256 staticDeltaPole = _getDeltaPole(
staticMaxPole,
staticMinPole
);
maxDepositValueToken[_params.poolToken] = _params.maxDepositAmount;
globalPoolData[_params.poolToken] = GlobalPoolEntry({
totalPool: 0,
utilization: 0,
totalBareToken: 0,
poolFee: 20 * PRECISION_FACTOR_E16
});
// Setting start value as mean of min and max value
uint256 startValuePole = _getStartValue(
staticMaxPole,
staticMinPole
);
// Rates Pool Data
borrowRatesData[_params.poolToken] = BorrowRatesEntry(
startValuePole,
staticDeltaPole,
staticMinPole,
staticMaxPole,
_params.poolMulFactor
);
// Borrow Pool Data
borrowPoolData[_params.poolToken] = BorrowPoolEntry({
allowBorrow: _params.allowBorrow,
pseudoTotalBorrowAmount: GHOST_AMOUNT,
totalBorrowShares: GHOST_AMOUNT,
borrowRate: 0
});
// Algorithm Pool Data
algorithmData[_params.poolToken] = AlgorithmEntry({
bestPole: startValuePole,
maxValue: 0,
previousValue: 0,
increasePole: false
});
// Lending Pool Data
lendingPoolData[_params.poolToken] = LendingPoolEntry({
pseudoTotalPool: GHOST_AMOUNT,
totalDepositShares: GHOST_AMOUNT,
collateralFactor: _params.poolCollFactor
});
// Timestamp Pool Data
timestampsPoolData[_params.poolToken] = TimestampsPoolEntry({
timeStamp: block.timestamp,
timeStampScaling: block.timestamp,
initialTimeStamp: block.timestamp
});
FEE_MANAGER.addPoolTokenAddress(
_params.poolToken
);
uint256 fetchBalance = _getBalance(
_params.poolToken
);
if (fetchBalance > 0) {
_safeTransfer(
_params.poolToken,
master,
fetchBalance
);
}
}
function _getPoleValue(
uint256 _poolMulFactor,
uint256 _poleBoundRate
)
private
pure
returns (uint256)
{
return PRECISION_FACTOR_E18 / 2
+ (PRECISION_FACTOR_E36 / 4
+ _poolMulFactor
* PRECISION_FACTOR_E36
/ _poleBoundRate
).sqrt();
}
function _getDeltaPole(
uint256 _maxPole,
uint256 _minPole
)
private
pure
returns (uint256)
{
return (_maxPole - _minPole) / NORMALISATION_FACTOR;
}
function _getStartValue(
uint256 _maxPole,
uint256 _minPole
)
private
pure
returns (uint256)
{
return (_maxPole + _minPole) / 2;
}
}
WiseLending.sol 1598 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
/**
* @author René Hochmuth
* @author Christoph Krpoun
* @author Vitally Marinchenko
*/
import "./PoolManager.sol";
/**
* @dev WISE lending is an automated lending platform on which users can collateralize
* their assets and borrow tokens against them.
*
* Users need to pay borrow rates for debt tokens, which are reflected in a borrow APY for
* each asset type (pool). This borrow rate is variable over time and determined through the
* utilization of the pool. The bounding curve is a family of different bonding curves adjusted
* automatically by LASA (Lending Automated Scaling Algorithm). For more information, see:
* [https://wisesoft.gitbook.io/wise/wise-lending-protocol/lasa-ai]
*
* In addition to normal deposit, withdraw, borrow, and payback functions, there are other
* interacting modes:
*
* - Solely deposit and withdraw allows the user to keep their funds private, enabling
* them to withdraw even when the pools are borrowed empty.
*
* - Aave pools allow for maximal capital efficiency by earning aave supply APY for not
* borrowed funds.
*
* - Special curve pools nside beefy farms can be used as collateral, opening up new usage
* possibilities for these asset types.
*
* - Users can pay back their borrow with lending shares of the same asset type, making it
* easier to manage their positions.
*
* - Users save their collaterals and borrows inside a position NFT, making it possible
* to trade their whole positions or use them in second-layer contracts
* (e.g., spot trading with PTP NFT trading platforms).
*/
contract WiseLending is PoolManager {
/**
* @dev Standard receive functions forwarding
* directly send ETH to the master address.
*/
receive()
external
payable
{
_checkReentrancy();
if (msg.sender == WETH_ADDRESS) {
return;
}
_sendValue(
master,
msg.value
);
}
/**
* @dev Checks if position is healthy
* after all state changes are done.
*/
modifier healthStateCheck(
uint256 _nftId
) {
_;
_healthStateCheck(
_nftId
);
}
function _healthStateCheck(
uint256 _nftId
)
private
{
_checkHealthState(
_nftId,
powerFarmCheck
);
if (powerFarmCheck == true) {
powerFarmCheck = false;
}
}
/**
* @dev Runs the LASA algorithm known as
* Lending Automated Scaling Algorithm
* and updates pool data based on token
*/
modifier syncPool(
address _poolToken
) {
(
uint256 lendSharePrice,
uint256 borrowSharePrice
) = _syncPoolBeforeCodeExecution(
_poolToken
);
_;
_syncPoolAfterCodeExecution(
_poolToken,
lendSharePrice,
borrowSharePrice
);
}
constructor(
address _master,
address _wiseOracleHubAddress,
address _nftContract
)
WiseLendingDeclaration(
_master,
_wiseOracleHubAddress,
_nftContract
)
{}
function _emitFundsSolelyWithdrawn(
address _caller,
uint256 _nftId,
address _poolToken,
uint256 _amount
)
private
{
emit FundsSolelyWithdrawn(
_caller,
_nftId,
_poolToken,
_amount,
block.timestamp
);
}
function _emitFundsSolelyDeposited(
address _caller,
uint256 _nftId,
address _poolToken,
uint256 _amount
)
private
{
emit FundsSolelyDeposited(
_caller,
_nftId,
_poolToken,
_amount,
block.timestamp
);
}
/**
* @dev Fetches share price of lending shares.
*/
function _getSharePrice(
address _poolToken
)
private
view
returns (
uint256,
uint256
)
{
uint256 borrowSharePrice = borrowPoolData[_poolToken].pseudoTotalBorrowAmount
* PRECISION_FACTOR_E18
/ borrowPoolData[_poolToken].totalBorrowShares;
_validateParameter(
MIN_BORROW_SHARE_PRICE,
borrowSharePrice
);
return (
lendingPoolData[_poolToken].pseudoTotalPool
* PRECISION_FACTOR_E18
/ lendingPoolData[_poolToken].totalDepositShares,
borrowSharePrice
);
}
function _checkHealthState(
uint256 _nftId,
bool _powerFarm
)
internal
view
{
WISE_SECURITY.checkHealthState(
_nftId,
_powerFarm
);
}
/**
* @dev Compares share prices before and after
* execution. If borrow share price increased
* or lending share price decreased, revert.
*/
function _compareSharePrices(
address _poolToken,
uint256 _lendSharePriceBefore,
uint256 _borrowSharePriceBefore
)
private
view
{
(
uint256 lendSharePriceAfter,
uint256 borrowSharePriceAfter
) = _getSharePrice(
_poolToken
);
uint256 currentSharePriceMax = _getCurrentSharePriceMax(
_poolToken
);
_validateParameter(
_lendSharePriceBefore,
lendSharePriceAfter
);
_validateParameter(
lendSharePriceAfter,
currentSharePriceMax
);
_validateParameter(
_borrowSharePriceBefore,
currentSharePriceMax
);
_validateParameter(
borrowSharePriceAfter,
_borrowSharePriceBefore
);
}
/**
* @dev Since pool inception share price
* increase for both lending and borrow shares
* is capped at 500% apr max in between a transaction.
*/
function _getCurrentSharePriceMax(
address _poolToken
)
private
view
returns (uint256)
{
uint256 timeDifference = block.timestamp
- timestampsPoolData[_poolToken].initialTimeStamp;
return timeDifference
* RESTRICTION_FACTOR
+ PRECISION_FACTOR_E18;
}
/**
* @dev First part of pool sync updating pseudo
* amounts. Is skipped when powerFarms or aaveHub
* is calling the function.
*/
function _syncPoolBeforeCodeExecution(
address _poolToken
)
private
returns (
uint256 lendSharePrice,
uint256 borrowSharePrice
)
{
_checkReentrancy();
_preparePool(
_poolToken
);
if (_aboveThreshold(_poolToken) == true) {
_scalingAlgorithm(
_poolToken
);
}
(
lendSharePrice,
borrowSharePrice
) = _getSharePrice(
_poolToken
);
}
/**
* @dev Second part of pool sync updating
* the borrow pool rate and share price.
*/
function _syncPoolAfterCodeExecution(
address _poolToken,
uint256 _lendSharePriceBefore,
uint256 _borrowSharePriceBefore
)
private
{
_newBorrowRate(
_poolToken
);
_compareSharePrices(
_poolToken,
_lendSharePriceBefore,
_borrowSharePriceBefore
);
}
/**
* @dev Enables _poolToken to be used as a collateral.
*/
function collateralizeDeposit(
uint256 _nftId,
address _poolToken
)
external
syncPool(_poolToken)
{
WISE_SECURITY.checksCollateralizeDeposit(
_nftId,
msg.sender,
_poolToken
);
userLendingData[_nftId][_poolToken].unCollateralized = false;
}
/**
* @dev Disables _poolToken to be used as a collateral.
*/
function unCollateralizeDeposit(
uint256 _nftId,
address _poolToken
)
external
syncPool(_poolToken)
{
_checkOwnerPosition(
_nftId,
msg.sender
);
(
address[] memory lendTokens,
address[] memory borrowTokens
) = _prepareAssociatedTokens(
_nftId,
_poolToken,
ZERO_ADDRESS
);
userLendingData[_nftId][_poolToken].unCollateralized = true;
WISE_SECURITY.checkUncollateralizedDeposit(
_nftId,
_poolToken
);
_curveSecurityChecks(
lendTokens,
borrowTokens
);
}
// --------------- Deposit Functions -------------
/**
* @dev Allows to supply funds using ETH.
* Without converting to WETH, use ETH directly.
*/
function depositExactAmountETH(
uint256 _nftId
)
external
payable
syncPool(WETH_ADDRESS)
returns (uint256)
{
return _depositExactAmountETH(
_nftId
);
}
function _depositExactAmountETH(
uint256 _nftId
)
private
returns (uint256)
{
uint256 shareAmount = _handleDeposit(
msg.sender,
_nftId,
WETH_ADDRESS,
msg.value
);
_wrapETH(
msg.value
);
return shareAmount;
}
/**
* @dev Allows to supply funds using ETH.
* Without converting to WETH, use ETH directly,
* also mints position to avoid extra transaction.
*/
function depositExactAmountETHMint()
external
payable
syncPool(WETH_ADDRESS)
returns (uint256)
{
return _depositExactAmountETH(
_reservePosition()
);
}
/**
* @dev Allows to supply _poolToken and user
* can decide if _poolToken should be collateralized,
* also mints position to avoid extra transaction.
*/
function depositExactAmountMint(
address _poolToken,
uint256 _amount
)
external
returns (uint256)
{
return depositExactAmount(
_reservePosition(),
_poolToken,
_amount
);
}
/**
* @dev Allows to supply _poolToken and user
* can decide if _poolToken should be collateralized.
*/
function depositExactAmount(
uint256 _nftId,
address _poolToken,
uint256 _amount
)
public
syncPool(_poolToken)
returns (uint256)
{
uint256 shareAmount = _handleDeposit(
msg.sender,
_nftId,
_poolToken,
_amount
);
_safeTransferFrom(
_poolToken,
msg.sender,
address(this),
_amount
);
return shareAmount;
}
/**
* @dev Allows to supply funds using ETH in solely mode,
* which does not earn APY, but keeps the funds private.
* Other users are restricted from borrowing these funds,
* owner can always withdraw even if all funds are borrowed.
* Also mints position to avoid extra transaction.
*/
function solelyDepositETHMint()
external
payable
{
solelyDepositETH(
_reservePosition()
);
}
/**
* @dev Allows to supply funds using ETH in solely mode,
* which does not earn APY, but keeps the funds private.
* Other users are restricted from borrowing these funds,
* owner can always withdraw even if all funds are borrowed.
*/
function solelyDepositETH(
uint256 _nftId
)
public
payable
syncPool(WETH_ADDRESS)
{
_handleSolelyDeposit(
msg.sender,
_nftId,
WETH_ADDRESS,
msg.value
);
_wrapETH(
msg.value
);
_emitFundsSolelyDeposited(
msg.sender,
_nftId,
WETH_ADDRESS,
msg.value
);
}
/**
* @dev Core function combining
* supply logic with security
* checks for solely deposit.
*/
function _handleSolelyDeposit(
address _caller,
uint256 _nftId,
address _poolToken,
uint256 _amount
)
private
{
_checkDeposit(
_nftId,
_caller,
_poolToken,
_amount
);
_increaseMappingValue(
pureCollateralAmount,
_nftId,
_poolToken,
_amount
);
_increaseTotalBareToken(
_poolToken,
_amount
);
_addPositionTokenData(
_nftId,
_poolToken,
hashMapPositionLending,
positionLendTokenData
);
}
/**
* @dev Allows to supply funds using ERC20 in solely mode,
* which does not earn APY, but keeps the funds private.
* Other users are restricted from borrowing these funds,
* owner can always withdraw even if all funds are borrowed.
* Also mints position to avoid extra transaction.
*/
function solelyDepositMint(
address _poolToken,
uint256 _amount
)
external
{
solelyDeposit(
_reservePosition(),
_poolToken,
_amount
);
}
/**
* @dev Allows to supply funds using ERC20 in solely mode,
* which does not earn APY, but keeps the funds private.
* Other users are restricted from borrowing these funds,
* owner can always withdraw even if all funds are borrowed.
*/
function solelyDeposit(
uint256 _nftId,
address _poolToken,
uint256 _amount
)
public
syncPool(_poolToken)
{
_handleSolelyDeposit(
msg.sender,
_nftId,
_poolToken,
_amount
);
_emitFundsSolelyDeposited(
msg.sender,
_nftId,
_poolToken,
_amount
);
_safeTransferFrom(
_poolToken,
msg.sender,
address(this),
_amount
);
}
// --------------- Withdraw Functions -------------
/**
* @dev Allows to withdraw publicly
* deposited ETH funds using exact amount.
*/
function withdrawExactAmountETH(
uint256 _nftId,
uint256 _amount
)
external
syncPool(WETH_ADDRESS)
healthStateCheck(_nftId)
returns (uint256)
{
uint256 withdrawShares = _handleWithdrawAmount(
{
_caller: msg.sender,
_nftId: _nftId,
_poolToken: WETH_ADDRESS,
_amount: _amount,
_onBehalf: false
}
);
_validateNonZero(
withdrawShares
);
_unwrapETH(
_amount
);
_sendValue(
msg.sender,
_amount
);
return withdrawShares;
}
/**
* @dev Allows to withdraw publicly
* deposited ETH funds using exact shares.
*/
function withdrawExactSharesETH(
uint256 _nftId,
uint256 _shares
)
external
syncPool(WETH_ADDRESS)
healthStateCheck(_nftId)
returns (uint256)
{
uint256 withdrawAmount = _handleWithdrawShares(
{
_caller: msg.sender,
_nftId: _nftId,
_poolToken: WETH_ADDRESS,
_shares: _shares,
_onBehalf: false
}
);
_validateNonZero(
withdrawAmount
);
_unwrapETH(
withdrawAmount
);
_sendValue(
msg.sender,
withdrawAmount
);
return withdrawAmount;
}
/**
* @dev Allows to withdraw publicly
* deposited ERC20 funds using exact amount.
*/
function withdrawExactAmount(
uint256 _nftId,
address _poolToken,
uint256 _withdrawAmount
)
external
syncPool(_poolToken)
healthStateCheck(_nftId)
returns (uint256)
{
uint256 withdrawShares = _handleWithdrawAmount(
{
_caller: msg.sender,
_nftId: _nftId,
_poolToken: _poolToken,
_amount: _withdrawAmount,
_onBehalf: false
}
);
_validateNonZero(
withdrawShares
);
_safeTransfer(
_poolToken,
msg.sender,
_withdrawAmount
);
return withdrawShares;
}
/**
* @dev Allows to withdraw privately
* deposited ETH funds using input amount.
*/
function solelyWithdrawETH(
uint256 _nftId,
uint256 _withdrawAmount
)
external
syncPool(WETH_ADDRESS)
healthStateCheck(_nftId)
{
_handleSolelyWithdraw(
msg.sender,
_nftId,
WETH_ADDRESS,
_withdrawAmount
);
_unwrapETH(
_withdrawAmount
);
_sendValue(
msg.sender,
_withdrawAmount
);
}
/**
* @dev Allows to withdraw privately
* deposited ERC20 funds using input amount.
*/
function solelyWithdraw(
uint256 _nftId,
address _poolToken,
uint256 _withdrawAmount
)
external
syncPool(_poolToken)
healthStateCheck(_nftId)
{
_handleSolelyWithdraw(
msg.sender,
_nftId,
_poolToken,
_withdrawAmount
);
_safeTransfer(
_poolToken,
msg.sender,
_withdrawAmount
);
}
/**
* @dev Core function combining
* withdraw logic for solely
* withdraw with security checks.
*/
function _coreSolelyWithdraw(
address _caller,
uint256 _nftId,
address _poolToken,
uint256 _amount
)
private
{
(
address[] memory lendTokens,
address[] memory borrowTokens
) = _prepareAssociatedTokens(
_nftId,
_poolToken,
ZERO_ADDRESS
);
powerFarmCheck = WISE_SECURITY.checksSolelyWithdraw(
_nftId,
_caller,
_poolToken
);
_decreasePositionMappingValue(
pureCollateralAmount,
_nftId,
_poolToken,
_amount
);
_decreaseTotalBareToken(
_poolToken,
_amount
);
_removeEmptyLendingData(
_nftId,
_poolToken
);
_curveSecurityChecks(
lendTokens,
borrowTokens
);
}
/**
* @dev Allows to withdraw privately
* deposited ERC20 on behalf of owner.
* Requires approval by _nftId owner.
*/
function withdrawOnBehalfExactAmount(
uint256 _nftId,
address _poolToken,
uint256 _withdrawAmount
)
external
onlyAaveHub
syncPool(_poolToken)
healthStateCheck(_nftId)
returns (uint256)
{
uint256 withdrawShares = calculateLendingShares(
{
_poolToken: _poolToken,
_amount: _withdrawAmount,
_maxSharePrice: true
}
);
_coreWithdrawToken(
{
_caller: msg.sender,
_nftId: _nftId,
_poolToken: _poolToken,
_amount: _withdrawAmount,
_shares: withdrawShares,
_onBehalf: true
}
);
_safeTransfer(
_poolToken,
msg.sender,
_withdrawAmount
);
return withdrawShares;
}
/**
* @dev Allows to withdraw ERC20
* funds using shares as input value
*/
function withdrawExactShares(
uint256 _nftId,
address _poolToken,
uint256 _shares
)
external
syncPool(_poolToken)
healthStateCheck(_nftId)
returns (uint256)
{
uint256 withdrawAmount = _handleWithdrawShares(
{
_caller: msg.sender,
_nftId: _nftId,
_poolToken: _poolToken,
_shares: _shares,
_onBehalf: false
}
);
_validateNonZero(
withdrawAmount
);
_safeTransfer(
_poolToken,
msg.sender,
withdrawAmount
);
return withdrawAmount;
}
/**
* @dev Withdraws ERC20 funds on behalf
* of _nftId owner, requires approval.
*/
function withdrawOnBehalfExactShares(
uint256 _nftId,
address _poolToken,
uint256 _shares
)
external
onlyAaveHub
syncPool(_poolToken)
healthStateCheck(_nftId)
returns (uint256)
{
uint256 withdrawAmount = _handleWithdrawShares(
{
_caller: msg.sender,
_nftId: _nftId,
_poolToken: _poolToken,
_shares: _shares,
_onBehalf: true
}
);
_safeTransfer(
_poolToken,
msg.sender,
withdrawAmount
);
return withdrawAmount;
}
// --------------- Borrow Functions -------------
/**
* @dev Allows to borrow ETH funds
* Requires user to have collateral.
*/
function borrowExactAmountETH(
uint256 _nftId,
uint256 _amount
)
external
syncPool(WETH_ADDRESS)
healthStateCheck(_nftId)
returns (uint256)
{
_checkOwnerPosition(
_nftId,
msg.sender
);
uint256 shares = _handleBorrowExactAmount({
_nftId: _nftId,
_poolToken: WETH_ADDRESS,
_amount: _amount,
_onBehalf: false
});
_validateNonZero(
shares
);
_unwrapETH(
_amount
);
_sendValue(
msg.sender,
_amount
);
return shares;
}
/**
* @dev Allows to borrow ERC20 funds
* Requires user to have collateral.
*/
function borrowExactAmount(
uint256 _nftId,
address _poolToken,
uint256 _amount
)
external
syncPool(_poolToken)
healthStateCheck(_nftId)
returns (uint256)
{
_checkOwnerPosition(
_nftId,
msg.sender
);
uint256 shares = _handleBorrowExactAmount({
_nftId: _nftId,
_poolToken: _poolToken,
_amount: _amount,
_onBehalf: false
});
_validateNonZero(
shares
);
_safeTransfer(
_poolToken,
msg.sender,
_amount
);
return shares;
}
/**
* @dev Allows to borrow ERC20 funds
* on behalf of _nftId owner, if approved.
*/
function borrowOnBehalfExactAmount(
uint256 _nftId,
address _poolToken,
uint256 _amount
)
external
onlyAaveHub
syncPool(_poolToken)
healthStateCheck(_nftId)
returns (uint256)
{
uint256 shares = _handleBorrowExactAmount({
_nftId: _nftId,
_poolToken: _poolToken,
_amount: _amount,
_onBehalf: true
});
_safeTransfer(
_poolToken,
msg.sender,
_amount
);
return shares;
}
// --------------- Payback Functions ------------
/**
* @dev Ability to payback ETH loans
* by providing exact payback amount.
*/
function paybackExactAmountETH(
uint256 _nftId
)
external
payable
syncPool(WETH_ADDRESS)
returns (uint256)
{
uint256 maxBorrowShares = userBorrowShares[_nftId][WETH_ADDRESS];
_validateNonZero(
maxBorrowShares
);
uint256 maxPaybackAmount = paybackAmount(
WETH_ADDRESS,
maxBorrowShares
);
uint256 paybackShares = calculateBorrowShares(
{
_poolToken: WETH_ADDRESS,
_amount: msg.value,
_maxSharePrice: false
}
);
_validateNonZero(
paybackShares
);
uint256 refundAmount;
uint256 requiredAmount = msg.value;
if (msg.value > maxPaybackAmount) {
unchecked {
refundAmount = msg.value
- maxPaybackAmount;
}
requiredAmount = requiredAmount
- refundAmount;
paybackShares = maxBorrowShares;
}
_handlePayback(
msg.sender,
_nftId,
WETH_ADDRESS,
requiredAmount,
paybackShares
);
_wrapETH(
requiredAmount
);
if (refundAmount > 0) {
_sendValue(
msg.sender,
refundAmount
);
}
return paybackShares;
}
/**
* @dev Ability to payback ERC20 loans
* by providing exact payback amount.
*/
function paybackExactAmount(
uint256 _nftId,
address _poolToken,
uint256 _amount
)
external
syncPool(_poolToken)
returns (uint256)
{
uint256 paybackShares = calculateBorrowShares(
{
_poolToken: _poolToken,
_amount: _amount,
_maxSharePrice: false
}
);
_validateNonZero(
paybackShares
);
_handlePayback(
msg.sender,
_nftId,
_poolToken,
_amount,
paybackShares
);
_safeTransferFrom(
_poolToken,
msg.sender,
address(this),
_amount
);
return paybackShares;
}
/**
* @dev Ability to payback ERC20 loans
* by providing exact payback shares.
*/
function paybackExactShares(
uint256 _nftId,
address _poolToken,
uint256 _shares
)
external
syncPool(_poolToken)
returns (uint256)
{
uint256 repaymentAmount = paybackAmount(
_poolToken,
_shares
);
_validateNonZero(
repaymentAmount
);
_handlePayback(
msg.sender,
_nftId,
_poolToken,
repaymentAmount,
_shares
);
_safeTransferFrom(
_poolToken,
msg.sender,
address(this),
repaymentAmount
);
return repaymentAmount;
}
// --------------- Liquidation Functions ------------
/**
* @dev Function to liquidate a postion which reaches
* a debt ratio greater than 100%. The liquidator can choose
* token to payback and receive. (Both can differ!). The
* amount is in shares of the payback token. The liquidator
* gets an incentive which is calculated inside the liquidation
* logic.
*/
function liquidatePartiallyFromTokens(
uint256 _nftId,
uint256 _nftIdLiquidator,
address _paybackToken,
address _receiveToken,
uint256 _shareAmountToPay
)
external
syncPool(_paybackToken)
syncPool(_receiveToken)
returns (uint256)
{
CoreLiquidationStruct memory data;
data.nftId = _nftId;
data.nftIdLiquidator = _nftIdLiquidator;
data.caller = msg.sender;
data.tokenToPayback = _paybackToken;
data.tokenToRecieve = _receiveToken;
data.shareAmountToPay = _shareAmountToPay;
data.maxFeeETH = WISE_SECURITY.maxFeeETH();
data.baseRewardLiquidation = WISE_SECURITY.baseRewardLiquidation();
(
data.lendTokens,
data.borrowTokens
) = _prepareAssociatedTokens(
_nftId,
_receiveToken,
_paybackToken
);
data.paybackAmount = paybackAmount(
_paybackToken,
_shareAmountToPay
);
_checkPositionLocked(
_nftId,
msg.sender
);
_checkLiquidatorNft(
_nftId,
_nftIdLiquidator
);
WISE_SECURITY.checksLiquidation(
_nftId,
_paybackToken,
_shareAmountToPay
);
return _coreLiquidation(
data
);
}
/**
* @dev Wrapper function for liqudaiton flow
*/
function coreLiquidationIsolationPools(
uint256 _nftId,
uint256 _nftIdLiquidator,
address _caller,
address _paybackToken,
address _receiveToken,
uint256 _paybackAmount,
uint256 _shareAmountToPay
)
external
syncPool(_paybackToken)
syncPool(_receiveToken)
returns (uint256)
{
CoreLiquidationStruct memory data;
data.nftId = _nftId;
data.nftIdLiquidator = _nftIdLiquidator;
data.caller = _caller;
data.paybackAmount = _paybackAmount;
data.tokenToPayback = _paybackToken;
data.tokenToRecieve = _receiveToken;
data.shareAmountToPay = _shareAmountToPay;
data.maxFeeETH = WISE_SECURITY.maxFeeFarmETH();
data.baseRewardLiquidation = WISE_SECURITY.baseRewardLiquidationFarm();
_validateIsolationPoolLiquidation(
msg.sender,
data.nftId,
data.nftIdLiquidator
);
(
data.lendTokens,
data.borrowTokens
) = _prepareAssociatedTokens(
data.nftId,
data.tokenToRecieve,
data.tokenToPayback
);
return _coreLiquidation(
data
);
}
/**
* @dev Allows to sync pool manually
* so that the pool is up to date.
*/
function syncManually(
address _poolToken
)
external
syncPool(_poolToken)
{
address[] memory tokens = new address[](1);
tokens[0] = _poolToken;
_curveSecurityChecks(
new address[](0),
tokens
);
}
/**
* @dev Registers position _nftId
* for isolation pool functionality
*/
function setRegistrationIsolationPool(
uint256 _nftId,
bool _registerState
)
external
{
_onlyIsolationPool(
msg.sender
);
_validateZero(
WISE_SECURITY.overallETHCollateralsBare(_nftId)
);
_validateZero(
WISE_SECURITY.overallETHBorrowBare(_nftId)
);
positionLocked[_nftId] = _registerState;
}
/**
* @dev External wrapper for
* {_corePayback} logic callable
* by feeMananger.
*/
function corePaybackFeeManager(
address _poolToken,
uint256 _nftId,
uint256 _amount,
uint256 _shares
)
external
onlyFeeManager
syncPool(_poolToken)
{
_corePayback(
_nftId,
_poolToken,
_amount,
_shares
);
}
/**
* @dev Internal function combining payback
* logic and emit of an event.
*/
function _handlePayback(
address _caller,
uint256 _nftId,
address _poolToken,
uint256 _amount,
uint256 _shares
)
private
{
_corePayback(
_nftId,
_poolToken,
_amount,
_shares
);
emit FundsReturned(
_caller,
_poolToken,
_nftId,
_amount,
_shares,
block.timestamp
);
}
function _handleWithdrawAmount(
address _caller,
uint256 _nftId,
address _poolToken,
uint256 _amount,
bool _onBehalf
)
private
returns (uint256 withdrawShares)
{
withdrawShares = _preparationsWithdraw(
_nftId,
msg.sender,
_poolToken,
_amount
);
_coreWithdrawToken(
{
_caller: _caller,
_nftId: _nftId,
_poolToken: _poolToken,
_amount: _amount,
_shares: withdrawShares,
_onBehalf: _onBehalf
}
);
}
function _handleSolelyWithdraw(
address _caller,
uint256 _nftId,
address _poolToken,
uint256 _amount
)
private
{
_checkOwnerPosition(
_nftId,
_caller
);
_coreSolelyWithdraw(
_caller,
_nftId,
_poolToken,
_amount
);
_emitFundsSolelyWithdrawn(
_caller,
_nftId,
_poolToken,
_amount
);
}
function _handleWithdrawShares(
address _caller,
uint256 _nftId,
address _poolToken,
uint256 _shares,
bool _onBehalf
)
private
returns (uint256)
{
if (_onBehalf == false) {
_checkOwnerPosition(
_nftId,
_caller
);
}
uint256 withdrawAmount = _cashoutAmount(
_poolToken,
_shares
);
_coreWithdrawToken(
{
_caller: _caller,
_nftId: _nftId,
_poolToken: _poolToken,
_amount: withdrawAmount,
_shares: _shares,
_onBehalf: _onBehalf
}
);
return withdrawAmount;
}
function _handleBorrowExactAmount(
uint256 _nftId,
address _poolToken,
uint256 _amount,
bool _onBehalf
)
private
returns (uint256)
{
uint256 shares = calculateBorrowShares(
{
_poolToken: _poolToken,
_amount: _amount,
_maxSharePrice: true
}
);
_coreBorrowTokens(
{
_caller: msg.sender,
_nftId: _nftId,
_poolToken: _poolToken,
_amount: _amount,
_shares: shares,
_onBehalf: _onBehalf
}
);
return shares;
}
/**
* @dev Internal helper function for reservating a
* position NFT id.
*/
function _reservePosition()
private
returns (uint256)
{
return POSITION_NFT.reservePositionForUser(
msg.sender
);
}
}
OwnableMaster.sol 114 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
error NoValue();
error NotMaster();
error NotProposed();
contract OwnableMaster {
address public master;
address public proposedMaster;
address internal constant ZERO_ADDRESS = address(0x0);
modifier onlyProposed() {
_onlyProposed();
_;
}
function _onlyMaster()
private
view
{
if (msg.sender == master) {
return;
}
revert NotMaster();
}
modifier onlyMaster() {
_onlyMaster();
_;
}
function _onlyProposed()
private
view
{
if (msg.sender == proposedMaster) {
return;
}
revert NotProposed();
}
event MasterProposed(
address indexed proposer,
address indexed proposedMaster
);
event RenouncedOwnership(
address indexed previousMaster
);
constructor(
address _master
) {
if (_master == ZERO_ADDRESS) {
revert NoValue();
}
master = _master;
}
/**
* @dev Allows to propose next master.
* Must be claimed by proposer.
*/
function proposeOwner(
address _proposedOwner
)
external
onlyMaster
{
if (_proposedOwner == ZERO_ADDRESS) {
revert NoValue();
}
proposedMaster = _proposedOwner;
emit MasterProposed(
msg.sender,
_proposedOwner
);
}
/**
* @dev Allows to claim master role.
* Must be called by proposer.
*/
function claimOwnership()
external
onlyProposed
{
master = msg.sender;
}
/**
* @dev Removes master role.
* No ability to be in control.
*/
function renounceOwnership()
external
onlyMaster
{
master = ZERO_ADDRESS;
proposedMaster = ZERO_ADDRESS;
emit RenouncedOwnership(
msg.sender
);
}
}
IWETH.sol 17 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
import "./IERC20.sol";
interface IWETH is IERC20 {
function deposit()
external
payable;
function withdraw(
uint256
)
external;
}
WiseLowLevelHelper.sol 468 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
import "./WiseLendingDeclaration.sol";
abstract contract WiseLowLevelHelper is WiseLendingDeclaration {
modifier onlyFeeManager() {
_onlyFeeManager();
_;
}
function _onlyFeeManager()
private
view
{
if (msg.sender == address(FEE_MANAGER)) {
return;
}
revert InvalidCaller();
}
function _validateParameter(
uint256 _parameterValue,
uint256 _parameterLimit
)
internal
pure
{
if (_parameterValue > _parameterLimit) {
revert InvalidAction();
}
}
// --- Basic Public Views Functions ----
function getTotalPool(
address _poolToken
)
public
view
returns (uint256)
{
return globalPoolData[_poolToken].totalPool;
}
function getPseudoTotalPool(
address _poolToken
)
public
view
returns (uint256)
{
return lendingPoolData[_poolToken].pseudoTotalPool;
}
function getTotalBareToken(
address _poolToken
)
external
view
returns (uint256)
{
return globalPoolData[_poolToken].totalBareToken;
}
function getPseudoTotalBorrowAmount(
address _poolToken
)
external
view
returns (uint256)
{
return borrowPoolData[_poolToken].pseudoTotalBorrowAmount;
}
function getTotalDepositShares(
address _poolToken
)
external
view
returns (uint256)
{
return lendingPoolData[_poolToken].totalDepositShares;
}
function getTotalBorrowShares(
address _poolToken
)
external
view
returns (uint256)
{
return borrowPoolData[_poolToken].totalBorrowShares;
}
function getPositionLendingShares(
uint256 _nftId,
address _poolToken
)
external
view
returns (uint256)
{
return userLendingData[_nftId][_poolToken].shares;
}
function getPositionBorrowShares(
uint256 _nftId,
address _poolToken
)
external
view
returns (uint256)
{
return userBorrowShares[_nftId][_poolToken];
}
function getPureCollateralAmount(
uint256 _nftId,
address _poolToken
)
external
view
returns (uint256)
{
return pureCollateralAmount[_nftId][_poolToken];
}
// --- Basic Internal Get Functions ----
function getTimeStamp(
address _poolToken
)
external
view
returns (uint256)
{
return timestampsPoolData[_poolToken].timeStamp;
}
function getPositionLendingTokenByIndex(
uint256 _nftId,
uint256 _index
)
public
view
returns (address)
{
return positionLendTokenData[_nftId][_index];
}
function getPositionLendingTokenLength(
uint256 _nftId
)
public
view
returns (uint256)
{
return positionLendTokenData[_nftId].length;
}
function getPositionBorrowTokenByIndex(
uint256 _nftId,
uint256 _index
)
public
view
returns (address)
{
return positionBorrowTokenData[_nftId][_index];
}
function getPositionBorrowTokenLength(
uint256 _nftId
)
public
view
returns (uint256)
{
return positionBorrowTokenData[_nftId].length;
}
// --- Basic Internal Set Functions ----
function _setMaxValue(
address _poolToken,
uint256 _value
)
internal
{
algorithmData[_poolToken].maxValue = _value;
}
function _setBestPole(
address _poolToken,
uint256 _value
)
internal
{
algorithmData[_poolToken].bestPole = _value;
}
function _setIncreasePole(
address _poolToken,
bool _state
)
internal
{
algorithmData[_poolToken].increasePole = _state;
}
function _setPole(
address _poolToken,
uint256 _value
)
internal
{
borrowRatesData[_poolToken].pole = _value;
}
function _increaseTotalPool(
address _poolToken,
uint256 _amount
)
internal
{
globalPoolData[_poolToken].totalPool += _amount;
}
function _decreaseTotalPool(
address _poolToken,
uint256 _amount
)
internal
{
globalPoolData[_poolToken].totalPool -= _amount;
}
function _increaseTotalDepositShares(
address _poolToken,
uint256 _amount
)
internal
{
lendingPoolData[_poolToken].totalDepositShares += _amount;
}
function _decreaseTotalDepositShares(
address _poolToken,
uint256 _amount
)
internal
{
lendingPoolData[_poolToken].totalDepositShares -= _amount;
}
function _increasePseudoTotalBorrowAmount(
address _poolToken,
uint256 _amount
)
internal
{
borrowPoolData[_poolToken].pseudoTotalBorrowAmount += _amount;
}
function _decreasePseudoTotalBorrowAmount(
address _poolToken,
uint256 _amount
)
internal
{
borrowPoolData[_poolToken].pseudoTotalBorrowAmount -= _amount;
}
function _increaseTotalBorrowShares(
address _poolToken,
uint256 _amount
)
internal
{
borrowPoolData[_poolToken].totalBorrowShares += _amount;
}
function _decreaseTotalBorrowShares(
address _poolToken,
uint256 _amount
)
internal
{
borrowPoolData[_poolToken].totalBorrowShares -= _amount;
}
function _increasePseudoTotalPool(
address _poolToken,
uint256 _amount
)
internal
{
lendingPoolData[_poolToken].pseudoTotalPool += _amount;
}
function _decreasePseudoTotalPool(
address _poolToken,
uint256 _amount
)
internal
{
lendingPoolData[_poolToken].pseudoTotalPool -= _amount;
}
function _setTimeStamp(
address _poolToken,
uint256 _time
)
internal
{
timestampsPoolData[_poolToken].timeStamp = _time;
}
function _setTimeStampScaling(
address _poolToken,
uint256 _time
)
internal
{
timestampsPoolData[_poolToken].timeStampScaling = _time;
}
function _increaseTotalBareToken(
address _poolToken,
uint256 _amount
)
internal
{
globalPoolData[_poolToken].totalBareToken += _amount;
}
function _decreaseTotalBareToken(
address _poolToken,
uint256 _amount
)
internal
{
globalPoolData[_poolToken].totalBareToken -= _amount;
}
function _checkReentrancy()
internal
view
{
if (sendingProgress == true) {
revert InvalidAction();
}
if (_sendingProgressAaveHub() == true) {
revert InvalidAction();
}
}
function _sendingProgressAaveHub()
private
view
returns (bool)
{
return IAaveHubLite(AAVE_HUB_ADDRESS).sendingProgressAaveHub();
}
function _decreasePositionMappingValue(
mapping(uint256 => mapping(address => uint256)) storage userMapping,
uint256 _nftId,
address _poolToken,
uint256 _amount
)
internal
{
userMapping[_nftId][_poolToken] -= _amount;
}
function _increaseMappingValue(
mapping(uint256 => mapping(address => uint256)) storage userMapping,
uint256 _nftId,
address _poolToken,
uint256 _amount
)
internal
{
userMapping[_nftId][_poolToken] += _amount;
}
function _byPassCase(
address _sender
)
internal
view
returns (bool)
{
if (verifiedIsolationPool[_sender] == true) {
return true;
}
return false;
}
function _increaseTotalAndPseudoTotalPool(
address _poolToken,
uint256 _amount
)
internal
{
_increasePseudoTotalPool(
_poolToken,
_amount
);
_increaseTotalPool(
_poolToken,
_amount
);
}
function setPoolFee(
address _poolToken,
uint256 _newFee
)
external
onlyFeeManager
{
globalPoolData[_poolToken].poolFee = _newFee;
}
function _checkOwnerPosition(
uint256 _nftId,
address _msgSender
)
internal
view
{
WISE_SECURITY.checkOwnerPosition(
_nftId,
_msgSender
);
}
function _validateNonZero(
uint256 _value
)
internal
pure
{
if (_value == 0) {
revert ValueIsZero();
}
}
function _validateZero(
uint256 _value
)
internal
pure
{
if (_value > 0) {
revert ValueNotZero();
}
}
}
IERC20.sol 75 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
interface IERC20 {
function totalSupply()
external
view
returns (uint256);
function balanceOf(
address _account
)
external
view
returns (uint256);
function transferFrom(
address _sender,
address _recipient,
uint256 _amount
)
external
returns (bool);
function transfer(
address _recipient,
uint256 _amount
)
external
returns (bool);
function allowance(
address owner,
address spender
)
external
view
returns (uint256);
function approve(
address _spender,
uint256 _amount
)
external
returns (bool);
function decimals()
external
view
returns (uint8);
event Transfer(
address indexed from,
address indexed to,
uint256 value
);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
event Deposit(
address indexed dst,
uint wad
);
event Withdrawal(
address indexed src,
uint wad
);
}
WiseLendingDeclaration.sol 327 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
import "./OwnableMaster.sol";
import "./InterfaceHub/IAaveHubLite.sol";
import "./InterfaceHub/IPositionNFTs.sol";
import "./InterfaceHub/IWiseSecurity.sol";
import "./InterfaceHub/IWiseOracleHub.sol";
import "./InterfaceHub/IFeeManagerLight.sol";
import "./TransferHub/WrapperHelper.sol";
import "./TransferHub/SendValueHelper.sol";
error DeadOracle();
error NotPowerFarm();
error InvalidAction();
error InvalidCaller();
error PositionLocked();
error LiquidatorIsInPowerFarm();
error PositionHasCollateral();
error PositionHasBorrow();
error InvalidAddress();
error InvalidLiquidator();
error ValueIsZero();
error ValueNotZero();
error TooManyTokens();
error TokenNotPresent();
contract WiseLendingDeclaration is
OwnableMaster,
WrapperHelper,
SendValueHelper
{
event FundsDeposited(
address indexed sender,
uint256 indexed nftId,
address indexed token,
uint256 amount,
uint256 shares,
uint256 timestamp
);
event FundsSolelyDeposited(
address indexed sender,
uint256 indexed nftId,
address indexed token,
uint256 amount,
uint256 timestamp
);
event FundsWithdrawn(
address indexed sender,
uint256 indexed nftId,
address indexed token,
uint256 amount,
uint256 shares,
uint256 timestamp
);
event FundsWithdrawnOnBehalf(
address indexed sender,
uint256 indexed nftId,
address indexed token,
uint256 amount,
uint256 shares,
uint256 timestamp
);
event FundsSolelyWithdrawn(
address indexed sender,
uint256 indexed nftId,
address indexed token,
uint256 amount,
uint256 timestamp
);
event FundsBorrowed(
address indexed borrower,
uint256 indexed nftId,
address indexed token,
uint256 amount,
uint256 shares,
uint256 timestamp
);
event FundsBorrowedOnBehalf(
address indexed sender,
uint256 indexed nftId,
address indexed token,
uint256 amount,
uint256 shares,
uint256 timestamp
);
event FundsReturned(
address indexed sender,
address indexed token,
uint256 indexed nftId,
uint256 totalPayment,
uint256 totalPaymentShares,
uint256 timestamp
);
constructor(
address _master,
address _wiseOracleHub,
address _nftContract
)
OwnableMaster(
_master
)
WrapperHelper(
IWiseOracleHub(
_wiseOracleHub
).WETH_ADDRESS()
)
{
if (_wiseOracleHub == ZERO_ADDRESS) {
revert NoValue();
}
if (_nftContract == ZERO_ADDRESS) {
revert NoValue();
}
WISE_ORACLE = IWiseOracleHub(
_wiseOracleHub
);
WETH_ADDRESS = WISE_ORACLE.WETH_ADDRESS();
POSITION_NFT = IPositionNFTs(
_nftContract
);
FEE_MANAGER_NFT = POSITION_NFT.FEE_MANAGER_NFT();
}
function setSecurity(
address _wiseSecurity
)
external
onlyMaster
{
if (address(WISE_SECURITY) > ZERO_ADDRESS) {
revert InvalidAction();
}
WISE_SECURITY = IWiseSecurity(
_wiseSecurity
);
FEE_MANAGER = IFeeManagerLight(
WISE_SECURITY.FEE_MANAGER()
);
AAVE_HUB_ADDRESS = WISE_SECURITY.AAVE_HUB();
}
// AaveHub address
address internal AAVE_HUB_ADDRESS;
// check if it is a powerfarm
bool internal powerFarmCheck;
// Wrapped ETH address
address public immutable WETH_ADDRESS;
// Nft id for feeManager
uint256 immutable FEE_MANAGER_NFT;
uint256 internal constant MIN_BORROW_SHARE_PRICE = 5 * PRECISION_FACTOR_E18
/ 10;
// WiseSecurity interface
IWiseSecurity public WISE_SECURITY;
// FeeManager interface
IFeeManagerLight internal FEE_MANAGER;
// NFT contract interface for positions
IPositionNFTs public immutable POSITION_NFT;
// OraceHub interface
IWiseOracleHub public immutable WISE_ORACLE;
uint256 internal constant GHOST_AMOUNT = 1E3;
// Structs ------------------------------------------
struct LendingEntry {
bool unCollateralized;
uint256 shares;
}
struct BorrowRatesEntry {
uint256 pole;
uint256 deltaPole;
uint256 minPole;
uint256 maxPole;
uint256 multiplicativeFactor;
}
struct AlgorithmEntry {
bool increasePole;
uint256 bestPole;
uint256 maxValue;
uint256 previousValue;
}
struct GlobalPoolEntry {
uint256 totalPool;
uint256 utilization;
uint256 totalBareToken;
uint256 poolFee;
}
struct LendingPoolEntry {
uint256 pseudoTotalPool;
uint256 totalDepositShares;
uint256 collateralFactor;
}
struct BorrowPoolEntry {
bool allowBorrow;
uint256 pseudoTotalBorrowAmount;
uint256 totalBorrowShares;
uint256 borrowRate;
}
struct TimestampsPoolEntry {
uint256 timeStamp;
uint256 timeStampScaling;
uint256 initialTimeStamp;
}
struct CoreLiquidationStruct {
uint256 nftId;
uint256 nftIdLiquidator;
address caller;
address tokenToPayback;
address tokenToRecieve;
uint256 paybackAmount;
uint256 shareAmountToPay;
uint256 maxFeeETH;
uint256 baseRewardLiquidation;
address[] lendTokens;
address[] borrowTokens;
}
modifier onlyAaveHub() {
_onlyAaveHub();
_;
}
function _onlyAaveHub()
private
view
{
if (msg.sender != AAVE_HUB_ADDRESS) {
revert InvalidCaller();
}
}
// Position mappings ------------------------------------------
mapping(address => uint256) internal bufferIncrease;
mapping(address => uint256) public maxDepositValueToken;
mapping(uint256 => address[]) public positionLendTokenData;
mapping(uint256 => address[]) public positionBorrowTokenData;
mapping(uint256 => mapping(address => uint256)) public userBorrowShares;
mapping(uint256 => mapping(address => uint256)) public pureCollateralAmount;
mapping(uint256 => mapping(address => LendingEntry)) public userLendingData;
// Struct mappings -------------------------------------
mapping(address => BorrowRatesEntry) public borrowRatesData;
mapping(address => AlgorithmEntry) public algorithmData;
mapping(address => GlobalPoolEntry) public globalPoolData;
mapping(address => LendingPoolEntry) public lendingPoolData;
mapping(address => BorrowPoolEntry) public borrowPoolData;
mapping(address => TimestampsPoolEntry) public timestampsPoolData;
// Bool mappings -------------------------------------
mapping(uint256 => bool) public positionLocked;
mapping(address => bool) internal parametersLocked;
mapping(address => bool) public verifiedIsolationPool;
// Hash mappings -------------------------------------
mapping(bytes32 => bool) internal hashMapPositionBorrow;
mapping(bytes32 => bool) internal hashMapPositionLending;
// PRECISION FACTORS ------------------------------------
uint256 internal constant PRECISION_FACTOR_E16 = 1E16;
uint256 internal constant PRECISION_FACTOR_E18 = 1E18;
uint256 internal constant PRECISION_FACTOR_E36 = PRECISION_FACTOR_E18 * PRECISION_FACTOR_E18;
// TIME CONSTANTS --------------------------------------
uint256 internal constant ONE_YEAR = 365 days;
uint256 internal constant THREE_HOURS = 3 hours;
uint256 internal constant PRECISION_FACTOR_YEAR = PRECISION_FACTOR_E18 * ONE_YEAR;
// Two months in seconds:
// Norming change in pole value that it steps from min to max value
// within two month (if nothing changes)
uint256 internal constant NORMALISATION_FACTOR = 4838400;
// Default boundary values for pool creation.
uint256 internal constant LOWER_BOUND_MAX_RATE = 100 * PRECISION_FACTOR_E16;
uint256 internal constant UPPER_BOUND_MAX_RATE = 300 * PRECISION_FACTOR_E16;
// LASA CONSTANTS -------------------------
uint256 internal constant THRESHOLD_SWITCH_DIRECTION = 90 * PRECISION_FACTOR_E16;
uint256 internal constant THRESHOLD_RESET_RESONANCE_FACTOR = 75 * PRECISION_FACTOR_E16;
// MORE THRESHHOLD VALUES
uint256 internal constant MAX_COLLATERAL_FACTOR = 85 * PRECISION_FACTOR_E16;
uint256 internal constant MAX_TOTAL_TOKEN_NUMBER = 8;
// APR RESTRICTIONS
uint256 internal constant RESTRICTION_FACTOR = 10
* PRECISION_FACTOR_E36
/ PRECISION_FACTOR_YEAR;
}
IAaveHubLite.sol 11 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
interface IAaveHubLite {
function sendingProgressAaveHub()
external
view
returns (bool);
}
WrapperHelper.sol 47 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
import "../InterfaceHub/IWETH.sol";
contract WrapperHelper {
IWETH internal immutable WETH;
constructor(
address _wethAddress
)
{
WETH = IWETH(
_wethAddress
);
}
/**
* @dev Wrapper for wrapping
* ETH call.
*/
function _wrapETH(
uint256 _value
)
internal
{
WETH.deposit{
value: _value
}();
}
/**
* @dev Wrapper for unwrapping
* ETH call.
*/
function _unwrapETH(
uint256 _value
)
internal
{
WETH.withdraw(
_value
);
}
}
IPositionNFTs.sol 90 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
interface IPositionNFTs {
function ownerOf(
uint256 _nftId
)
external
view
returns (address);
function totalSupply()
external
view
returns (uint256);
function reserved(
address _owner
)
external
view
returns (uint256);
function reservePosition()
external;
function mintPosition()
external
returns (uint256);
function tokenOfOwnerByIndex(
address _owner,
uint256 _index
)
external
view
returns (uint256);
function walletOfOwner(
address _owner
)
external
view
returns (uint256[] memory);
function mintPositionForUser(
address _user
)
external
returns (uint256);
function reservePositionForUser(
address _user
)
external
returns (uint256);
function getNextExpectedId()
external
view
returns (uint256);
function getApproved(
uint256 _nftId
)
external
view
returns (address);
function approve(
address _to,
uint256 _nftId
)
external;
function isOwner(
uint256 _nftId,
address _caller
)
external
view
returns (bool);
function FEE_MANAGER_NFT()
external
view
returns (uint256);
}
IWiseSecurity.sol 252 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
struct CurveSwapStructToken {
uint256 curvePoolTokenIndexFrom;
uint256 curvePoolTokenIndexTo;
uint256 curveMetaPoolTokenIndexFrom;
uint256 curveMetaPoolTokenIndexTo;
}
struct CurveSwapStructData {
address curvePool;
address curveMetaPool;
bytes swapBytesPool;
bytes swapBytesMeta;
}
interface IWiseSecurity {
function checkMinDepositValue(
address _poolToken,
uint256 _amount
)
external
view
returns (bool);
function overallETHBorrow(
uint256 _nftId
)
external
view
returns (uint256 buffer);
function overallETHCollateralsBoth(
uint256 _nftId
)
external
view
returns (uint256 weighted, uint256 unweightedamount);
function getLiveDebtRatio(
uint256 _nftId
)
external
view
returns (uint256);
function checkHealthState(
uint256 _nftId,
bool _isPowerFarm
)
external
view;
function checkPoolCondition(
address _token
)
external
view;
function checkPoolWithMinDeposit(
address _poolToken,
uint256 _amount
)
external
view
returns (bool);
function overallETHBorrowHeartbeat(
uint256 _nftId
)
external
view
returns (uint256 buffer);
function checksLiquidation(
uint256 _nftIdLiquidate,
address _tokenToPayback,
uint256 _shareAmountToPay
)
external
view;
function getPositionLendingAmount(
uint256 _nftId,
address _poolToken
)
external
view
returns (uint256);
function getBorrowRate(
address _poolToken
)
external
view
returns (uint256);
function getPositionBorrowAmount(
uint256 _nftId,
address _poolToken
)
external
view
returns (uint256);
function overallUSDCollateralsBare(
uint256 _nftId
)
external
view
returns (uint256 amount);
function overallETHCollateralsBare(
uint256 _nftId
)
external
view
returns (uint256 amount);
function FEE_MANAGER()
external
view
returns (address);
function AAVE_HUB()
external
view
returns (address);
function curveSecurityCheck(
address _poolAddress
)
external;
function prepareCurvePools(
address _poolToken,
CurveSwapStructData calldata _curveSwapStructData,
CurveSwapStructToken calldata _curveSwapStructToken
)
external;
function overallETHBorrowBare(
uint256 _nftId
)
external
view
returns (uint256 amount);
function checksWithdraw(
uint256 _nftId,
address _caller,
address _poolToken
)
external
view
returns (bool);
function checksBorrow(
uint256 _nftId,
address _caller,
address _poolToken
)
external
view
returns (bool);
function checksSolelyWithdraw(
uint256 _nftId,
address _caller,
address _poolToken
)
external
view
returns (bool);
function checkOwnerPosition(
uint256 _nftId,
address _caller
)
external
view;
function checksCollateralizeDeposit(
uint256 _nftIdCaller,
address _caller,
address _poolAddress
)
external
view;
function calculateWishPercentage(
uint256 _nftId,
address _receiveToken,
uint256 _paybackETH,
uint256 _maxFeeETH,
uint256 _baseRewardLiquidation
)
external
view
returns (uint256);
function checkUncollateralizedDeposit(
uint256 _nftIdCaller,
address _poolToken
)
external
view;
function checkPositionLocked(
uint256 _nftId,
address _caller
)
external
view;
function maxFeeETH()
external
view
returns (uint256);
function maxFeeFarmETH()
external
view
returns (uint256);
function baseRewardLiquidation()
external
view
returns (uint256);
function baseRewardLiquidationFarm()
external
view
returns (uint256);
function checksRegister(
uint256 _nftId,
address _caller
)
external
view;
function getLendingRate(
address _poolToken
)
external
view
returns (uint256);
}
TransferHelper.sol 52 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
import "./CallOptionalReturn.sol";
contract TransferHelper is CallOptionalReturn {
/**
* @dev
* Allows to execute safe transfer for a token
*/
function _safeTransfer(
address _token,
address _to,
uint256 _value
)
internal
{
_callOptionalReturn(
_token,
abi.encodeWithSelector(
IERC20.transfer.selector,
_to,
_value
)
);
}
/**
* @dev
* Allows to execute safe transferFrom for a token
*/
function _safeTransferFrom(
address _token,
address _from,
address _to,
uint256 _value
)
internal
{
_callOptionalReturn(
_token,
abi.encodeWithSelector(
IERC20.transferFrom.selector,
_from,
_to,
_value
)
);
}
}
IWiseOracleHub.sol 104 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
interface IWiseOracleHub {
function getTokensPriceFromUSD(
address _tokenAddress,
uint256 _usdValue
)
external
view
returns (uint256);
function getTokensPriceInUSD(
address _tokenAddress,
uint256 _tokenAmount
)
external
view
returns (uint256);
function latestResolver(
address _tokenAddress
)
external
view
returns (uint256);
function latestResolverTwap(
address _tokenAddress
)
external
view
returns (uint256);
function getTokensFromUSD(
address _tokenAddress,
uint256 _usdValue
)
external
view
returns (uint256);
function getTokensFromETH(
address _tokenAddress,
uint256 _ethValue
)
external
view
returns (uint256);
function getTokensInUSD(
address _tokenAddress,
uint256 _amount
)
external
view
returns (uint256);
function getTokensInETH(
address _tokenAddress,
uint256 _tokenAmount
)
external
view
returns (uint256);
function chainLinkIsDead(
address _tokenAddress
)
external
view
returns (bool);
function decimalsUSD()
external
pure
returns (uint8);
function addOracle(
address _tokenAddress,
address _priceFeedAddress,
address[] calldata _underlyingFeedTokens
)
external;
function recalibrate(
address _tokenAddress
)
external;
function WETH_ADDRESS()
external
view
returns (address);
function priceFeed(
address _tokenAddress
)
external
view
returns (address);
}
SendValueHelper.sol 37 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
error AmountTooSmall();
error SendValueFailed();
contract SendValueHelper {
bool public sendingProgress;
function _sendValue(
address _recipient,
uint256 _amount
)
internal
{
if (address(this).balance < _amount) {
revert AmountTooSmall();
}
sendingProgress = true;
(
bool success
,
) = payable(_recipient).call{
value: _amount
}("");
sendingProgress = false;
if (success == false) {
revert SendValueFailed();
}
}
}
IFeeManagerLight.sol 15 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
interface IFeeManagerLight {
function addPoolTokenAddress(
address _poolToken
)
external;
function updatePositionCurrentBadDebt(
uint256 _nftId
)
external;
}
CallOptionalReturn.sol 39 lines
// SPDX-License-Identifier: -- WISE --
pragma solidity =0.8.25;
import "../InterfaceHub/IERC20.sol";
contract CallOptionalReturn {
/**
* @dev Helper function to do low-level call
*/
function _callOptionalReturn(
address token,
bytes memory data
)
internal
returns (bool call)
{
(
bool success,
bytes memory returndata
) = token.call(
data
);
bool results = returndata.length == 0 || abi.decode(
returndata,
(bool)
);
if (success == false) {
revert();
}
call = success
&& results
&& token.code.length > 0;
}
}
Read Contract
POSITION_NFT 0x7c854ec7 → address
WETH_ADDRESS 0x040141e5 → address
WISE_ORACLE 0x7cc97da5 → address
WISE_SECURITY 0x0f9f234d → address
algorithmData 0x00001536 → bool, uint256, uint256, uint256
borrowPoolData 0x81cc49a3 → bool, uint256, uint256, uint256
borrowRatesData 0x49622c49 → uint256, uint256, uint256, uint256, uint256
calculateBorrowShares 0xca36c04a → uint256
calculateLendingShares 0xef55aa08 → uint256
cashoutAmount 0x65d57877 → uint256
checkDeposit 0x7eb823c8
checkPositionLocked 0xeabad60a
getPositionBorrowShares 0x2a145e25 → uint256
getPositionBorrowTokenByIndex 0x115e8423 → address
getPositionBorrowTokenLength 0x7b1f847c → uint256
getPositionLendingShares 0x951e435d → uint256
getPositionLendingTokenByIndex 0x62aa126d → address
getPositionLendingTokenLength 0x8ba8d15e → uint256
getPseudoTotalBorrowAmount 0x1d0f9fe7 → uint256
getPseudoTotalPool 0xcfdc148f → uint256
getPureCollateralAmount 0x5295bd46 → uint256
getTimeStamp 0xeb470ebf → uint256
getTotalBareToken 0xaa5d03dd → uint256
getTotalBorrowShares 0x40ee5d73 → uint256
getTotalDepositShares 0xca7d9073 → uint256
getTotalPool 0x2ab88d1c → uint256
globalPoolData 0x07ed5000 → uint256, uint256, uint256, uint256
isUncollateralized 0xe65bcf98 → bool
lendingPoolData 0xc1919dd9 → uint256, uint256, uint256
master 0xee97f7f3 → address
maxDepositValueToken 0xc98f4134 → uint256
paybackAmount 0x86b47ce1 → uint256
positionBorrowTokenData 0x6f4330c1 → address
positionLendTokenData 0x2256b491 → address
positionLocked 0x9d0f5450 → bool
proposedMaster 0xd3573a33 → address
pureCollateralAmount 0x6c2b34a8 → uint256
sendingProgress 0x019dbb63 → bool
timestampsPoolData 0xc82c94bf → uint256, uint256, uint256
userBorrowShares 0x251671ac → uint256
userLendingData 0x1f0ae5dc → bool, uint256
verifiedIsolationPool 0x4969b6c1 → bool
Write Contract 39 functions
These functions modify contract state and require a wallet transaction to execute.
borrowExactAmount 0xc7c5c4a7
uint256 _nftId
address _poolToken
uint256 _amount
returns: uint256
borrowExactAmountETH 0x9f61557e
uint256 _nftId
uint256 _amount
returns: uint256
borrowOnBehalfExactAmount 0xc579d753
uint256 _nftId
address _poolToken
uint256 _amount
returns: uint256
claimOwnership 0x4e71e0c8
No parameters
collateralizeDeposit 0xf26f1ea6
uint256 _nftId
address _poolToken
coreLiquidationIsolationPools 0x7fb668c4
uint256 _nftId
uint256 _nftIdLiquidator
address _caller
address _paybackToken
address _receiveToken
uint256 _paybackAmount
uint256 _shareAmountToPay
returns: uint256
corePaybackFeeManager 0xd1f63462
address _poolToken
uint256 _nftId
uint256 _amount
uint256 _shares
createCurvePool 0xbf6ae6b5
tuple _params
tuple _settings
createPool 0xe6550fd9
tuple _params
depositExactAmount 0xd30f6292
uint256 _nftId
address _poolToken
uint256 _amount
returns: uint256
depositExactAmountETH 0xd91c1b50
uint256 _nftId
returns: uint256
depositExactAmountETHMint 0xd8162488
No parameters
returns: uint256
depositExactAmountMint 0x13f7642c
address _poolToken
uint256 _amount
returns: uint256
liquidatePartiallyFromTokens 0x22d7fd02
uint256 _nftId
uint256 _nftIdLiquidator
address _paybackToken
address _receiveToken
uint256 _shareAmountToPay
returns: uint256
paybackExactAmount 0x335956fd
uint256 _nftId
address _poolToken
uint256 _amount
returns: uint256
paybackExactAmountETH 0x12d8947a
uint256 _nftId
returns: uint256
paybackExactShares 0x3d007263
uint256 _nftId
address _poolToken
uint256 _shares
returns: uint256
proposeOwner 0xb5ed298a
address _proposedOwner
renounceOwnership 0x715018a6
No parameters
setParamsLASA 0x02daa233
address _poolToken
uint256 _poolMulFactor
uint256 _upperBoundMaxRate
uint256 _lowerBoundMaxRate
bool _steppingDirection
bool _isFinal
setPoolFee 0x7844a199
address _poolToken
uint256 _newFee
setPoolParameters 0xc5619dfe
address _poolToken
uint256 _collateralFactor
uint256 _maximumDeposit
setRegistrationIsolationPool 0xd6745e78
uint256 _nftId
bool _registerState
setSecurity 0x52228054
address _wiseSecurity
setVerifiedIsolationPool 0x9785d0e7
address _isolationPool
bool _state
solelyDeposit 0x52d7220e
uint256 _nftId
address _poolToken
uint256 _amount
solelyDepositETH 0xc0e6d407
uint256 _nftId
solelyDepositETHMint 0x86c5cb9d
No parameters
solelyDepositMint 0x3dda0c63
address _poolToken
uint256 _amount
solelyWithdraw 0x655ac965
uint256 _nftId
address _poolToken
uint256 _withdrawAmount
solelyWithdrawETH 0xcd886740
uint256 _nftId
uint256 _withdrawAmount
syncManually 0x3fec6386
address _poolToken
unCollateralizeDeposit 0x901accb8
uint256 _nftId
address _poolToken
withdrawExactAmount 0x77cfd4a5
uint256 _nftId
address _poolToken
uint256 _withdrawAmount
returns: uint256
withdrawExactAmountETH 0x99080e70
uint256 _nftId
uint256 _amount
returns: uint256
withdrawExactShares 0xc2e77e44
uint256 _nftId
address _poolToken
uint256 _shares
returns: uint256
withdrawExactSharesETH 0xfa83f4ce
uint256 _nftId
uint256 _shares
returns: uint256
withdrawOnBehalfExactAmount 0xa4c6a7d5
uint256 _nftId
address _poolToken
uint256 _withdrawAmount
returns: uint256
withdrawOnBehalfExactShares 0xaced8d74
uint256 _nftId
address _poolToken
uint256 _shares
returns: uint256
Token Balances (5)
View Transfers →Recent Transactions
No transactions found for this address