Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0x06f12B17D97EF27152B68cba208e3415EA65369B
Balance 0 ETH
Nonce 1
Code Size 11153 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

11153 bytes
0x6080604052600436106100ab5760003560e01c8063715018a611610064578063715018a6146102345780638da5cb5b14610249578063c45a015514610267578063d33355531461029b578063f2fde38b146102bb578063fa461e33146102db57600080fd5b806318edaaf21461012757806333cbf0e81461016e5780633667bde7146101815780633fc8cef314610194578063550ba367146101e05780635705ae431461021457600080fd5b3661012257336001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216146101205760405162461bcd60e51b815260206004820152601060248201526f0e4cac6cad2ecca5edcdee85aeecae8d60831b60448201526064015b60405180910390fd5b005b600080fd5b34801561013357600080fd5b5061015b7fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b5481565b6040519081526020015b60405180910390f35b61012061017c3660046127ea565b6102fb565b61012061018f3660046127ea565b6105dc565b3480156101a057600080fd5b506101c87f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6040516001600160a01b039091168152602001610165565b3480156101ec57600080fd5b506101c87f000000000000000000000000972a785b390d05123497169a04c72de652493be181565b34801561022057600080fd5b5061012061022f3660046125fa565b61075e565b34801561024057600080fd5b50610120610824565b34801561025557600080fd5b506000546001600160a01b03166101c8565b34801561027357600080fd5b506101c87f0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f98481565b3480156102a757600080fd5b506101206102b6366004612827565b610896565b3480156102c757600080fd5b506101206102d6366004612586565b610981565b3480156102e757600080fd5b506101206102f636600461266c565b610a1c565b3332146103435760405162461bcd60e51b81526020600482015260166024820152754265746152756e6e6572426173652f6e6f742d656f6160501b6044820152606401610117565b6001546001600160a01b0316602a1461035b57600080fd5b600180546001600160a01b0319163317905560006103b961037f60608401846129a7565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c1192505050565b509150506103cc81338460400135610c82565b6000808061041a6103e060608701876129a7565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ec992505050565b9250925092506000826001600160a01b0316846001600160a01b031610905060006040518060c0016040528088600001358152602001866001600160a01b03168152602001886020013581526020016104768960400135610efe565b815260200161048860608a018a6129a7565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250608089013560209091015290506104d7858585610f14565b6001600160a01b031663128acb0830846104f48b60200135610efe565b8661051d57610518600173fffd8963efd1fc6a506488495d951d5263988d26612a92565b61052d565b61052d6401000276a36001612a4f565b8660405160200161053e9190612945565b6040516020818303038152906040526040518663ffffffff1660e01b815260040161056d9594939291906128a1565b6040805180830381600087803b15801561058657600080fd5b505af115801561059a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105be9190612648565b5050600180546001600160a01b031916602a17905550505050505050565b3332146106245760405162461bcd60e51b81526020600482015260166024820152754265746152756e6e6572426173652f6e6f742d656f6160501b6044820152606401610117565b6001546001600160a01b0316602a1461063c57600080fd5b600180546001600160a01b03191633908117909155600090610664908335602085013561101a565b90506000808061067a6103e060608701876129a7565b9250925092506000836001600160a01b0316836001600160a01b031610905060006040518060c0016040528088600001358152602001866001600160a01b031681526020018781526020016106d28960400135610efe565b6106db90612afd565b81526020016106ed60608a018a6129a7565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506080890135602090910152905061073c848685610f14565b6001600160a01b031663128acb0830846107558a610efe565b6104f490612afd565b6000546001600160a01b031633146107885760405162461bcd60e51b815260040161011790612910565b60001981141561080c576040516370a0823160e01b81523060048201526001600160a01b038316906370a082319060240160206040518083038186803b1580156107d157600080fd5b505afa1580156107e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108099190612840565b90505b6108206001600160a01b03831633836110ca565b5050565b6000546001600160a01b0316331461084e5760405162461bcd60e51b815260040161011790612910565b60405162461bcd60e51b815260206004820152601a60248201527f72656e6f756e63654f776e6572736869702f64697361626c65640000000000006044820152606401610117565b6000546001600160a01b031633146108c05760405162461bcd60e51b815260040161011790612910565b6000198114156108cd5750475b60408051600080825260208201909252339083906040516108ee9190612885565b60006040518083038185875af1925050503d806000811461092b576040519150601f19603f3d011682016040523d82523d6000602084013e610930565b606091505b50509050806108205760405162461bcd60e51b815260206004820152601e60248201527f7265636f7665724554482f6574682d7472616e736665722d6661696c656400006044820152606401610117565b6000546001600160a01b031633146109ab5760405162461bcd60e51b815260040161011790612910565b6001600160a01b038116610a105760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610117565b610a19816110fa565b50565b6001546001600160a01b03163214610a3357600080fd5b6000610a41828401846126ec565b905060008060008713610a5d5785610a5888612afd565b610a67565b86610a6787612afd565b91509150600083606001511315610a8857610a8382828561114a565b610a93565b610a9382828561139a565b50505050505050565b801580610b255750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b158015610aeb57600080fd5b505afa158015610aff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b239190612840565b155b610b905760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610117565b6040516001600160a01b038316602482015260448101829052610bf390849063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261166b565b505050565b6060610c07848460008561173d565b90505b9392505050565b6000806000610c2e60148551610c279190612aba565b8590611865565b9150610c52610c3f60036014612a7a565b8551610c4b9190612aba565b8590611919565b9050610c7a6014610c64600382612a7a565b610c6e9190612a7a565b8551610c279190612aba565b949193509150565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316836001600160a01b03161415610eb4576001600160a01b0382163314610d145760405162461bcd60e51b815260206004820152601b60248201527f5f7472616e73666572496e2f6e6f742d66726f6d2d73656e64657200000000006044820152606401610117565b34811115610d705760405162461bcd60e51b815260206004820152602360248201527f5f7472616e73666572496e2f696e73756666696369656e742d6574682d616d6f6044820152621d5b9d60ea1b6064820152608401610117565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015610dcb57600080fd5b505af1158015610ddf573d6000803e3d6000fd5b505050505080341115610bf35760006001600160a01b038316610e028334612aba565b60408051600081526020810191829052610e1b91612885565b60006040518083038185875af1925050503d8060008114610e58576040519150601f19603f3d011682016040523d82523d6000602084013e610e5d565b606091505b5050905080610eae5760405162461bcd60e51b815260206004820152601f60248201527f5f7472616e73666572496e2f6574682d7472616e736665722d6661696c6564006044820152606401610117565b50505050565b610bf36001600160a01b0384168330846119c4565b60008080610ed78482611865565b9250610ee4846014611919565b9050610ef5610c2760036014612a7a565b91509193909250565b6000600160ff1b8210610f1057600080fd5b5090565b6000806000846001600160a01b0316866001600160a01b031610610f39578486610f3c565b85855b604080516001600160a01b03938416602080830191909152929093168382015262ffffff969096166060808401919091528651808403820181526080840188528051908301206001600160f81b031960a08501527f0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f98490911b6bffffffffffffffffffffffff191660a184015260b58301527fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b5460d5808401919091528651808403909101815260f5909201909552805194019390932095945050505050565b604051620c3a4160e11b81526001600160a01b03848116600483015260248201849052600091610c079184917f000000000000000000000000972a785b390d05123497169a04c72de652493be1909116906218748290604401602060405180830381600087803b15801561108d57600080fd5b505af11580156110a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c59190612840565b6119fc565b6040516001600160a01b038316602482015260448101829052610bf390849063a9059cbb60e01b90606401610bbc565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080600061115c8460800151610ec9565b92509250925061116d838383610f14565b6001600160a01b0316336001600160a01b0316146111cd5760405162461bcd60e51b815260206004820152601960248201527f5f73686f727443616c6c6261636b2f6261642d63616c6c6572000000000000006044820152606401610117565b6111da8460800151611a12565b1561130e576111ec8460800151611a4c565b60808501819052600090819061120190610ec9565b9093509150506001600160a01b0380831690851610611221858484610f14565b6001600160a01b031663128acb08308361123a8c610efe565b856112635761125e600173fffd8963efd1fc6a506488495d951d5263988d26612a92565b611273565b6112736401000276a36001612a4f565b8c6040516020016112849190612945565b6040516020818303038152906040526040518663ffffffff1660e01b81526004016112b39594939291906128a1565b6040805180830381600087803b1580156112cc57600080fd5b505af11580156112e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113049190612648565b505050505061137e565b60008460600151866113209190612a7a565b90508460a001518610156113625760405162461bcd60e51b815260206004820152600960248201526821736c69707061676560b81b6044820152606401610117565b61137c328660000151876020015186896040015186611a83565b505b6113926001600160a01b03841633886110ca565b505050505050565b60008060006113ac8460800151610ec9565b9250925092506113bd828483610f14565b6001600160a01b0316336001600160a01b03161461141d5760405162461bcd60e51b815260206004820152601960248201527f5f636c6f736543616c6c6261636b2f6261642d63616c6c6572000000000000006044820152606401610117565b61142a8460800151611a12565b156115675761143c8460800151611a4c565b60808501819052600090819061145190610ec9565b9093509150506001600160a01b0380851690831610611471858484610f14565b6001600160a01b031663128acb08338361148a8d610efe565b61149390612afd565b856114bc576114b7600173fffd8963efd1fc6a506488495d951d5263988d26612a92565b6114cc565b6114cc6401000276a36001612a4f565b8c6040516020016114dd9190612945565b6040516020818303038152906040526040518663ffffffff1660e01b815260040161150c9594939291906128a1565b6040805180830381600087803b15801561152557600080fd5b505af1158015611539573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061155d9190612648565b5050505050611392565b8360a001518611156115a75760405162461bcd60e51b815260206004820152600960248201526821736c69707061676560b81b6044820152606401610117565b600084606001516115b790612afd565b90506115d3328660000151876020015186896040015186611e7f565b6115e76001600160a01b03841633896110ca565b6040516370a0823160e01b8152306004820152610a9390849032906001600160a01b038316906370a082319060240160206040518083038186803b15801561162e57600080fd5b505afa158015611642573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116669190612840565b61219c565b60006116c0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610bf89092919063ffffffff16565b805190915015610bf357808060200190518101906116de9190612626565b610bf35760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610117565b60608247101561179e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610117565b843b6117ec5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610117565b600080866001600160a01b031685876040516118089190612885565b60006040518083038185875af1925050503d8060008114611845576040519150601f19603f3d011682016040523d82523d6000602084013e61184a565b606091505b509150915061185a828286612320565b979650505050505050565b600081611873816014612a7a565b10156118b65760405162461bcd60e51b8152602060048201526012602482015271746f416464726573735f6f766572666c6f7760701b6044820152606401610117565b6118c1826014612a7a565b835110156119095760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b6044820152606401610117565b500160200151600160601b900490565b600081611927816003612a7a565b10156119695760405162461bcd60e51b8152602060048201526011602482015270746f55696e7432345f6f766572666c6f7760781b6044820152606401610117565b611974826003612a7a565b835110156119bb5760405162461bcd60e51b8152602060048201526014602482015273746f55696e7432345f6f75744f66426f756e647360601b6044820152606401610117565b50016003015190565b6040516001600160a01b0380851660248301528316604482015260648101829052610eae9085906323b872dd60e01b90608401610bbc565b6000818310611a0b5781610c0a565b5090919050565b6000611a2060036014612a7a565b6014611a2d600382612a7a565b611a379190612a7a565b611a419190612a7a565b825110159050919050565b6060611a7d611a5d60036014612a7a565b611a6960036014612a7a565b8451611a759190612aba565b849190612359565b92915050565b600019851415611b3f57604051637b8feacb60e11b81526001600160a01b038781166004830152858116602483015284811660448301527f000000000000000000000000972a785b390d05123497169a04c72de652493be1169063f71fd59690606401602060405180830381600087803b158015611b0057600080fd5b505af1158015611b14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b389190612840565b9450611d48565b60405163e507470960e01b81526001600160a01b0387811660048301526024820187905260009182917f000000000000000000000000972a785b390d05123497169a04c72de652493be1169063e507470990604401604080518083038186803b158015611bab57600080fd5b505afa158015611bbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611be391906125c0565b91509150816001600160a01b0316856001600160a01b031614611c535760405162461bcd60e51b815260206004820152602260248201527f5f626f72726f772f636f6c6c61746572616c2d6e6f742d5f636f6c6c61746572604482015261185b60f21b6064820152608401610117565b604051630cf351b560e31b81526001600160a01b0382811660048301527f000000000000000000000000972a785b390d05123497169a04c72de652493be1169063679a8da89060240160206040518083038186803b158015611cb457600080fd5b505afa158015611cc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cec91906125a3565b6001600160a01b0316866001600160a01b031614611d455760405162461bcd60e51b81526020600482015260166024820152755f626f72726f772f6261642d756e6465726c79696e6760501b6044820152606401610117565b50505b611d73837f000000000000000000000000972a785b390d05123497169a04c72de652493be1836124b0565b6040516315d21c8d60e11b81526001600160a01b037f000000000000000000000000972a785b390d05123497169a04c72de652493be11690632ba4391a90611dc3908990899086906004016128dc565b600060405180830381600087803b158015611ddd57600080fd5b505af1158015611df1573d6000803e3d6000fd5b505060405163c1bce0b760e01b81526001600160a01b037f000000000000000000000000972a785b390d05123497169a04c72de652493be116925063c1bce0b79150611e45908990899087906004016128dc565b600060405180830381600087803b158015611e5f57600080fd5b505af1158015611e73573d6000803e3d6000fd5b50505050505050505050565b60405163e507470960e01b81526001600160a01b0387811660048301526024820187905260009182917f000000000000000000000000972a785b390d05123497169a04c72de652493be1169063e507470990604401604080518083038186803b158015611eeb57600080fd5b505afa158015611eff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2391906125c0565b91509150816001600160a01b0316856001600160a01b031614611f925760405162461bcd60e51b815260206004820152602160248201527f5f72657061792f636f6c6c61746572616c2d6e6f742d5f636f6c6c61746572616044820152601b60fa1b6064820152608401610117565b604051630cf351b560e31b81526001600160a01b0382811660048301527f000000000000000000000000972a785b390d05123497169a04c72de652493be1169063679a8da89060240160206040518083038186803b158015611ff357600080fd5b505afa158015612007573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061202b91906125a3565b6001600160a01b0316866001600160a01b0316146120835760405162461bcd60e51b81526020600482015260156024820152745f72657061792f6261642d756e6465726c79696e6760581b6044820152606401610117565b61208e8682866124b0565b604051638cd2e0c760e01b81526001600160a01b037f000000000000000000000000972a785b390d05123497169a04c72de652493be11690638cd2e0c7906120de908b908b9089906004016128dc565b600060405180830381600087803b1580156120f857600080fd5b505af115801561210c573d6000803e3d6000fd5b505060405163c640e9bf60e01b81526001600160a01b037f000000000000000000000000972a785b390d05123497169a04c72de652493be116925063c640e9bf9150612160908b908b9088906004016128dc565b600060405180830381600087803b15801561217a57600080fd5b505af115801561218e573d6000803e3d6000fd5b505050505050505050505050565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316836001600160a01b0316141561230c57604051632e1a7d4d60e01b8152600481018290527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561223857600080fd5b505af115801561224c573d6000803e3d6000fd5b5050604080516000808252602082019283905293506001600160a01b038616925084916122799190612885565b60006040518083038185875af1925050503d80600081146122b6576040519150601f19603f3d011682016040523d82523d6000602084013e6122bb565b606091505b5050905080610eae5760405162461bcd60e51b815260206004820181905260248201527f5f7472616e736665724f75742f6574682d7472616e736665722d6661696c65646044820152606401610117565b610bf36001600160a01b03841683836110ca565b6060831561232f575081610c0a565b82511561233f5782518084602001fd5b8160405162461bcd60e51b815260040161011791906128fd565b60608161236781601f612a7a565b10156123a65760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610117565b826123b18382612a7a565b10156123f05760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610117565b6123fa8284612a7a565b8451101561243e5760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610117565b60608215801561245d57604051915060008252602082016040526124a7565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561249657805183526020928301920161247e565b5050858452601f01601f1916604052505b50949350505050565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e9060440160206040518083038186803b1580156124fb57600080fd5b505afa15801561250f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125339190612840565b905081811015610eae578015612558576125586001600160a01b038516846000610a9c565b610eae6001600160a01b03851684600019610a9c565b600060a0828403121561258057600080fd5b50919050565b60006020828403121561259857600080fd5b8135610c0a81612b46565b6000602082840312156125b557600080fd5b8151610c0a81612b46565b600080604083850312156125d357600080fd5b82516125de81612b46565b60208401519092506125ef81612b46565b809150509250929050565b6000806040838503121561260d57600080fd5b823561261881612b46565b946020939093013593505050565b60006020828403121561263857600080fd5b81518015158114610c0a57600080fd5b6000806040838503121561265b57600080fd5b505080516020909101519092909150565b6000806000806060858703121561268257600080fd5b8435935060208501359250604085013567ffffffffffffffff808211156126a857600080fd5b818701915087601f8301126126bc57600080fd5b8135818111156126cb57600080fd5b8860208285010111156126dd57600080fd5b95989497505060200194505050565b600060208083850312156126ff57600080fd5b823567ffffffffffffffff8082111561271757600080fd5b9084019060c0828703121561272b57600080fd5b6127336129f5565b823581528383013561274481612b46565b808583015250604083013560408201526060830135606082015260808301358281111561277057600080fd5b8301601f8101881361278157600080fd5b80358381111561279357612793612b30565b6127a5601f8201601f19168701612a1e565b935080845288868284010111156127bb57600080fd5b80868301878601376000868286010152505081608082015260a083013560a08201528094505050505092915050565b6000602082840312156127fc57600080fd5b813567ffffffffffffffff81111561281357600080fd5b61281f8482850161256e565b949350505050565b60006020828403121561283957600080fd5b5035919050565b60006020828403121561285257600080fd5b5051919050565b60008151808452612871816020860160208601612ad1565b601f01601f19169290920160200192915050565b60008251612897818460208701612ad1565b9190910192915050565b6001600160a01b0386811682528515156020830152604082018590528316606082015260a06080820181905260009061185a90830184612859565b6001600160a01b039390931683526020830191909152604082015260600190565b602081526000610c0a6020830184612859565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b602081528151602082015260018060a01b03602083015116604082015260408201516060820152606082015160808201526000608083015160c060a084015261299160e0840182612859565b905060a084015160c08401528091505092915050565b6000808335601e198436030181126129be57600080fd5b83018035915067ffffffffffffffff8211156129d957600080fd5b6020019150368190038213156129ee57600080fd5b9250929050565b60405160c0810167ffffffffffffffff81118282101715612a1857612a18612b30565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715612a4757612a47612b30565b604052919050565b60006001600160a01b03828116848216808303821115612a7157612a71612b1a565b01949350505050565b60008219821115612a8d57612a8d612b1a565b500190565b60006001600160a01b0383811690831681811015612ab257612ab2612b1a565b039392505050565b600082821015612acc57612acc612b1a565b500390565b60005b83811015612aec578181015183820152602001612ad4565b83811115610eae5750506000910152565b6000600160ff1b821415612b1357612b13612b1a565b5060000390565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610a1957600080fdfea2646970667358221220175f1d4d40b6ad58ec5b57918929a5eefd3003a412603597f328dd56576301e564736f6c63430008060033

Verified Source Code Partial Match

Compiler: v0.8.6+commit.11564f7e EVM: berlin Optimization: Yes (200 runs)
BetaRunnerUniswapV3.sol 1163 lines
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.6;



// Part: BetaRunnerWithCallback

contract BetaRunnerWithCallback {
  address private constant NO_CALLER = address(42); // nonzero so we don't repeatedly clear storage
  address private caller = NO_CALLER;

  modifier withCallback() {
    require(caller == NO_CALLER);
    caller = msg.sender;
    _;
    caller = NO_CALLER;
  }

  modifier isCallback() {
    require(caller == tx.origin);
    _;
  }
}

// Part: BytesLib

library BytesLib {
  function slice(
    bytes memory _bytes,
    uint _start,
    uint _length
  ) internal pure returns (bytes memory) {
    require(_length + 31 >= _length, 'slice_overflow');
    require(_start + _length >= _start, 'slice_overflow');
    require(_bytes.length >= _start + _length, 'slice_outOfBounds');

    bytes memory tempBytes;

    assembly {
      switch iszero(_length)
      case 0 {
        // Get a location of some free memory and store it in tempBytes as
        // Solidity does for memory variables.
        tempBytes := mload(0x40)

        // The first word of the slice result is potentially a partial
        // word read from the original array. To read it, we calculate
        // the length of that partial word and start copying that many
        // bytes into the array. The first word we copy will start with
        // data we don't care about, but the last `lengthmod` bytes will
        // land at the beginning of the contents of the new array. When
        // we're done copying, we overwrite the full first word with
        // the actual length of the slice.
        let lengthmod := and(_length, 31)

        // The multiplication in the next line is necessary
        // because when slicing multiples of 32 bytes (lengthmod == 0)
        // the following copy loop was copying the origin's length
        // and then ending prematurely not copying everything it should.
        let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
        let end := add(mc, _length)

        for {
          // The multiplication in the next line has the same exact purpose
          // as the one above.
          let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
        } lt(mc, end) {
          mc := add(mc, 0x20)
          cc := add(cc, 0x20)
        } {
          mstore(mc, mload(cc))
        }

        mstore(tempBytes, _length)

        //update free-memory pointer
        //allocating the array padded to 32 bytes like the compiler does now
        mstore(0x40, and(add(mc, 31), not(31)))
      }
      //if we want a zero-length slice let's just return a zero-length array
      default {
        tempBytes := mload(0x40)
        //zero out the 32 bytes slice we are about to return
        //we need to do it because Solidity does not garbage collect
        mstore(tempBytes, 0)

        mstore(0x40, add(tempBytes, 0x20))
      }
    }

    return tempBytes;
  }

  function toAddress(bytes memory _bytes, uint _start) internal pure returns (address) {
    require(_start + 20 >= _start, 'toAddress_overflow');
    require(_bytes.length >= _start + 20, 'toAddress_outOfBounds');
    address tempAddress;

    assembly {
      tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
    }

    return tempAddress;
  }

  function toUint24(bytes memory _bytes, uint _start) internal pure returns (uint24) {
    require(_start + 3 >= _start, 'toUint24_overflow');
    require(_bytes.length >= _start + 3, 'toUint24_outOfBounds');
    uint24 tempUint;

    assembly {
      tempUint := mload(add(add(_bytes, 0x3), _start))
    }

    return tempUint;
  }
}

// Part: IBetaBank

interface IBetaBank {
  /// @dev Returns the address of BToken of the given underlying token, or 0 if not exists.
  function bTokens(address _underlying) external view returns (address);

  /// @dev Returns the address of the underlying of the given BToken, or 0 if not exists.
  function underlyings(address _bToken) external view returns (address);

  /// @dev Returns the address of the oracle contract.
  function oracle() external view returns (address);

  /// @dev Returns the address of the config contract.
  function config() external view returns (address);

  /// @dev Returns the interest rate model smart contract.
  function interestModel() external view returns (address);

  /// @dev Returns the position's collateral token and AmToken.
  function getPositionTokens(address _owner, uint _pid)
    external
    view
    returns (address _collateral, address _bToken);

  /// @dev Returns the debt of the given position. Can't be view as it needs to call accrue.
  function fetchPositionDebt(address _owner, uint _pid) external returns (uint);

  /// @dev Returns the LTV of the given position. Can't be view as it needs to call accrue.
  function fetchPositionLTV(address _owner, uint _pid) external returns (uint);

  /// @dev Opens a new position in the Beta smart contract.
  function open(
    address _owner,
    address _underlying,
    address _collateral
  ) external returns (uint pid);

  /// @dev Borrows tokens on the given position.
  function borrow(
    address _owner,
    uint _pid,
    uint _amount
  ) external;

  /// @dev Repays tokens on the given position.
  function repay(
    address _owner,
    uint _pid,
    uint _amount
  ) external;

  /// @dev Puts more collateral to the given position.
  function put(
    address _owner,
    uint _pid,
    uint _amount
  ) external;

  /// @dev Takes some collateral out of the position.
  function take(
    address _owner,
    uint _pid,
    uint _amount
  ) external;

  /// @dev Liquidates the given position.
  function liquidate(
    address _owner,
    uint _pid,
    uint _amount
  ) external;
}

// Part: IUniswapV3Pool

interface IUniswapV3Pool {
  function mint(
    address recipient,
    int24 tickLower,
    int24 tickUpper,
    uint128 amount,
    bytes calldata data
  ) external returns (uint amount0, uint amount1);

  function swap(
    address recipient,
    bool zeroForOne,
    int amountSpecified,
    uint160 sqrtPriceLimitX96,
    bytes calldata data
  ) external returns (int amount0, int amount1);

  function initialize(uint160 sqrtPriceX96) external;
}

// Part: IUniswapV3SwapCallback

interface IUniswapV3SwapCallback {
  function uniswapV3SwapCallback(
    int amount0Delta,
    int amount1Delta,
    bytes calldata data
  ) external;
}

// Part: IWETH

interface IWETH {
  function deposit() external payable;

  function withdraw(uint wad) external;

  function approve(address guy, uint wad) external returns (bool);
}

// Part: OpenZeppelin/[email protected]/Address

/**
 * @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;
        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");

        (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");

        (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");

        (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");

        (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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// Part: OpenZeppelin/[email protected]/Context

/*
 * @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 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) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

// Part: OpenZeppelin/[email protected]/IERC20

/**
 * @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);
}

// Part: OpenZeppelin/[email protected]/Math

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow, so we distribute.
        return (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2);
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a / b + (a % b == 0 ? 0 : 1);
    }
}

// Part: SafeCast

/// @title Safe casting methods
/// @notice Contains methods for safely casting between types
library SafeCast {
  /// @notice Cast a uint256 to a uint160, revert on overflow
  /// @param y The uint256 to be downcasted
  /// @return z The downcasted integer, now type uint160
  function toUint160(uint y) internal pure returns (uint160 z) {
    require((z = uint160(y)) == y);
  }

  /// @notice Cast a int256 to a int128, revert on overflow or underflow
  /// @param y The int256 to be downcasted
  /// @return z The downcasted integer, now type int128
  function toInt128(int y) internal pure returns (int128 z) {
    require((z = int128(y)) == y);
  }

  /// @notice Cast a uint256 to a int256, revert on overflow
  /// @param y The uint256 to be casted
  /// @return z The casted integer, now type int256
  function toInt256(uint y) internal pure returns (int z) {
    require(y < 2**255);
    z = int(y);
  }
}

// Part: OpenZeppelin/[email protected]/Ownable

/**
 * @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() {
        _setOwner(_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 {
        _setOwner(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");
        _setOwner(newOwner);
    }

    function _setOwner(address newOwner) private {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// Part: OpenZeppelin/[email protected]/SafeERC20

/**
 * @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 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'
        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) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _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
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

// Part: Path

/// @title Functions for manipulating path data for multihop swaps
library Path {
  using BytesLib for bytes;

  /// @dev The length of the bytes encoded address
  uint private constant ADDR_SIZE = 20;
  /// @dev The length of the bytes encoded fee
  uint private constant FEE_SIZE = 3;

  /// @dev The offset of a single token address and pool fee
  uint private constant NEXT_OFFSET = ADDR_SIZE + FEE_SIZE;
  /// @dev The offset of an encoded pool key
  uint private constant POP_OFFSET = NEXT_OFFSET + ADDR_SIZE;
  /// @dev The minimum length of an encoding that contains 2 or more pools
  uint private constant MULTIPLE_POOLS_MIN_LENGTH = POP_OFFSET + NEXT_OFFSET;

  /// @notice Returns true iff the path contains two or more pools
  /// @param path The encoded swap path
  /// @return True if path contains two or more pools, otherwise false
  function hasMultiplePools(bytes memory path) internal pure returns (bool) {
    return path.length >= MULTIPLE_POOLS_MIN_LENGTH;
  }

  /// @notice Decodes the first pool in path
  /// @param path The bytes encoded swap path
  /// @return tokenA The first token of the given pool
  /// @return tokenB The second token of the given pool
  /// @return fee The fee level of the pool
  function decodeFirstPool(bytes memory path)
    internal
    pure
    returns (
      address tokenA,
      address tokenB,
      uint24 fee
    )
  {
    tokenA = path.toAddress(0);
    fee = path.toUint24(ADDR_SIZE);
    tokenB = path.toAddress(NEXT_OFFSET);
  }

  /// @notice Decodes the last pool in path
  /// @param path The bytes encoded swap path
  /// @return tokenA The first token of the given pool
  /// @return tokenB The second token of the given pool
  /// @return fee The fee level of the pool
  function decodeLastPool(bytes memory path)
    internal
    pure
    returns (
      address tokenA,
      address tokenB,
      uint24 fee
    )
  {
    tokenB = path.toAddress(path.length - ADDR_SIZE);
    fee = path.toUint24(path.length - NEXT_OFFSET);
    tokenA = path.toAddress(path.length - POP_OFFSET);
  }

  /// @notice Skips a token + fee element from the buffer and returns the remainder
  /// @param path The swap path
  /// @return The remaining token + fee elements in the path
  function skipToken(bytes memory path) internal pure returns (bytes memory) {
    return path.slice(NEXT_OFFSET, path.length - NEXT_OFFSET);
  }
}

// Part: BetaRunnerBase

contract BetaRunnerBase is Ownable {
  using SafeERC20 for IERC20;

  address public immutable betaBank;
  address public immutable weth;

  modifier onlyEOA() {
    require(msg.sender == tx.origin, 'BetaRunnerBase/not-eoa');
    _;
  }

  constructor(address _betaBank, address _weth) {
    address bweth = IBetaBank(_betaBank).bTokens(_weth);
    require(bweth != address(0), 'BetaRunnerBase/no-bweth');
    IERC20(_weth).safeApprove(_betaBank, type(uint).max);
    IERC20(_weth).safeApprove(bweth, type(uint).max);
    betaBank = _betaBank;
    weth = _weth;
  }

  function _borrow(
    address _owner,
    uint _pid,
    address _underlying,
    address _collateral,
    uint _amountBorrow,
    uint _amountCollateral
  ) internal {
    if (_pid == type(uint).max) {
      _pid = IBetaBank(betaBank).open(_owner, _underlying, _collateral);
    } else {
      (address collateral, address bToken) = IBetaBank(betaBank).getPositionTokens(_owner, _pid);
      require(_collateral == collateral, '_borrow/collateral-not-_collateral');
      require(_underlying == IBetaBank(betaBank).underlyings(bToken), '_borrow/bad-underlying');
    }
    _approve(_collateral, betaBank, _amountCollateral);
    IBetaBank(betaBank).put(_owner, _pid, _amountCollateral);
    IBetaBank(betaBank).borrow(_owner, _pid, _amountBorrow);
  }

  function _repay(
    address _owner,
    uint _pid,
    address _underlying,
    address _collateral,
    uint _amountRepay,
    uint _amountCollateral
  ) internal {
    (address collateral, address bToken) = IBetaBank(betaBank).getPositionTokens(_owner, _pid);
    require(_collateral == collateral, '_repay/collateral-not-_collateral');
    require(_underlying == IBetaBank(betaBank).underlyings(bToken), '_repay/bad-underlying');
    _approve(_underlying, bToken, _amountRepay);
    IBetaBank(betaBank).repay(_owner, _pid, _amountRepay);
    IBetaBank(betaBank).take(_owner, _pid, _amountCollateral);
  }

  function _transferIn(
    address _token,
    address _from,
    uint _amount
  ) internal {
    if (_token == weth) {
      require(_from == msg.sender, '_transferIn/not-from-sender');
      require(_amount <= msg.value, '_transferIn/insufficient-eth-amount');
      IWETH(weth).deposit{value: _amount}();
      if (msg.value > _amount) {
        (bool success, ) = _from.call{value: msg.value - _amount}(new bytes(0));
        require(success, '_transferIn/eth-transfer-failed');
      }
    } else {
      IERC20(_token).safeTransferFrom(_from, address(this), _amount);
    }
  }

  function _transferOut(
    address _token,
    address _to,
    uint _amount
  ) internal {
    if (_token == weth) {
      IWETH(weth).withdraw(_amount);
      (bool success, ) = _to.call{value: _amount}(new bytes(0));
      require(success, '_transferOut/eth-transfer-failed');
    } else {
      IERC20(_token).safeTransfer(_to, _amount);
    }
  }

  /// @dev Approves infinite on the given token for the given spender if current approval is insufficient.
  function _approve(
    address _token,
    address _spender,
    uint _minAmount
  ) internal {
    uint current = IERC20(_token).allowance(address(this), _spender);
    if (current < _minAmount) {
      if (current != 0) {
        IERC20(_token).safeApprove(_spender, 0);
      }
      IERC20(_token).safeApprove(_spender, type(uint).max);
    }
  }

  /// @dev Caps repay amount by current position's debt.
  function _capRepay(
    address _owner,
    uint _pid,
    uint _amountRepay
  ) internal returns (uint) {
    return Math.min(_amountRepay, IBetaBank(betaBank).fetchPositionDebt(_owner, _pid));
  }

  /// @dev Recovers lost tokens for whatever reason by the owner.
  function recover(address _token, uint _amount) external onlyOwner {
    if (_amount == type(uint).max) {
      _amount = IERC20(_token).balanceOf(address(this));
    }
    IERC20(_token).safeTransfer(msg.sender, _amount);
  }

  /// @dev Recovers lost ETH for whatever reason by the owner.
  function recoverETH(uint _amount) external onlyOwner {
    if (_amount == type(uint).max) {
      _amount = address(this).balance;
    }
    (bool success, ) = msg.sender.call{value: _amount}(new bytes(0));
    require(success, 'recoverETH/eth-transfer-failed');
  }

  /// @dev Override Ownable.sol renounceOwnership to prevent accidental call
  function renounceOwnership() public override onlyOwner {
    revert('renounceOwnership/disabled');
  }

  receive() external payable {
    require(msg.sender == weth, 'receive/not-weth');
  }
}

// File: BetaRunnerUniswapV3.sol

contract BetaRunnerUniswapV3 is BetaRunnerBase, BetaRunnerWithCallback, IUniswapV3SwapCallback {
  using SafeERC20 for IERC20;
  using Path for bytes;
  using SafeCast for uint;

  /// @dev Constants from Uniswap V3 to be used for swap
  /// (https://github.com/Uniswap/uniswap-v3-core/blob/main/contracts/libraries/TickMath.sol)
  uint160 internal constant MIN_SQRT_RATIO = 4295128739;
  uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;

  address public immutable factory;
  bytes32 public immutable codeHash;

  constructor(
    address _betaBank,
    address _weth,
    address _factory,
    bytes32 _codeHash
  ) BetaRunnerBase(_betaBank, _weth) {
    factory = _factory;
    codeHash = _codeHash;
  }

  struct ShortData {
    uint pid;
    uint amountBorrow;
    uint amountPutExtra;
    bytes path;
    uint amountOutMin;
  }

  struct CloseData {
    uint pid;
    uint amountRepay;
    uint amountTake;
    bytes path;
    uint amountInMax;
  }

  struct CallbackData {
    uint pid;
    address path0;
    uint amount0;
    int memo; // positive if short (extra collateral) | negative if close (amount to take)
    bytes path;
    uint slippageControl; // amountInMax if close | amountOutMin if short
  }

  /// @dev Borrows the asset using the given collateral, and swaps it using the given path.
  function short(ShortData calldata _data) external payable onlyEOA withCallback {
    (, address collateral, ) = _data.path.decodeLastPool();
    _transferIn(collateral, msg.sender, _data.amountPutExtra);
    (address tokenIn, address tokenOut, uint24 fee) = _data.path.decodeFirstPool();
    bool zeroForOne = tokenIn < tokenOut;
    CallbackData memory cb = CallbackData({
      pid: _data.pid,
      path0: tokenIn,
      amount0: _data.amountBorrow,
      memo: _data.amountPutExtra.toInt256(),
      path: _data.path,
      slippageControl: _data.amountOutMin
    });
    IUniswapV3Pool(_poolFor(tokenIn, tokenOut, fee)).swap(
      address(this),
      zeroForOne,
      _data.amountBorrow.toInt256(),
      zeroForOne ? MIN_SQRT_RATIO + 1 : MAX_SQRT_RATIO - 1,
      abi.encode(cb)
    );
  }

  /// @dev Swaps the collateral to the underlying asset using the given path, and repays it to the pool.
  function close(CloseData calldata _data) external payable onlyEOA withCallback {
    uint amountRepay = _capRepay(msg.sender, _data.pid, _data.amountRepay);
    (address tokenOut, address tokenIn, uint24 fee) = _data.path.decodeFirstPool();
    bool zeroForOne = tokenIn < tokenOut;
    CallbackData memory cb = CallbackData({
      pid: _data.pid,
      path0: tokenOut,
      amount0: amountRepay,
      memo: -_data.amountTake.toInt256(),
      path: _data.path,
      slippageControl: _data.amountInMax
    });
    IUniswapV3Pool(_poolFor(tokenIn, tokenOut, fee)).swap(
      address(this),
      zeroForOne,
      -amountRepay.toInt256(),
      zeroForOne ? MIN_SQRT_RATIO + 1 : MAX_SQRT_RATIO - 1,
      abi.encode(cb)
    );
  }

  /// @dev Continues the action through uniswapv3
  function uniswapV3SwapCallback(
    int _amount0Delta,
    int _amount1Delta,
    bytes calldata _data
  ) external override isCallback {
    CallbackData memory data = abi.decode(_data, (CallbackData));
    (uint amountToPay, uint amountReceived) = _amount0Delta > 0
      ? (uint(_amount0Delta), uint(-_amount1Delta))
      : (uint(_amount1Delta), uint(-_amount0Delta));
    if (data.memo > 0) {
      _shortCallback(amountToPay, amountReceived, data);
    } else {
      _closeCallback(amountToPay, amountReceived, data);
    }
  }

  function _shortCallback(
    uint _amountToPay,
    uint _amountReceived,
    CallbackData memory data
  ) internal {
    (address tokenIn, address tokenOut, uint24 prevFee) = data.path.decodeFirstPool();
    require(msg.sender == _poolFor(tokenIn, tokenOut, prevFee), '_shortCallback/bad-caller');
    if (data.path.hasMultiplePools()) {
      data.path = data.path.skipToken();
      (, address tokenNext, uint24 fee) = data.path.decodeFirstPool();
      bool zeroForOne = tokenOut < tokenNext;
      IUniswapV3Pool(_poolFor(tokenOut, tokenNext, fee)).swap(
        address(this),
        zeroForOne,
        _amountReceived.toInt256(),
        zeroForOne ? MIN_SQRT_RATIO + 1 : MAX_SQRT_RATIO - 1,
        abi.encode(data)
      );
    } else {
      uint amountPut = _amountReceived + uint(data.memo);
      require(_amountReceived >= data.slippageControl, '!slippage');
      _borrow(tx.origin, data.pid, data.path0, tokenOut, data.amount0, amountPut);
    }
    IERC20(tokenIn).safeTransfer(msg.sender, _amountToPay);
  }

  function _closeCallback(
    uint _amountToPay,
    uint,
    CallbackData memory data
  ) internal {
    (address tokenOut, address tokenIn, uint24 prevFee) = data.path.decodeFirstPool();
    require(msg.sender == _poolFor(tokenIn, tokenOut, prevFee), '_closeCallback/bad-caller');
    if (data.path.hasMultiplePools()) {
      data.path = data.path.skipToken();
      (, address tokenNext, uint24 fee) = data.path.decodeFirstPool();
      bool zeroForOne = tokenNext < tokenIn;
      IUniswapV3Pool(_poolFor(tokenIn, tokenNext, fee)).swap(
        msg.sender,
        zeroForOne,
        -_amountToPay.toInt256(),
        zeroForOne ? MIN_SQRT_RATIO + 1 : MAX_SQRT_RATIO - 1,
        abi.encode(data)
      );
    } else {
      require(_amountToPay <= data.slippageControl, '!slippage');
      uint amountTake = uint(-data.memo);
      _repay(tx.origin, data.pid, data.path0, tokenIn, data.amount0, amountTake);
      IERC20(tokenIn).safeTransfer(msg.sender, _amountToPay);
      _transferOut(tokenIn, tx.origin, IERC20(tokenIn).balanceOf(address(this)));
    }
  }

  function _poolFor(
    address tokenA,
    address tokenB,
    uint24 fee
  ) internal view returns (address) {
    (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
    bytes32 salt = keccak256(abi.encode(token0, token1, fee));
    return address(uint160(uint(keccak256(abi.encodePacked(hex'ff', factory, salt, codeHash)))));
  }
}

Read Contract

betaBank 0x550ba367 → address
codeHash 0x18edaaf2 → bytes32
factory 0xc45a0155 → address
owner 0x8da5cb5b → address
weth 0x3fc8cef3 → address

Write Contract 7 functions

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

close 0xcb463dce
tuple _data
recover 0x5705ae43
address _token
uint256 _amount
recoverETH 0xd3335553
uint256 _amount
renounceOwnership 0x715018a6
No parameters
short 0x626a79cb
tuple _data
transferOwnership 0xf2fde38b
address newOwner
uniswapV3SwapCallback 0xfa461e33
int256 _amount0Delta
int256 _amount1Delta
bytes _data

Recent Transactions

No transactions found for this address