eth-offline

EVM token minter frontend for offline issuance using ERC712 structured signatures.
Log | Files | Refs

commit e9da18c74fea2847a4752505d2f1a9e97286d5d0
parent 303df79b3b6360f5cfa1207cd48300a6d361d187
Author: lash <dev@holbrook.no>
Date:   Wed, 29 Mar 2023 15:08:12 +0100

Implement ERC712 validation alternative

Diffstat:
Mpython/eth_offline/data/Offline.bin | 4++--
Mpython/eth_offline/data/Offline.json | 2+-
Mpython/requirements.txt | 4+++-
Mpython/test_requirements.txt | 3++-
Mpython/tests/test_basic.py | 126+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msolidity/Offline.sol | 117++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msolidity/OfflineBase.sol | 33++++++++++++++++++++++++++++++++-
7 files changed, 244 insertions(+), 45 deletions(-)

diff --git a/python/eth_offline/data/Offline.bin b/python/eth_offline/data/Offline.bin @@ -1 +1 @@ -608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610e2f806100606000396000f3fe608060405234801561001057600080fd5b5060043610610074576000357c0100000000000000000000000000000000000000000000000000000000900480631ecc95c8146100795780632c0b80e2146100a95780633327670c146100d9578063602f7c72146100f7578063ce606ee014610127575b600080fd5b610093600480360381019061008e9190610826565b610145565b6040516100a091906108b9565b60405180910390f35b6100c360048036038101906100be9190610932565b610210565b6040516100d091906108b9565b60405180910390f35b6100e16102f8565b6040516100ee91906109a7565b60405180910390f35b610111600480360381019061010c9190610826565b6102fe565b60405161011e91906109a7565b60405180910390f35b61012f61036b565b60405161013c91906109d1565b60405180910390f35b600060606000806101558661038f565b92508280519060200120915061016b82866105f5565b90503073ffffffffffffffffffffffffffffffffffffffff16632c0b80e282886040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004016101c4929190610a6b565b602060405180830381865afa1580156101e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102059190610ac7565b935050505092915050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361024e57600090506102f2565b60008261025a90610b55565b7401000000000000000000000000000000000000000090046bffffffffffffffffffffffff160361028e57600090506102f2565b60608251146102a057600090506102f2565b8273ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161490505b92915050565b60015481565b600061030a8383610145565b610349576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161034090610c19565b60405180910390fd5b6001600081548092919061035c90610c68565b91905055506000905092915050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b606080600080845160166103a39190610cb0565b67ffffffffffffffff8111156103bc576103bb6106fb565b5b6040519080825280601f01601f1916602001820160405280156103ee5781602001600182028036833780820191505090505b50925060197f0100000000000000000000000000000000000000000000000000000000000000028360008151811061042957610428610ce4565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060029150306c0100000000000000000000000002905060005b60148110156105105781816014811061048d5761048c610ce4565b5b1a7f0100000000000000000000000000000000000000000000000000000000000000028484836104bd9190610cb0565b815181106104ce576104cd610ce4565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350808061050890610c68565b915050610471565b5060148261051e9190610cb0565b915060005b85518110156105e95785818151811061053f5761053e610ce4565b5b60200101517f010000000000000000000000000000000000000000000000000000000000000090047f0100000000000000000000000000000000000000000000000000000000000000028484836105969190610cb0565b815181106105a7576105a6610ce4565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535080806105e190610c68565b915050610523565b50829350505050919050565b60008060008061060485610664565b9250925092506001868285856040516000815260200160405260405161062d9493929190610d48565b6020604051602081039080840390855afa15801561064f573d6000803e3d6000fd5b50505060206040510351935050505092915050565b600080600060418451146106ad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106a490610dd9565b60405180910390fd5b6020840151925060408401519150606084015160001a90509193909250565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610733826106ea565b810181811067ffffffffffffffff82111715610752576107516106fb565b5b80604052505050565b60006107656106cc565b9050610771828261072a565b919050565b600067ffffffffffffffff821115610791576107906106fb565b5b61079a826106ea565b9050602081019050919050565b82818337600083830152505050565b60006107c96107c484610776565b61075b565b9050828152602081018484840111156107e5576107e46106e5565b5b6107f08482856107a7565b509392505050565b600082601f83011261080d5761080c6106e0565b5b813561081d8482602086016107b6565b91505092915050565b6000806040838503121561083d5761083c6106d6565b5b600083013567ffffffffffffffff81111561085b5761085a6106db565b5b610867858286016107f8565b925050602083013567ffffffffffffffff811115610888576108876106db565b5b610894858286016107f8565b9150509250929050565b60008115159050919050565b6108b38161089e565b82525050565b60006020820190506108ce60008301846108aa565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006108ff826108d4565b9050919050565b61090f816108f4565b811461091a57600080fd5b50565b60008135905061092c81610906565b92915050565b60008060408385031215610949576109486106d6565b5b60006109578582860161091d565b925050602083013567ffffffffffffffff811115610978576109776106db565b5b610984858286016107f8565b9150509250929050565b6000819050919050565b6109a18161098e565b82525050565b60006020820190506109bc6000830184610998565b92915050565b6109cb816108f4565b82525050565b60006020820190506109e660008301846109c2565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610a26578082015181840152602081019050610a0b565b60008484015250505050565b6000610a3d826109ec565b610a4781856109f7565b9350610a57818560208601610a08565b610a60816106ea565b840191505092915050565b6000604082019050610a8060008301856109c2565b8181036020830152610a928184610a32565b90509392505050565b610aa48161089e565b8114610aaf57600080fd5b50565b600081519050610ac181610a9b565b92915050565b600060208284031215610add57610adc6106d6565b5b6000610aeb84828501610ab2565b91505092915050565b6000819050602082019050919050565b60007fffffffffffffffffffffffff000000000000000000000000000000000000000082169050919050565b6000610b3c8251610b04565b80915050919050565b60008160020a8302905092915050565b6000610b60826109ec565b82610b6a84610af4565b9050610b7581610b30565b9250600c821015610bb557610bb07fffffffffffffffffffffffff000000000000000000000000000000000000000083600c03600802610b45565b831692505b5050919050565b600082825260208201905092915050565b7f4552525f554e5645524946494544000000000000000000000000000000000000600082015250565b6000610c03600e83610bbc565b9150610c0e82610bcd565b602082019050919050565b60006020820190508181036000830152610c3281610bf6565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610c738261098e565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610ca557610ca4610c39565b5b600182019050919050565b6000610cbb8261098e565b9150610cc68361098e565b9250828201905080821115610cde57610cdd610c39565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000819050919050565b610d2681610d13565b82525050565b600060ff82169050919050565b610d4281610d2c565b82525050565b6000608082019050610d5d6000830187610d1d565b610d6a6020830186610d39565b610d776040830185610d1d565b610d846060830184610d1d565b95945050505050565b7f696e76616c6964207369676e6174757265206c656e6774680000000000000000600082015250565b6000610dc3601883610bbc565b9150610dce82610d8d565b602082019050919050565b60006020820190508181036000830152610df281610db6565b905091905056fea2646970667358221220a6507aa34b62bae066116d9284c60596eab1ef5a189481fdd7c617f6052f928d64736f6c63430008130033 -\ No newline at end of file +60806040523480156200001157600080fd5b5060405162001bb538038062001bb5833981810160405281019062000037919062000206565b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506200013b6040518060a001604052806040518060400160405280601481526020017f4f66666c696e65207369676e696e67207465737400000000000000000000000081525081526020016040518060400160405280600181526020017f300000000000000000000000000000000000000000000000000000000000000081525081526020018381526020013073ffffffffffffffffffffffffffffffffffffffff168152602001600060010281525062000148640100000000026401000000009004565b6002819055505062000316565b60007fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac56472826000015180519060200120836020015180519060200120846040015185606001518660800151604051602001620001a996959493929190620002a9565b604051602081830303815290604052805190602001209050919050565b600080fd5b6000819050919050565b620001e081620001cb565b8114620001ec57600080fd5b50565b6000815190506200020081620001d5565b92915050565b6000602082840312156200021f576200021e620001c6565b5b60006200022f84828501620001ef565b91505092915050565b6000819050919050565b6200024d8162000238565b82525050565b6200025e81620001cb565b82525050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620002918262000264565b9050919050565b620002a38162000284565b82525050565b600060c082019050620002c0600083018962000242565b620002cf602083018862000242565b620002de604083018762000242565b620002ed606083018662000253565b620002fc608083018562000298565b6200030b60a083018462000242565b979650505050505050565b61188f80620003266000396000f3fe608060405234801561001057600080fd5b50600436106100b0576000357c0100000000000000000000000000000000000000000000000000000000900480635b07fdd8116100835780635b07fdd814610163578063964a7543146101815780639da6b49b1461019f578063c13fbebe146101cf578063ce606ee0146101ff576100b0565b80631ecc95c8146100b55780632c0b80e2146100e55780633327670c14610115578063527f58c914610133575b600080fd5b6100cf60048036038101906100ca9190610f0f565b61021d565b6040516100dc9190610fa2565b60405180910390f35b6100ff60048036038101906100fa919061101b565b6102e8565b60405161010c9190610fa2565b60405180910390f35b61011d6103d0565b60405161012a9190611090565b60405180910390f35b61014d600480360381019061014891906110e1565b6103d6565b60405161015a9190610fa2565b60405180910390f35b61016b6108cb565b604051610178919061118f565b60405180910390f35b6101896108d1565b604051610196919061118f565b60405180910390f35b6101b960048036038101906101b491906111e3565b6108f5565b6040516101c69190611090565b60405180910390f35b6101e960048036038101906101e49190611303565b610a2b565b6040516101f691906113af565b60405180910390f35b610207610a54565b60405161021491906113e0565b60405180910390f35b6000606060008061022d86610a78565b9250828051906020012091506102438286610cde565b90503073ffffffffffffffffffffffffffffffffffffffff16632c0b80e282886040518363ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040161029c9291906113fb565b602060405180830381865afa1580156102b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102dd9190611457565b935050505092915050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361032657600090506103ca565b600082610332906114e5565b7401000000000000000000000000000000000000000090046bffffffffffffffffffffffff160361036657600090506103ca565b606082511461037857600090506103ca565b8273ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161490505b92915050565b60015481565b60006060600060606000885160206103ee919061157b565b67ffffffffffffffff81111561040757610406610de4565b5b6040519080825280601f01601f1916602001820160405280156104395781602001600182028036833780820191505090505b50915060005b60208110156104d35786816020811061045b5761045a6115af565b5b1a7f010000000000000000000000000000000000000000000000000000000000000002838281518110610491576104906115af565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535080806104cb906115de565b91505061043f565b5060005b895181101561059e578981815181106104f3576104f26115af565b5b60200101517f010000000000000000000000000000000000000000000000000000000000000090047f0100000000000000000000000000000000000000000000000000000000000000028360208361054b919061157b565b8151811061055c5761055b6115af565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508080610596906115de565b9150506104d7565b5081805190602001209250604267ffffffffffffffff8111156105c4576105c3610de4565b5b6040519080825280601f01601f1916602001820160405280156105f65781602001600182028036833780820191505090505b50935060197f01000000000000000000000000000000000000000000000000000000000000000284600081518110610631576106306115af565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060017f01000000000000000000000000000000000000000000000000000000000000000284600181518110610698576106976115af565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060005b602081101561076a578781602081106106e6576106e56115af565b5b1a7f01000000000000000000000000000000000000000000000000000000000000000285600283610717919061157b565b81518110610728576107276115af565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508080610762906115de565b9150506106ca565b5060005b602081101561080e5783816020811061078a576107896115af565b5b1a7f010000000000000000000000000000000000000000000000000000000000000002856022836107bb919061157b565b815181106107cc576107cb6115af565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508080610806906115de565b91505061076e565b50838051906020012092506108238389610cde565b90503073ffffffffffffffffffffffffffffffffffffffff16632c0b80e2828b6040518363ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040161087c9291906113fb565b602060405180830381865afa158015610899573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108bd9190611457565b945050505050949350505050565b60025481565b7f36adcc29d081b2c3e5344b4ae737ccb866954437436de1e2fcd77747ea2dea1481565b6000808260ff160361094f5761090b848461021d565b61094a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161094190611683565b60405180910390fd5b610a08565b60018260ff16036109cc5761098884846002547f36adcc29d081b2c3e5344b4ae737ccb866954437436de1e2fcd77747ea2dea146103d6565b6109c7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109be90611683565b60405180910390fd5b610a07565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109fe906116ef565b60405180910390fd5b5b60016000815480929190610a1b906115de565b9190505550600090509392505050565b606081604051602001610a3e919061177e565b6040516020818303038152906040529050919050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60608060008084516016610a8c919061157b565b67ffffffffffffffff811115610aa557610aa4610de4565b5b6040519080825280601f01601f191660200182016040528015610ad75781602001600182028036833780820191505090505b50925060197f01000000000000000000000000000000000000000000000000000000000000000283600081518110610b1257610b116115af565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060029150306c0100000000000000000000000002905060005b6014811015610bf957818160148110610b7657610b756115af565b5b1a7f010000000000000000000000000000000000000000000000000000000000000002848483610ba6919061157b565b81518110610bb757610bb66115af565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508080610bf1906115de565b915050610b5a565b50601482610c07919061157b565b915060005b8551811015610cd257858181518110610c2857610c276115af565b5b60200101517f010000000000000000000000000000000000000000000000000000000000000090047f010000000000000000000000000000000000000000000000000000000000000002848483610c7f919061157b565b81518110610c9057610c8f6115af565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508080610cca906115de565b915050610c0c565b50829350505050919050565b600080600080610ced85610d4d565b92509250925060018682858560405160008152602001604052604051610d1694939291906117a8565b6020604051602081039080840390855afa158015610d38573d6000803e3d6000fd5b50505060206040510351935050505092915050565b60008060006041845114610d96576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d8d90611839565b60405180910390fd5b6020840151925060408401519150606084015160001a90509193909250565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610e1c82610dd3565b810181811067ffffffffffffffff82111715610e3b57610e3a610de4565b5b80604052505050565b6000610e4e610db5565b9050610e5a8282610e13565b919050565b600067ffffffffffffffff821115610e7a57610e79610de4565b5b610e8382610dd3565b9050602081019050919050565b82818337600083830152505050565b6000610eb2610ead84610e5f565b610e44565b905082815260208101848484011115610ece57610ecd610dce565b5b610ed9848285610e90565b509392505050565b600082601f830112610ef657610ef5610dc9565b5b8135610f06848260208601610e9f565b91505092915050565b60008060408385031215610f2657610f25610dbf565b5b600083013567ffffffffffffffff811115610f4457610f43610dc4565b5b610f5085828601610ee1565b925050602083013567ffffffffffffffff811115610f7157610f70610dc4565b5b610f7d85828601610ee1565b9150509250929050565b60008115159050919050565b610f9c81610f87565b82525050565b6000602082019050610fb76000830184610f93565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610fe882610fbd565b9050919050565b610ff881610fdd565b811461100357600080fd5b50565b60008135905061101581610fef565b92915050565b6000806040838503121561103257611031610dbf565b5b600061104085828601611006565b925050602083013567ffffffffffffffff81111561106157611060610dc4565b5b61106d85828601610ee1565b9150509250929050565b6000819050919050565b61108a81611077565b82525050565b60006020820190506110a56000830184611081565b92915050565b6000819050919050565b6110be816110ab565b81146110c957600080fd5b50565b6000813590506110db816110b5565b92915050565b600080600080608085870312156110fb576110fa610dbf565b5b600085013567ffffffffffffffff81111561111957611118610dc4565b5b61112587828801610ee1565b945050602085013567ffffffffffffffff81111561114657611145610dc4565b5b61115287828801610ee1565b9350506040611163878288016110cc565b9250506060611174878288016110cc565b91505092959194509250565b611189816110ab565b82525050565b60006020820190506111a46000830184611180565b92915050565b600060ff82169050919050565b6111c0816111aa565b81146111cb57600080fd5b50565b6000813590506111dd816111b7565b92915050565b6000806000606084860312156111fc576111fb610dbf565b5b600084013567ffffffffffffffff81111561121a57611219610dc4565b5b61122686828701610ee1565b935050602084013567ffffffffffffffff81111561124757611246610dc4565b5b61125386828701610ee1565b9250506040611264868287016111ce565b9150509250925092565b600080fd5b61127c81611077565b811461128757600080fd5b50565b60008135905061129981611273565b92915050565b6000606082840312156112b5576112b461126e565b5b6112bf6060610e44565b905060006112cf848285016110cc565b60008301525060206112e38482850161128a565b60208301525060406112f784828501611006565b60408301525092915050565b60006060828403121561131957611318610dbf565b5b60006113278482850161129f565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561136a57808201518184015260208101905061134f565b60008484015250505050565b600061138182611330565b61138b818561133b565b935061139b81856020860161134c565b6113a481610dd3565b840191505092915050565b600060208201905081810360008301526113c98184611376565b905092915050565b6113da81610fdd565b82525050565b60006020820190506113f560008301846113d1565b92915050565b600060408201905061141060008301856113d1565b81810360208301526114228184611376565b90509392505050565b61143481610f87565b811461143f57600080fd5b50565b6000815190506114518161142b565b92915050565b60006020828403121561146d5761146c610dbf565b5b600061147b84828501611442565b91505092915050565b6000819050602082019050919050565b60007fffffffffffffffffffffffff000000000000000000000000000000000000000082169050919050565b60006114cc8251611494565b80915050919050565b60008160020a8302905092915050565b60006114f082611330565b826114fa84611484565b9050611505816114c0565b9250600c821015611545576115407fffffffffffffffffffffffff000000000000000000000000000000000000000083600c036008026114d5565b831692505b5050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061158682611077565b915061159183611077565b92508282019050808211156115a9576115a861154c565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006115e982611077565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361161b5761161a61154c565b5b600182019050919050565b600082825260208201905092915050565b7f4552525f554e5645524946494544000000000000000000000000000000000000600082015250565b600061166d600e83611626565b915061167882611637565b602082019050919050565b6000602082019050818103600083015261169c81611660565b9050919050565b7f554e4b4e4f574e2056455253494f4e0000000000000000000000000000000000600082015250565b60006116d9600f83611626565b91506116e4826116a3565b602082019050919050565b60006020820190508181036000830152611708816116cc565b9050919050565b611718816110ab565b82525050565b61172781611077565b82525050565b61173681610fdd565b82525050565b606082016000820151611752600085018261170f565b506020820151611765602085018261171e565b506040820151611778604085018261172d565b50505050565b6000606082019050611793600083018461173c565b92915050565b6117a2816111aa565b82525050565b60006080820190506117bd6000830187611180565b6117ca6020830186611799565b6117d76040830185611180565b6117e46060830184611180565b95945050505050565b7f696e76616c6964207369676e6174757265206c656e6774680000000000000000600082015250565b6000611823601883611626565b915061182e826117ed565b602082019050919050565b6000602082019050818103600083015261185281611816565b905091905056fea264697066735822122022688a4c741e1d7beaf776a08dbf95fb5601aa6fcb2108e20f4c3b4c29f4e8ae64736f6c63430008130033 +\ No newline at end of file diff --git a/python/eth_offline/data/Offline.json b/python/eth_offline/data/Offline.json @@ -1 +1 @@ -[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"contractOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"executeOfflineRequest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"executedTimes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"isOfflineValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"verifyOfflineRequest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}] +[{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"contractOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712DomainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712TypeHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"bytes","name":"_signature","type":"bytes"},{"internalType":"uint8","name":"_version","type":"uint8"}],"name":"executeOfflineRequest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"executedTimes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"isOfflineValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"domain","type":"bytes32"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"address","name":"beneficiary","type":"address"}],"internalType":"struct OfflineRubber.Instruction","name":"_instruction","type":"tuple"}],"name":"toBytes","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"verifyOfflineRequest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"bytes","name":"_signature","type":"bytes"},{"internalType":"bytes32","name":"_domainSeparator","type":"bytes32"},{"internalType":"bytes32","name":"_typeHash","type":"bytes32"}],"name":"verifyOfflineRequest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}] diff --git a/python/requirements.txt b/python/requirements.txt @@ -1 +1,3 @@ -chainlib-eth~=0.4.17 +chainlib-eth~=0.4.18 +chainlib~=0.4.13 +eth_erc712==0.0.1 diff --git a/python/test_requirements.txt b/python/test_requirements.txt @@ -1,3 +1,4 @@ eth_tester==0.5.0b3 py-evm==0.3.0a20 -funga-eth~=0.6.5 +#eth_tester==0.8.0b3 +#py-evm==0.6.1a2 diff --git a/python/tests/test_basic.py b/python/tests/test_basic.py @@ -21,6 +21,8 @@ from hexathon import add_0x from hexathon import strip_0x from hexathon import same as same_hex from funga.eth.message import to_validator_message +from eth_erc712 import EIP712Domain +from eth_erc712 import EIP712DomainEncoder script_dir = os.path.realpath(os.path.dirname(__file__)) data_dir = os.path.join(script_dir, '..', 'eth_offline', 'data') @@ -28,6 +30,9 @@ data_dir = os.path.join(script_dir, '..', 'eth_offline', 'data') logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger(__name__) +hash_of_foo = '2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae' +hash_of_bar = 'fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9' + class TestOfflineEth(EthTesterCase): @@ -44,12 +49,14 @@ class TestOfflineEth(EthTesterCase): c = Gas(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle) self.conn = RPCConnection.connect(self.chain_spec, 'default') - (tx_hash, o) = c.create(self.accounts[0], None, 0, data=bytecode) + data = self.chain_spec.chain_id().to_bytes(32, byteorder='big').hex() + (tx_hash, o) = c.create(self.accounts[0], None, 0, data=bytecode + data) r = self.conn.do(o) - o = receipt(r) r = self.conn.do(o) + self.assertEqual(r['status'], 1) self.address = to_checksum_address(r['contract_address']) + self.contract_block_hash = r['block_hash'] logg.debug('smart contract published with hash {} address {}'.format(r, self.address)) @@ -232,8 +239,10 @@ class TestOfflineEth(EthTesterCase): enc.method('executeOfflineRequest') enc.typ(ABIContractType.BYTES) enc.typ(ABIContractType.BYTES) + enc.typ(ABIContractType.UINT8) enc.bytes(msg_data.hex()) enc.bytes(sig.hex()) + enc.uintn(0, 8) data = enc.get() tx = c.template(self.accounts[0], self.address, use_nonce=True) tx = c.set_code(tx, data) @@ -260,5 +269,118 @@ class TestOfflineEth(EthTesterCase): self.assertEqual(int(r, 16), 1) + # TODO: check if uint96 etc works with packed data + def test_from_struct(self): + instruction_nonce = os.urandom(16) + enc_instruction = ABIContractEncoder() + # bytes12 does not work with this pyevm in struct encoding + #enc_instruction.typ(ABIContractType.BYTES32) + enc_instruction.typ(ABIContractType.BYTES32) + enc_instruction.typ(ABIContractType.UINT256) + enc_instruction.typ(ABIContractType.ADDRESS) + #enc_instruction.typ_literal('uint96') + #enc_instruction.bytesn(instruction_nonce.hex(), 12) + #enc_instruction.bytes32(hash_of_bar) + enc_instruction.bytes32(hash_of_foo) + enc_instruction.uint256(42) + enc_instruction.address(self.accounts[2]) + #enc_instruction.uintn(int(instruction_nonce.hex(), 16), 96) + + c = TxFactory(self.chain_spec) + j = JSONRPCRequest() + o = j.template() + o['method'] = 'eth_call' + enc = ABIContractEncoder() + enc.method('toBytes') + enc.typ(enc_instruction) + enc.tuple(enc_instruction) + data = strip_0x(enc.get()) + data = data[:8] + data[8+64:] + data = add_0x(data) + tx = c.template(self.accounts[0], self.address) + tx = c.set_code(tx, data) + o['params'].append(c.normalize(tx)) + o['params'].append('latest') + o = j.finalize(o) + r = self.rpc.do(o) + r = strip_0x(r) + print(r) + + + def test_execute_erc712(self): + c = TxFactory(self.chain_spec) + j = JSONRPCRequest() + o = j.template() + o['method'] = 'eth_call' + enc = ABIContractEncoder() + enc.method('eip712DomainSeparator') + data = add_0x(enc.get()) + tx = c.template(self.accounts[0], self.address) + tx = c.set_code(tx, data) + o['params'].append(c.normalize(tx)) + o['params'].append('latest') + o = j.finalize(o) + r = self.rpc.do(o) + r = strip_0x(r) + + domain = EIP712Domain( + name='Offline signing test', + version='0', + chain_id=self.chain_spec.chain_id(), + verifying_contract=self.address, + #salt=self.contract_block_hash, + salt='0x00', + ) + + self.assertEqual(r, domain.get_contents().hex()) + + c = TxFactory(self.chain_spec) + j = JSONRPCRequest() + o = j.template() + o['method'] = 'eth_call' + enc = ABIContractEncoder() + enc.method('eip712TypeHash') + data = add_0x(enc.get()) + tx = c.template(self.accounts[0], self.address) + tx = c.set_code(tx, data) + o['params'].append(c.normalize(tx)) + o['params'].append('latest') + o = j.finalize(o) + r = self.rpc.do(o) + r = strip_0x(r) + + subdomain = os.urandom(32) + enc = EIP712DomainEncoder('Instruction', domain) + enc.add('domain', ABIContractType.BYTES32, subdomain) + enc.add('value', ABIContractType.UINT256, 42) + enc.add('beneficiary', ABIContractType.ADDRESS, self.accounts[2]) + + self.assertEqual(r, enc.get_type_hash().hex()) + + msg_data = enc.get_typed_data() + sig = self.signer.sign_typed_message(self.accounts[0], enc.get_domain(), enc.get_hash()) + sig = sig[:64] + (sig[64] + 27).to_bytes(1, byteorder='big') + logg.debug('message is:\n{}\nsigned by {}'.format(enc, self.accounts[0])) + + nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) + c = TxFactory(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) + enc = ABIContractEncoder() + enc.method('executeOfflineRequest') + enc.typ(ABIContractType.BYTES) + enc.typ(ABIContractType.BYTES) + enc.typ(ABIContractType.UINT8) + enc.bytes(msg_data.hex()) + enc.bytes(sig.hex()) + enc.uintn(1, 8) + data = enc.get() + tx = c.template(self.accounts[0], self.address, use_nonce=True) + tx = c.set_code(tx, data) + (tx_hash, o) = c.finalize(tx, TxFormat.JSONRPC) + self.rpc.do(o) + o = receipt(tx_hash) + r = self.rpc.do(o) + self.assertEqual(r['status'], 1) + + if __name__ == '__main__': unittest.main() diff --git a/solidity/Offline.sol b/solidity/Offline.sol @@ -7,21 +7,64 @@ import './OfflineBase.sol'; contract OfflineRubber is Offline { struct Instruction { - bytes12 nonce; - address beneficiary; bytes32 domain; uint256 value; + address beneficiary; } address public contractOwner; uint256 public executedTimes; - constructor() { + bytes32 public eip712DomainSeparator; + bytes32 constant public eip712TypeHash = keccak256("Instruction(bytes32 domain,uint256 value,address beneficiary)"); + + struct EIP712Domain { + string name; + string version; + uint256 chainId; + address verifyingContract; + bytes32 salt; + } + + bytes32 constant eip712DomainTypehash = keccak256( + "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)" + ); + + function hash(EIP712Domain memory eip712Domain) internal pure returns (bytes32) { + return keccak256(abi.encode( + eip712DomainTypehash, + keccak256(bytes(eip712Domain.name)), + keccak256(bytes(eip712Domain.version)), + eip712Domain.chainId, + eip712Domain.verifyingContract, + eip712Domain.salt + )); + } + + constructor(uint256 chainId) { contractOwner = msg.sender; + eip712DomainSeparator = hash(EIP712Domain({ + name: "Offline signing test", + version: '0', + chainId: chainId, + verifyingContract: address(this), + //salt: blockhash(block.number) + salt: bytes32(0x00) + })); + } + + function toBytes(Instruction memory _instruction) public pure returns(bytes memory) { + return abi.encode(_instruction); } - function executeOfflineRequest(bytes memory _data, bytes memory _signature) public override returns(uint256) { - require(verifyOfflineRequest(_data, _signature), 'ERR_UNVERIFIED'); + function executeOfflineRequest(bytes memory _data, bytes memory _signature, uint8 _version) public override returns(uint256) { + if (_version == 0) { + require(verifyOfflineRequest(_data, _signature), 'ERR_UNVERIFIED'); + } else if (_version == 1) { + require(verifyOfflineRequest(_data, _signature, eip712DomainSeparator, eip712TypeHash), 'ERR_UNVERIFIED'); + } else { + revert('UNKNOWN VERSION'); + } executedTimes++; return 0; } @@ -39,36 +82,36 @@ contract OfflineRubber is Offline { return contractOwner == _signer; } - function splitData(bytes memory _data) private pure returns(Instruction memory instruction) { - bytes memory nonce; - bytes memory beneficiary; - bytes memory domain; - bytes memory value; - - if(_data.length != 84) { - return instruction; - } - - nonce = new bytes(12); - beneficiary = new bytes(20); - value = new bytes(32); - domain = new bytes(32); - - for (uint256 i; i < nonce.length; i++) { - nonce[i] = _data[i]; - } - for (uint256 i; i < beneficiary.length; i++) { - beneficiary[i] = _data[i+12]; - } - for (uint256 i; i < 32; i++) { - domain[i] = _data[i + 32]; - } - for (uint256 i; i < 32; i++) { - value[i] = _data[i + 64]; - } - instruction.nonce = bytes12(nonce); - instruction.beneficiary = address(bytes20(beneficiary)); - instruction.domain = bytes32(domain); - instruction.value = uint256(bytes32(value)); - } +// function splitData(bytes memory _data) private pure returns(Instruction memory instruction) { +// bytes memory nonce; +// bytes memory beneficiary; +// bytes memory domain; +// bytes memory value; +// +// if(_data.length != 84) { +// return instruction; +// } +// +// nonce = new bytes(12); +// beneficiary = new bytes(20); +// value = new bytes(32); +// domain = new bytes(32); +// +// for (uint256 i; i < nonce.length; i++) { +// nonce[i] = _data[i]; +// } +// for (uint256 i; i < beneficiary.length; i++) { +// beneficiary[i] = _data[i+12]; +// } +// for (uint256 i; i < 32; i++) { +// domain[i] = _data[i + 32]; +// } +// for (uint256 i; i < 32; i++) { +// value[i] = _data[i + 64]; +// } +// instruction.nonce = bytes12(nonce); +// instruction.beneficiary = address(bytes20(beneficiary)); +// instruction.domain = bytes32(domain); +// instruction.value = uint256(bytes32(value)); +// } } diff --git a/solidity/OfflineBase.sol b/solidity/OfflineBase.sol @@ -4,10 +4,41 @@ pragma solidity ^0.8.0; // Some methods are copied under other licenses, please see code comments for details abstract contract Offline { - function executeOfflineRequest(bytes memory _data, bytes memory _signature) public virtual returns(uint256); + function executeOfflineRequest(bytes memory _data, bytes memory _signature, uint8 _version) public virtual returns(uint256); function isOfflineValid(address _validator, bytes memory _data) external virtual view returns(bool); + function verifyOfflineRequest(bytes memory _data, bytes memory _signature, bytes32 _domainSeparator, bytes32 _typeHash) public view returns(bool) { + bytes memory message; + bytes32 messageDigest; + bytes memory dataDigest; + address _owner; + + dataDigest = new bytes(32 + _data.length); + for (uint256 i = 0; i < 32; i++) { + dataDigest[i] = _typeHash[i]; + } + for (uint256 i = 0; i < _data.length; i++) { + dataDigest[i+32] = _data[i]; + } + messageDigest = keccak256(dataDigest); + + message = new bytes(2 + 32 + 32); + message[0] = 0x19; + message[1] = 0x01; + for (uint256 i = 0; i < 32; i++) { + message[i+2] = _domainSeparator[i]; + } + for (uint256 i = 0; i < 32; i++) { + message[i+34] = messageDigest[i]; + } + + messageDigest = keccak256(message); + _owner = recoverSigner(messageDigest, _signature); + + return this.isOfflineValid(_owner, _data); + } + function verifyOfflineRequest(bytes memory _data, bytes memory _signature) public view returns(bool) { bytes memory message; bytes32 messageDigest;