Address Contract Partially Verified
Address
0x052B82b3A096A592F3F28d4736c4796445BB98Ef
Balance
0 ETH
Nonce
1
Code Size
13282 bytes
Creator
0x5fD7D0d6...6d34 at tx 0x43c6694a...5ad498
Indexed Transactions
0
Contract Bytecode
13282 bytes
0x60806040526004361061015f5760003560e01c80638da5cb5b116100c0578063e272ad3f11610074578063f290aafa11610059578063f290aafa146103db578063fc0c546a146103fb578063fc3a7b981461042f57600080fd5b8063e272ad3f1461038b578063e9ee1eaf146103ab57600080fd5b80639dc7b023116100a55780639dc7b0231461032b578063aad48d801461034b578063d547741f1461036b57600080fd5b80638da5cb5b146102d057806391d14854146102fb57600080fd5b80634b0a8854116101175780636ccae054116100fc5780636ccae0541461027057806370bab2c014610290578063873ea755146102bd57600080fd5b80634b0a8854146102235780635b94db271461025057600080fd5b80632f2ff15d116101485780632f2ff15d146101d95780633bd1adec146101fb578063405e720a1461021057600080fd5b806320f99c0a146101645780632421e155146101b5575b600080fd5b34801561017057600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156101c157600080fd5b506101cb60045481565b6040519081526020016101ac565b3480156101e557600080fd5b506101f96101f4366004612741565b61044f565b005b34801561020757600080fd5b506101f96104ae565b6101f961021e3660046127b3565b61050a565b34801561022f57600080fd5b5061024361023e36600461285b565b61065b565b6040516101ac91906128ee565b34801561025c57600080fd5b506101f961026b36600461285b565b6106f5565b34801561027c57600080fd5b506101f961028b366004612901565b6107b5565b34801561029c57600080fd5b5060055461018b9073ffffffffffffffffffffffffffffffffffffffff1681565b6101f96102cb366004612a06565b610853565b3480156102dc57600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff1661018b565b34801561030757600080fd5b5061031b610316366004612741565b61095c565b60405190151581526020016101ac565b34801561033757600080fd5b506101f9610346366004612aa2565b610997565b34801561035757600080fd5b506101f9610366366004612ae3565b610a41565b34801561037757600080fd5b506101f9610386366004612741565b610cb6565b34801561039757600080fd5b506101f96103a6366004612b5d565b610d11565b3480156103b757600080fd5b5061031b6103c636600461285b565b60086020526000908152604090205460ff1681565b3480156103e757600080fd5b506102436103f6366004612bc9565b610ecb565b34801561040757600080fd5b5061018b7f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca081565b34801561043b57600080fd5b506101cb61044a366004612be2565b610ee4565b60015473ffffffffffffffffffffffffffffffffffffffff1633146104a0576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104aa8282610f85565b5050565b60025473ffffffffffffffffffffffffffffffffffffffff1633146104ff576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105083361100b565b565b60005460011461057b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e43590000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b60026000819055506000806105f48760405180606001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c815260200189898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050915250611084565b9150915061060582602001516112eb565b61064a888886868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525087925088915061138e9050565b505060016000555050505050505050565b6007602052600090815260409020805461067490612c17565b80601f01602080910402602001604051908101604052809291908181526020018280546106a090612c17565b80156106ed5780601f106106c2576101008083540402835291602001916106ed565b820191906000526020600020905b8154815290600101906020018083116106d057829003601f168201915b505050505081565b60015473ffffffffffffffffffffffffffffffffffffffff163314610746576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b3360009081527f271b3e2292ab6fd3ff496cd98d6d375af02f11568a701741f48bba7789f13a7060205260409020547fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292539060ff16610842576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610572565b61084d8484846116d3565b50505050565b6000546001146108bf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e4359000000000000000000000000000000000000000000006044820152606401610572565b6002600081905550600080600080848060200190518101906108e19190612caf565b9350935093509350600060405180606001604052808673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001838152509050606061092a88836117c8565b805160208201519194509192506109419190611a52565b61094d85858385611b06565b50506001600055505050505050565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff165b9392505050565b600054600114610a03576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e4359000000000000000000000000000000000000000000006044820152606401610572565b6002600090815580610a158484611d42565b91509150610a2b81600001518260200151611a52565b610a3684848461204a565b505060016000555050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610a92576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca073ffffffffffffffffffffffffffffffffffffffff1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610c3c576005546040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff91821660248201526000917f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0169063dd62ed3e90604401602060405180830381865afa158015610b7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b9f9190612d14565b1115610beb57600554610beb907f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca09073ffffffffffffffffffffffffffffffffffffffff166000612305565b8015610c3c57610c3c7f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff612305565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527fe816c20840d998c8612f9b624b91687a80510eeb293cb09f7637379f6d73342d9060200160405180910390a15050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610d07576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104aa82826123d4565b60015473ffffffffffffffffffffffffffffffffffffffff163314610d62576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260005b81811015610ec357838382818110610d8057610d80612d2d565b9050602002016020810190610d959190612d5c565b60086000888885818110610dab57610dab612d2d565b9050602002016020810190610dc0919061285b565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790557f857309f1a328784e9fc9749624be5d32fd8e7afab58e7fe9a218dd613a37f15c868683818110610e4657610e46612d2d565b9050602002016020810190610e5b919061285b565b858584818110610e6d57610e6d612d2d565b9050602002016020810190610e829190612d5c565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835290151560208301520160405180910390a180610ebb81612da6565b915050610d66565b505050505050565b6006602052600090815260409020805461067490612c17565b6040517f666758ca000000000000000000000000000000000000000000000000000000008152600481018390526024810182905260009073ffffffffffffffffffffffffffffffffffffffff85169063666758ca90604401602060405180830381865afa158015610f59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f7d9190612d14565b949350505050565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6001805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff000000000000000000000000000000000000000091821681179092556002805490911690556040517ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8790600090a250565b60408051606080820183526000808352602083015291810191909152815160609073ffffffffffffffffffffffffffffffffffffffff166110f1576040517f96bbcf1e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff841660009081526008602052604090205460ff16611150576040517f5b0a758300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca073ffffffffffffffffffffffffffffffffffffffff1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480156111ac5750826020015134105b156111e3576040517f78f38f7600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055473ffffffffffffffffffffffffffffffffffffffff16156112e0576005546040805160608101825273ffffffffffffffffffffffffffffffffffffffff878116825233602083015281830187905291517ff59ad990000000000000000000000000000000000000000000000000000000008152919092169163f59ad990916112719190600401612e1d565b6000604051808303816000875af1158015611290573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526112d69190810190612eeb565b90925090506112e4565b8291505b9250929050565b80158061134157507f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca073ffffffffffffffffffffffffffffffffffffffff1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b156113495750565b61138b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca016333084612457565b50565b600554819073ffffffffffffffffffffffffffffffffffffffff161561148e576005546040805160808101825273ffffffffffffffffffffffffffffffffffffffff8881168252602082018890528183018790526060820186905291517f62811bf200000000000000000000000000000000000000000000000000000000815291909216916362811bf2916114269190600401612f4f565b6000604051808303816000875af1158015611445573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261148b9190810190612fee565b90505b60007f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca073ffffffffffffffffffffffffffffffffffffffff1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee146114e757346114f6565b60208201516114f69034613023565b905060008673ffffffffffffffffffffffffffffffffffffffff166374fa24a66040518163ffffffff1660e01b8152600401602060405180830381865afa158015611545573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115699190612d14565b905060008773ffffffffffffffffffffffffffffffffffffffff1663ac0710cb848b87600001518860200151878a604001516040516020016115ae949392919061303a565b6040516020818303038152906040528b6040518563ffffffff1660e01b81526004016115dc9392919061307f565b60206040518083038185885af11580156115fa573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061161f9190612d14565b905081811461165a576040517f7b7bbbe000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83516020808601516040805173ffffffffffffffffffffffffffffffffffffffff8d811682523394820194909452929093168284015260608201526080810184905290517fc74a00177d2c63e6eead5ea7936974ad9d0121f86140723b8909f8ec9662cc619181900360a00190a1505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8216611720576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161176c576117678282612542565b505050565b8273ffffffffffffffffffffffffffffffffffffffff163b6000036117bd576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6117678383836125b7565b6040805160608181018352600080835260208301529181018290523360009081526008602052604090205460ff1661182c576040517f5b0a758300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825173ffffffffffffffffffffffffffffffffffffffff163014806118a057507f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff16145b156118d7576040517f285c601600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055473ffffffffffffffffffffffffffffffffffffffff1615611a4b576005546040805160608101825233808252600090815260076020908152929020805473ffffffffffffffffffffffffffffffffffffffff9094169363cf36b917938301919061194390612c17565b80601f016020809104026020016040519081016040528092919081815260200182805461196f90612c17565b80156119bc5780601f10611991576101008083540402835291602001916119bc565b820191906000526020600020905b81548152906001019060200180831161199f57829003601f168201915b50505050508152602001868152506040518263ffffffff1660e01b81526004016119e691906130aa565b6000604051808303816000875af1158015611a05573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526112d69190810190613121565b5092909150565b80600003611a5e575050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111127f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca073ffffffffffffffffffffffffffffffffffffffff1601611ac5576104aa8282612542565b6104aa73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca01683836125b7565b60055473ffffffffffffffffffffffffffffffffffffffff1615611cd8576005546040805160a0810182523380825260208083018890526000918252600790528281208054919473ffffffffffffffffffffffffffffffffffffffff169363dd19fe3893929083019190611b7990612c17565b80601f0160208091040260200160405190810160405280929190818152602001828054611ba590612c17565b8015611bf25780601f10611bc757610100808354040283529160200191611bf2565b820191906000526020600020905b815481529060010190602001808311611bd557829003601f168201915b50505050508152602001868152602001858152506040518263ffffffff1660e01b8152600401611c22919061317b565b6000604051808303816000875af1158015611c41573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611c87919081019061321b565b805160008681526006602090815260409091208251939450611caf9390929190910190612686565b5060208082015133600090815260078352604090208151611cd593919290910190612686565b50505b80516020808301516040805133815273ffffffffffffffffffffffffffffffffffffffff909416928401929092528282015260608201859052517f9afd47907e25028cdaca89d193518c302bbb128617d5a992c5abd458155265939181900360800190a150505050565b60408051606081810183526000808352602083015291810182905273ffffffffffffffffffffffffffffffffffffffff841660009081526008602052604090205460ff16611dbc576040517f5b0a758300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518082018252600085815260066020529182208054829190611de090612c17565b80601f0160208091040260200160405190810160405280929190818152602001828054611e0c90612c17565b8015611e595780601f10611e2e57610100808354040283529160200191611e59565b820191906000526020600020905b815481529060010190602001808311611e3c57829003601f168201915b50505050508152602001600760008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054611ead90612c17565b80601f0160208091040260200160405190810160405280929190818152602001828054611ed990612c17565b8015611f265780601f10611efb57610100808354040283529160200191611f26565b820191906000526020600020905b815481529060010190602001808311611f0957829003601f168201915b50505050508152509050806000015151600003611f6f576040517fd3d38f6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055460408051808201825273ffffffffffffffffffffffffffffffffffffffff88811682526020820185905291517f7afb99530000000000000000000000000000000000000000000000000000000081529190921691637afb995391611fd991906004016132f0565b6000604051808303816000875af1158015611ff8573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261203e9190810190613121565b90969095509350505050565b60408051808201825260008481526006602052918220805482919061206e90612c17565b80601f016020809104026020016040519081016040528092919081815260200182805461209a90612c17565b80156120e75780601f106120bc576101008083540402835291602001916120e7565b820191906000526020600020905b8154815290600101906020018083116120ca57829003601f168201915b50505050508152602001600760008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805461213b90612c17565b80601f016020809104026020016040519081016040528092919081815260200182805461216790612c17565b80156121b45780601f10612189576101008083540402835291602001916121b4565b820191906000526020600020905b81548152906001019060200180831161219757829003601f168201915b5050509190925250506005546040805160808101825273ffffffffffffffffffffffffffffffffffffffff8881168252602082018890528183018790526060820185905291517f1306ac3b000000000000000000000000000000000000000000000000000000008152939450911691631306ac3b916122359160040161332b565b6000604051808303816000875af1158015612254573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261229a919081019061321b565b8051600085815260066020908152604090912082519394506122c29390929190910190612686565b5060208082015173ffffffffffffffffffffffffffffffffffffffff86166000908152600783526040902081516122fe93919290910190612686565b5050505050565b60006040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d116001600051141617169150508061084d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f415050524f56455f4641494c45440000000000000000000000000000000000006044820152606401610572565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551909184917f155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a529190a35050565b60006040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff841660248201528260448201526020600060648360008a5af13d15601f3d11600160005114161716915050806122fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152606401610572565b600080600080600085875af1905080611767576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401610572565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d116001600051141617169150508061084d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610572565b82805461269290612c17565b90600052602060002090601f0160209004810192826126b457600085556126fa565b82601f106126cd57805160ff19168380011785556126fa565b828001600101855582156126fa579182015b828111156126fa5782518255916020019190600101906126df565b5061270692915061270a565b5090565b5b80821115612706576000815560010161270b565b73ffffffffffffffffffffffffffffffffffffffff8116811461138b57600080fd5b6000806040838503121561275457600080fd5b8235915060208301356127668161271f565b809150509250929050565b60008083601f84011261278357600080fd5b50813567ffffffffffffffff81111561279b57600080fd5b6020830191508360208285010111156112e457600080fd5b60008060008060008060008060c0898b0312156127cf57600080fd5b88356127da8161271f565b9750602089013596506040890135955060608901356127f88161271f565b9450608089013567ffffffffffffffff8082111561281557600080fd5b6128218c838d01612771565b909650945060a08b013591508082111561283a57600080fd5b506128478b828c01612771565b999c989b5096995094979396929594505050565b60006020828403121561286d57600080fd5b81356109908161271f565b60005b8381101561289357818101518382015260200161287b565b8381111561084d5750506000910152565b600081518084526128bc816020860160208601612878565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061099060208301846128a4565b60008060006060848603121561291657600080fd5b83356129218161271f565b925060208401356129318161271f565b929592945050506040919091013590565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156129b8576129b8612942565b604052919050565b600067ffffffffffffffff8211156129da576129da612942565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215612a1957600080fd5b823563ffffffff81168114612a2d57600080fd5b9150602083013567ffffffffffffffff811115612a4957600080fd5b8301601f81018513612a5a57600080fd5b8035612a6d612a68826129c0565b612971565b818152866020838501011115612a8257600080fd5b816020840160208301376000602083830101528093505050509250929050565b60008060408385031215612ab557600080fd5b8235612ac08161271f565b946020939093013593505050565b80358015158114612ade57600080fd5b919050565b60008060408385031215612af657600080fd5b8235612b018161271f565b9150612b0f60208401612ace565b90509250929050565b60008083601f840112612b2a57600080fd5b50813567ffffffffffffffff811115612b4257600080fd5b6020830191508360208260051b85010111156112e457600080fd5b60008060008060408587031215612b7357600080fd5b843567ffffffffffffffff80821115612b8b57600080fd5b612b9788838901612b18565b90965094506020870135915080821115612bb057600080fd5b50612bbd87828801612b18565b95989497509550505050565b600060208284031215612bdb57600080fd5b5035919050565b600080600060608486031215612bf757600080fd5b8335612c028161271f565b95602085013595506040909401359392505050565b600181811c90821680612c2b57607f821691505b602082108103612c64577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600082601f830112612c7b57600080fd5b8151612c89612a68826129c0565b818152846020838601011115612c9e57600080fd5b610f7d826020830160208701612878565b60008060008060808587031215612cc557600080fd5b8451612cd08161271f565b809450506020850151925060408501519150606085015167ffffffffffffffff811115612cfc57600080fd5b612d0887828801612c6a565b91505092959194509250565b600060208284031215612d2657600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215612d6e57600080fd5b61099082612ace565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612dd757612dd7612d77565b5060010190565b73ffffffffffffffffffffffffffffffffffffffff8151168252602081015160208301526000604082015160606040850152610f7d60608501826128a4565b60208152600073ffffffffffffffffffffffffffffffffffffffff808451166020840152806020850151166040840152506040830151606080840152610f7d6080840182612dde565b600060608284031215612e7857600080fd5b6040516060810167ffffffffffffffff8282108183111715612e9c57612e9c612942565b8160405282935084519150612eb08261271f565b818352602085015160208401526040850151915080821115612ed157600080fd5b50612ede85828601612c6a565b6040830152505092915050565b60008060408385031215612efe57600080fd5b825167ffffffffffffffff80821115612f1657600080fd5b612f2286838701612e66565b93506020850151915080821115612f3857600080fd5b50612f4585828601612c6a565b9150509250929050565b6020815273ffffffffffffffffffffffffffffffffffffffff82511660208201526000602083015160806040840152612f8b60a08401826128a4565b905060408401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe080858403016060860152612fc783836128a4565b9250606086015191508085840301608086015250612fe58282612dde565b95945050505050565b60006020828403121561300057600080fd5b815167ffffffffffffffff81111561301757600080fd5b610f7d84828501612e66565b60008282101561303557613035612d77565b500390565b73ffffffffffffffffffffffffffffffffffffffff8516815283602082015282604082015260806060820152600061307560808301846128a4565b9695505050505050565b83815260606020820152600061309860608301856128a4565b828103604084015261307581856128a4565b6020815273ffffffffffffffffffffffffffffffffffffffff825116602082015260006020830151606060408401526130e660808401826128a4565b905060408401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848303016060850152612fe58282612dde565b6000806040838503121561313457600080fd5b825167ffffffffffffffff8082111561314c57600080fd5b61315886838701612c6a565b9350602085015191508082111561316e57600080fd5b50612f4585828601612e66565b6020815273ffffffffffffffffffffffffffffffffffffffff8251166020820152602082015160408201526000604083015160a060608401526131c160c08401826128a4565b905060608401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0808584030160808601526131fd83836128a4565b925060808601519150808584030160a086015250612fe58282612dde565b60006020828403121561322d57600080fd5b815167ffffffffffffffff8082111561324557600080fd5b908301906040828603121561325957600080fd5b60405160408101818110838211171561327457613274612942565b60405282518281111561328657600080fd5b61329287828601612c6a565b8252506020830151828111156132a757600080fd5b6132b387828601612c6a565b60208301525095945050505050565b60008151604084526132d760408501826128a4565b905060208301518482036020860152612fe582826128a4565b6020815273ffffffffffffffffffffffffffffffffffffffff825116602082015260006020830151604080840152610f7d60608401826132c2565b6020815273ffffffffffffffffffffffffffffffffffffffff825116602082015260208201516040820152600060408301516080606084015261337160a08401826128a4565b905060608401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848303016080850152612fe582826132c256fea2646970667358221220f2b993bea39713c0431d0b917b24039332fede3157ebbfabae799d1395a24c4c64736f6c634300080d0033
Verified Source Code Partial Match
Compiler: v0.8.13+commit.abaa5c0e
EVM: london
Optimization: Yes (999999 runs)
Base.sol 339 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;
import {IMintableERC20} from "../interfaces/IMintableERC20.sol";
import {IConnector} from "../interfaces/IConnector.sol";
import "lib/solmate/src/utils/SafeTransferLib.sol";
import "../interfaces/IHook.sol";
import "../common/Errors.sol";
import "lib/solmate/src/utils/ReentrancyGuard.sol";
import "../interfaces/IBridge.sol";
import "../utils/RescueBase.sol";
import "../common/Constants.sol";
abstract contract Base is ReentrancyGuard, IBridge, RescueBase {
address public immutable token;
bytes32 public bridgeType;
IHook public hook__;
// message identifier => cache
mapping(bytes32 => bytes) public identifierCache;
// connector => cache
mapping(address => bytes) public connectorCache;
mapping(address => bool) public validConnectors;
event ConnectorStatusUpdated(address connector, bool status);
event HookUpdated(address newHook);
event BridgingTokens(
address connector,
address sender,
address receiver,
uint256 amount,
bytes32 messageId
);
event TokensBridged(
address connecter,
address receiver,
uint256 amount,
bytes32 messageId
);
constructor(address token_) AccessControl(msg.sender) {
if (token_ != ETH_ADDRESS && token_.code.length == 0)
revert InvalidTokenContract();
token = token_;
_grantRole(RESCUE_ROLE, msg.sender);
}
/**
* @notice this function is used to update hook
* @dev it can only be updated by owner
* @dev should be carefully migrated as it can risk user funds
* @param hook_ new hook address
*/
function updateHook(
address hook_,
bool approve_
) external virtual onlyOwner {
// remove the approval from the old hook
if (token != ETH_ADDRESS) {
if (ERC20(token).allowance(address(this), address(hook__)) > 0) {
SafeTransferLib.safeApprove(ERC20(token), address(hook__), 0);
}
if (approve_) {
SafeTransferLib.safeApprove(
ERC20(token),
hook_,
type(uint256).max
);
}
}
hook__ = IHook(hook_);
emit HookUpdated(hook_);
}
function updateConnectorStatus(
address[] calldata connectors,
bool[] calldata statuses
) external onlyOwner {
uint256 length = connectors.length;
for (uint256 i; i < length; i++) {
validConnectors[connectors[i]] = statuses[i];
emit ConnectorStatusUpdated(connectors[i], statuses[i]);
}
}
/**
* @notice Executes pre-bridge operations before initiating a token bridge transfer.
* @dev This internal function is called before initiating a token bridge transfer.
* It validates the receiver address and the connector, and if a pre-hook contract is defined,
* it executes the source pre-hook call.
* @param connector_ The address of the connector responsible for the transfer.
* @param transferInfo_ Information about the transfer.
* @return transferInfo Information about the transfer after pre-bridge operations.
* @return postHookData Data returned from the pre-hook call.
* @dev Reverts with `ZeroAddressReceiver` if the receiver address is zero.
* Reverts with `InvalidConnector` if the connector address is not valid.
*/
function _beforeBridge(
address connector_,
TransferInfo memory transferInfo_
)
internal
returns (TransferInfo memory transferInfo, bytes memory postHookData)
{
if (transferInfo_.receiver == address(0)) revert ZeroAddressReceiver();
if (!validConnectors[connector_]) revert InvalidConnector();
if (token == ETH_ADDRESS && msg.value < transferInfo_.amount)
revert InsufficientMsgValue();
if (address(hook__) != address(0)) {
(transferInfo, postHookData) = hook__.srcPreHookCall(
SrcPreHookCallParams(connector_, msg.sender, transferInfo_)
);
} else {
transferInfo = transferInfo_;
}
}
/**
* @notice Executes post-bridge operations after completing a token bridge transfer.
* @dev This internal function is called after completing a token bridge transfer.
* It executes the source post-hook call if a hook contract is defined, calculates fees,
* calls the outbound function of the connector, and emits an event for tokens withdrawn.
* @param msgGasLimit_ The gas limit for the outbound call.
* @param connector_ The address of the connector responsible for the transfer.
* @param options_ Additional options for the outbound call.
* @param postHookData_ Data returned from the source post-hook call.
* @param transferInfo_ Information about the transfer.
* @dev Reverts with `MessageIdMisMatched` if the returned message ID does not match the expected message ID.
*/
function _afterBridge(
uint256 msgGasLimit_,
address connector_,
bytes memory options_,
bytes memory postHookData_,
TransferInfo memory transferInfo_
) internal {
TransferInfo memory transferInfo = transferInfo_;
if (address(hook__) != address(0)) {
transferInfo = hook__.srcPostHookCall(
SrcPostHookCallParams(
connector_,
options_,
postHookData_,
transferInfo_
)
);
}
uint256 fees = token == ETH_ADDRESS
? msg.value - transferInfo.amount
: msg.value;
bytes32 messageId = IConnector(connector_).getMessageId();
bytes32 returnedMessageId = IConnector(connector_).outbound{
value: fees
}(
msgGasLimit_,
abi.encode(
transferInfo.receiver,
transferInfo.amount,
messageId,
transferInfo.extraData
),
options_
);
if (returnedMessageId != messageId) revert MessageIdMisMatched();
emit BridgingTokens(
connector_,
msg.sender,
transferInfo.receiver,
transferInfo.amount,
messageId
);
}
/**
* @notice Executes pre-mint operations before minting tokens.
* @dev This internal function is called before minting tokens.
* It validates the caller as a valid connector, checks if the receiver is not this contract, the bridge contract,
* or the token contract, and executes the destination pre-hook call if a hook contract is defined.
* @param transferInfo_ Information about the transfer.
* @return postHookData Data returned from the destination pre-hook call.
* @return transferInfo Information about the transfer after pre-mint operations.
* @dev Reverts with `InvalidConnector` if the caller is not a valid connector.
* Reverts with `CannotTransferOrExecuteOnBridgeContracts` if the receiver is this contract, the bridge contract,
* or the token contract.
*/
function _beforeMint(
uint32,
TransferInfo memory transferInfo_
)
internal
returns (bytes memory postHookData, TransferInfo memory transferInfo)
{
if (!validConnectors[msg.sender]) revert InvalidConnector();
// no need of source check here, as if invalid caller, will revert with InvalidPoolId
if (
transferInfo_.receiver == address(this) ||
// transferInfo_.receiver == address(bridge__) ||
transferInfo_.receiver == token
) revert CannotTransferOrExecuteOnBridgeContracts();
if (address(hook__) != address(0)) {
(postHookData, transferInfo) = hook__.dstPreHookCall(
DstPreHookCallParams(
msg.sender,
connectorCache[msg.sender],
transferInfo_
)
);
} else {
transferInfo = transferInfo_;
}
}
/**
* @notice Executes post-mint operations after minting tokens.
* @dev This internal function is called after minting tokens.
* It executes the destination post-hook call if a hook contract is defined and updates cache data.
* @param messageId_ The unique identifier for the mint transaction.
* @param postHookData_ Data returned from the destination pre-hook call.
* @param transferInfo_ Information about the mint transaction.
*/
function _afterMint(
uint256,
bytes32 messageId_,
bytes memory postHookData_,
TransferInfo memory transferInfo_
) internal {
if (address(hook__) != address(0)) {
CacheData memory cacheData = hook__.dstPostHookCall(
DstPostHookCallParams(
msg.sender,
messageId_,
connectorCache[msg.sender],
postHookData_,
transferInfo_
)
);
identifierCache[messageId_] = cacheData.identifierCache;
connectorCache[msg.sender] = cacheData.connectorCache;
}
emit TokensBridged(
msg.sender,
transferInfo_.receiver,
transferInfo_.amount,
messageId_
);
}
/**
* @notice Executes pre-retry operations before retrying a failed transaction.
* @dev This internal function is called before retrying a failed transaction.
* It validates the connector, retrieves cache data for the given message ID,
* and executes the pre-retry hook if defined.
* @param connector_ The address of the connector responsible for the failed transaction.
* @param messageId_ The unique identifier for the failed transaction.
* @return postHookData Data returned from the pre-retry hook call.
* @return transferInfo Information about the transfer.
* @dev Reverts with `InvalidConnector` if the connector is not valid.
* Reverts with `NoPendingData` if there is no pending data for the given message ID.
*/
function _beforeRetry(
address connector_,
bytes32 messageId_
)
internal
returns (bytes memory postHookData, TransferInfo memory transferInfo)
{
if (!validConnectors[connector_]) revert InvalidConnector();
CacheData memory cacheData = CacheData(
identifierCache[messageId_],
connectorCache[connector_]
);
if (cacheData.identifierCache.length == 0) revert NoPendingData();
(postHookData, transferInfo) = hook__.preRetryHook(
PreRetryHookCallParams(connector_, cacheData)
);
}
/**
* @notice Executes post-retry operations after retrying a failed transaction.
* @dev This internal function is called after retrying a failed transaction.
* It retrieves cache data for the given message ID, executes the post-retry hook if defined,
* and updates cache data.
* @param connector_ The address of the connector responsible for the failed transaction.
* @param messageId_ The unique identifier for the failed transaction.
* @param postHookData Data returned from the pre-retry hook call.
*/
function _afterRetry(
address connector_,
bytes32 messageId_,
bytes memory postHookData
) internal {
CacheData memory cacheData = CacheData(
identifierCache[messageId_],
connectorCache[connector_]
);
(cacheData) = hook__.postRetryHook(
PostRetryHookCallParams(
connector_,
messageId_,
postHookData,
cacheData
)
);
identifierCache[messageId_] = cacheData.identifierCache;
connectorCache[connector_] = cacheData.connectorCache;
}
/**
* @notice Retrieves the minimum fees required for a transaction from a connector.
* @dev This function returns the minimum fees required for a transaction from the specified connector,
* based on the provided message gas limit and payload size.
* @param connector_ The address of the connector.
* @param msgGasLimit_ The gas limit for the transaction.
* @param payloadSize_ The size of the payload for the transaction.
* @return totalFees The total minimum fees required for the transaction.
*/
function getMinFees(
address connector_,
uint256 msgGasLimit_,
uint256 payloadSize_
) external view returns (uint256 totalFees) {
return IConnector(connector_).getMinFees(msgGasLimit_, payloadSize_);
}
}
Vault.sol 128 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;
import "./Base.sol";
import "../interfaces/IConnector.sol";
import "lib/solmate/src/tokens/ERC20.sol";
/**
* @title SuperToken
* @notice A contract which enables bridging a token to its sibling chains.
* @dev This contract implements ISuperTokenOrVault to support message bridging through IMessageBridge compliant contracts.
*/
contract Vault is Base {
using SafeTransferLib for ERC20;
// /**
// * @notice constructor for creating a new SuperTokenVault.
// * @param token_ token contract address which is to be bridged.
// */
constructor(address token_) Base(token_) {
bridgeType = token_ == ETH_ADDRESS ? NATIVE_VAULT : ERC20_VAULT;
}
/**
* @notice Bridges tokens between chains.
* @dev This function allows bridging tokens between different chains.
* @param receiver_ The address to receive the bridged tokens.
* @param amount_ The amount of tokens to bridge.
* @param msgGasLimit_ The gas limit for the execution of the bridging process.
* @param connector_ The address of the connector contract responsible for the bridge.
* @param extraData_ The extra data passed to hook functions.
* @param options_ Additional options for the bridging process.
*/
function bridge(
address receiver_,
uint256 amount_,
uint256 msgGasLimit_,
address connector_,
bytes calldata extraData_,
bytes calldata options_
) external payable nonReentrant {
(
TransferInfo memory transferInfo,
bytes memory postHookData
) = _beforeBridge(
connector_,
TransferInfo(receiver_, amount_, extraData_)
);
_receiveTokens(transferInfo.amount);
_afterBridge(
msgGasLimit_,
connector_,
options_,
postHookData,
transferInfo
);
}
/**
* @notice Receives inbound tokens from another chain.
* @dev This function is used to receive tokens from another chain.
* @param siblingChainSlug_ The identifier of the sibling chain.
* @param payload_ The payload containing the inbound tokens.
*/
function receiveInbound(
uint32 siblingChainSlug_,
bytes memory payload_
) external payable override nonReentrant {
(
address receiver,
uint256 unlockAmount,
bytes32 messageId,
bytes memory extraData
) = abi.decode(payload_, (address, uint256, bytes32, bytes));
TransferInfo memory transferInfo = TransferInfo(
receiver,
unlockAmount,
extraData
);
bytes memory postHookData;
(postHookData, transferInfo) = _beforeMint(
siblingChainSlug_,
transferInfo
);
_transferTokens(transferInfo.receiver, transferInfo.amount);
_afterMint(unlockAmount, messageId, postHookData, transferInfo);
}
/**
* @notice Retry a failed transaction.
* @dev This function allows retrying a failed transaction sent through a connector.
* @param connector_ The address of the connector contract responsible for the failed transaction.
* @param messageId_ The unique identifier of the failed transaction.
*/
function retry(
address connector_,
bytes32 messageId_
) external nonReentrant {
(
bytes memory postHookData,
TransferInfo memory transferInfo
) = _beforeRetry(connector_, messageId_);
_transferTokens(transferInfo.receiver, transferInfo.amount);
_afterRetry(connector_, messageId_, postHookData);
}
function _transferTokens(address receiver_, uint256 amount_) internal {
if (amount_ == 0) return;
if (address(token) == ETH_ADDRESS) {
SafeTransferLib.safeTransferETH(receiver_, amount_);
} else {
ERC20(token).safeTransfer(receiver_, amount_);
}
}
function _receiveTokens(uint256 amount_) internal {
if (amount_ == 0 || address(token) == ETH_ADDRESS) return;
ERC20(token).safeTransferFrom(msg.sender, address(this), amount_);
}
}
Errors.sol 29 lines
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; error SiblingNotSupported(); error NotAuthorized(); error NotBridge(); error NotSocket(); error ConnectorUnavailable(); error InvalidPoolId(); error CannotTransferOrExecuteOnBridgeContracts(); error NoPendingData(); error MessageIdMisMatched(); error NotMessageBridge(); error InvalidSiblingChainSlug(); error InvalidTokenContract(); error InvalidExchangeRateContract(); error InvalidConnector(); error InvalidConnectorPoolId(); error ZeroAddressReceiver(); error ZeroAddress(); error ZeroAmount(); error DebtRatioTooHigh(); error NotEnoughAssets(); error VaultShutdown(); error InsufficientFunds(); error PermitDeadlineExpired(); error InvalidSigner(); error InsufficientMsgValue(); error InvalidOptionsLength();
Ownable.sol 80 lines
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.13;
/**
* @title Ownable
* @dev The Ownable contract provides a simple way to manage ownership of a contract
* and allows for ownership to be transferred to a nominated address.
*/
abstract contract Ownable {
address private _owner;
address private _nominee;
event OwnerNominated(address indexed nominee);
event OwnerClaimed(address indexed claimer);
error OnlyOwner();
error OnlyNominee();
/**
* @dev Sets the contract's owner to the address that is passed to the constructor.
*/
constructor(address owner_) {
_claimOwner(owner_);
}
/**
* @dev Modifier that restricts access to only the contract's owner.
* Throws an error if the caller is not the owner.
*/
modifier onlyOwner() {
if (msg.sender != _owner) revert OnlyOwner();
_;
}
/**
* @dev Returns the current owner of the contract.
*/
function owner() external view returns (address) {
return _owner;
}
/**
* @dev Returns the current nominee for ownership of the contract.
*/
function nominee() external view returns (address) {
return _nominee;
}
/**
* @dev Allows the current owner to nominate a new owner for the contract.
* Throws an error if the caller is not the owner.
* Emits an `OwnerNominated` event with the address of the nominee.
*/
function nominateOwner(address nominee_) external {
if (msg.sender != _owner) revert OnlyOwner();
_nominee = nominee_;
emit OwnerNominated(_nominee);
}
/**
* @dev Allows the nominated owner to claim ownership of the contract.
* Throws an error if the caller is not the nominee.
* Sets the nominated owner as the new owner of the contract.
* Emits an `OwnerClaimed` event with the address of the new owner.
*/
function claimOwner() external {
if (msg.sender != _nominee) revert OnlyNominee();
_claimOwner(msg.sender);
}
/**
* @dev Internal function that sets the owner of the contract to the specified address
* and sets the nominee to address(0).
*/
function _claimOwner(address claimer_) internal {
_owner = claimer_;
_nominee = address(0);
emit OwnerClaimed(claimer_);
}
}
Structs.sol 66 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;
struct UpdateLimitParams {
bool isMint;
address connector;
uint256 maxLimit;
uint256 ratePerSecond;
}
struct SrcPreHookCallParams {
address connector;
address msgSender;
TransferInfo transferInfo;
}
struct SrcPostHookCallParams {
address connector;
bytes options;
bytes postHookData;
TransferInfo transferInfo;
}
struct DstPreHookCallParams {
address connector;
bytes connectorCache;
TransferInfo transferInfo;
}
struct DstPostHookCallParams {
address connector;
bytes32 messageId;
bytes connectorCache;
bytes postHookData;
TransferInfo transferInfo;
}
struct PreRetryHookCallParams {
address connector;
CacheData cacheData;
}
struct PostRetryHookCallParams {
address connector;
bytes32 messageId;
bytes postHookData;
CacheData cacheData;
}
struct TransferInfo {
address receiver;
uint256 amount;
bytes extraData;
}
struct CacheData {
bytes identifierCache;
bytes connectorCache;
}
struct LimitParams {
uint256 lastUpdateTimestamp;
uint256 ratePerSecond;
uint256 maxLimit;
uint256 lastUpdateLimit;
}
Constants.sol 21 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;
address constant ETH_ADDRESS = address(
0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
);
bytes32 constant NORMAL_CONTROLLER = keccak256("NORMAL_CONTROLLER");
bytes32 constant FIAT_TOKEN_CONTROLLER = keccak256("FIAT_TOKEN_CONTROLLER");
bytes32 constant LIMIT_HOOK = keccak256("LIMIT_HOOK");
bytes32 constant LIMIT_EXECUTION_HOOK = keccak256("LIMIT_EXECUTION_HOOK");
bytes32 constant LIMIT_EXECUTION_YIELD_HOOK = keccak256(
"LIMIT_EXECUTION_YIELD_HOOK"
);
bytes32 constant LIMIT_EXECUTION_YIELD_TOKEN_HOOK = keccak256(
"LIMIT_EXECUTION_YIELD_TOKEN_HOOK"
);
bytes32 constant ERC20_VAULT = keccak256("ERC20_VAULT");
bytes32 constant NATIVE_VAULT = keccak256("NATIVE_VAULT");
IHook.sol 66 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
import "../common/Structs.sol";
interface IHook {
/**
* @notice Executes pre-hook call for source underlyingAsset.
* @dev This function is used to execute a pre-hook call for the source underlyingAsset before initiating a transfer.
* @param params_ Parameters for the pre-hook call.
* @return transferInfo Information about the transfer.
* @return postHookData returned from the pre-hook call.
*/
function srcPreHookCall(
SrcPreHookCallParams calldata params_
)
external
returns (TransferInfo memory transferInfo, bytes memory postHookData);
function srcPostHookCall(
SrcPostHookCallParams calldata params_
) external returns (TransferInfo memory transferInfo);
/**
* @notice Executes pre-hook call for destination underlyingAsset.
* @dev This function is used to execute a pre-hook call for the destination underlyingAsset before initiating a transfer.
* @param params_ Parameters for the pre-hook call.
*/
function dstPreHookCall(
DstPreHookCallParams calldata params_
)
external
returns (bytes memory postHookData, TransferInfo memory transferInfo);
/**
* @notice Executes post-hook call for destination underlyingAsset.
* @dev This function is used to execute a post-hook call for the destination underlyingAsset after completing a transfer.
* @param params_ Parameters for the post-hook call.
* @return cacheData Cached data for the post-hook call.
*/
function dstPostHookCall(
DstPostHookCallParams calldata params_
) external returns (CacheData memory cacheData);
/**
* @notice Executes a pre-retry hook for a failed transaction.
* @dev This function is used to execute a pre-retry hook for a failed transaction.
* @param params_ Parameters for the pre-retry hook.
* @return postHookData Data from the post-retry hook.
* @return transferInfo Information about the transfer.
*/
function preRetryHook(
PreRetryHookCallParams calldata params_
)
external
returns (bytes memory postHookData, TransferInfo memory transferInfo);
/**
* @notice Executes a post-retry hook for a failed transaction.
* @dev This function is used to execute a post-retry hook for a failed transaction.
* @param params_ Parameters for the post-retry hook.
* @return cacheData Cached data for the post-retry hook.
*/
function postRetryHook(
PostRetryHookCallParams calldata params_
) external returns (CacheData memory cacheData);
}
RescueBase.sol 28 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;
import {RescueFundsLib} from "../libraries/RescueFundsLib.sol";
import {AccessControl} from "./AccessControl.sol";
/**
* @title Base contract for super token and vault
* @notice It contains relevant execution payload storages.
* @dev This contract implements Socket's IPlug to enable message bridging and IMessageBridge
* to support any type of message bridge.
*/
abstract contract RescueBase is AccessControl {
bytes32 constant RESCUE_ROLE = keccak256("RESCUE_ROLE");
/**
* @notice Rescues funds from the contract if they are locked by mistake.
* @param token_ The address of the token contract.
* @param rescueTo_ The address where rescued tokens need to be sent.
* @param amount_ The amount of tokens to be rescued.
*/
function rescueFunds(
address token_,
address rescueTo_,
uint256 amount_
) external onlyRole(RESCUE_ROLE) {
RescueFundsLib.rescueFunds(token_, rescueTo_, amount_);
}
}
IBridge.sol 20 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
interface IBridge {
function bridge(
address receiver_,
uint256 amount_,
uint256 msgGasLimit_,
address connector_,
bytes calldata extraData_,
bytes calldata options_
) external payable;
function receiveInbound(
uint32 siblingChainSlug_,
bytes memory payload_
) external payable;
function retry(address connector_, bytes32 messageId_) external;
}
ERC20.sol 206 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}
AccessControl.sol 125 lines
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.13;
import "./Ownable.sol";
/**
* @title AccessControl
* @dev This abstract contract implements access control mechanism based on roles.
* Each role can have one or more addresses associated with it, which are granted
* permission to execute functions with the onlyRole modifier.
*/
abstract contract AccessControl is Ownable {
/**
* @dev A mapping of roles to a mapping of addresses to boolean values indicating whether or not they have the role.
*/
mapping(bytes32 => mapping(address => bool)) private _permits;
/**
* @dev Emitted when a role is granted to an address.
*/
event RoleGranted(bytes32 indexed role, address indexed grantee);
/**
* @dev Emitted when a role is revoked from an address.
*/
event RoleRevoked(bytes32 indexed role, address indexed revokee);
/**
* @dev Error message thrown when an address does not have permission to execute a function with onlyRole modifier.
*/
error NoPermit(bytes32 role);
/**
* @dev Constructor that sets the owner of the contract.
*/
constructor(address owner_) Ownable(owner_) {}
/**
* @dev Modifier that restricts access to addresses having roles
* Throws an error if the caller do not have permit
*/
modifier onlyRole(bytes32 role) {
if (!_permits[role][msg.sender]) revert NoPermit(role);
_;
}
/**
* @dev Checks and reverts if an address do not have a specific role.
* @param role_ The role to check.
* @param address_ The address to check.
*/
function _checkRole(bytes32 role_, address address_) internal virtual {
if (!_hasRole(role_, address_)) revert NoPermit(role_);
}
/**
* @dev Grants a role to a given address.
* @param role_ The role to grant.
* @param grantee_ The address to grant the role to.
* Emits a RoleGranted event.
* Can only be called by the owner of the contract.
*/
function grantRole(
bytes32 role_,
address grantee_
) external virtual onlyOwner {
_grantRole(role_, grantee_);
}
/**
* @dev Revokes a role from a given address.
* @param role_ The role to revoke.
* @param revokee_ The address to revoke the role from.
* Emits a RoleRevoked event.
* Can only be called by the owner of the contract.
*/
function revokeRole(
bytes32 role_,
address revokee_
) external virtual onlyOwner {
_revokeRole(role_, revokee_);
}
/**
* @dev Internal function to grant a role to a given address.
* @param role_ The role to grant.
* @param grantee_ The address to grant the role to.
* Emits a RoleGranted event.
*/
function _grantRole(bytes32 role_, address grantee_) internal {
_permits[role_][grantee_] = true;
emit RoleGranted(role_, grantee_);
}
/**
* @dev Internal function to revoke a role from a given address.
* @param role_ The role to revoke.
* @param revokee_ The address to revoke the role from.
* Emits a RoleRevoked event.
*/
function _revokeRole(bytes32 role_, address revokee_) internal {
_permits[role_][revokee_] = false;
emit RoleRevoked(role_, revokee_);
}
/**
* @dev Checks whether an address has a specific role.
* @param role_ The role to check.
* @param address_ The address to check.
* @return A boolean value indicating whether or not the address has the role.
*/
function hasRole(
bytes32 role_,
address address_
) external view returns (bool) {
return _hasRole(role_, address_);
}
function _hasRole(
bytes32 role_,
address address_
) internal view returns (bool) {
return _permits[role_][address_];
}
}
IConnector.sol 19 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
interface IConnector {
function outbound(
uint256 msgGasLimit_,
bytes memory payload_,
bytes memory options_
) external payable returns (bytes32 messageId_);
function siblingChainSlug() external view returns (uint32);
function getMinFees(
uint256 msgGasLimit_,
uint256 payloadSize_
) external view returns (uint256 totalFees);
function getMessageId() external view returns (bytes32);
}
RescueFundsLib.sol 46 lines
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.13;
import "lib/solmate/src/utils/SafeTransferLib.sol";
import "lib/solmate/src/tokens/ERC20.sol";
error ZeroAddress();
/**
* @title RescueFundsLib
* @dev A library that provides a function to rescue funds from a contract.
*/
library RescueFundsLib {
/**
* @dev The address used to identify ETH.
*/
address public constant ETH_ADDRESS =
address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
/**
* @dev thrown when the given token address don't have any code
*/
error InvalidTokenAddress();
/**
* @dev Rescues funds from a contract.
* @param token_ The address of the token contract.
* @param rescueTo_ The address of the user.
* @param amount_ The amount of tokens to be rescued.
*/
function rescueFunds(
address token_,
address rescueTo_,
uint256 amount_
) internal {
if (rescueTo_ == address(0)) revert ZeroAddress();
if (token_ == ETH_ADDRESS) {
SafeTransferLib.safeTransferETH(rescueTo_, amount_);
} else {
if (token_.code.length == 0) revert InvalidTokenAddress();
SafeTransferLib.safeTransfer(ERC20(token_), rescueTo_, amount_);
}
}
}
IMintableERC20.sol 8 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;
interface IMintableERC20 {
function mint(address receiver_, uint256 amount_) external;
function burn(address burner_, uint256 amount_) external;
}
ReentrancyGuard.sol 19 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Gas optimized reentrancy protection for smart contracts.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ReentrancyGuard.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
uint256 private locked = 1;
modifier nonReentrant() virtual {
require(locked == 1, "REENTRANCY");
locked = 2;
_;
locked = 1;
}
}
SafeTransferLib.sol 128 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
/*//////////////////////////////////////////////////////////////
ETH OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferETH(address to, uint256 amount) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Transfer the ETH and store if it succeeded or not.
success := call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
/*//////////////////////////////////////////////////////////////
ERC20 OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
)
}
require(success, "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "APPROVE_FAILED");
}
}
Read Contract
bridgeType 0x2421e155 → bytes32
connectorCache 0x4b0a8854 → bytes
getMinFees 0xfc3a7b98 → uint256
hasRole 0x91d14854 → bool
hook__ 0x70bab2c0 → address
identifierCache 0xf290aafa → bytes
nominee 0x20f99c0a → address
owner 0x8da5cb5b → address
token 0xfc0c546a → address
validConnectors 0xe9ee1eaf → bool
Write Contract 10 functions
These functions modify contract state and require a wallet transaction to execute.
bridge 0x405e720a
address receiver_
uint256 amount_
uint256 msgGasLimit_
address connector_
bytes extraData_
bytes options_
claimOwner 0x3bd1adec
No parameters
grantRole 0x2f2ff15d
bytes32 role_
address grantee_
nominateOwner 0x5b94db27
address nominee_
receiveInbound 0x873ea755
uint32 siblingChainSlug_
bytes payload_
rescueFunds 0x6ccae054
address token_
address rescueTo_
uint256 amount_
retry 0x9dc7b023
address connector_
bytes32 messageId_
revokeRole 0xd547741f
bytes32 role_
address revokee_
updateConnectorStatus 0xe272ad3f
address[] connectors
bool[] statuses
updateHook 0xaad48d80
address hook_
bool approve_
Token Balances (1)
View Transfers →Recent Transactions
No transactions found for this address