Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0xCb1eEA349f25288627f008C5e2a69b684bddDf49
Balance 0 ETH
Nonce 1
Code Size 20829 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

20829 bytes
0x6080604052600436106101a05760003560e01c80638da5cb5b116100ec578063cdf930251161008a578063ee0b3f8111610064578063ee0b3f8114610443578063ef50273814610463578063f2fde38b14610476578063fa483e7214610496576101a7565b8063cdf93025146103f0578063da3e339714610403578063e714faed14610423576101a7565b8063a9b008b6116100c6578063a9b008b614610391578063b7711c63146103a6578063c1fe3e48146103c6578063c75f6955146103db576101a7565b80638da5cb5b1461034057806391f03efd146103555780639f14646f1461037e576101a7565b8063715018a61161015957806382f24a381161013357806382f24a38146102d657806386e54bc5146102eb5780638b2704ec146102fe5780638b446a3c14610313576101a7565b8063715018a61461027c57806372536f821461029157806372a8b9d7146102c1576101a7565b80630e8cc705146101ac5780631db00932146101c15780634f746bfc146101ec57806353ba28d91461021a5780635fdf4d4c1461023a57806363d0aefd1461025c576101a7565b366101a757005b600080fd5b6101bf6101ba366004614016565b6104b6565b005b3480156101cd57600080fd5b506101d6610651565b6040516101e39190615031565b60405180910390f35b3480156101f857600080fd5b5061020c610207366004613ea4565b610656565b6040516101e39291906149db565b34801561022657600080fd5b506101bf610235366004613f3c565b610689565b34801561024657600080fd5b5061024f6106f3565b6040516101e391906148bc565b34801561026857600080fd5b506101bf610277366004613edc565b61070b565b34801561028857600080fd5b506101bf61080a565b34801561029d57600080fd5b506102b16102ac366004613e6c565b610893565b6040516101e39493929190614a26565b3480156102cd57600080fd5b5061024f6108cb565b3480156102e257600080fd5b5061024f6108ef565b6101d66102f9366004614156565b610907565b34801561030a57600080fd5b5061024f61096c565b34801561031f57600080fd5b5061033361032e366004613e6c565b610990565b6040516101e39190614a1b565b34801561034c57600080fd5b5061024f6109a5565b34801561036157600080fd5b5061036a6109b5565b6040516101e398979695949392919061496d565b6101d661038c3660046141a3565b6109f5565b34801561039d57600080fd5b5061024f610a88565b3480156103b257600080fd5b506101bf6103c1366004613e6c565b610aa0565b3480156103d257600080fd5b5061024f610d40565b3480156103e757600080fd5b5061024f610d64565b6101d66103fe36600461423b565b610d7c565b34801561040f57600080fd5b506101bf61041e3660046140b3565b610e38565b34801561042f57600080fd5b5061024f61043e366004613e6c565b610ea5565b34801561044f57600080fd5b506101bf61045e3660046140f3565b610ec0565b6101d66104713660046142f8565b610f9c565b34801561048257600080fd5b506101bf610491366004613e6c565b611013565b3480156104a257600080fd5b506101bf6104b1366004614359565b6110d3565b6104be611615565b6001600160a01b03166104cf6109a5565b6001600160a01b0316146104fe5760405162461bcd60e51b81526004016104f590614df2565b60405180910390fd5b60005b8281101561064b5773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee84848381811061052a57fe5b905060200201602081019061053f9190613e6c565b6001600160a01b0316141561056c576105676001600160a01b0383164763ffffffff61161916565b610643565b6106438285858481811061057c57fe5b90506020020160208101906105919190613e6c565b6001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016105bc91906148bc565b60206040518083038186803b1580156105d457600080fd5b505afa1580156105e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060c91906143d6565b86868581811061061857fe5b905060200201602081019061062d9190613e6c565b6001600160a01b0316919063ffffffff6116ba16565b600101610501565b50505050565b600a81565b6004602081815260009384526040808520909152918352912060028101549101546001600160a01b039091169060ff1682565b610691611615565b6001600160a01b03166106a26109a5565b6001600160a01b0316146106c85760405162461bcd60e51b81526004016104f590614df2565b6001600160a01b03919091166000908152600560205260409020805460ff1916911515919091179055565b73c186fa914353c44b2e33ebe05f21846f1048beda81565b610713611615565b6001600160a01b03166107246109a5565b6001600160a01b03161461074a5760405162461bcd60e51b81526004016104f590614df2565b6001600160a01b038084166000908152600460209081526040808320938616835292815291902082518051849361078592849291019061397a565b50602082810151805161079e92600185019201906139df565b5060408201516002820180546001600160a01b0319166001600160a01b03909216919091179055606082015180516107e0916003840191602090910190613a87565b50608082015160048201805460ff191660018360058111156107fe57fe5b02179055505050505050565b610812611615565b6001600160a01b03166108236109a5565b6001600160a01b0316146108495760405162461bcd60e51b81526004016104f590614df2565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b600360208190526000918252604090912080546001820154600283015492909301546001600160a01b03918216938216929091169084565b7f00000000000000000000000004b59f9f09750c044d7cfbc177561e409085f0f381565b73bf28c9fcb12a97441488f9c68faa49811a98688a81565b60006002600154141561092c5760405162461bcd60e51b81526004016104f590614ed6565b6002600155600061093e858585611710565b9050610960610953348363ffffffff6118b916565b339063ffffffff61161916565b60018055949350505050565b7f000000000000000000000000d2463675a099101e36d85278494268261a66603a81565b60056020526000908152604090205460ff1681565b6000546001600160a01b03165b90565b600654600754600854600954600a54600b54600c54600d546001600160a01b03978816979687169695861695948516949384169392831692918216911688565b600060026001541415610a1a5760405162461bcd60e51b81526004016104f590614ed6565b60026001556000610a2d888883866118e6565b90506000610a3c878387611aa6565b905085811015610a5e5760405162461bcd60e51b81526004016104f590614ca4565b610a786001600160a01b038816338363ffffffff6116ba16565b6001805598975050505050505050565b73e1b4d34e8754600962cd944b535180bd758e6c2e81565b604051631d3af8fb60e21b815281906001600160a01b037f000000000000000000000000d2463675a099101e36d85278494268261a66603a16906374ebe3ec90610aee9084906004016148bc565b60206040518083038186803b158015610b0657600080fd5b505afa158015610b1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3e9190614097565b610b5a5760405162461bcd60e51b81526004016104f590614dc2565b6060826001600160a01b03166399d50d5d6040518163ffffffff1660e01b815260040160006040518083038186803b158015610b9557600080fd5b505afa158015610ba9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610bd19190810190613f69565b905060005b8151811015610c9d57818181518110610beb57fe5b60200260200101516001600160a01b031663095ea7b37f00000000000000000000000004b59f9f09750c044d7cfbc177561e409085f0f36000196040518363ffffffff1660e01b8152600401610c429291906148f9565b602060405180830381600087803b158015610c5c57600080fd5b505af1158015610c70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c949190614097565b50600101610bd6565b5060405163095ea7b360e01b81526001600160a01b0384169063095ea7b390610cee907f00000000000000000000000004b59f9f09750c044d7cfbc177561e409085f0f390600019906004016148f9565b602060405180830381600087803b158015610d0857600080fd5b505af1158015610d1c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061064b9190614097565b7f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe8481565b7328f77208728b0a45cab24c4868334581fe86f95b81565b600060026001541415610da15760405162461bcd60e51b81526004016104f590614ed6565b6002600155610dc16001600160a01b03871633308863ffffffff611cac16565b6000610dce878787611ccd565b9050610deb610dde8a8a86611710565b829063ffffffff6118b916565b90506000610dfa888387611aa6565b9050610e166001600160a01b038916338363ffffffff6116ba16565b610e26878263ffffffff6118b916565b600180559a9950505050505050505050565b610e40611615565b6001600160a01b0316610e516109a5565b6001600160a01b031614610e775760405162461bcd60e51b81526004016104f590614df2565b60405163095ea7b360e01b81526001600160a01b0384169063095ea7b390610cee90859085906004016148f9565b6002602052600090815260409020546001600160a01b031681565b610ec8611615565b6001600160a01b0316610ed96109a5565b6001600160a01b031614610eff5760405162461bcd60e51b81526004016104f590614df2565b6001600160a01b03948516600081815260026020818152604080842080546001600160a01b0319908116988c169889179091558151608081018352958652988a16858301908152978a16858201908152606086019687529684526003918290529092209251835488169089161783559451600183018054881691891691909117905592519381018054909516939095169290921790925551910155565b600060026001541415610fc15760405162461bcd60e51b81526004016104f590614ed6565b60026001556000610fd4868686866118e6565b905083811015610ff65760405162461bcd60e51b81526004016104f590614ca4565b611006338263ffffffff61161916565b6001805595945050505050565b61101b611615565b6001600160a01b031661102c6109a5565b6001600160a01b0316146110525760405162461bcd60e51b81526004016104f590614df2565b6001600160a01b0381166110785760405162461bcd60e51b81526004016104f590614ab0565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b33600090815260036020526040902060018101546001600160a01b031661110c5760405162461bcd60e51b81526004016104f590614e27565b60008512156111a357805460405163a9059cbb60e01b81526000879003916001600160a01b03169063a9059cbb9061114a90339085906004016148f9565b602060405180830381600087803b15801561116457600080fd5b505af1158015611178573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061119c9190614097565b505061160e565b60008412156115f65760008460000390506000611266670de0b6b3a764000061125a8560010160009054906101000a90046001600160a01b03166001600160a01b0316633ba0b9a96040518163ffffffff1660e01b815260040160206040518083038186803b15801561121557600080fd5b505afa158015611229573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124d91906143d6565b859063ffffffff611edc16565b9063ffffffff611f1616565b6001840154604051635c7c159360e11b81529192506000916001600160a01b039091169063b8f82b26906112a090849086906004016148f9565b60206040518083038186803b1580156112b857600080fd5b505afa1580156112cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f091906143d6565b90508281101561131557670de0b6b3a7640000846003015483028161131157fe5b0491505b60028401546001600160a01b031673e1b4d34e8754600962cd944b535180bd758e6c2e14156114d857604051634e3c04bd60e01b815273bf28c9fcb12a97441488f9c68faa49811a98688a90634e3c04bd90849061137590600401614e44565b6000604051808303818588803b15801561138e57600080fd5b505af11580156113a2573d6000803e3d6000fd5b50506040516370a0823160e01b81526000935073e1b4d34e8754600962cd944b535180bd758e6c2e92506370a0823191506113e19030906004016148bc565b60206040518083038186803b1580156113f957600080fd5b505afa15801561140d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061143191906143d6565b60018601546040516320e8c56560e01b81529192506001600160a01b0316906320e8c5659061147f90309073e1b4d34e8754600962cd944b535180bd758e6c2e9086906000906004016148d0565b602060405180830381600087803b15801561149957600080fd5b505af11580156114ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d191906143d6565b5050611567565b60018401546040516320e8c56560e01b81526001600160a01b03909116906320e8c565908490611513903090600090849082906004016148d0565b6020604051808303818588803b15801561152c57600080fd5b505af1158015611540573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061156591906143d6565b505b600184015460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061159b90339087906004016148f9565b602060405180830381600087803b1580156115b557600080fd5b505af11580156115c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ed9190614097565b5050505061160e565b60405162461bcd60e51b81526004016104f590614a86565b5050505050565b3390565b804710156116395760405162461bcd60e51b81526004016104f590614bc1565b6000826001600160a01b031682604051611652906109b2565b60006040518083038185875af1925050503d806000811461168f576040519150601f19603f3d011682016040523d82523d6000602084013e611694565b606091505b50509050806116b55760405162461bcd60e51b81526004016104f590614b64565b505050565b6116b58363a9059cbb60e01b84846040516024016116d99291906148f9565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611f48565b60006060807f00000000000000000000000004b59f9f09750c044d7cfbc177561e409085f0f36001600160a01b031663131e26b987876040518363ffffffff1660e01b81526004016117639291906148f9565b60006040518083038186803b15801561177b57600080fd5b505afa15801561178f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526117b79190810190613f9c565b5090925090504760005b83518110156118165761180e8482815181106117d957fe5b60200260200101518483815181106117ed57fe5b602002602001015188848151811061180157fe5b6020026020010151611fd7565b6001016117c1565b506040516336bc7a3d60e11b81526001600160a01b037f00000000000000000000000004b59f9f09750c044d7cfbc177561e409085f0f31690636d78f47a90611867908a908a903390600401614a50565b600060405180830381600087803b15801561188157600080fd5b505af1158015611895573d6000803e3d6000fd5b505050506118ac47826118b990919063ffffffff16565b93505050505b9392505050565b6000828211156118db5760405162461bcd60e51b81526004016104f590614b2d565b508082035b92915050565b6000476119046001600160a01b03871633308863ffffffff611cac16565b604051635c833bfd60e01b81526001600160a01b037f00000000000000000000000004b59f9f09750c044d7cfbc177561e409085f0f31690635c833bfd9061195490899089903090600401614a50565b600060405180830381600087803b15801561196e57600080fd5b505af1158015611982573d6000803e3d6000fd5b505050506060807f00000000000000000000000004b59f9f09750c044d7cfbc177561e409085f0f36001600160a01b0316636b8e53b689896040518363ffffffff1660e01b81526004016119d79291906148f9565b60006040518083038186803b1580156119ef57600080fd5b505afa158015611a03573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611a2b9190810190613f9c565b50909250905060005b8251811015611a8957611a81838281518110611a4c57fe5b6020026020010151838381518110611a6057fe5b6020026020010151888481518110611a7457fe5b602002602001015161245f565b600101611a34565b50611a9a478463ffffffff6118b916565b98975050505050505050565b600d546000906001600160a01b0385811691161415611b265750600d5460408051630d0e30db60e41b8152905184926001600160a01b03169163d0e30db091849160048082019260009290919082900301818588803b158015611b0857600080fd5b505af1158015611b1c573d6000803e3d6000fd5b50505050506118b2565b600d54825180516001600160a01b0390921691600090611b4257fe5b60200260200101516001600160a01b03161415611bba57600d5460408051630d0e30db60e41b815290516001600160a01b039092169163d0e30db0918691600480830192600092919082900301818588803b158015611ba057600080fd5b505af1158015611bb4573d6000803e3d6000fd5b50505050505b60408051610100810182526006546001600160a01b0390811682526007548116602083015260085481168284015260095481166060830152600a5481166080830152600b54811660a0830152600c54811660c0830152600d541660e08201529051622e1a3760e31b81527328764a27139d7241c9198c43720a0df1c18e50ef91630170d1b891611c54919087906000908890600401614f0d565b60206040518083038186803b158015611c6c57600080fd5b505af4158015611c80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ca491906143d6565b949350505050565b61064b846323b872dd60e01b8585856040516024016116d9939291906149b7565b600d546000906001600160a01b0385811691161415611d4e5750600d54604051632e1a7d4d60e01b815283916001600160a01b031690632e1a7d4d90611d17908490600401615031565b600060405180830381600087803b158015611d3157600080fd5b505af1158015611d45573d6000803e3d6000fd5b505050506118b2565b60408051610100810182526006546001600160a01b0390811682526007548116602083015260085481168284015260095481166060830152600a5481166080830152600b54811660a0830152600c54811660c0830152600d541660e08201529051622e1a3760e31b81527328764a27139d7241c9198c43720a0df1c18e50ef91630170d1b891611de8919087906000908890600401614f0d565b60206040518083038186803b158015611e0057600080fd5b505af4158015611e14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e3891906143d6565b600d54835180519293506001600160a01b03909116916000198101908110611e5c57fe5b60200260200101516001600160a01b031614156118b257600d54604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d90611ea3908490600401615031565b600060405180830381600087803b158015611ebd57600080fd5b505af1158015611ed1573d6000803e3d6000fd5b505050509392505050565b600082611eeb575060006118e0565b82820282848281611ef857fe5b04146118b25760405162461bcd60e51b81526004016104f590614d81565b6000808211611f375760405162461bcd60e51b81526004016104f590614c3e565b818381611f4057fe5b049392505050565b6060611f9d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612a8b9092919063ffffffff16565b8051909150156116b55780806020019051810190611fbb9190614097565b6116b55760405162461bcd60e51b81526004016104f590614e8c565b600081608001516005811115611fe957fe5b14611ffe57611ff9838383612a9a565b6116b5565b61200783613006565b1561201657611ff98383613028565b60006120218461310e565b90506001600160a01b038116156120435761203d84848361313e565b506116b5565b6001600160a01b0384167328f77208728b0a45cab24c4868334581fe86f95b14156120715761203d836131ec565b600d546001600160a01b03858116911614156120ed57600d5460408051630d0e30db60e41b815290516001600160a01b039092169163d0e30db0918691600480830192600092919082900301818588803b1580156120ce57600080fd5b505af11580156120e2573d6000803e3d6000fd5b5050505050506116b5565b6001600160a01b03841660009081526005602052604090205460ff16156124475760405163b3d7f6b960e01b81526000906001600160a01b0386169063b3d7f6b99061213d908790600401615031565b60206040518083038186803b15801561215557600080fd5b505afa158015612169573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218d91906143d6565b90506000856001600160a01b03166338d52e0f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156121ca57600080fd5b505afa1580156121de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122029190613e88565b6001600160a01b03811660009081527ff0f2fe64297d6f5ba18daddd165143adda9d1be31e3172fbca589ee2e039f82b60209081526040918290208251815460c09381028201840190945260a081018481529495506123be948694889492939284929184918401828280156122a057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612282575b505050505081526020016001820180548060200260200160405190810160405280929190818152602001828054801561232257602002820191906000526020600020906000905b82829054906101000a900462ffffff1662ffffff16815260200190600301906020826002010492830192600103820291508084116122e75790505b505050918352505060028201546001600160a01b0316602080830191909152600383018054604080518285028101850182528281529401939283018282801561238a57602002820191906000526020600020905b815481526020019060010190808311612376575b5050509183525050600482015460209091019060ff1660058111156123ab57fe5b60058111156123b657fe5b905250612a9a565b6040516394bf804d60e01b81526001600160a01b038716906394bf804d906123ec908890309060040161503a565b602060405180830381600087803b15801561240657600080fd5b505af115801561241a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243e91906143d6565b505050506116b5565b60405162461bcd60e51b81526004016104f590614d36565b60008160800151600581111561247157fe5b14612700578051516001106124985760405162461bcd60e51b81526004016104f590614c75565b826001600160a01b031681600001516000815181106124b357fe5b60200260200101516001600160a01b0316146124e15760405162461bcd60e51b81526004016104f590614d09565b8051805173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9190600019810190811061250a57fe5b60200260200101516001600160a01b031614806125565750600d54815180516001600160a01b0390921691600019810190811061254357fe5b60200260200101516001600160a01b0316145b6125725760405162461bcd60e51b81526004016104f590614cdb565b60408051610100810182526006546001600160a01b0390811682526007548116602083015260085481168284015260095481166060830152600a5481166080830152600b54811660a0830152600c54811660c0830152600d541660e08201529051622e1a3760e31b81526000917328764a27139d7241c9198c43720a0df1c18e50ef91630170d1b89161260d91879086908890600401614f0d565b60206040518083038186803b15801561262557600080fd5b505af4158015612639573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061265d91906143d6565b600d54835180519293506001600160a01b0390911691600019810190811061268157fe5b60200260200101516001600160a01b0316141561203d57600d54604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d906126c8908490600401615031565b600060405180830381600087803b1580156126e257600080fd5b505af11580156126f6573d6000803e3d6000fd5b50505050506116b5565b61270983613006565b1561271857611ff98383613336565b6001600160a01b038084166000908152600260205260409020541680156127445761203d8484836133e9565b6001600160a01b0384167328f77208728b0a45cab24c4868334581fe86f95b14156127725761203d8361362a565b600d546001600160a01b03858116911614156127b857600d54604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d906126c8908690600401615031565b6001600160a01b03841660009081526005602052604090205460ff1615612447576000846001600160a01b03166338d52e0f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561281457600080fd5b505afa158015612828573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284c9190613e88565b90506000856001600160a01b031663ba0876528630306040518463ffffffff1660e01b815260040161288093929190615051565b602060405180830381600087803b15801561289a57600080fd5b505af11580156128ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128d291906143d6565b6001600160a01b038316600090815260046020908152604080832073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee84528252918290208251815460c09381028201840190945260a0810184815294955061243e9487948794929392849291849184018282801561296d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161294f575b50505050508152602001600182018054806020026020016040519081016040528092919081815260200182805480156129ef57602002820191906000526020600020906000905b82829054906101000a900462ffffff1662ffffff16815260200190600301906020826002010492830192600103820291508084116129b45790505b505050918352505060028201546001600160a01b03166020808301919091526003830180546040805182850281018501825282815294019392830182828015612a5757602002820191906000526020600020905b815481526020019060010190808311612a43575b5050509183525050600482015460209091019060ff166005811115612a7857fe5b6005811115612a8357fe5b905250611ccd565b6060611ca4848460008561369f565b600d546001600160a01b0384811691161415612af757600d5460408051630d0e30db60e41b815290516001600160a01b039092169163d0e30db0918591600480830192600092919082900301818588803b1580156126e257600080fd5b805151600110612b195760405162461bcd60e51b81526004016104f590614c75565b8051805173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9190600090612b3d57fe5b60200260200101516001600160a01b03161480612b845750600d54815180516001600160a01b0390921691600090612b7157fe5b60200260200101516001600160a01b0316145b612ba05760405162461bcd60e51b81526004016104f590614d09565b805180516001600160a01b03851691906000198101908110612bbe57fe5b60200260200101516001600160a01b031614612bec5760405162461bcd60e51b81526004016104f590614cdb565b600d54815180516001600160a01b0390921691600090612c0857fe5b60200260200101516001600160a01b03161415612f1c57600d546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612c509030906004016148bc565b60206040518083038186803b158015612c6857600080fd5b505afa158015612c7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ca091906143d6565b600d5460408051630d0e30db60e41b815290519293506001600160a01b039091169163d0e30db0914791600480830192600092919082900301818588803b158015612cea57600080fd5b505af1158015612cfe573d6000803e3d6000fd5b505060408051610100810182526006546001600160a01b0390811682526007548116602083015260085481168284015260095481166060830152600a5481166080830152600b54811660a0830152600c54811660c0830152600d541660e0820181905291516370a0823160e01b81527328764a27139d7241c9198c43720a0df1c18e50ef9550639f564f8494509092508791906370a0823190612da59030906004016148bc565b60206040518083038186803b158015612dbd57600080fd5b505afa158015612dd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612df591906143d6565b866040518563ffffffff1660e01b8152600401612e159493929190614f0d565b60206040518083038186803b158015612e2d57600080fd5b505af4158015612e41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6591906143d6565b50600d546040516370a0823160e01b81526001600160a01b0390911690632e1a7d4d90612f0090849084906370a0823190612ea49030906004016148bc565b60206040518083038186803b158015612ebc57600080fd5b505afa158015612ed0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ef491906143d6565b9063ffffffff6118b916565b6040518263ffffffff1660e01b81526004016126c89190615031565b60408051610100810182526006546001600160a01b0390811682526007548116602083015260085481168284015260095481166060830152600a5481166080830152600b54811660a0830152600c54811660c0830152600d541660e082015290516327d593e160e21b81527328764a27139d7241c9198c43720a0df1c18e50ef91639f564f8491612fb69190869047908790600401614f0d565b60206040518083038186803b158015612fce57600080fd5b505af4158015612fe2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061064b91906143d6565b6001600160a01b031673a0d3707c569ff8c87fa923d3823ec5d81c98be781490565b60405163b3d7f6b960e01b81526000906001600160a01b0384169063b3d7f6b990613057908590600401615031565b60206040518083038186803b15801561306f57600080fd5b505afa158015613083573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130a791906143d6565b90506130b281613760565b6040516394bf804d60e01b81526001600160a01b038416906394bf804d906130e0908590309060040161503a565b602060405180830381600087803b1580156130fa57600080fd5b505af1158015612fe2573d6000803e3d6000fd5b6001600160a01b039081166000908152600260209081526040808320548416835260039091529020600101541690565b6001600160a01b03808416600090815260026020908152604091829020548251808401845260018152606160f81b928101929092529151635b709f1760e01b81529190921691635b709f179161319b913091879190600401614946565b6040805180830381600087803b1580156131b457600080fd5b505af11580156131c8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061160e91906143ee565b600d5460405163e0f339e360e01b81526000916132b891600a916132ac91670de0b6b3a76400009161125a91889173c186fa914353c44b2e33ebe05f21846f1048beda9163e0f339e39161324e916001600160a01b03909116906004016148bc565b602060405180830381600087803b15801561326857600080fd5b505af115801561327c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132a091906143d6565b9063ffffffff611edc16565b9063ffffffff61380516565b600d546040516256688760e81b815291925073c186fa914353c44b2e33ebe05f21846f1048beda916356688700918491613300916001600160a01b03169083906004016148f9565b6000604051808303818588803b15801561331957600080fd5b505af115801561332d573d6000803e3d6000fd5b50505050505050565b604051635d043b2960e11b81526000906001600160a01b0384169063ba0876529061336990859030908190600401615051565b602060405180830381600087803b15801561338357600080fd5b505af1158015613397573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133bb91906143d6565b905061064b817f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84600061382a565b60408051808201825260018152606160f81b602082015290516329910b1160e01b81526000916001600160a01b038416916329910b11916134309130918891600401614946565b6040805180830381600087803b15801561344957600080fd5b505af115801561345d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061348191906143ee565b506001600160a01b0380841660009081526003602052604080822060018101546002820154925163769f8e5d60e01b8152959650909492939081169263769f8e5d926134db92309289929091169087908190600401614912565b602060405180830381600087803b1580156134f557600080fd5b505af1158015613509573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061352d91906143d6565b600283015490915061354b9082906001600160a01b0316600061382a565b50600d546040516370a0823160e01b81526001600160a01b0390911690632e1a7d4d9082906370a08231906135849030906004016148bc565b60206040518083038186803b15801561359c57600080fd5b505afa1580156135b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135d491906143d6565b6040518263ffffffff1660e01b81526004016135f09190615031565b600060405180830381600087803b15801561360a57600080fd5b505af115801561361e573d6000803e3d6000fd5b50505050505050505050565b600d546040516301dc515160e31b815273c186fa914353c44b2e33ebe05f21846f1048beda91630ee28a8891613671916001600160a01b03169085906001906004016149f8565b600060405180830381600087803b15801561368b57600080fd5b505af115801561160e573d6000803e3d6000fd5b6060824710156136c15760405162461bcd60e51b81526004016104f590614bf8565b6136ca8561393b565b6136e65760405162461bcd60e51b81526004016104f590614e55565b60006060866001600160a01b0316858760405161370391906148a0565b60006040518083038185875af1925050503d8060008114613740576040519150601f19603f3d011682016040523d82523d6000602084013e613745565b606091505b5091509150613755828286613941565b979650505050505050565b60405163a1903eab60e01b81526001600160a01b037f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84169063a1903eab9083906137af906000906004016148bc565b6020604051808303818588803b1580156137c857600080fd5b505af11580156137dc573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061380191906143d6565b5050565b6000828201838110156118b25760405162461bcd60e51b81526004016104f590614af6565b60408051610100810182526006546001600160a01b039081168252600754811660208084019190915260085482168385015260095482166060840152600a5482166080840152600b54821660a0840152600c54821660c0840152600d54821660e0840152858216600090815260048083528582209387168252929091528381209351622e1a3760e31b815290937328764a27139d7241c9198c43720a0df1c18e50ef93630170d1b8936138e39391928a92889201614f3d565b60206040518083038186803b1580156138fb57600080fd5b505af415801561390f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061393391906143d6565b509392505050565b3b151590565b606083156139505750816118b2565b8251156139605782518084602001fd5b8160405162461bcd60e51b81526004016104f59190614a73565b8280548282559060005260206000209081019282156139cf579160200282015b828111156139cf57825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019061399a565b506139db929150613ace565b5090565b82805482825590600052602060002090600901600a90048101928215613a7b5791602002820160005b83821115613a4a57835183826101000a81548162ffffff021916908362ffffff1602179055509260200192600301602081600201049283019260010302613a08565b8015613a795782816101000a81549062ffffff0219169055600301602081600201049283019260010302613a4a565b505b506139db929150613af2565b828054828255906000526020600020908101928215613ac2579160200282015b82811115613ac2578251825591602001919060010190613aa7565b506139db929150613b12565b6109b291905b808211156139db5780546001600160a01b0319168155600101613ad4565b6109b291905b808211156139db57805462ffffff19168155600101613af8565b6109b291905b808211156139db5760008155600101613b18565b80356118e081615101565b600082601f830112613b47578081fd5b8135613b5a613b5582615097565b615070565b818152915060208083019084810181840286018201871015613b7b57600080fd5b60005b84811015613ba3578135613b9181615101565b84529282019290820190600101613b7e565b505050505092915050565b600082601f830112613bbe578081fd5b8151613bcc613b5582615097565b818152915060208083019084810181840286018201871015613bed57600080fd5b60005b84811015613ba3578151613c0381615101565b84529282019290820190600101613bf0565b600082601f830112613c25578081fd5b8135613c33613b5582615097565b818152915060208083019084810181840286018201871015613c5457600080fd5b60005b84811015613ba357813584529282019290820190600101613c57565b600082601f830112613c83578081fd5b8135613c91613b5582615097565b818152915060208083019084810160005b84811015613ba357613cb9888484358a0101613db3565b84529282019290820190600101613ca2565b600082601f830112613cdb578081fd5b8135613ce9613b5582615097565b818152915060208083019084810181840286018201871015613d0a57600080fd5b6000805b85811015613d3a57823562ffffff81168114613d28578283fd5b85529383019391830191600101613d0e565b50505050505092915050565b600082601f830112613d56578081fd5b8151613d64613b5582615097565b818152915060208083019084810181840286018201871015613d8557600080fd5b60005b84811015613ba357815184529282019290820190600101613d88565b8035600681106118e057600080fd5b600060a08284031215613dc4578081fd5b613dce60a0615070565b9050813567ffffffffffffffff80821115613de857600080fd5b613df485838601613b37565b83526020840135915080821115613e0a57600080fd5b613e1685838601613ccb565b6020840152613e288560408601613b2c565b60408401526060840135915080821115613e4157600080fd5b50613e4e84828501613c15565b606083015250613e618360808401613da4565b608082015292915050565b600060208284031215613e7d578081fd5b81356118b281615101565b600060208284031215613e99578081fd5b81516118b281615101565b60008060408385031215613eb6578081fd5b8235613ec181615101565b91506020830135613ed181615101565b809150509250929050565b600080600060608486031215613ef0578081fd5b8335613efb81615101565b92506020840135613f0b81615101565b9150604084013567ffffffffffffffff811115613f26578182fd5b613f3286828701613db3565b9150509250925092565b60008060408385031215613f4e578182fd5b8235613f5981615101565b91506020830135613ed181615119565b600060208284031215613f7a578081fd5b815167ffffffffffffffff811115613f90578182fd5b611ca484828501613bae565b600080600060608486031215613fb0578081fd5b835167ffffffffffffffff80821115613fc7578283fd5b613fd387838801613bae565b94506020860151915080821115613fe8578283fd5b613ff487838801613d46565b93506040860151915080821115614009578283fd5b50613f3286828701613d46565b60008060006040848603121561402a578081fd5b833567ffffffffffffffff80821115614041578283fd5b81860187601f820112614052578384fd5b8035925081831115614062578384fd5b8760208085028301011115614075578384fd5b602090810195509193505084013561408c81615101565b809150509250925092565b6000602082840312156140a8578081fd5b81516118b281615119565b6000806000606084860312156140c7578081fd5b83356140d281615101565b925060208401356140e281615101565b929592945050506040919091013590565b600080600080600060a0868803121561410a578283fd5b853561411581615101565b9450602086013561412581615101565b9350604086013561413581615101565b9250606086013561414581615101565b949793965091946080013592915050565b60008060006060848603121561416a578081fd5b833561417581615101565b925060208401359150604084013567ffffffffffffffff811115614197578182fd5b613f3286828701613c73565b60008060008060008060c087890312156141bb578384fd5b86356141c681615101565b95506020870135945060408701356141dd81615101565b935060608701359250608087013567ffffffffffffffff80821115614200578283fd5b61420c8a838b01613db3565b935060a0890135915080821115614221578283fd5b5061422e89828a01613c73565b9150509295509295509295565b600080600080600080600060e0888a031215614255578485fd5b873561426081615101565b965060208801359550604088013561427781615101565b945060608801359350608088013567ffffffffffffffff8082111561429a578283fd5b6142a68b838c01613db3565b945060a08a01359150808211156142bb578283fd5b6142c78b838c01613db3565b935060c08a01359150808211156142dc578283fd5b506142e98a828b01613c73565b91505092959891949750929550565b6000806000806080858703121561430d578182fd5b843561431881615101565b93506020850135925060408501359150606085013567ffffffffffffffff811115614341578182fd5b61434d87828801613c73565b91505092959194509250565b6000806000806060858703121561436e578182fd5b8435935060208501359250604085013567ffffffffffffffff80821115614393578384fd5b81870188601f8201126143a4578485fd5b80359250818311156143b4578485fd5b8860208483010111156143c5578485fd5b959894975050602090940194505050565b6000602082840312156143e7578081fd5b5051919050565b60008060408385031215614400578182fd5b505080516020909101519092909150565b6001600160a01b0316815260200190565b6001600160a01b03169052565b6000815180845260208085019450808401835b8381101561445e57815187529582019590820190600101614442565b509495945050505050565b6000815480845260208085019450838352808320835b8381101561445e5781548752958201956001918201910161447f565b6000815180845260208085019450808401835b8381101561445e57815162ffffff16875295820195908201906001016144ae565b600081546144dd8185615031565b93506144e8836150b7565b825b826009820110156145c657815462ffffff61450788828416614897565b61451960208901828460181c16614897565b61452b60408901828460301c16614897565b606061453e818a01838560481c16614897565b61454f60808a018385841c16614897565b5061456260a08901828460781c16614897565b60c0614575818a01838560901c16614897565b61458760e08a01838560a81c16614897565b6145996101008a018385841c16614897565b506145ad6101208901828460d81c16614897565b5050610140959095019460019190910190600a016144ea565b8154838210156145ec576145df8762ffffff8316614897565b6020870196506001820191505b83821015614613576146068762ffffff8360181c16614897565b6020870196506001820191505b8382101561463a5761462d8762ffffff8360301c16614897565b6020870196506001820191505b83821015614661576146548762ffffff8360481c16614897565b6020870196506001820191505b838210156146885761467b8762ffffff8360601c16614897565b6020870196506001820191505b838210156146af576146a28762ffffff8360781c16614897565b6020870196506001820191505b838210156146d6576146c98762ffffff8360901c16614897565b6020870196506001820191505b838210156146fd576146f08762ffffff8360a81c16614897565b6020870196506001820191505b83821015614724576147178762ffffff8360c01c16614897565b6020870196506001820191505b8382101561445e5761473e8762ffffff8360d81c16614897565b5050506020939093019392505050565b600081518084526147668160208601602086016150cf565b601f01601f19169290920160200192915050565b6006811061478457fe5b9052565b80516001600160a01b03908116835260208083015182169084015260408083015182169084015260608083015182169084015260808083015182169084015260a08281015182169084015260c08083015182169084015260e09182015116910152565b600060a08301825160a085528181516148048185615031565b60209450859390925084015b8184101561483357614823838251614411565b6001949094019392508401614810565b50508285015191508581038387015261484c818361449b565b9250505060408301516148626040860182614422565b506060830151848203606086015261487a828261442f565b6080850151925061488e608087018461477a565b95945050505050565b62ffffff169052565b600082516148b28184602087016150cf565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03958616815260208101949094529190931660408301526060820192909252901515608082015260a00190565b600060018060a01b03851682528360208301526060604083015261488e606083018461474e565b6001600160a01b0398891681529688166020880152948716604087015292861660608601529085166080850152841660a0840152831660c083015290911660e08201526101000190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0383168152604081016118b2602083018461477a565b6001600160a01b0393909316835260208301919091521515604082015260600190565b901515815260200190565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b6000602082526118b2602083018461474e565b60208082526010908201526f496e76616c69642063616c6c6261636b60801b604082015260600190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601e908201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604082015260600190565b6020808252603a908201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260408201527f6563697069656e74206d61792068617665207265766572746564000000000000606082015260800190565b6020808252601d908201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b6020808252601a908201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604082015260600190565b6020808252601590820152740f4cae4de40d8cadccee8d040e6eec2e040e0c2e8d605b1b604082015260600190565b6020808252601e908201527f466c6173684d696e743a20494e53554646494349454e545f4f55545055540000604082015260600190565b60208082526014908201527324b73b30b634b21037baba383aba103a37b5b2b760611b604082015260600190565b60208082526013908201527224b73b30b634b21034b7383aba103a37b5b2b760691b604082015260600190565b6020808252602b908201527f4d697373696e6720537761706461746120666f72206e6f6e2d7374616e64617260408201526a190818dbdb5c1bdb995b9d60aa1b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b602080825260169082015275119b185cda135a5b9d0e881253959053125117d4d15560521b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526003908201526249534360e81b604082015260600190565b602080825260009082015260400190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6000610160614f1c8388614788565b856101008401528461012084015280610140840152613755818401856147eb565b6000610160614f4c8388614788565b856101008401528461012084015280610140840152610200830160a0828501528091508454614f7b8183615031565b9250614f86866150b7565b9150835b81811015614fb357614fa584614fa085546150c3565b614411565b935060019283019201614f8a565b50505061015f198084830301610180850152614fd282600187016144cf565b614fdf60028701546150c3565b9250614fef6101a0860184614422565b81858203016101c08601526150078160038801614469565b9250505061501860048501546150fb565b6150266101e085018261477a565b509695505050505050565b90815260200190565b9182526001600160a01b0316602082015260400190565b9283526001600160a01b03918216602084015216604082015260600190565b60405181810167ffffffffffffffff8111828210171561508f57600080fd5b604052919050565b600067ffffffffffffffff8211156150ad578081fd5b5060209081020190565b60009081526020902090565b6001600160a01b031690565b60005b838110156150ea5781810151838201526020016150d2565b8381111561064b5750506000910152565b60ff1690565b6001600160a01b038116811461511657600080fd5b50565b801515811461511657600080fdfea2646970667358221220dac833038131b8067ebcdae2e613249db2975379b8d3765e722675a5697e5cce64736f6c634300060a0033

Verified Source Code Partial Match

Compiler: v0.6.10+commit.00c0fcaf EVM: istanbul Optimization: Yes (200 runs)
Ownable.sol 68 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "../utils/Context.sol";
/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}
SafeMath.sol 214 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) return (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}
SignedSafeMath.sol 92 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @title SignedSafeMath
 * @dev Signed math operations with safety checks that revert on error.
 */
library SignedSafeMath {
    int256 constant private _INT256_MIN = -2**255;

    /**
     * @dev Returns the multiplication of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(int256 a, int256 b) internal pure returns (int256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow");

        int256 c = a * b;
        require(c / a == b, "SignedSafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two signed integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(int256 a, int256 b) internal pure returns (int256) {
        require(b != 0, "SignedSafeMath: division by zero");
        require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow");

        int256 c = a / b;

        return c;
    }

    /**
     * @dev Returns the subtraction of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a - b;
        require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow");

        return c;
    }

    /**
     * @dev Returns the addition of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a + b;
        require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow");

        return c;
    }
}
IERC20.sol 77 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}
SafeERC20.sol 75 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}
Address.sol 189 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain`call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}
Context.sol 24 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}
ReentrancyGuard.sol 62 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor () internal {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}
IUniswapV2Router01.sol 95 lines
pragma solidity >=0.6.2;

interface IUniswapV2Router01 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB, uint liquidity);
    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETH(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountToken, uint amountETH);
    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETHWithPermit(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountToken, uint amountETH);
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapTokensForExactTokens(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);
    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);

    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
IUniswapV2Router02.sol 44 lines
pragma solidity >=0.6.2;

import './IUniswapV2Router01.sol';

interface IUniswapV2Router02 is IUniswapV2Router01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountETH);
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}
DEXAdapterV3.sol 1147 lines
/*
    Copyright 2024 Index Cooperative

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

    SPDX-License-Identifier: Apache License, Version 2.0
*/
pragma solidity 0.6.10;
pragma experimental ABIEncoderV2;

import { IUniswapV2Router02 } from "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";

import { ICurveCalculator } from "../interfaces/external/ICurveCalculator.sol";
import { ICurveAddressProvider } from "../interfaces/external/ICurveAddressProvider.sol";
import { ICurvePoolRegistry } from "../interfaces/external/ICurvePoolRegistry.sol";
import { ICurvePool } from "../interfaces/external/ICurvePool.sol";
import { ISwapRouter02 } from "../interfaces/external/ISwapRouter02.sol";
import { IVault } from "../interfaces/external/balancer-v2/IVault.sol";
import { IQuoter } from "../interfaces/IQuoter.sol";
import { IWETH } from "../interfaces/IWETH.sol";
import { PreciseUnitMath } from "../lib/PreciseUnitMath.sol";


/**
 * @title DEXAdapterV3
 * @author Index Coop
 *
 * Same as DEXAdapterV2 but adds BalancerV2 support
 */
library DEXAdapterV3 {
    using SafeERC20 for IERC20;
    using PreciseUnitMath for uint256;
    using SafeMath for uint256;

    /* ============ Constants ============= */

    uint256 constant private MAX_UINT256 = type(uint256).max;
    address public constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
    uint256 public constant ROUNDING_ERROR_MARGIN = 2;

    /* ============ Enums ============ */

    enum Exchange { None, Quickswap, Sushiswap, UniV3, Curve, BalancerV2 }

    /* ============ Structs ============ */

    struct Addresses {
        address quickRouter;
        address sushiRouter;
        address uniV3Router;
        address uniV3Quoter;
        address curveAddressProvider;
        address curveCalculator;
        address balV2Vault;
        // Wrapped native token (WMATIC on polygon)
        address weth;
    }

    struct SwapData {
        address[] path;
        uint24[] fees;
        address pool;         // For Curve swaps
        bytes32[] poolIds;    // For Balancer V2 multihop swaps
        Exchange exchange;
    }

    struct CurvePoolData {
        int128 nCoins;
        uint256[8] balances;
        uint256 A;
        uint256 fee;
        uint256[8] rates;
        uint256[8] decimals;
    }

    /**
     * Swap exact tokens for another token on a given DEX.
     *
     * @param _addresses    Struct containing relevant smart contract addresses.
     * @param _amountIn     The amount of input token to be spent
     * @param _minAmountOut Minimum amount of output token to receive
     * @param _swapData     Swap data containing the path, fees, pool, and pool IDs
     *
     * @return amountOut    The amount of output tokens
     */
    function swapExactTokensForTokens(
        Addresses memory _addresses,
        uint256 _amountIn,
        uint256 _minAmountOut,
        SwapData memory _swapData
    )
        external
        returns (uint256)
    {
        if (_swapData.path.length == 0 || _swapData.path[0] == _swapData.path[_swapData.path.length -1]) {
            return _amountIn;
        }

        if(_swapData.exchange == Exchange.Curve){
            return _swapExactTokensForTokensCurve(
                _swapData.path,
                _swapData.pool,
                _amountIn,
                _minAmountOut,
                _addresses
            );
        }
        if(_swapData.exchange== Exchange.UniV3){
            return _swapExactTokensForTokensUniV3(
                _swapData.path,
                _swapData.fees,
                _amountIn,
                _minAmountOut,
                ISwapRouter02(_addresses.uniV3Router)
            );
        }
        if(_swapData.exchange == Exchange.BalancerV2){
            return _swapExactTokensForTokensBalancerV2(
                _swapData.path,
                _amountIn,
                _minAmountOut,
                _swapData.poolIds,
                IVault(_addresses.balV2Vault)
            );
        } else {
            return _swapExactTokensForTokensUniV2(
                _swapData.path,
                _amountIn,
                _minAmountOut,
                _getRouter(_swapData.exchange, _addresses)
            );
        }
    }


    /**
     * Swap tokens for exact amount of output tokens on a given DEX.
     *
     * @param _addresses    Struct containing relevant smart contract addresses.
     * @param _amountOut    The amount of output token required
     * @param _maxAmountIn  Maximum amount of input token to be spent
     * @param _swapData     Swap data containing the path, fees, pool, and pool IDs
     *
     * @return amountIn     The amount of input tokens spent
     */
    function swapTokensForExactTokens(
        Addresses memory _addresses,
        uint256 _amountOut,
        uint256 _maxAmountIn,
        SwapData memory _swapData
    )
        external
        returns (uint256 amountIn)
    {
        if (_swapData.path.length == 0 || _swapData.path[0] == _swapData.path[_swapData.path.length -1]) {
            return _amountOut;
        }

        if(_swapData.exchange == Exchange.Curve){
            return _swapTokensForExactTokensCurve(
                _swapData.path,
                _swapData.pool,
                _amountOut,
                _maxAmountIn,
                _addresses
            );
        }
        if(_swapData.exchange == Exchange.UniV3){
            return _swapTokensForExactTokensUniV3(
                _swapData.path,
                _swapData.fees,
                _amountOut,
                _maxAmountIn,
                ISwapRouter02(_addresses.uniV3Router)
            );
        }
        if(_swapData.exchange == Exchange.BalancerV2){
            return _swapTokensForExactTokensBalancerV2(
                _swapData.path,
                _amountOut,
                _maxAmountIn,
                _swapData.poolIds,
                IVault(_addresses.balV2Vault)
            );
        } else {
            return _swapTokensForExactTokensUniV2(
                _swapData.path,
                _amountOut,
                _maxAmountIn,
                _getRouter(_swapData.exchange, _addresses)
            );
        }
    }

    /**
     * Gets the output amount of a token swap.
     *
     * @param _swapData     the swap parameters
     * @param _addresses    Struct containing relevant smart contract addresses.
     * @param _amountIn     the input amount of the trade
     *
     * @return              the output amount of the swap
     */
    function getAmountOut(
        Addresses memory _addresses,
        SwapData memory _swapData,
        uint256 _amountIn
    )
        external
        returns (uint256)
    {
        if (_swapData.path.length == 0 || _swapData.path[0] == _swapData.path[_swapData.path.length-1]) {
            return _amountIn;
        }

        if (_swapData.exchange == Exchange.UniV3) {
            return _getAmountOutUniV3(_swapData, _addresses.uniV3Quoter, _amountIn);
        } else if (_swapData.exchange == Exchange.Curve) {
            (int128 i, int128 j) = _getCoinIndices(
                _swapData.pool,
                _swapData.path[0],
                _swapData.path[1],
                ICurveAddressProvider(_addresses.curveAddressProvider)
            );
            return _getAmountOutCurve(_swapData.pool, i, j, _amountIn, _addresses);
        } else if (_swapData.exchange == Exchange.BalancerV2) {
            return _getAmountOutBalancerV2(
                _swapData,
                _addresses,
                _amountIn
            );
        } else {
            return _getAmountOutUniV2(
                _swapData,
                _getRouter(_swapData.exchange, _addresses),
                _amountIn
            );
        }
    }

    /**
     * Gets the input amount of a fixed output swap.
     *
     * @param _swapData     the swap parameters
     * @param _addresses    Struct containing relevant smart contract addresses.
     * @param _amountOut    the output amount of the swap
     *
     * @return              the input amount of the swap
     */
    function getAmountIn(
        Addresses memory _addresses,
        SwapData memory _swapData,
        uint256 _amountOut
    )
        external
        returns (uint256)
    {
        if (_swapData.path.length == 0 || _swapData.path[0] == _swapData.path[_swapData.path.length-1]) {
            return _amountOut;
        }

        if (_swapData.exchange == Exchange.UniV3) {
            return _getAmountInUniV3(_swapData, _addresses.uniV3Quoter, _amountOut);
        } else if (_swapData.exchange == Exchange.Curve) {
            (int128 i, int128 j) = _getCoinIndices(
                _swapData.pool,
                _swapData.path[0],
                _swapData.path[1],
                ICurveAddressProvider(_addresses.curveAddressProvider)
            );
            return _getAmountInCurve(_swapData.pool, i, j, _amountOut, _addresses);
        } else if (_swapData.exchange == Exchange.BalancerV2) {
            return _getAmountInBalancerV2(
                _swapData,
                _addresses,
                _amountOut
            );
        } else {
            return _getAmountInUniV2(
                _swapData,
                _getRouter(_swapData.exchange, _addresses),
                _amountOut
            );
        }
    }

    /**
     * Sets a max approval limit for an ERC20 token, provided the current allowance
     * is less than the required allownce.
     *
     * @param _token              Token to approve
     * @param _spender            Spender address to approve
     * @param _requiredAllowance  Target allowance to set
     */
    function _safeApprove(
        IERC20 _token,
        address _spender,
        uint256 _requiredAllowance
    )
        internal
    {
        uint256 allowance = _token.allowance(address(this), _spender);
        if (allowance < _requiredAllowance) {
            _token.safeIncreaseAllowance(_spender, MAX_UINT256 - allowance);
        }
    }

    /* ============ Private Methods ============ */

    /**
     *  Execute exact output swap via a UniV2 based DEX. (such as sushiswap);
     *
     * @param _path         List of token address to swap via. 
     * @param _amountOut    The amount of output token required
     * @param _maxAmountIn  Maximum amount of input token to be spent
     * @param _router       Address of the uniV2 router to use
     *
     * @return amountIn    The amount of input tokens spent
     */
    function _swapTokensForExactTokensUniV2(
        address[] memory _path,
        uint256 _amountOut,
        uint256 _maxAmountIn,
        IUniswapV2Router02 _router
    )
        private
        returns (uint256)
    {
        _safeApprove(IERC20(_path[0]), address(_router), _maxAmountIn);
        return _router.swapTokensForExactTokens(_amountOut, _maxAmountIn, _path, address(this), block.timestamp)[0];
    }

    /**
     *  Execute exact output swap via UniswapV3
     *
     * @param _path         List of token address to swap via. (In the order as
     *                      expected by uniV2, the first element being the input toen)
     * @param _fees         List of fee levels identifying the pools to swap via.
     *                      (_fees[0] refers to pool between _path[0] and _path[1])
     * @param _amountOut    The amount of output token required
     * @param _maxAmountIn  Maximum amount of input token to be spent
     * @param _uniV3Router  Address of the uniswapV3 router
     *
     * @return amountIn    The amount of input tokens spent
     */
    function _swapTokensForExactTokensUniV3(
        address[] memory _path,
        uint24[] memory _fees,
        uint256 _amountOut,
        uint256 _maxAmountIn,
        ISwapRouter02 _uniV3Router
    )
        private
        returns(uint256)
    {

        require(_path.length == _fees.length + 1, "ExchangeIssuance: PATHS_FEES_MISMATCH");
        _safeApprove(IERC20(_path[0]), address(_uniV3Router), _maxAmountIn);
        if(_path.length == 2){
            ISwapRouter02.ExactOutputSingleParams memory params =
                ISwapRouter02.ExactOutputSingleParams({
                    tokenIn: _path[0],
                    tokenOut: _path[1],
                    fee: _fees[0],
                    recipient: address(this),
                    amountOut: _amountOut,
                    amountInMaximum: _maxAmountIn,
                    sqrtPriceLimitX96: 0
                });
            return _uniV3Router.exactOutputSingle(params);
        } else {
            bytes memory pathV3 = _encodePathV3(_path, _fees, true);
            ISwapRouter02.ExactOutputParams memory params =
                ISwapRouter02.ExactOutputParams({
                    path: pathV3,
                    recipient: address(this),
                    amountOut: _amountOut,
                    amountInMaximum: _maxAmountIn
                });
            return _uniV3Router.exactOutput(params);
        }
    }

    /**
     *  Execute exact input swap via Curve
     *
     * @param _path         Path (has to be of length 2)
     * @param _pool         Address of curve pool to use
     * @param _amountIn     The amount of input token to be spent
     * @param _minAmountOut Minimum amount of output token to receive
     * @param _addresses    Struct containing relevant smart contract addresses.
     *
     * @return amountOut    The amount of output token obtained
     */
    function _swapExactTokensForTokensCurve(
        address[] memory _path,
        address _pool,
        uint256 _amountIn,
        uint256 _minAmountOut,
        Addresses memory _addresses
    )
        private
        returns (uint256 amountOut)
    {
        require(_path.length == 2, "ExchangeIssuance: CURVE_WRONG_PATH_LENGTH");
        (int128 i, int128 j) = _getCoinIndices(_pool, _path[0], _path[1], ICurveAddressProvider(_addresses.curveAddressProvider));

        amountOut = _exchangeCurve(i, j, _pool, _amountIn, _minAmountOut, _path[0]);

    }

    /**
     *  Execute exact output swap via Curve
     *
     * @param _path         Path (has to be of length 2)
     * @param _pool         Address of curve pool to use
     * @param _amountOut    The amount of output token required
     * @param _maxAmountIn  Maximum amount of input token to be spent
     *
     * @return amountOut    The amount of output token obtained
     */
    function _swapTokensForExactTokensCurve(
        address[] memory _path,
        address _pool,
        uint256 _amountOut,
        uint256 _maxAmountIn,
        Addresses memory _addresses
    )
        private
        returns (uint256)
    {
        require(_path.length == 2, "ExchangeIssuance: CURVE_WRONG_PATH_LENGTH");
        (int128 i, int128 j) = _getCoinIndices(_pool, _path[0], _path[1], ICurveAddressProvider(_addresses.curveAddressProvider));


        uint256 returnedAmountOut = _exchangeCurve(i, j, _pool, _maxAmountIn, _amountOut, _path[0]);
        require(_amountOut <= returnedAmountOut, "ExchangeIssuance: CURVE_UNDERBOUGHT");

        uint256 swappedBackAmountIn;
        if(returnedAmountOut > _amountOut){
            swappedBackAmountIn = _exchangeCurve(j, i, _pool, returnedAmountOut.sub(_amountOut), 0, _path[1]);
        }

        return _maxAmountIn.sub(swappedBackAmountIn);
    }
    
    function _exchangeCurve(
        int128 _i,
        int128 _j,
        address _pool,
        uint256 _amountIn,
        uint256 _minAmountOut,
        address _from
    )
        private
        returns (uint256 amountOut)
    {
        ICurvePool pool = ICurvePool(_pool);
        if(_from == ETH_ADDRESS){
            amountOut = pool.exchange{value: _amountIn}(
                _i,
                _j,
                _amountIn,
                _minAmountOut
            );
        }
        else {
            IERC20(_from).approve(_pool, _amountIn);
            amountOut = pool.exchange(
                _i,
                _j,
                _amountIn,
                _minAmountOut
            );
        }
    }

    /**
     *  Calculate required input amount to get a given output amount via Curve swap
     *
     * @param _i            Index of input token as per the ordering of the pools tokens
     * @param _j            Index of output token as per the ordering of the pools tokens
     * @param _pool         Address of curve pool to use
     * @param _amountOut    The amount of output token to be received
     * @param _addresses    Struct containing relevant smart contract addresses.
     *
     * @return amountOut    The amount of output token obtained
     */
    function _getAmountInCurve(
        address _pool,
        int128 _i,
        int128 _j,
        uint256 _amountOut,
        Addresses memory _addresses
    )
        private
        view
        returns (uint256)
    {
        CurvePoolData memory poolData = _getCurvePoolData(_pool, ICurveAddressProvider(_addresses.curveAddressProvider));

        return ICurveCalculator(_addresses.curveCalculator).get_dx(
            poolData.nCoins,
            poolData.balances,
            poolData.A,
            poolData.fee,
            poolData.rates,
            poolData.decimals,
            false,
            _i,
            _j,
            _amountOut
        ) + ROUNDING_ERROR_MARGIN;
    }

    /**
     *  Calculate output amount of a Curve swap
     *
     * @param _i            Index of input token as per the ordering of the pools tokens
     * @param _j            Index of output token as per the ordering of the pools tokens
     * @param _pool         Address of curve pool to use
     * @param _amountIn     The amount of output token to be received
     * @param _addresses    Struct containing relevant smart contract addresses.
     *
     * @return amountOut    The amount of output token obtained
     */
    function _getAmountOutCurve(
        address _pool,
        int128 _i,
        int128 _j,
        uint256 _amountIn,
        Addresses memory _addresses
    )
        private
        view
        returns (uint256)
    {
        return ICurvePool(_pool).get_dy(_i, _j, _amountIn);
    }

    /**
     *  Get metadata on curve pool required to calculate input amount from output amount
     *
     * @param _pool                    Address of curve pool to use
     * @param _curveAddressProvider    Address of curve address provider
     *
     * @return Struct containing all required data to perform getAmountInCurve calculation
     */
    function _getCurvePoolData(
        address _pool,
        ICurveAddressProvider _curveAddressProvider
    ) private view returns(CurvePoolData memory)
    {
        ICurvePoolRegistry registry = ICurvePoolRegistry(_curveAddressProvider.get_registry());

        return CurvePoolData(
            int128(registry.get_n_coins(_pool)[0]),
            registry.get_balances(_pool),
            registry.get_A(_pool),
            registry.get_fees(_pool)[0],
            registry.get_rates(_pool),
            registry.get_decimals(_pool)
        );
    }
    
    /**
     *  Get token indices for given pool
     *  NOTE: This was necessary sine the get_coin_indices function of the CurvePoolRegistry did not work for StEth/ETH pool
     *
     * @param _pool                    Address of curve pool to use
     * @param _from                    Address of input token
     * @param _to                      Address of output token
     * @param _curveAddressProvider    Address of curve address provider
     *
     * @return i Index of input token
     * @return j Index of output token
     */
    function _getCoinIndices(
        address _pool,
        address _from,
        address _to,
        ICurveAddressProvider _curveAddressProvider
    )
        private
        view
        returns (int128 i, int128 j)
    {
        ICurvePoolRegistry registry = ICurvePoolRegistry(_curveAddressProvider.get_registry());

        // Set to out of range index to signal the coin is not found yet
        i = 9;
        j = 9;
        address[8] memory poolCoins = registry.get_coins(_pool);

        for(uint256 k = 0; k < 8; k++){
            if(poolCoins[k] == _from){
                i = int128(k);
            }
            else if(poolCoins[k] == _to){
                j = int128(k);
            }
            // ZeroAddress signals end of list
            if(poolCoins[k] == address(0) || (i != 9 && j != 9)){
                break;
            }
        }

        require(i != 9, "ExchangeIssuance: CURVE_FROM_NOT_FOUND");
        require(j != 9, "ExchangeIssuance: CURVE_TO_NOT_FOUND");

        return (i, j);
    }

    /**
     *  Execute exact input swap via UniswapV3
     *
     * @param _path         List of token address to swap via. 
     * @param _fees         List of fee levels identifying the pools to swap via.
     *                      (_fees[0] refers to pool between _path[0] and _path[1])
     * @param _amountIn     The amount of input token to be spent
     * @param _minAmountOut Minimum amount of output token to receive
     * @param _uniV3Router  Address of the uniswapV3 router
     *
     * @return amountOut    The amount of output token obtained
     */
    function _swapExactTokensForTokensUniV3(
        address[] memory _path,
        uint24[] memory _fees,
        uint256 _amountIn,
        uint256 _minAmountOut,
        ISwapRouter02 _uniV3Router
    )
        private
        returns (uint256)
    {
        require(_path.length == _fees.length + 1, "ExchangeIssuance: PATHS_FEES_MISMATCH");
        _safeApprove(IERC20(_path[0]), address(_uniV3Router), _amountIn);
        if(_path.length == 2){
            ISwapRouter02.ExactInputSingleParams memory params =
                ISwapRouter02.ExactInputSingleParams({
                    tokenIn: _path[0],
                    tokenOut: _path[1],
                    fee: _fees[0],
                    recipient: address(this),
                    amountIn: _amountIn,
                    amountOutMinimum: _minAmountOut,
                    sqrtPriceLimitX96: 0
                });
            return _uniV3Router.exactInputSingle(params);
        } else {
            bytes memory pathV3 = _encodePathV3(_path, _fees, false);
            ISwapRouter02.ExactInputParams memory params =
                ISwapRouter02.ExactInputParams({
                    path: pathV3,
                    recipient: address(this),
                    amountIn: _amountIn,
                    amountOutMinimum: _minAmountOut
                });
            uint amountOut = _uniV3Router.exactInput(params);
            return amountOut;
        }
    }

    /**
     *  Execute exact input swap via UniswapV2
     *
     * @param _path         List of token address to swap via. 
     * @param _amountIn     The amount of input token to be spent
     * @param _minAmountOut Minimum amount of output token to receive
     * @param _router       Address of uniV2 router to use
     *
     * @return amountOut    The amount of output token obtained
     */
    function _swapExactTokensForTokensUniV2(
        address[] memory _path,
        uint256 _amountIn,
        uint256 _minAmountOut,
        IUniswapV2Router02 _router
    )
        private
        returns (uint256)
    {
        _safeApprove(IERC20(_path[0]), address(_router), _amountIn);
        // NOTE: The following was changed from always returning result at position [1] to returning the last element of the result array
        // With this change, the actual output is correctly returned also for multi-hop swaps
        // See https://github.com/IndexCoop/index-coop-smart-contracts/pull/116 
        uint256[] memory result = _router.swapExactTokensForTokens(_amountIn, _minAmountOut, _path, address(this), block.timestamp);
        // result = uint[] memory	The input token amount and all subsequent output token amounts.
        // we are usually only interested in the actual amount of the output token (so result element at the last place)
        return result[result.length-1];
    }

    /**
     * Gets the output amount of a token swap on Uniswap V2
     *
     * @param _swapData     the swap parameters
     * @param _router       the uniswap v2 router address
     * @param _amountIn     the input amount of the trade
     *
     * @return              the output amount of the swap
     */
    function _getAmountOutUniV2(
        SwapData memory _swapData,
        IUniswapV2Router02 _router,
        uint256 _amountIn
    )
        private
        view
        returns (uint256)
    {
        return _router.getAmountsOut(_amountIn, _swapData.path)[_swapData.path.length-1];
    }

    /**
     * Gets the input amount of a fixed output swap on Uniswap V2.
     *
     * @param _swapData     the swap parameters
     * @param _router       the uniswap v2 router address
     * @param _amountOut    the output amount of the swap
     *
     * @return              the input amount of the swap
     */
    function _getAmountInUniV2(
        SwapData memory _swapData,
        IUniswapV2Router02 _router,
        uint256 _amountOut
    )
        private
        view
        returns (uint256)
    {
        return _router.getAmountsIn(_amountOut, _swapData.path)[0];
    }

    /**
     * Gets the output amount of a token swap on Uniswap V3.
     *
     * @param _swapData     the swap parameters
     * @param _quoter       the uniswap v3 quoter
     * @param _amountIn     the input amount of the trade
     *
     * @return              the output amount of the swap
     */

    function _getAmountOutUniV3(
        SwapData memory _swapData,
        address _quoter,
        uint256 _amountIn
    )
        private
        returns (uint256)
    {
        bytes memory path = _encodePathV3(_swapData.path, _swapData.fees, false);
        return IQuoter(_quoter).quoteExactInput(path, _amountIn);
    }

    /**
     * Gets the input amount of a fixed output swap on Uniswap V3.
     *
     * @param _swapData     the swap parameters
     * @param _quoter       uniswap v3 quoter
     * @param _amountOut    the output amount of the swap
     *
     * @return              the input amount of the swap
     */
    function _getAmountInUniV3(
        SwapData memory _swapData,
        address _quoter,
        uint256 _amountOut
    )
        private
        returns (uint256)
    {
        bytes memory path = _encodePathV3(_swapData.path, _swapData.fees, true);
        return IQuoter(_quoter).quoteExactOutput(path, _amountOut);
    }

    /**
     * Encode path / fees to bytes in the format expected by UniV3 router
     *
     * @param _path          List of token address to swap via (starting with input token)
     * @param _fees          List of fee levels identifying the pools to swap via.
     *                       (_fees[0] refers to pool between _path[0] and _path[1])
     * @param _reverseOrder  Boolean indicating if path needs to be reversed to start with output token.
     *                       (which is the case for exact output swap)
     *
     * @return encodedPath   Encoded path to be forwared to uniV3 router
     */
    function _encodePathV3(
        address[] memory _path,
        uint24[] memory _fees,
        bool _reverseOrder
    )
        private
        pure
        returns(bytes memory encodedPath)
    {
        if(_reverseOrder){
            encodedPath = abi.encodePacked(_path[_path.length-1]);
            for(uint i = 0; i < _fees.length; i++){
                uint index = _fees.length - i - 1;
                encodedPath = abi.encodePacked(encodedPath, _fees[index], _path[index]);
            }
        } else {
            encodedPath = abi.encodePacked(_path[0]);
            for(uint i = 0; i < _fees.length; i++){
                encodedPath = abi.encodePacked(encodedPath, _fees[i], _path[i+1]);
            }
        }
    }

    function _getRouter(
        Exchange _exchange,
        Addresses memory _addresses
    )
        private
        pure
        returns (IUniswapV2Router02)
    {
        return IUniswapV2Router02(
            (_exchange == Exchange.Quickswap) ? _addresses.quickRouter : _addresses.sushiRouter
        );
    }

    /**
     *  Execute exact input swap via Balancer V2 (supports multihop swaps)
     *
     * @param _path         List of token addresses to swap via.
     * @param _amountIn     The amount of input token to be spent
     * @param _minAmountOut Minimum amount of output token to receive
     * @param _poolIds      List of pool IDs for each swap step
     * @param _vault        Address of the Balancer V2 Vault
     *
     * @return amountOut    The amount of output tokens received
     */
    function _swapExactTokensForTokensBalancerV2(
        address[] memory _path,
        uint256 _amountIn,
        uint256 _minAmountOut,
        bytes32[] memory _poolIds,
        IVault _vault
    )
        private
        returns (uint256 amountOut)
    {
        require(_path.length >= 2, "DEXAdapterV3: BALANCER_PATH_LENGTH");
        require(_poolIds.length == _path.length - 1, "DEXAdapterV3: INVALID_POOL_IDS");

        // Approve the Vault to spend the input token
        _safeApprove(IERC20(_path[0]), address(_vault), _amountIn);

        // Build the assets array (unique tokens in the path)
        address[] memory assets = _getAssets(_path);

        // Build the swaps array
        IVault.BatchSwapStep[] memory swaps = new IVault.BatchSwapStep[](_path.length - 1);

        for (uint256 i = 0; i < _path.length - 1; i++) {
            swaps[i] = IVault.BatchSwapStep({
                poolId: _poolIds[i],
                assetInIndex: _getAssetIndex(assets, _path[i]),
                assetOutIndex: _getAssetIndex(assets, _path[i + 1]),
                amount: i == 0 ? _amountIn : 0, // Only specify amount for first swap
                userData: ""
            });
        }

        // Set up funds
        IVault.FundManagement memory funds = IVault.FundManagement({
            sender: address(this),
            fromInternalBalance: false,
            recipient: payable(address(this)),
            toInternalBalance: false
        });

        // Set up limits
        int256[] memory limits = new int256[](assets.length);

        for (uint256 i = 0; i < assets.length; i++) {
            if (assets[i] == _path[0]) {
                limits[i] = int256(_amountIn);
            } else if (assets[i] == _path[_path.length - 1]) {
                limits[i] = -int256(_minAmountOut);
            } else {
                limits[i] = 0;
            }
        }

        // Perform the batch swap
        int256[] memory deltas = _vault.batchSwap(
            IVault.SwapKind.GIVEN_IN,
            swaps,
            assets,
            funds,
            limits,
            block.timestamp
        );

        amountOut = uint256(-deltas[_getAssetIndex(assets, _path[_path.length - 1])]);
        require(amountOut >= _minAmountOut, "DEXAdapterV3: INSUFFICIENT_OUTPUT_AMOUNT");
    }

    /**
     *  Execute exact output swap via Balancer V2 (supports multihop swaps)
     *
     * @param _path         List of token addresses to swap via.
     * @param _amountOut    The amount of output token required
     * @param _maxAmountIn  Maximum amount of input token to be spent
     * @param _poolIds      List of pool IDs for each swap step
     * @param _vault        Address of the Balancer V2 Vault
     *
     * @return amountIn     The amount of input tokens spent
     */
    function _swapTokensForExactTokensBalancerV2(
        address[] memory _path,
        uint256 _amountOut,
        uint256 _maxAmountIn,
        bytes32[] memory _poolIds,
        IVault _vault
    )
        private
        returns (uint256 amountIn)
    {
        require(_path.length >= 2, "DEXAdapterV3: BALANCER_PATH_LENGTH");
        require(_poolIds.length == _path.length - 1, "DEXAdapterV3: INVALID_POOL_IDS");

        // Approve the Vault to spend the input token
        _safeApprove(IERC20(_path[0]), address(_vault), _maxAmountIn);

        // Build the assets array (unique tokens in the path)
        address[] memory assets = _getAssets(_path);

        // Build the swaps array
        IVault.BatchSwapStep[] memory swaps = new IVault.BatchSwapStep[](_path.length - 1);

        for (uint256 i = 0; i < _path.length - 1; i++) {
            swaps[i] = IVault.BatchSwapStep({
                poolId: _poolIds[i],
                assetInIndex: _getAssetIndex(assets, _path[i]),
                assetOutIndex: _getAssetIndex(assets, _path[i + 1]),
                amount: 0, // Amount is determined by the Vault
                userData: ""
            });
        }

        // Set up funds
        IVault.FundManagement memory funds = IVault.FundManagement({
            sender: address(this),
            fromInternalBalance: false,
            recipient: payable(address(this)),
            toInternalBalance: false
        });

        // Set up limits
        int256[] memory limits = new int256[](assets.length);

        for (uint256 i = 0; i < assets.length; i++) {
            if (assets[i] == _path[0]) {
                limits[i] = int256(_maxAmountIn);
            } else if (assets[i] == _path[_path.length - 1]) {
                limits[i] = -int256(_amountOut);
            } else {
                limits[i] = 0;
            }
        }

        // Perform the batch swap
        int256[] memory deltas = _vault.batchSwap(
            IVault.SwapKind.GIVEN_OUT,
            swaps,
            assets,
            funds,
            limits,
            block.timestamp
        );

        amountIn = uint256(deltas[_getAssetIndex(assets, _path[0])]);
        require(amountIn <= _maxAmountIn, "DEXAdapterV3: EXCESSIVE_INPUT_AMOUNT");
    }

    /**
     * Gets the output amount of a token swap on Balancer V2 using queryBatchSwap.
     *
     * @param _swapData     the swap parameters
     * @param _addresses    Struct containing relevant smart contract addresses
     * @param _amountIn     the input amount of the trade
     *
     * @return amountOut    the output amount of the swap
     */
    function _getAmountOutBalancerV2(
        SwapData memory _swapData,
        Addresses memory _addresses,
        uint256 _amountIn
    )
        private
        returns (uint256 amountOut)
    {
        IVault _vault = IVault(_addresses.balV2Vault);

        // Build the assets array (unique tokens in the path)
        address[] memory assets = _getAssets(_swapData.path);

        // Build the swaps array
        IVault.BatchSwapStep[] memory swaps = new IVault.BatchSwapStep[](_swapData.path.length - 1);

        for (uint256 i = 0; i < _swapData.path.length - 1; i++) {
            swaps[i] = IVault.BatchSwapStep({
                poolId: _swapData.poolIds[i],
                assetInIndex: _getAssetIndex(assets, _swapData.path[i]),
                assetOutIndex: _getAssetIndex(assets, _swapData.path[i + 1]),
                amount: i == 0 ? _amountIn : 0, // Only specify amount for first swap
                userData: ""
            });
        }

        // Set up funds (not used in query)
        IVault.FundManagement memory funds = IVault.FundManagement({
            sender: address(this),
            fromInternalBalance: false,
            recipient: payable(address(this)),
            toInternalBalance: false
        });

        // Perform the query
        int256[] memory deltas = _vault.queryBatchSwap(
            IVault.SwapKind.GIVEN_IN,
            swaps,
            assets,
            funds
        );

        amountOut = uint256(-deltas[_getAssetIndex(assets, _swapData.path[_swapData.path.length - 1])]);
    }

    /**
     * Gets the input amount of a fixed output swap on Balancer V2 using queryBatchSwap.
     *
     * @param _swapData     the swap parameters
     * @param _addresses    Struct containing relevant smart contract addresses
     * @param _amountOut    the output amount of the swap
     *
     * @return amountIn     the input amount of the swap
     */
    function _getAmountInBalancerV2(
        SwapData memory _swapData,
        Addresses memory _addresses,
        uint256 _amountOut
    )
        private
        returns (uint256 amountIn)
    {
        IVault _vault = IVault(_addresses.balV2Vault);

        // Build the assets array (unique tokens in the path)
        address[] memory assets = _getAssets(_swapData.path);

        // Build the swaps array
        IVault.BatchSwapStep[] memory swaps = new IVault.BatchSwapStep[](_swapData.path.length - 1);

        for (uint256 i = 0; i < _swapData.path.length - 1; i++) {
            swaps[i] = IVault.BatchSwapStep({
                poolId: _swapData.poolIds[i],
                assetInIndex: _getAssetIndex(assets, _swapData.path[i]),
                assetOutIndex: _getAssetIndex(assets, _swapData.path[i + 1]),
                amount: i == swaps.length - 1 ? _amountOut : 0, // Only specify amount for last swap
                userData: ""
            });
        }

        // Set up funds (not used in query)
        IVault.FundManagement memory funds = IVault.FundManagement({
            sender: address(this),
            fromInternalBalance: false,
            recipient: payable(address(this)),
            toInternalBalance: false
        });

        // Perform the query
        int256[] memory deltas = _vault.queryBatchSwap(
            IVault.SwapKind.GIVEN_OUT,
            swaps,
            assets,
            funds
        );

        amountIn = uint256(deltas[_getAssetIndex(assets, _swapData.path[0])]);
    }

    /**
     * Helper function to get the list of unique assets from the path.
     *
     * @param _path         List of token addresses in the swap path
     *
     * @return assets       List of unique assets
     */
    function _getAssets(address[] memory _path) private pure returns (address[] memory assets) {
        uint256 assetCount = 0;
        address[] memory tempAssets = new address[](_path.length);

        for (uint256 i = 0; i < _path.length; i++) {
            bool alreadyAdded = false;
            for (uint256 j = 0; j < assetCount; j++) {
                if (tempAssets[j] == _path[i]) {
                    alreadyAdded = true;
                    break;
                }
            }
            if (!alreadyAdded) {
                tempAssets[assetCount] = _path[i];
                assetCount++;
            }
        }

        assets = new address[](assetCount);
        for (uint256 i = 0; i < assetCount; i++) {
            assets[i] = tempAssets[i];
        }
    }

    /**
     * Helper function to get the index of an asset in the assets array.
     *
     * @param assets        List of assets
     * @param token         Token address to find
     *
     * @return index        Index of the token in the assets array
     */
    function _getAssetIndex(address[] memory assets, address token) private pure returns (uint256) {
        for (uint256 i = 0; i < assets.length; i++) {
            if (assets[i] == token) {
                return i;
            }
        }
        revert("DEXAdapterV3: TOKEN_NOT_IN_ASSETS");
    }
}
FlashMintHyETHV3.sol 698 lines
/*
    Copyright 2024 Index Cooperative

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

    SPDX-License-Identifier: Apache License, Version 2.0
*/

pragma solidity 0.6.10;
pragma experimental ABIEncoderV2;

import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

import { IERC4626 } from "../interfaces/IERC4626.sol";
import { IStETH } from "../interfaces/external/IStETH.sol";
import { IAcrossHubPoolV2 } from "../interfaces/external/IAcrossHubPoolV2.sol";
import { IPendlePrincipalToken } from "../interfaces/external/IPendlePrincipalToken.sol";
import { IPendleMarketV3 } from "../interfaces/external/IPendleMarketV3.sol";
import { IPendleStandardizedYield } from "../interfaces/external/IPendleStandardizedYield.sol";
import { IRsEthAdapter } from "../interfaces/external/IRsEthAdapter.sol";
import { IController } from "../interfaces/IController.sol";
import { IDebtIssuanceModule } from "../interfaces/IDebtIssuanceModule.sol";
import { ISetToken } from "../interfaces/ISetToken.sol";
import { IWETH } from "../interfaces/IWETH.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { DEXAdapterV3 } from "./DEXAdapterV3.sol";

/**
 * @title FlashMintHyETHV3
 */
contract FlashMintHyETHV3 is Ownable, ReentrancyGuard {
    using DEXAdapterV3 for DEXAdapterV3.Addresses;
    using Address for address payable;
    using Address for address;
    using SafeMath for uint256;
    using SafeERC20 for IERC20;
    using SafeERC20 for ISetToken;

    struct PendleMarketData {
        IPendlePrincipalToken pt;
        IPendleStandardizedYield sy;
        address underlying;
        uint256 exchangeRateFactor;
    }
    /* ============ Constants ============= */

    uint256 private constant MAX_UINT256 = type(uint256).max;
    uint256 public constant ROUNDING_ERROR = 10;
    IERC20 public constant acrossToken = IERC20(0x28F77208728B0A45cAb24c4868334581Fe86F95B);
    IAcrossHubPoolV2 public constant acrossPool =
        IAcrossHubPoolV2(0xc186fA914353c44b2E33eBE05f21846F1048bEda);
    IERC20 public constant agETH = IERC20(0xe1B4d34E8754600962Cd944B535180Bd758E6c2e);
    IRsEthAdapter public constant rsEthAdapter = IRsEthAdapter(0xbf28C9FCb12A97441488f9C68FaA49811a98688a);

    /* ============ Immutables ============ */

    IController public immutable setController;
    IStETH public immutable stETH;
    IDebtIssuanceModule public immutable issuanceModule; // interface is compatible with DebtIssuanceModuleV2
    mapping(IPendlePrincipalToken => IPendleMarketV3) public pendleMarkets;
    mapping(IPendleMarketV3 => PendleMarketData) public pendleMarketData;
    mapping(address => mapping(address => DEXAdapterV3.SwapData)) public swapData;
    mapping(address => bool) public erc4626Components;

    /* ============ State Variables ============ */

    DEXAdapterV3.Addresses public dexAdapter;

    /* ============ Events ============ */

    event FlashMint(
        address indexed _recipient, // The recipient address of the minted Set token
        ISetToken indexed _setToken, // The minted Set token
        IERC20 indexed _inputToken, // The address of the input asset(ERC20/ETH) used to mint the Set tokens
        uint256 _amountInputToken, // The amount of input tokens used for minting
        uint256 _amountSetIssued // The amount of Set tokens received by the recipient
    );

    event FlashRedeem(
        address indexed _recipient, // The recipient address which redeemed the Set token
        ISetToken indexed _setToken, // The redeemed Set token
        IERC20 indexed _outputToken, // The address of output asset(ERC20/ETH) received by the recipient
        uint256 _amountSetRedeemed, // The amount of Set token redeemed for output tokens
        uint256 _amountOutputToken // The amount of output tokens received by the recipient
    );

    /* ============ Modifiers ============ */

    /**
     * checks that _setToken is a valid listed set token on the setController
     *
     * @param _setToken       set token to check
     */
    modifier isSetToken(ISetToken _setToken) {
        require(setController.isSet(address(_setToken)), "FlashMint: INVALID_SET");
        _;
    }

    /**
     * checks that _inputToken is the first adress in _path and _outputToken is the last address in _path
     *
     * @param _path                      Array of addresses for a DEX swap path
     * @param _inputToken                input token of DEX swap
     * @param _outputToken               output token of DEX swap
     */
    modifier isValidPath(
        address[] memory _path,
        address _inputToken,
        address _outputToken
    ) {
        if (_inputToken != _outputToken) {
            require(
                _path[0] == _inputToken ||
                    (_inputToken == dexAdapter.weth && _path[0] == DEXAdapterV3.ETH_ADDRESS),
                "FlashMint: INPUT_TOKEN_NOT_IN_PATH"
            );
            require(
                _path[_path.length - 1] == _outputToken ||
                    (_outputToken == dexAdapter.weth &&
                        _path[_path.length - 1] == DEXAdapterV3.ETH_ADDRESS),
                "FlashMint: OUTPUT_TOKEN_NOT_IN_PATH"
            );
        }
        _;
    }

    /* ========== Constructor ========== */

    constructor(
        DEXAdapterV3.Addresses memory _dexAddresses,
        IController _setController,
        IDebtIssuanceModule _issuanceModule,
        IStETH _stETH,
        address _stEthETHPool
    ) public {
        dexAdapter = _dexAddresses;
        setController = _setController;
        issuanceModule = _issuanceModule;
        stETH = _stETH;

        IERC20(address(_stETH)).approve(_stEthETHPool, MAX_UINT256);
    }

    /* ============ External Functions (Publicly Accesible) ============ */

    /**
     * Runs all the necessary approval functions required before issuing
     * or redeeming a SetToken. This function needs to be called only once before the first time
     * this smart contract is used on any particular SetToken.
     *
     * @param _setToken          Address of the SetToken being initialized
     */
    function approveSetToken(ISetToken _setToken) external isSetToken(_setToken) {
        address[] memory _components = _setToken.getComponents();
        for (uint256 i = 0; i < _components.length; ++i) {
            IERC20(_components[i]).approve(address(issuanceModule), MAX_UINT256);
        }
        _setToken.approve(address(issuanceModule), MAX_UINT256);
    }

    /**
     * Issue exact amount of SetToken from ETH
     *
     * @param _setToken     Address of the SetToken to issue
     * @param _amountSetToken   Amount of SetToken to issue
     */
    function issueExactSetFromETH(
        ISetToken _setToken,
        uint256 _amountSetToken,
        DEXAdapterV3.SwapData[] memory _swapDataEthToComponent
    ) external payable nonReentrant returns (uint256) {
        uint256 ethSpent = _issueExactSetFromEth(_setToken, _amountSetToken, _swapDataEthToComponent);
        msg.sender.sendValue(msg.value.sub(ethSpent));
        return ethSpent;
    }

    /**
     * Issue exact amount of SetToken from ERC20 token
     *
     * @param _setToken     Address of the SetToken to issue
     * @param _amountSetToken   Amount of SetToken to issue
     * @param _inputToken    Address of the input token
     * @param _maxInputTokenAmount  Maximum amount of input token to spend
     * @param _swapDataInputTokenToEth Swap data from input token to ETH
     * @param _swapDataEthToInputToken Swap data from ETH to input token (used to swap back the leftover eth)
     */
    function issueExactSetFromERC20(
        ISetToken _setToken,
        uint256 _amountSetToken,
        IERC20 _inputToken,
        uint256 _maxInputTokenAmount,
        DEXAdapterV3.SwapData memory _swapDataInputTokenToEth,
        DEXAdapterV3.SwapData memory _swapDataEthToInputToken,
        DEXAdapterV3.SwapData[] memory _swapDataEthToComponent
    ) external payable nonReentrant returns (uint256) {
        _inputToken.safeTransferFrom(msg.sender, address(this), _maxInputTokenAmount);

        uint256 ethAmount = _swapExactTokenForEth(_inputToken, _maxInputTokenAmount, _swapDataInputTokenToEth);
        ethAmount = ethAmount.sub(_issueExactSetFromEth(_setToken, _amountSetToken, _swapDataEthToComponent));

        uint256 inputTokenLeft = _swapFromEthToToken(_inputToken, ethAmount, _swapDataEthToInputToken);

        _inputToken.safeTransfer(msg.sender, inputTokenLeft);
        return _maxInputTokenAmount.sub(inputTokenLeft);
    }

    /**
     * Redeem exact amount of SetToken for ETH
     *
     * @param _setToken         Address of the SetToken to redeem
     * @param _amountSetToken   Amount of SetToken to redeem
     * @param _minETHOut        Minimum amount of ETH to receive (tx will revert if actual amount is less)
     * @param _swapDataComponentToEth Swap data from component to ETH (for non-standard components)
     */
    function redeemExactSetForETH(
        ISetToken _setToken,
        uint256 _amountSetToken,
        uint256 _minETHOut,
        DEXAdapterV3.SwapData[] memory _swapDataComponentToEth
    ) external payable nonReentrant returns (uint256) {
        uint256 ethObtained = _redeemExactSetForETH(_setToken, _amountSetToken, _minETHOut, _swapDataComponentToEth);
        require(ethObtained >= _minETHOut, "FlashMint: INSUFFICIENT_OUTPUT");
        msg.sender.sendValue(ethObtained);
        return ethObtained;
    }

    /**
     * Redeem exact amount of SetToken for ERC20
     *
     * @param _setToken         Address of the SetToken to redeem
     * @param _amountSetToken   Amount of SetToken to redeem
     * @param _outputToken      Address of the output token
     * @param _minOutputTokenAmount  Minimum amount of output token to receive (tx will revert if actual amount is less)
     * @param _swapDataEthToOutputToken Swap data from ETH to output token
     * @param _swapDataComponentToEth Swap data from component to ETH (for non-standard components)
     */
    function redeemExactSetForERC20(
        ISetToken _setToken,
        uint256 _amountSetToken,
        IERC20 _outputToken,
        uint256 _minOutputTokenAmount,
        DEXAdapterV3.SwapData memory _swapDataEthToOutputToken,
        DEXAdapterV3.SwapData[] memory _swapDataComponentToEth
    ) external payable nonReentrant returns (uint256) {
        uint256 ethObtained = _redeemExactSetForETH(_setToken, _amountSetToken, 0, _swapDataComponentToEth);
        uint256 outputTokenAmount = _swapFromEthToToken(_outputToken, ethObtained, _swapDataEthToOutputToken);
        require(outputTokenAmount >= _minOutputTokenAmount, "FlashMint: INSUFFICIENT_OUTPUT");
        _outputToken.safeTransfer(msg.sender, outputTokenAmount);
        return outputTokenAmount;
    }

    receive() external payable {}

    /* ============ External Functions (Access controlled) ============ */

    /**
     * Control wether a component is registered as an ERC4626 token
     *
     * @param _component     Address of the component
     * @param _isERC4626     Boolean indicating if the component is an ERC4626 token
     */
    function setERC4626Component(
        address _component,
        bool _isERC4626
    ) external onlyOwner {
        erc4626Components[_component] = _isERC4626;
    }

    /**
     * Approve spender to spend specific token on behalf of this contract
     *
     * @param _token        Address of the token to approve
     * @param _spender      Address of the spender
     * @param _allowance    Amount to approve
     */
    function approveToken(IERC20 _token, address _spender, uint256 _allowance) external onlyOwner {
        _token.approve(_spender, _allowance);
    }

    /**
     * Withdraw slippage to selected address
     *
     * @param _tokens    Addresses of tokens to withdraw, specify ETH_ADDRESS to withdraw ETH
     * @param _to        Address to send the tokens to
     */
    function withdrawTokens(
        IERC20[] calldata _tokens,
        address payable _to
    ) external payable onlyOwner {
        for (uint256 i = 0; i < _tokens.length; i++) {
            if (address(_tokens[i]) == DEXAdapterV3.ETH_ADDRESS) {
                _to.sendValue(address(this).balance);
            } else {
                _tokens[i].safeTransfer(_to, _tokens[i].balanceOf(address(this)));
            }
        }
    }

    /**
     * Set swap data for specific token pair
     *
     * @param _inputToken     Address of the input token
     * @param _outputToken    Address of the output token
     * @param _swapData       Swap data for the token pair describing DEX / route
     */
    function setSwapData(
        address _inputToken,
        address _outputToken,
        DEXAdapterV3.SwapData memory _swapData
    ) external onlyOwner {
        swapData[_inputToken][_outputToken] = _swapData;
    }

    /**
     * Set Pendle Market to use for specific pt including relevant metadata
     *
     * @param _pt             Address of the Pendle Principal Token
     * @param _sy             Address of the corresponding Standardized Yield Token
     * @param _underlying     Address of the underlying token to redeem to
     * @param _market         Address of the Pendle Market to use for swapping between pt and sy
     * @param _exchangeRateFactor  Factor to multiply the exchange rate when supplying to Pendle Market
     */
    function setPendleMarket(
        IPendlePrincipalToken _pt,
        IPendleStandardizedYield _sy,
        address _underlying,
        IPendleMarketV3 _market,
        uint256 _exchangeRateFactor
    ) external onlyOwner {
        pendleMarkets[_pt] = _market;
        pendleMarketData[_market] = PendleMarketData({
            pt: _pt,
            sy: _sy,
            underlying: _underlying,
            exchangeRateFactor: _exchangeRateFactor
        });
    }

    /**
     * Callback method that is called by Pendle Market during the swap to request input token
     *
     * @param _ptToAccount  Swap balance of pt token (negative -> swapping pt to sy)
     * @param _syToAccount  Swap balance of sy token (negative -> swapping sy to pt)
     * @param _data         Arbitrary data passed by Pendle Market (not used)
     */
    function swapCallback(int256 _ptToAccount, int256 _syToAccount, bytes calldata _data) external {
        PendleMarketData storage marketData = pendleMarketData[IPendleMarketV3(msg.sender)];
        require(address(marketData.sy) != address(0), "ISC");
        if (_ptToAccount < 0) {
            uint256 ptAmount = uint256(-_ptToAccount);
            marketData.pt.transfer(msg.sender, ptAmount);
        } else if (_syToAccount < 0) {
            uint256 syAmount = uint256(-_syToAccount);

            // Withdraw necessary ETH, if deposit size is enough to move the oracle, then the exchange rate will not be
            // valid for computing the amount of ETH to withdraw, so increase by exchangeRateFactor
            uint256 ethAmount = syAmount.mul(marketData.sy.exchangeRate()).div(1 ether);
            uint256 syAmountPreview = marketData.sy.previewDeposit(address(0), ethAmount);
            if (syAmountPreview < syAmount) {
                ethAmount = ethAmount * marketData.exchangeRateFactor / 1 ether;
            }

            // Special handling for agETH
            if (marketData.underlying == address(agETH)) {
                rsEthAdapter.getRSETHWithETH{value: ethAmount}("");
                uint256 agEthAmount = agETH.balanceOf(address(this));
                marketData.sy.deposit(address(this), address(agETH), agEthAmount, 0);
            } else {
                marketData.sy.deposit{ value: ethAmount }(address(this), address(0), ethAmount, 0);
            }
            marketData.sy.transfer(msg.sender, syAmount);
        } else {
            revert("Invalid callback");
        }
    }

    /* ============ Internal ============ */

    /**
     * @dev Issue exact amount of SetToken from ETH
     *
     */
    function _issueExactSetFromEth(
        ISetToken _setToken,
        uint256 _amountSetToken,
        DEXAdapterV3.SwapData[] memory _swapDataEthToComponent
    ) internal returns (uint256) {
        (address[] memory components, uint256[] memory positions, ) = IDebtIssuanceModule(
            issuanceModule
        ).getRequiredComponentIssuanceUnits(_setToken, _amountSetToken);
        uint256 ethBalanceBefore = address(this).balance;
        for (uint256 i = 0; i < components.length; i++) {
            _depositIntoComponent(components[i], positions[i], _swapDataEthToComponent[i]);
        }
        issuanceModule.issue(_setToken, _amountSetToken, msg.sender);
        return ethBalanceBefore.sub(address(this).balance);
    }

    /**
     * @dev Redeem exact amount of SetToken for ETH
     *
     */
    function _redeemExactSetForETH(
        ISetToken _setToken,
        uint256 _amountSetToken,
        uint256 _minETHOut,
        DEXAdapterV3.SwapData[] memory _swapDataComponentToEth
    ) internal returns (uint256) {
        uint256 ethBalanceBefore = address(this).balance;

        _setToken.safeTransferFrom(msg.sender, address(this), _amountSetToken);
        issuanceModule.redeem(_setToken, _amountSetToken, address(this));
        (address[] memory components, uint256[] memory positions, ) = IDebtIssuanceModule(
            issuanceModule
        ).getRequiredComponentRedemptionUnits(_setToken, _amountSetToken);

        for (uint256 i = 0; i < components.length; i++) {
            _withdrawFromComponent(components[i], positions[i], _swapDataComponentToEth[i]);
        }

        return address(this).balance.sub(ethBalanceBefore);
    }

    /**
     * @dev Deposit ETH into given component
     *
     */
    function _depositIntoComponent(
        address _component,
        uint256 _amount,
        DEXAdapterV3.SwapData memory _swapData
    ) internal {
        if(_swapData.exchange != DEXAdapterV3.Exchange.None) {
            _swapEthForExactToken(_component, _amount, _swapData);
            return;
        }
        if (_isInstadapp(_component)) {
            _depositIntoInstadapp(IERC4626(_component), _amount);
            return;
        }
        IPendleStandardizedYield syToken = _getSyToken(IPendlePrincipalToken(_component));
        if (syToken != IPendleStandardizedYield(address(0))) {
            _depositIntoPendle(IPendlePrincipalToken(_component), _amount, syToken);
            return;
        }
        if (IERC20(_component) == acrossToken) {
            _depositIntoAcross(_amount);
            return;
        }
        if (_component == dexAdapter.weth) {
            IWETH(dexAdapter.weth).deposit{ value: _amount }();
            return;
        }
        if (erc4626Components[_component]) {
            uint256 assetAmount = IERC4626(_component).previewMint(_amount);
            address asset = IERC4626(_component).asset();
            _swapEthForExactToken(asset, assetAmount, swapData[DEXAdapterV3.ETH_ADDRESS][asset]);
            IERC4626(_component).mint(_amount, address(this));
            return;
        }
        revert("Missing Swapdata for non-standard component");
    }

    /**
     * @dev Withdraw ETH from given component
     *
     */
    function _withdrawFromComponent(
        address _component,
        uint256 _amount,
        DEXAdapterV3.SwapData memory _swapData
    ) internal {
        if(_swapData.exchange != DEXAdapterV3.Exchange.None) {
            require(_swapData.path.length > 1, "zero length swap path");
            require(_swapData.path[0] == _component, "Invalid input token");
            require(_swapData.path[_swapData.path.length - 1] == DEXAdapterV3.ETH_ADDRESS || _swapData.path[_swapData.path.length - 1] == dexAdapter.weth, "Invalid output token");
            uint256 ethReceived = dexAdapter.swapExactTokensForTokens(_amount, 0, _swapData);
            if(_swapData.path[_swapData.path.length - 1] == dexAdapter.weth) {
                IWETH(dexAdapter.weth).withdraw(ethReceived);
            }
            return;
        }
        if (_isInstadapp(_component)) {
            _withdrawFromInstadapp(IERC4626(_component), _amount);
            return;
        }
        IPendleMarketV3 market = pendleMarkets[IPendlePrincipalToken(_component)];
        if (market != IPendleMarketV3(address(0))) {
            _withdrawFromPendle(IPendlePrincipalToken(_component), _amount, market);
            return;
        }
        if (IERC20(_component) == acrossToken) {
            _withdrawFromAcross(_amount);
            return;
        }
        if (_component == dexAdapter.weth) {
            IWETH(dexAdapter.weth).withdraw(_amount);
            return;
        }
        if (erc4626Components[_component]) {
            address asset = IERC4626(_component).asset();
            uint256 assetAmount = IERC4626(_component).redeem(_amount, address(this), address(this));
            _swapExactTokenForEth(IERC20(asset), assetAmount, swapData[asset][DEXAdapterV3.ETH_ADDRESS]);
            return;
        }
        revert("Missing Swapdata for non-standard component");
    }

    /**
     * @dev Deposit eth into steth and then into instadapp vault
     *
     */
    function _depositIntoInstadapp(IERC4626 _vault, uint256 _amount) internal {
        uint256 stETHAmount = _vault.previewMint(_amount);
        _depositIntoLido(stETHAmount);
        _vault.mint(_amount, address(this));
    }

    /**
     * @dev Deposit eth into steth
     *
     */
    function _depositIntoLido(uint256 _amount) internal {
        stETH.submit{ value: _amount }(address(0));
    }

    /**
     * @dev Withdraw steth from instadapp vault and then swap to eth
     * @dev Requires the respective swap data (stETH -> ETH) to be set
     *
     */
    function _withdrawFromInstadapp(IERC4626 _vault, uint256 _amount) internal {
        uint256 stETHAmount = _vault.redeem(_amount, address(this), address(this));
        _swapExactTokensForTokens(stETHAmount, address(stETH), address(0));
    }

    /**
     * @dev Check if given component is the Instadapp vault
     *
     */
    function _isInstadapp(address _token) internal pure returns (bool) {
        return _token == 0xA0D3707c569ff8C87FA923d3823eC5D81c98Be78;
    }

    /**
     * @dev Get Sy token for given pt token
     * @dev Also functions as check if given component is a Pendle Principal Token
     *
     */
    function _getSyToken(
        IPendlePrincipalToken _pt
    ) internal view returns (IPendleStandardizedYield) {
        return pendleMarketData[pendleMarkets[_pt]].sy;
    }

    /**
     * @dev Initiate deposit into Pendle by swapping pt for sy
     * @dev Deposit from eth to sy is done in swapCallback
     */
    function _depositIntoPendle(
        IPendlePrincipalToken _pt,
        uint256 _ptAmount,
        IPendleStandardizedYield _sy
    ) internal {
        // Adding random bytes here since PendleMarket will not call back if data is empty
        IPendleMarketV3(pendleMarkets[_pt]).swapSyForExactPt(address(this), _ptAmount, bytes("a"));
    }

    /**
     * @dev Obtain across lp tokens by adding eth liquidity into the across pool
     */
    function _depositIntoAcross(uint256 _acrossLpAmount) internal {
        uint256 ethAmount = acrossPool
            .exchangeRateCurrent(dexAdapter.weth)
            .mul(_acrossLpAmount)
            .div(1e18)
            .add(ROUNDING_ERROR);
        acrossPool.addLiquidity{ value: ethAmount }(dexAdapter.weth, ethAmount);
    }

    /**
     * @dev Withdraw eth by removing liquidity from across pool
     */
    function _withdrawFromAcross(uint256 _acrossLpAmount) internal {
        acrossPool.removeLiquidity(dexAdapter.weth, _acrossLpAmount, true);
    }

    /**
     * @dev Withdraw from Pendle by swapping pt for sy, redeeming sy for underlying and swapping underlying to eth
     */
    function _withdrawFromPendle(
        IPendlePrincipalToken _pt,
        uint256 _ptAmount,
        IPendleMarketV3 _pendleMarket
    ) internal {
        // Adding random bytes here since PendleMarket will not call back if data is empty
        (uint256 syAmount, ) = _pendleMarket.swapExactPtForSy(address(this), _ptAmount, bytes("a"));
        PendleMarketData storage data = pendleMarketData[_pendleMarket];
        uint256 amountUnderlying = data.sy.redeem(
            address(this),
            syAmount,
            data.underlying,
            0,
            false
        );
        _swapExactTokensForTokens(amountUnderlying, data.underlying, address(0));
        IWETH(dexAdapter.weth).withdraw(IERC20(dexAdapter.weth).balanceOf(address(this)));
    }

    /**
     * @dev Swap exact amount of input token for output token using configured swap data
     */
    function _swapExactTokensForTokens(
        uint256 _amountIn,
        address _inputToken,
        address _outputToken
    ) internal returns (uint256) {
        dexAdapter.swapExactTokensForTokens(_amountIn, 0, swapData[_inputToken][_outputToken]);
    }

    /**
     * @dev Convert ETH to specified token, either swapping or simply depositing if outputToken is WETH
     */
    function _swapFromEthToToken(
        IERC20 _outputToken,
        uint256 _ethAmount,
        DEXAdapterV3.SwapData memory _swapDataEthToOutputToken
    ) internal returns(uint256 outputTokenAmount) {
        if(address(_outputToken) == address(dexAdapter.weth)) {
           outputTokenAmount = _ethAmount;
           IWETH(dexAdapter.weth).deposit{value: _ethAmount}();
        } else {
           if(_swapDataEthToOutputToken.path[0] == dexAdapter.weth) {
               IWETH(dexAdapter.weth).deposit{value: _ethAmount}();
           } 
           outputTokenAmount = dexAdapter.swapExactTokensForTokens(
               _ethAmount,
               0,
               _swapDataEthToOutputToken
           );
        }
    }

    /**
     * @dev Convert specified token to ETH, either swapping or simply withdrawing if inputToken is WETH
     */
    function _swapExactTokenForEth(
        IERC20 _inputToken,
        uint256 _inputTokenAmount,
        DEXAdapterV3.SwapData memory _swapDataInputTokenToEth
    ) internal returns (uint256 ethAmount) {
        if(address(_inputToken) == dexAdapter.weth) {
           ethAmount = _inputTokenAmount;
           IWETH(dexAdapter.weth).withdraw(ethAmount);
        } else {
           ethAmount = dexAdapter.swapExactTokensForTokens(
               _inputTokenAmount,
               0,
               _swapDataInputTokenToEth
           );
           if(_swapDataInputTokenToEth.path[_swapDataInputTokenToEth.path.length - 1] == dexAdapter.weth) {
               IWETH(dexAdapter.weth).withdraw(ethAmount);
           } 
        }
    }

    function _swapEthForExactToken(address _token, uint256 _amount, DEXAdapterV3.SwapData memory _swapData) internal {
        if(_token == dexAdapter.weth) {
           IWETH(dexAdapter.weth).deposit{value: _amount}();
           return;
        } 

        require(_swapData.path.length > 1, "zero length swap path");
        require(_swapData.path[0] == DEXAdapterV3.ETH_ADDRESS || _swapData.path[0] == dexAdapter.weth, "Invalid input token");
        require(_swapData.path[_swapData.path.length - 1] == _token, "Invalid output token");
        if(_swapData.path[0] == dexAdapter.weth) {
            uint256 balanceBefore = IWETH(dexAdapter.weth).balanceOf(address(this));
            IWETH(dexAdapter.weth).deposit{value: address(this).balance}();
            dexAdapter.swapTokensForExactTokens(_amount, IWETH(dexAdapter.weth).balanceOf(address(this)), _swapData);
            IWETH(dexAdapter.weth).withdraw(IWETH(dexAdapter.weth).balanceOf(address(this)).sub(balanceBefore));
        }
        else {
            dexAdapter.swapTokensForExactTokens(_amount, address(this).balance, _swapData);
        }
    }
}
IController.sol 28 lines
/*
    Copyright 2020 Set Labs Inc.
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
    SPDX-License-Identifier: Apache License, Version 2.0
*/
pragma solidity 0.6.10;

interface IController {
    function addSet(address _setToken) external;
    function feeRecipient() external view returns(address);
    function getModuleFee(address _module, uint256 _feeType) external view returns(uint256);
    function isModule(address _module) external view returns(bool);
    function isSet(address _setToken) external view returns(bool);
    function isSystemContract(address _contractAddress) external view returns (bool);
    function isResource(address _resource) external view returns(bool);
    function resourceId(uint256 _id) external view returns(address);
    function owner() external view returns(address);
    function addFactory(address _factory) external;
    function addModule(address _module) external;
}
IDebtIssuanceModule.sol 38 lines
/*
    Copyright 2020 Set Labs Inc.
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
    SPDX-License-Identifier: Apache License, Version 2.0
*/
pragma solidity >=0.6.10;

import { ISetToken } from "./ISetToken.sol";
import { IManagerIssuanceHook } from "./IManagerIssuanceHook.sol";

interface IDebtIssuanceModule {
    function getRequiredComponentIssuanceUnits(
        ISetToken _setToken,
        uint256 _quantity
    ) external view returns (address[] memory, uint256[] memory, uint256[] memory);
    function getRequiredComponentRedemptionUnits(
        ISetToken _setToken,
        uint256 _quantity
    ) external view returns (address[] memory, uint256[] memory, uint256[] memory);
    function issue(ISetToken _setToken, uint256 _quantity, address _to) external;
    function redeem(ISetToken _token, uint256 _quantity, address _to) external;
    function initialize(
        ISetToken _setToken,
        uint256 _maxManagerFee,
        uint256 _managerIssueFee,
        uint256 _managerRedeemFee,
        address _feeRecipient,
        IManagerIssuanceHook _managerIssuanceHook
    ) external;
}
IERC4626.sol 14 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.6.10;

interface IERC4626 {
    function asset() external view returns (address);
    function deposit(uint256 assets_, address receiver_) external returns (uint256 shares_);
    function mint(uint256 shares_, address receiver_) external returns (uint256 assets_);
    function redeem(uint256 shares_, address receiver_, address owner_) external returns (uint256 assetsAfterFee_);
    function withdraw(uint256 assets_, address receiver_, address owner_) external returns (uint256 shares_);
    function previewDeposit(uint256 assets) external view returns (uint256);
    function previewMint(uint256 shares) external view returns (uint256);
    function previewRedeem(uint256 shares) external view returns (uint256);
    function previewWithdraw(uint256 assets) external view returns (uint256);
}
IManagerIssuanceHook.sol 25 lines
/*
    Copyright 2020 Set Labs Inc.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

    SPDX-License-Identifier: Apache License, Version 2.0
*/
pragma solidity 0.6.10;

import { ISetToken } from "./ISetToken.sol";

interface IManagerIssuanceHook {
    function invokePreIssueHook(ISetToken _setToken, uint256 _issueQuantity, address _sender, address _to) external;
    function invokePreRedeemHook(ISetToken _setToken, uint256 _redeemQuantity, address _sender, address _to) external;
}
IQuoter.sol 51 lines
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.6.10;
pragma experimental ABIEncoderV2;

/// @title Quoter Interface
/// @notice Supports quoting the calculated amounts from exact input or exact output swaps
/// @dev These functions are not marked view because they rely on calling non-view functions and reverting
/// to compute the result. They are also not gas efficient and should not be called on-chain.
interface IQuoter {
    /// @notice Returns the amount out received for a given exact input swap without executing the swap
    /// @param path The path of the swap, i.e. each token pair and the pool fee
    /// @param amountIn The amount of the first token to swap
    /// @return amountOut The amount of the last token that would be received
    function quoteExactInput(bytes memory path, uint256 amountIn) external returns (uint256 amountOut);

    /// @notice Returns the amount out received for a given exact input but for a swap of a single pool
    /// @param tokenIn The token being swapped in
    /// @param tokenOut The token being swapped out
    /// @param fee The fee of the token pool to consider for the pair
    /// @param amountIn The desired input amount
    /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap
    /// @return amountOut The amount of `tokenOut` that would be received
    function quoteExactInputSingle(
        address tokenIn,
        address tokenOut,
        uint24 fee,
        uint256 amountIn,
        uint160 sqrtPriceLimitX96
    ) external returns (uint256 amountOut);

    /// @notice Returns the amount in required for a given exact output swap without executing the swap
    /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order
    /// @param amountOut The amount of the last token to receive
    /// @return amountIn The amount of first token required to be paid
    function quoteExactOutput(bytes memory path, uint256 amountOut) external returns (uint256 amountIn);

    /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool
    /// @param tokenIn The token being swapped in
    /// @param tokenOut The token being swapped out
    /// @param fee The fee of the token pool to consider for the pair
    /// @param amountOut The desired output amount
    /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap
    /// @return amountIn The amount required as the input for the swap in order to receive `amountOut`
    function quoteExactOutputSingle(
        address tokenIn,
        address tokenOut,
        uint24 fee,
        uint256 amountOut,
        uint160 sqrtPriceLimitX96
    ) external returns (uint256 amountIn);
}
ISetToken.sol 120 lines
// SPDX-License-Identifier: Apache License, Version 2.0
pragma solidity 0.6.10;
pragma experimental "ABIEncoderV2";

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @title ISetToken
 * @author Set Protocol
 *
 * Interface for operating with SetTokens.
 */
interface ISetToken is IERC20 {

    /* ============ Enums ============ */

    enum ModuleState {
        NONE,
        PENDING,
        INITIALIZED
    }

    /* ============ Structs ============ */
    /**
     * The base definition of a SetToken Position
     *
     * @param component           Address of token in the Position
     * @param module              If not in default state, the address of associated module
     * @param unit                Each unit is the # of components per 10^18 of a SetToken
     * @param positionState       Position ENUM. Default is 0; External is 1
     * @param data                Arbitrary data
     */
    struct Position {
        address component;
        address module;
        int256 unit;
        uint8 positionState;
        bytes data;
    }

    /**
     * A struct that stores a component's cash position details and external positions
     * This data structure allows O(1) access to a component's cash position units and
     * virtual units.
     *
     * @param virtualUnit               Virtual value of a component's DEFAULT position. Stored as virtual for efficiency
     *                                  updating all units at once via the position multiplier. Virtual units are achieved
     *                                  by dividing a "real" value by the "positionMultiplier"
     * @param componentIndex
     * @param externalPositionModules   List of external modules attached to each external position. Each module
     *                                  maps to an external position
     * @param externalPositions         Mapping of module => ExternalPosition struct for a given component
     */
    struct ComponentPosition {
      int256 virtualUnit;
      address[] externalPositionModules;
      mapping(address => ExternalPosition) externalPositions;
    }

    /**
     * A struct that stores a component's external position details including virtual unit and any
     * auxiliary data.
     *
     * @param virtualUnit       Virtual value of a component's EXTERNAL position.
     * @param data              Arbitrary data
     */
    struct ExternalPosition {
      int256 virtualUnit;
      bytes data;
    }


    /* ============ Functions ============ */

    function controller() external view returns (address);

    function addComponent(address _component) external;
    function removeComponent(address _component) external;
    function editDefaultPositionUnit(address _component, int256 _realUnit) external;
    function addExternalPositionModule(address _component, address _positionModule) external;
    function removeExternalPositionModule(address _component, address _positionModule) external;
    function editExternalPositionUnit(address _component, address _positionModule, int256 _realUnit) external;
    function editExternalPositionData(address _component, address _positionModule, bytes calldata _data) external;

    function invoke(address _target, uint256 _value, bytes calldata _data) external returns(bytes memory);

    function editPositionMultiplier(int256 _newMultiplier) external;

    function mint(address _account, uint256 _quantity) external;
    function burn(address _account, uint256 _quantity) external;

    function lock() external;
    function unlock() external;

    function addModule(address _module) external;
    function removeModule(address _module) external;
    function initializeModule() external;

    function setManager(address _manager) external;

    function manager() external view returns (address);
    function moduleStates(address _module) external view returns (ModuleState);
    function getModules() external view returns (address[] memory);

    function getDefaultPositionRealUnit(address _component) external view returns(int256);
    function getExternalPositionRealUnit(address _component, address _positionModule) external view returns(int256);
    function getComponents() external view returns(address[] memory);
    function getExternalPositionModules(address _component) external view returns(address[] memory);
    function getExternalPositionData(address _component, address _positionModule) external view returns(bytes memory);
    function isExternalPositionModule(address _component, address _module) external view returns(bool);
    function isComponent(address _component) external view returns(bool);

    function positionMultiplier() external view returns (int256);
    function getPositions() external view returns (Position[] memory);
    function getTotalComponentRealUnits(address _component) external view returns(int256);

    function isInitializedModule(address _module) external view returns(bool);
    function isPendingModule(address _module) external view returns(bool);
    function isLocked() external view returns (bool);
}
IWETH.sol 8 lines
// SPDX-License-Identifier: Apache License, Version 2.0
pragma solidity >=0.6.10;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IWETH is IERC20 {
    function deposit() external payable;
    function withdraw(uint) external;
}
IAcrossHubPoolV2.sol 97 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.6.10;
pragma experimental ABIEncoderV2;

interface IAcrossHubPoolV2 {
    function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;
    function bondAmount() external view returns (uint256);
    function bondToken() external view returns (address);
    function claimProtocolFeesCaptured(address l1Token) external;
    function crossChainContracts(uint256) external view returns (address adapter, address spokePool);
    function disableL1TokenForLiquidityProvision(address l1Token) external;
    function disputeRootBundle() external;
    function emergencyDeleteProposal() external;
    function enableL1TokenForLiquidityProvision(address l1Token) external;
    function exchangeRateCurrent(address l1Token) external returns (uint256);
    function executeRootBundle(
        uint256 chainId,
        uint256 groupIndex,
        uint256[] memory bundleLpFees,
        int256[] memory netSendAmounts,
        int256[] memory runningBalances,
        uint8 leafId,
        address[] memory l1Tokens,
        bytes32[] memory proof
    ) external;
    function finder() external view returns (address);
    function getCurrentTime() external view returns (uint256);
    function haircutReserves(address l1Token, int256 haircutAmount) external;
    function identifier() external view returns (bytes32);
    function liquidityUtilizationCurrent(address l1Token) external returns (uint256);
    function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);
    function liveness() external view returns (uint32);
    function loadEthForL2Calls() external payable;
    function lpFeeRatePerSecond() external view returns (uint256);
    function lpTokenFactory() external view returns (address);
    function multicall(bytes[] memory data) external payable returns (bytes[] memory results);
    function owner() external view returns (address);
    function paused() external view returns (bool);
    function poolRebalanceRoute(uint256 destinationChainId, address l1Token)
        external
        view
        returns (address destinationToken);
    function pooledTokens(address)
        external
        view
        returns (
            address lpToken,
            bool isEnabled,
            uint32 lastLpFeeUpdate,
            int256 utilizedReserves,
            uint256 liquidReserves,
            uint256 undistributedLpFees
        );
    function proposeRootBundle(
        uint256[] memory bundleEvaluationBlockNumbers,
        uint8 poolRebalanceLeafCount,
        bytes32 poolRebalanceRoot,
        bytes32 relayerRefundRoot,
        bytes32 slowRelayRoot
    ) external;
    function protocolFeeCaptureAddress() external view returns (address);
    function protocolFeeCapturePct() external view returns (uint256);
    function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;
    function removeLiquidity(address l1Token, uint256 lpTokenAmount, bool sendEth) external;
    function renounceOwnership() external;
    function rootBundleProposal()
        external
        view
        returns (
            bytes32 poolRebalanceRoot,
            bytes32 relayerRefundRoot,
            bytes32 slowRelayRoot,
            uint256 claimedBitMap,
            address proposer,
            uint8 unclaimedPoolRebalanceLeafCount,
            uint32 challengePeriodEndTimestamp
        );
    function setBond(address newBondToken, uint256 newBondAmount) external;
    function setCrossChainContracts(uint256 l2ChainId, address adapter, address spokePool) external;
    function setCurrentTime(uint256 time) external;
    function setDepositRoute(
        uint256 originChainId,
        uint256 destinationChainId,
        address originToken,
        bool depositsEnabled
    ) external;
    function setIdentifier(bytes32 newIdentifier) external;
    function setLiveness(uint32 newLiveness) external;
    function setPaused(bool pause) external;
    function setPoolRebalanceRoute(uint256 destinationChainId, address l1Token, address destinationToken) external;
    function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;
    function sync(address l1Token) external;
    function timerAddress() external view returns (address);
    function transferOwnership(address newOwner) external;
    function unclaimedAccumulatedProtocolFees(address) external view returns (uint256);
    function weth() external view returns (address);
}
ICurveAddressProvider.sol 23 lines
/*
    Copyright 2022 Index Cooperative

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

    SPDX-License-Identifier: Apache License, Version 2.0
*/
pragma solidity 0.6.10;
pragma experimental ABIEncoderV2;

// Implementation: https://etherscan.io/address/0x0000000022d53366457f9d5e68ec105046fc4383#readContract
interface ICurveAddressProvider {
    function get_registry() external view returns(address);
    function get_address(uint256 _id) external view returns(address);
}
ICurveCalculator.sol 46 lines
/*
    Copyright 2022 Index Cooperative

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

    SPDX-License-Identifier: Apache License, Version 2.0
*/
pragma solidity 0.6.10;
pragma experimental ABIEncoderV2;

// Implementation: https://etherscan.io/address/0xc1DB00a8E5Ef7bfa476395cdbcc98235477cDE4E#readContract
interface ICurveCalculator {
    function get_dx(
        int128 n_coins,
        uint256[8] memory balances,
        uint256 amp,
        uint256 fee,
        uint256[8] memory rates,
        uint256[8] memory precisions,
        bool underlying,
        int128 i,
        int128 j,
        uint256 dy
    ) external view returns(uint256);

    function get_dy(
        int128 n_coins,
        uint256[8] memory balances,
        uint256 amp,
        uint256 fee,
        uint256[8] memory rates,
        uint256[8] memory precisions,
        bool underlying,
        int128 i,
        int128 j,
        uint256 dx
    ) external view returns(uint256);
}
ICurvePool.sol 34 lines
/*
    Copyright 2022 Index Cooperative

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

    SPDX-License-Identifier: Apache License, Version 2.0
*/
pragma solidity 0.6.10;
pragma experimental ABIEncoderV2;

// Implementation: https://etherscan.io/address/0x8e764bE4288B842791989DB5b8ec067279829809#writeContract
interface ICurvePool {
    function exchange(
        int128 i,
        int128 j,
        uint256 dx,
        uint256 min_dy
    ) external payable returns (uint256);

    function get_dy(
        int128 i,
        int128 j,
        uint256 dx
    ) external view returns (uint256);
}
ICurvePoolRegistry.sol 30 lines
/*
    Copyright 2022 Index Cooperative

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

    SPDX-License-Identifier: Apache License, Version 2.0
*/
pragma solidity 0.6.10;
pragma experimental ABIEncoderV2;

// Implementation: https://etherscan.io/address/0x90E00ACe148ca3b23Ac1bC8C240C2a7Dd9c2d7f5#readContract
interface ICurvePoolRegistry {
    // amplification factor
    function get_A(address _pool) external view returns(uint256);
    function get_balances(address _pool) external view returns(uint256[8] memory);
    function get_coins(address _pool) external view returns(address[8] memory);
    function get_coin_indices(address _pool, address _from, address _to) external view returns(int128, int128, bool);
    function get_decimals(address _pool) external view returns(uint256[8] memory);
    function get_n_coins(address _pool) external view returns(uint256[2] memory);
    function get_fees(address _pool) external view returns(uint256[2] memory);
    function get_rates(address _pool) external view returns(uint256[8] memory);
}
IPendleMarketV3.sol 86 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.6.10;
pragma experimental ABIEncoderV2;

interface IPendleMarketV3 {
    struct MarketState {
        int256 totalPt;
        int256 totalSy;
        int256 totalLp;
        address treasury;
        int256 scalarRoot;
        uint256 expiry;
        uint256 lnFeeRateRoot;
        uint256 reserveFeePercent;
        uint256 lastLnImpliedRate;
    }

    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function _storage()
        external
        view
        returns (
            int128 totalPt,
            int128 totalSy,
            uint96 lastLnImpliedRate,
            uint16 observationIndex,
            uint16 observationCardinality,
            uint16 observationCardinalityNext
        );
    function activeBalance(address) external view returns (uint256);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function balanceOf(address account) external view returns (uint256);
    function burn(address receiverSy, address receiverPt, uint256 netLpToBurn)
        external
        returns (uint256 netSyOut, uint256 netPtOut);
    function decimals() external view returns (uint8);
    function eip712Domain()
        external
        view
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        );
    function expiry() external view returns (uint256);
    function factory() external view returns (address);
    function getNonOverrideLnFeeRateRoot() external view returns (uint80);
    function getRewardTokens() external view returns (address[] memory);
    function increaseObservationsCardinalityNext(uint16 cardinalityNext) external;
    function isExpired() external view returns (bool);
    function lastRewardBlock() external view returns (uint256);
    function mint(address receiver, uint256 netSyDesired, uint256 netPtDesired)
        external
        returns (uint256 netLpOut, uint256 netSyUsed, uint256 netPtUsed);
    function name() external view returns (string memory);
    function nonces(address owner) external view returns (uint256);
    function observations(uint256)
        external
        view
        returns (uint32 blockTimestamp, uint216 lnImpliedRateCumulative, bool initialized);
    function observe(uint32[] memory secondsAgos) external view returns (uint216[] memory lnImpliedRateCumulative);
    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
        external;
    function readState(address router) external view returns (MarketState memory market);
    function readTokens() external view returns (address _SY, address _PT, address _YT);
    function redeemRewards(address user) external returns (uint256[] memory);
    function rewardState(address) external view returns (uint128 index, uint128 lastBalance);
    function skim() external;
    function swapExactPtForSy(address receiver, uint256 exactPtIn, bytes memory data)
        external
        returns (uint256 netSyOut, uint256 netSyFee);
    function swapSyForExactPt(address receiver, uint256 exactPtOut, bytes memory data)
        external
        returns (uint256 netSyIn, uint256 netSyFee);
    function symbol() external view returns (string memory);
    function totalActiveSupply() external view returns (uint256);
    function totalSupply() external view returns (uint256);
    function transfer(address to, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
    function userReward(address, address) external view returns (uint128 index, uint128 accrued);
}
IPendlePrincipalToken.sol 39 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.6.10;
pragma experimental ABIEncoderV2;

interface IPendlePrincipalToken {
    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function SY() external view returns (address);
    function YT() external view returns (address);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function balanceOf(address account) external view returns (uint256);
    function burnByYT(address user, uint256 amount) external;
    function decimals() external view returns (uint8);
    function eip712Domain()
        external
        view
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        );
    function expiry() external view returns (uint256);
    function factory() external view returns (address);
    function initialize(address _YT) external;
    function isExpired() external view returns (bool);
    function mintByYT(address user, uint256 amount) external;
    function name() external view returns (string memory);
    function nonces(address owner) external view returns (uint256);
    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
        external;
    function symbol() external view returns (string memory);
    function totalSupply() external view returns (uint256);
    function transfer(address to, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
IPendleStandardizedYield.sol 73 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.6.10;
pragma experimental ABIEncoderV2;

interface IPendleStandardizedYield {
    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function accruedRewards(address) external view returns (uint256[] memory rewardAmounts);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function assetInfo() external view returns (uint8, address, uint8);
    function balanceOf(address account) external view returns (uint256);
    function claimOwnership() external;
    function claimRewards(address) external returns (uint256[] memory rewardAmounts);
    function decimals() external view returns (uint8);
    function deposit(address receiver, address tokenIn, uint256 amountTokenToDeposit, uint256 minSharesOut)
        external
        payable
        returns (uint256 amountSharesOut);
    function eETH() external view returns (address);
    function eip712Domain()
        external
        view
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        );
    function exchangeRate() external view returns (uint256);
    function getRewardTokens() external view returns (address[] memory rewardTokens);
    function getTokensIn() external view returns (address[] memory res);
    function getTokensOut() external view returns (address[] memory res);
    function isValidTokenIn(address token) external view returns (bool);
    function isValidTokenOut(address token) external view returns (bool);
    function liquidityPool() external view returns (address);
    function name() external view returns (string memory);
    function nonces(address owner) external view returns (uint256);
    function owner() external view returns (address);
    function pause() external;
    function paused() external view returns (bool);
    function pendingOwner() external view returns (address);
    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
        external;
    function previewDeposit(address tokenIn, uint256 amountTokenToDeposit)
        external
        view
        returns (uint256 amountSharesOut);
    function previewRedeem(address tokenOut, uint256 amountSharesToRedeem)
        external
        view
        returns (uint256 amountTokenOut);
    function redeem(
        address receiver,
        uint256 amountSharesToRedeem,
        address tokenOut,
        uint256 minTokenOut,
        bool burnFromInternalBalance
    ) external returns (uint256 amountTokenOut);
    function referee() external view returns (address);
    function rewardIndexesCurrent() external returns (uint256[] memory indexes);
    function rewardIndexesStored() external view returns (uint256[] memory indexes);
    function symbol() external view returns (string memory);
    function totalSupply() external view returns (uint256);
    function transfer(address to, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
    function transferOwnership(address newOwner, bool direct, bool renounce) external;
    function unpause() external;
    function weETH() external view returns (address);
    function yieldToken() external view returns (address);
}
IRsEthAdapter.sol 11 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.6.10;

interface IRsEthAdapter {
    function depositRsETH(uint256 rsETHAmount, string memory referralId) external;
    function getRSETHWithERC20(address asset, uint256 depositAmount, string memory referralId) external;
    function getRSETHWithETH(string memory referralId) external payable;
    function lrtDepositPool() external view returns (address);
    function rsETH() external view returns (address);
    function vault() external view returns (address);
}
IStETH.sol 6 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.6.10;

interface IStETH {
    function submit(address _referral) external payable returns (uint256);
}
ISwapRouter02.sol 127 lines
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.6.10;
pragma experimental ABIEncoderV2;

interface ISwapRouter02 {
    struct IncreaseLiquidityParams {
        address token0;
        address token1;
        uint256 tokenId;
        uint256 amount0Min;
        uint256 amount1Min;
    }

    struct MintParams {
        address token0;
        address token1;
        uint24 fee;
        int24 tickLower;
        int24 tickUpper;
        uint256 amount0Min;
        uint256 amount1Min;
        address recipient;
    }

    struct ExactInputParams {
        bytes path;
        address recipient;
        uint256 amountIn;
        uint256 amountOutMinimum;
    }

    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 amountIn;
        uint256 amountOutMinimum;
        uint160 sqrtPriceLimitX96;
    }

    struct ExactOutputParams {
        bytes path;
        address recipient;
        uint256 amountOut;
        uint256 amountInMaximum;
    }

    struct ExactOutputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 amountOut;
        uint256 amountInMaximum;
        uint160 sqrtPriceLimitX96;
    }

    function WETH9() external view returns (address);
    function approveMax(address token) external payable;
    function approveMaxMinusOne(address token) external payable;
    function approveZeroThenMax(address token) external payable;
    function approveZeroThenMaxMinusOne(address token) external payable;
    function callPositionManager(bytes memory data) external payable returns (bytes memory result);
    function checkOracleSlippage(
        bytes[] memory paths,
        uint128[] memory amounts,
        uint24 maximumTickDivergence,
        uint32 secondsAgo
    ) external view;
    function checkOracleSlippage(bytes memory path, uint24 maximumTickDivergence, uint32 secondsAgo) external view;
    function exactInput(ExactInputParams memory params) external payable returns (uint256 amountOut);
    function exactInputSingle(ExactInputSingleParams memory params) external payable returns (uint256 amountOut);
    function exactOutput(ExactOutputParams memory params) external payable returns (uint256 amountIn);
    function exactOutputSingle(ExactOutputSingleParams memory params) external payable returns (uint256 amountIn);
    function factory() external view returns (address);
    function factoryV2() external view returns (address);
    function getApprovalType(address token, uint256 amount) external returns (uint8);
    function increaseLiquidity(IncreaseLiquidityParams memory params) external payable returns (bytes memory result);
    function mint(MintParams memory params) external payable returns (bytes memory result);
    function multicall(bytes32 previousBlockhash, bytes[] memory data) external payable returns (bytes[] memory);
    function multicall(uint256 deadline, bytes[] memory data) external payable returns (bytes[] memory);
    function multicall(bytes[] memory data) external payable returns (bytes[] memory results);
    function positionManager() external view returns (address);
    function pull(address token, uint256 value) external payable;
    function refundETH() external payable;
    function selfPermit(address token, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
    external
    payable;
    function selfPermitAllowed(address token, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s)
    external
    payable;
    function selfPermitAllowedIfNecessary(address token, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s)
    external
    payable;
    function selfPermitIfNecessary(address token, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
    external
    payable;
    function swapExactTokensForTokens(uint256 amountIn, uint256 amountOutMin, address[] memory path, address to)
    external
    payable
    returns (uint256 amountOut);
    function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] memory path, address to)
    external
    payable
    returns (uint256 amountIn);
    function sweepToken(address token, uint256 amountMinimum, address recipient) external payable;
    function sweepToken(address token, uint256 amountMinimum) external payable;
    function sweepTokenWithFee(address token, uint256 amountMinimum, uint256 feeBips, address feeRecipient)
    external
    payable;
    function sweepTokenWithFee(
        address token,
        uint256 amountMinimum,
        address recipient,
        uint256 feeBips,
        address feeRecipient
    ) external payable;
    function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes memory _data) external;
    function unwrapWETH9(uint256 amountMinimum, address recipient) external payable;
    function unwrapWETH9(uint256 amountMinimum) external payable;
    function unwrapWETH9WithFee(uint256 amountMinimum, address recipient, uint256 feeBips, address feeRecipient)
    external
    payable;
    function unwrapWETH9WithFee(uint256 amountMinimum, uint256 feeBips, address feeRecipient) external payable;
    function wrapETH(uint256 value) external payable;
}
IVault.sol 273 lines
// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity >=0.6.10 <0.9.0;
pragma experimental ABIEncoderV2;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IFlashLoanRecipient {
    /**
     * @dev When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the recipient.
     *
     * At the time of the call, the Vault will have transferred `amounts` for `tokens` to the recipient. Before this
     * call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token back to the
     * Vault, or else the entire flash loan will revert.
     *
     * `userData` is the same value passed in the `IVault.flashLoan` call.
     */
    function receiveFlashLoan(
        IERC20[] memory tokens,
        uint256[] memory amounts,
        uint256[] memory feeAmounts,
        bytes memory userData
    ) external;
}

/**
 * Stripped down interface of IVault.
 * https://github.com/balancer/balancer-v2-monorepo/blob/master/pkg/interfaces/contracts/vault/IVault.sol
 */
interface IVault {
  // Swaps
  //
  // Users can swap tokens with Pools by calling the `swap` and `batchSwap` functions. To do this,
  // they need not trust Pool contracts in any way: all security checks are made by the Vault. They must however be
  // aware of the Pools' pricing algorithms in order to estimate the prices Pools will quote.
  //
  // The `swap` function executes a single swap, while `batchSwap` can perform multiple swaps in sequence.
  // In each individual swap, tokens of one kind are sent from the sender to the Pool (this is the 'token in'),
  // and tokens of another kind are sent from the Pool to the recipient in exchange (this is the 'token out').
  // More complex swaps, such as one token in to multiple tokens out can be achieved by batching together
  // individual swaps.
  //
  // There are two swap kinds:
  //  - 'given in' swaps, where the amount of tokens in (sent to the Pool) is known, and the Pool determines (via the
  // `onSwap` hook) the amount of tokens out (to send to the recipient).
  //  - 'given out' swaps, where the amount of tokens out (received from the Pool) is known, and the Pool determines
  // (via the `onSwap` hook) the amount of tokens in (to receive from the sender).
  //
  // Additionally, it is possible to chain swaps using a placeholder input amount, which the Vault replaces with
  // the calculated output of the previous swap. If the previous swap was 'given in', this will be the calculated
  // tokenOut amount. If the previous swap was 'given out', it will use the calculated tokenIn amount. These extended
  // swaps are known as 'multihop' swaps, since they 'hop' through a number of intermediate tokens before arriving at
  // the final intended token.
  //
  // In all cases, tokens are only transferred in and out of the Vault (or withdrawn from and deposited into Internal
  // Balance) after all individual swaps have been completed, and the net token balance change computed. This makes
  // certain swap patterns, such as multihops, or swaps that interact with the same token pair in multiple Pools, cost
  // much less gas than they would otherwise.
  //
  // It also means that under certain conditions it is possible to perform arbitrage by swapping with multiple
  // Pools in a way that results in net token movement out of the Vault (profit), with no tokens being sent in (only
  // updating the Pool's internal accounting).
  //
  // To protect users from front-running or the market changing rapidly, they supply a list of 'limits' for each token
  // involved in the swap, where either the maximum number of tokens to send (by passing a positive value) or the
  // minimum amount of tokens to receive (by passing a negative value) is specified.
  //
  // Additionally, a 'deadline' timestamp can also be provided, forcing the swap to fail if it occurs after
  // this point in time (e.g. if the transaction failed to be included in a block promptly).
  //
  // If interacting with Pools that hold WETH, it is possible to both send and receive ETH directly: the Vault will do
  // the wrapping and unwrapping. To enable this mechanism, the IAsset sentinel value (the zero address) must be
  // passed in the `assets` array instead of the WETH address. Note that it is possible to combine ETH and WETH in the
  // same swap. Any excess ETH will be sent back to the caller (not the sender, which is relevant for relayers).
  //
  // Finally, Internal Balance can be used when either sending or receiving tokens.

  enum SwapKind {
    GIVEN_IN,
    GIVEN_OUT
  }

  /**
   * @dev Performs a swap with a single Pool.
   *
   * If the swap is 'given in' (the number of tokens to send to the Pool is known), it returns the amount of tokens
   * taken from the Pool, which must be greater than or equal to `limit`.
   *
   * If the swap is 'given out' (the number of tokens to take from the Pool is known), it returns the amount of tokens
   * sent to the Pool, which must be less than or equal to `limit`.
   *
   * Internal Balance usage and the recipient are determined by the `funds` struct.
   *
   * Emits a `Swap` event.
   */
  function swap(
    SingleSwap memory singleSwap,
    FundManagement memory funds,
    uint256 limit,
    uint256 deadline
  ) external payable returns (uint256);

  /**
   * @dev Data for a single swap executed by `swap`. `amount` is either `amountIn` or `amountOut` depending on
   * the `kind` value.
   *
   * `assetIn` and `assetOut` are either token addresses, or the IAsset sentinel value for ETH (the zero address).
   * Note that Pools never interact with ETH directly: it will be wrapped to or unwrapped from WETH by the Vault.
   *
   * The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be
   * used to extend swap behavior.
   */
  struct SingleSwap {
    bytes32 poolId;
    SwapKind kind;
    address assetIn;
    address assetOut;
    uint256 amount;
    bytes userData;
  }

  /**
   * @dev Performs a series of swaps with one or multiple Pools. In each individual swap, the caller determines either
   * the amount of tokens sent to or received from the Pool, depending on the `kind` value.
   *
   * Returns an array with the net Vault asset balance deltas. Positive amounts represent tokens (or ETH) sent to the
   * Vault, and negative amounts represent tokens (or ETH) sent by the Vault. Each delta corresponds to the asset at
   * the same index in the `assets` array.
   *
   * Swaps are executed sequentially, in the order specified by the `swaps` array. Each array element describes a
   * Pool, the token to be sent to this Pool, the token to receive from it, and an amount that is either `amountIn` or
   * `amountOut` depending on the swap kind.
   *
   * Multihop swaps can be executed by passing an `amount` value of zero for a swap. This will cause the amount in/out
   * of the previous swap to be used as the amount in for the current one. In a 'given in' swap, 'tokenIn' must equal
   * the previous swap's `tokenOut`. For a 'given out' swap, `tokenOut` must equal the previous swap's `tokenIn`.
   *
   * The `assets` array contains the addresses of all assets involved in the swaps. These are either token addresses,
   * or the IAsset sentinel value for ETH (the zero address). Each entry in the `swaps` array specifies tokens in and
   * out by referencing an index in `assets`. Note that Pools never interact with ETH directly: it will be wrapped to
   * or unwrapped from WETH by the Vault.
   *
   * Internal Balance usage, sender, and recipient are determined by the `funds` struct. The `limits` array specifies
   * the minimum or maximum amount of each token the vault is allowed to transfer.
   *
   * `batchSwap` can be used to make a single swap, like `swap` does, but doing so requires more gas than the
   * equivalent `swap` call.
   *
   * Emits `Swap` events.
   */
  function batchSwap(
    SwapKind kind,
    BatchSwapStep[] memory swaps,
    address[] memory assets,
    FundManagement memory funds,
    int256[] memory limits,
    uint256 deadline
  ) external payable returns (int256[] memory);

  /**
   * @dev Data for each individual swap executed by `batchSwap`. The asset in and out fields are indexes into the
   * `assets` array passed to that function, and ETH assets are converted to WETH.
   *
   * If `amount` is zero, the multihop mechanism is used to determine the actual amount based on the amount in/out
   * from the previous swap, depending on the swap kind.
   *
   * The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be
   * used to extend swap behavior.
   */
  struct BatchSwapStep {
    bytes32 poolId;
    uint256 assetInIndex;
    uint256 assetOutIndex;
    uint256 amount;
    bytes userData;
  }

  /**
   * @dev Emitted for each individual swap performed by `swap` or `batchSwap`.
   */
  event Swap(
    bytes32 indexed poolId,
    IERC20 indexed tokenIn,
    IERC20 indexed tokenOut,
    uint256 amountIn,
    uint256 amountOut
  );

  /**
   * @dev All tokens in a swap are either sent from the `sender` account to the Vault, or from the Vault to the
   * `recipient` account.
   *
   * If the caller is not `sender`, it must be an authorized relayer for them.
   *
   * If `fromInternalBalance` is true, the `sender`'s Internal Balance will be preferred, performing an ERC20
   * transfer for the difference between the requested amount and the User's Internal Balance (if any). The `sender`
   * must have allowed the Vault to use their tokens via `IERC20.approve()`. This matches the behavior of
   * `joinPool`.
   *
   * If `toInternalBalance` is true, tokens will be deposited to `recipient`'s internal balance instead of
   * transferred. This matches the behavior of `exitPool`.
   *
   * Note that ETH cannot be deposited to or withdrawn from Internal Balance: attempting to do so will trigger a
   * revert.
   */
  struct FundManagement {
    address sender;
    bool fromInternalBalance;
    address payable recipient;
    bool toInternalBalance;
  }

  /**
   * @dev Simulates a call to `batchSwap`, returning an array of Vault asset deltas. Calls to `swap` cannot be
   * simulated directly, but an equivalent `batchSwap` call can and will yield the exact same result.
   *
   * Each element in the array corresponds to the asset at the same index, and indicates the number of tokens (or ETH)
   * the Vault would take from the sender (if positive) or send to the recipient (if negative). The arguments it
   * receives are the same that an equivalent `batchSwap` call would receive.
   *
   * Unlike `batchSwap`, this function performs no checks on the sender or recipient field in the `funds` struct.
   * This makes it suitable to be called by off-chain applications via eth_call without needing to hold tokens,
   * approve them for the Vault, or even know a user's address.
   *
   * Note that this function is not 'view' (due to implementation details): the client code must explicitly execute
   * eth_call instead of eth_sendTransaction.
   */
  function queryBatchSwap(
    SwapKind kind,
    BatchSwapStep[] memory swaps,
    address[] memory assets,
    FundManagement memory funds
  ) external returns (int256[] memory assetDeltas);

      // Flash Loans

    /**
     * @dev Performs a 'flash loan', sending tokens to `recipient`, executing the `receiveFlashLoan` hook on it,
     * and then reverting unless the tokens plus a proportional protocol fee have been returned.
     *
     * The `tokens` and `amounts` arrays must have the same length, and each entry in these indicates the loan amount
     * for each token contract. `tokens` must be sorted in ascending order.
     *
     * The 'userData' field is ignored by the Vault, and forwarded as-is to `recipient` as part of the
     * `receiveFlashLoan` call.
     *
     * Emits `FlashLoan` events.
     */
    function flashLoan(
        IFlashLoanRecipient recipient,
        address[] memory tokens,
        uint256[] memory amounts,
        bytes memory userData
    ) external;

    /**
     * @dev Emitted for each individual flash loan performed by `flashLoan`.
     */
    event FlashLoan(IFlashLoanRecipient indexed recipient, IERC20 indexed token, uint256 amount, uint256 feeAmount);

}
PreciseUnitMath.sol 190 lines
/*
    Copyright 2020 Set Labs Inc.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

    SPDX-License-Identifier: Apache License, Version 2.0
*/

pragma solidity 0.6.10;
pragma experimental ABIEncoderV2;

import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
import { SignedSafeMath } from "@openzeppelin/contracts/math/SignedSafeMath.sol";


/**
 * @title PreciseUnitMath
 * @author Set Protocol
 *
 * Arithmetic for fixed-point numbers with 18 decimals of precision. Some functions taken from
 * dYdX's BaseMath library.
 *
 * CHANGELOG:
 * - 9/21/20: Added safePower function
 */
library PreciseUnitMath {
    using SafeMath for uint256;
    using SignedSafeMath for int256;

    // The number One in precise units.
    uint256 constant internal PRECISE_UNIT = 10 ** 18;
    int256 constant internal PRECISE_UNIT_INT = 10 ** 18;

    // Max unsigned integer value
    uint256 constant internal MAX_UINT_256 = type(uint256).max;
    // Max and min signed integer value
    int256 constant internal MAX_INT_256 = type(int256).max;
    int256 constant internal MIN_INT_256 = type(int256).min;

    /**
     * @dev Getter function since constants can't be read directly from libraries.
     */
    function preciseUnit() internal pure returns (uint256) {
        return PRECISE_UNIT;
    }

    /**
     * @dev Getter function since constants can't be read directly from libraries.
     */
    function preciseUnitInt() internal pure returns (int256) {
        return PRECISE_UNIT_INT;
    }

    /**
     * @dev Getter function since constants can't be read directly from libraries.
     */
    function maxUint256() internal pure returns (uint256) {
        return MAX_UINT_256;
    }

    /**
     * @dev Getter function since constants can't be read directly from libraries.
     */
    function maxInt256() internal pure returns (int256) {
        return MAX_INT_256;
    }

    /**
     * @dev Getter function since constants can't be read directly from libraries.
     */
    function minInt256() internal pure returns (int256) {
        return MIN_INT_256;
    }

    /**
     * @dev Multiplies value a by value b (result is rounded down). It's assumed that the value b is the significand
     * of a number with 18 decimals precision.
     */
    function preciseMul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a.mul(b).div(PRECISE_UNIT);
    }

    /**
     * @dev Multiplies value a by value b (result is rounded towards zero). It's assumed that the value b is the
     * significand of a number with 18 decimals precision.
     */
    function preciseMul(int256 a, int256 b) internal pure returns (int256) {
        return a.mul(b).div(PRECISE_UNIT_INT);
    }

    /**
     * @dev Multiplies value a by value b (result is rounded up). It's assumed that the value b is the significand
     * of a number with 18 decimals precision.
     */
    function preciseMulCeil(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0 || b == 0) {
            return 0;
        }
        return a.mul(b).sub(1).div(PRECISE_UNIT).add(1);
    }

    /**
     * @dev Divides value a by value b (result is rounded down).
     */
    function preciseDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        return a.mul(PRECISE_UNIT).div(b);
    }


    /**
     * @dev Divides value a by value b (result is rounded towards 0).
     */
    function preciseDiv(int256 a, int256 b) internal pure returns (int256) {
        return a.mul(PRECISE_UNIT_INT).div(b);
    }

    /**
     * @dev Divides value a by value b (result is rounded up or away from 0).
     */
    function preciseDivCeil(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, "Cant divide by 0");

        return a > 0 ? a.mul(PRECISE_UNIT).sub(1).div(b).add(1) : 0;
    }

    /**
     * @dev Divides value a by value b (result is rounded down - positive numbers toward 0 and negative away from 0).
     */
    function divDown(int256 a, int256 b) internal pure returns (int256) {
        require(b != 0, "Cant divide by 0");
        require(a != MIN_INT_256 || b != -1, "Invalid input");

        int256 result = a.div(b);
        if (a ^ b < 0 && a % b != 0) {
            result -= 1;
        }

        return result;
    }

    /**
     * @dev Multiplies value a by value b where rounding is towards the lesser number. 
     * (positive values are rounded towards zero and negative values are rounded away from 0). 
     */
    function conservativePreciseMul(int256 a, int256 b) internal pure returns (int256) {
        return divDown(a.mul(b), PRECISE_UNIT_INT);
    }

    /**
     * @dev Divides value a by value b where rounding is towards the lesser number. 
     * (positive values are rounded towards zero and negative values are rounded away from 0). 
     */
    function conservativePreciseDiv(int256 a, int256 b) internal pure returns (int256) {
        return divDown(a.mul(PRECISE_UNIT_INT), b);
    }

    /**
    * @dev Performs the power on a specified value, reverts on overflow.
    */
    function safePower(
        uint256 a,
        uint256 pow
    )
        internal
        pure
        returns (uint256)
    {
        require(a > 0, "Value must be positive");

        uint256 result = 1;
        for (uint256 i = 0; i < pow; i++){
            uint256 previousResult = result;

            // Using safemath multiplication prevents overflows
            result = previousResult.mul(a);
        }

        return result;
    }
}

Read Contract

ROUNDING_ERROR 0x1db00932 → uint256
acrossPool 0x5fdf4d4c → address
acrossToken 0xc75f6955 → address
agETH 0xa9b008b6 → address
dexAdapter 0x91f03efd → address, address, address, address, address, address, address, address
erc4626Components 0x8b446a3c → bool
issuanceModule 0x72a8b9d7 → address
owner 0x8da5cb5b → address
pendleMarketData 0x72536f82 → address, address, address, uint256
pendleMarkets 0xe714faed → address
rsEthAdapter 0x82f24a38 → address
setController 0x8b2704ec → address
stETH 0xc1fe3e48 → address
swapData 0x4f746bfc → address, uint8

Write Contract 13 functions

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

approveSetToken 0xb7711c63
address _setToken
approveToken 0xda3e3397
address _token
address _spender
uint256 _allowance
issueExactSetFromERC20 0x2cf6c3d6
address _setToken
uint256 _amountSetToken
address _inputToken
uint256 _maxInputTokenAmount
tuple _swapDataInputTokenToEth
tuple _swapDataEthToInputToken
tuple[] _swapDataEthToComponent
returns: uint256
issueExactSetFromETH 0xbc4e830f
address _setToken
uint256 _amountSetToken
tuple[] _swapDataEthToComponent
returns: uint256
redeemExactSetForERC20 0x0a8edc9e
address _setToken
uint256 _amountSetToken
address _outputToken
uint256 _minOutputTokenAmount
tuple _swapDataEthToOutputToken
tuple[] _swapDataComponentToEth
returns: uint256
redeemExactSetForETH 0x328e3f36
address _setToken
uint256 _amountSetToken
uint256 _minETHOut
tuple[] _swapDataComponentToEth
returns: uint256
renounceOwnership 0x715018a6
No parameters
setERC4626Component 0x53ba28d9
address _component
bool _isERC4626
setPendleMarket 0xee0b3f81
address _pt
address _sy
address _underlying
address _market
uint256 _exchangeRateFactor
setSwapData 0x8644d7ec
address _inputToken
address _outputToken
tuple _swapData
swapCallback 0xfa483e72
int256 _ptToAccount
int256 _syToAccount
bytes _data
transferOwnership 0xf2fde38b
address newOwner
withdrawTokens 0x0e8cc705
address[] _tokens
address _to

Token Balances (1)

View Transfers →
WETH 0

Recent Transactions

No transactions found for this address