Address Contract Partially Verified
Address
0x06f12B17D97EF27152B68cba208e3415EA65369B
Balance
0 ETH
Nonce
1
Code Size
11153 bytes
Creator
0x38a466b5...0080 at tx 0xea9b9a29...e400a5
Indexed Transactions
0
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