erc20-transfer-authorization

Simple approval escrow for ERC20 spending
Log | Files | Refs

commit 2be890e96b69abe2420ed36b1d9a119827dac96a
parent 7cda7d09a91e173d2210b1a9a86bc54b0a66513c
Author: lash <dev@holbrook.no>
Date:   Thu,  8 Dec 2022 18:54:33 +0000

Add basic quorum test

Diffstat:
Mpython/erc20_transfer_authorization/data/ERC20TransferAuthorization.bin | 4++--
Mpython/erc20_transfer_authorization/data/ERC20TransferAuthorization.json | 2+-
Mpython/erc20_transfer_authorization/transfer_authorization.py | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mpython/requirements.txt | 2+-
Mpython/setup.cfg | 2+-
Mpython/tests/test_app.py | 36+++++++++++++++++++++++++++++-------
Mpython/tests/test_quorum.py | 352+++++++++++++++----------------------------------------------------------------
Dpython/tests/test_transfer.py | 47-----------------------------------------------
Msolidity/ERC20TransferAuthorization.sol | 19++++++++++++-------
9 files changed, 233 insertions(+), 356 deletions(-)

diff --git a/python/erc20_transfer_authorization/data/ERC20TransferAuthorization.bin b/python/erc20_transfer_authorization/data/ERC20TransferAuthorization.bin @@ -1 +1 @@ -60806040523480156200001157600080fd5b5033600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600260146101000a81548163ffffffff021916908363ffffffff1602179055506001600260186101000a81548163ffffffff021916908363ffffffff160217905550620000b133620000d6640100000000026401000000009004565b50620000cf60016000620002ef640100000000026401000000009004565b50620005e7565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146200016b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620001629062000481565b60405180910390fd5b60001515600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615151462000201576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620001f890620004f3565b60405180910390fd5b6001600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506003600881819054906101000a900463ffffffff16809291906200027d9062000554565b91906101000a81548163ffffffff021916908363ffffffff160217905550507f47d1c22a25bb3a5d4e481b9b1e6944c2eade3181a0a20b495ed61d35b5323f2482604051620002cd9190620005ca565b60405180910390a1600360089054906101000a900463ffffffff169050919050565b6000600360089054906101000a900463ffffffff1663ffffffff168363ffffffff1611156200031d57600080fd5b60008363ffffffff16116200033157600080fd5b600360089054906101000a900463ffffffff1663ffffffff168263ffffffff1611156200035d57600080fd5b82600360006101000a81548163ffffffff021916908363ffffffff16021790555081600360046101000a81548163ffffffff021916908363ffffffff160217905550600360089054906101000a900463ffffffff1663ffffffff16600360049054906101000a900463ffffffff1663ffffffff16600360009054906101000a900463ffffffff1663ffffffff167fe77378573ac0f86c7fa8dd116b1fa17cf9c328a09a0c56a2c42d786103ac5bc360405160405180910390a46001905092915050565b600082825260208201905092915050565b7f4552525f41434345535300000000000000000000000000000000000000000000600082015250565b600062000469600a8362000420565b9150620004768262000431565b602082019050919050565b600060208201905081810360008301526200049c816200045a565b9050919050565b7f4552525f4e4f54464f554e440000000000000000000000000000000000000000600082015250565b6000620004db600c8362000420565b9150620004e882620004a3565b602082019050919050565b600060208201905081810360008301526200050e81620004cc565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff82169050919050565b6000620005618262000544565b915063ffffffff82036200057a576200057962000515565b5b600182019050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620005b28262000585565b9050919050565b620005c481620005a5565b82525050565b6000602082019050620005e16000830184620005b9565b92915050565b6125d680620005f76000396000f3fe608060405234801561001057600080fd5b506004361061013e576000357c010000000000000000000000000000000000000000000000000000000090048063614f427f116100ca5780637f4dbec11161008e5780637f4dbec11461037e5780638da5cb5b146103ae578063eb12d61e146103cc578063ed71262a146103fc578063fdd33d681461042c5761013e565b8063614f427f146102b2578063655c0131146102d0578063669cd53b14610300578063736c0d5b146103305780637ca548c6146103605761013e565b80630e316ab7116101115780630e316ab7146101e657806310858c67146102165780631703a01814610246578063476ce3ad1461026457806357ec347a146102945761013e565b806306661abd1461014357806308ae6377146101615780630ab469b01461017f5780630ac94000146101b6575b600080fd5b61014b61045c565b6040516101589190611e02565b60405180910390f35b610169610472565b6040516101769190611e02565b60405180910390f35b61019960048036038101906101949190611e4e565b6104d2565b6040516101ad989796959493929190611ef1565b60405180910390f35b6101d060048036038101906101cb9190611e4e565b6105b7565b6040516101dd9190611f8a565b60405180910390f35b61020060048036038101906101fb9190611fd1565b610902565b60405161020d9190611e02565b60405180910390f35b610230600480360381019061022b9190611e4e565b610bbe565b60405161023d9190611e02565b60405180910390f35b61024e610ca0565b60405161025b9190611e02565b60405180910390f35b61027e60048036038101906102799190611e4e565b610cb6565b60405161028b9190611e02565b60405180910390f35b61029c610f40565b6040516102a99190611e02565b60405180910390f35b6102ba610f66565b6040516102c79190611e02565b60405180910390f35b6102ea60048036038101906102e59190611ffe565b610f7c565b6040516102f7919061205a565b60405180910390f35b61031a60048036038101906103159190612075565b610fab565b6040516103279190611f8a565b60405180910390f35b61034a60048036038101906103459190611fd1565b6110d9565b6040516103579190611f8a565b60405180910390f35b6103686110f9565b6040516103759190611e02565b60405180910390f35b61039860048036038101906103939190611e4e565b61110f565b6040516103a59190611e02565b60405180910390f35b6103b66113b8565b6040516103c391906120b5565b60405180910390f35b6103e660048036038101906103e19190611fd1565b6113de565b6040516103f39190611e02565b60405180910390f35b610416600480360381019061041191906120fc565b6115ed565b6040516104239190611e02565b60405180910390f35b61044660048036038101906104419190611e4e565b6118ec565b6040516104539190611f8a565b60405180910390f35b6002601c9054906101000a900463ffffffff1681565b600080600260189054906101000a900463ffffffff16600260149054906101000a900463ffffffff166104a59190612192565b63ffffffff16036104b957600090506104cf565b600260189054906101000a900463ffffffff1690505b90565b60016020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030160149054906101000a900463ffffffff16908060030160189054906101000a900463ffffffff169080600301601c9054906101000a900463ffffffff16908060040160009054906101000a900460ff16905088565b600080600160008463ffffffff1663ffffffff168152602001908152602001600020905060008160030160149054906101000a900463ffffffff1663ffffffff1611610638576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161062f90612227565b60405180910390fd5b60038160040160009054906101000a900460ff1660ff161461068f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161068690612293565b60405180910390fd5b6106ac8160030160149054906101000a900463ffffffff16611c8f565b5060088160040160008282829054906101000a900460ff161792506101000a81548160ff021916908360ff1602179055506000808260030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168360010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168460020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16856000015460405160240161077c939291906122b3565b6040516020818303038152906040527f23b872dd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610806919061235b565b6000604051808303816000865af19150503d8060008114610843576040519150601f19603f3d011682016040523d82523d6000602084013e610848565b606091505b5091509150811561088f577fa80d5e3445b11533e6c584c506299aa14168f2ad1fe65b0266e7d622c5461c30856040516108829190611e02565b60405180910390a16108f7565b60108360040160008282829054906101000a900460ff161792506101000a81548160ff021916908360ff1602179055507f8f15e24c8a8ecaa6b067f0cd2c220532e6496f53b2ac3263129d1496cb6f192e856040516108ee9190611e02565b60405180910390a15b819350505050919050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610994576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161098b906123be565b60405180910390fd5b60011515600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16151514610a27576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a1e9061242a565b60405180910390fd5b600360009054906101000a900463ffffffff1663ffffffff16600360089054906101000a900463ffffffff1663ffffffff16118015610a955750600360049054906101000a900463ffffffff1663ffffffff16600360089054906101000a900463ffffffff1663ffffffff16115b610ad4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610acb90612496565b60405180910390fd5b6000600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506003600881819054906101000a900463ffffffff1680929190610b4e906124b6565b91906101000a81548163ffffffff021916908363ffffffff160217905550507f3525e22824a8a7df2c9a6029941c824cf95b6447f1e13d5128fd3826d35afe8b82604051610b9c91906120b5565b60405180910390a1600360089054906101000a900463ffffffff169050919050565b6000806000600260189054906101000a900463ffffffff1690505b600260149054906101000a900463ffffffff1663ffffffff168163ffffffff161015610c94576000600160008363ffffffff1663ffffffff168152602001908152602001600020905060008160040160009054906101000a900460ff1660ff161115610c80578463ffffffff168363ffffffff1603610c71578060030160149054906101000a900463ffffffff169350505050610c9b565b8280610c7c906124df565b9350505b508080610c8c906124df565b915050610bd9565b5060009150505b919050565b600360009054906101000a900463ffffffff1681565b6000600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610d44576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d3b906123be565b60405180910390fd5b60008060008463ffffffff1663ffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460000b60000b14610df2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610de990612557565b60405180910390fd5b6000600160008463ffffffff1663ffffffff168152602001908152602001600020905060018160040160009054906101000a900460ff1660ff1614610e3657600080fd5b60016000808360030160149054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908360000b60ff16021790555080600301601881819054906101000a900463ffffffff1680929190610ee6906124df565b91906101000a81548163ffffffff021916908363ffffffff16021790555050610f228160030160149054906101000a900463ffffffff166118ec565b508060030160189054906101000a900463ffffffff16915050919050565b60006001600260149054906101000a900463ffffffff16610f619190612192565b905090565b600360049054906101000a900463ffffffff1681565b60006020528160005260406000206020528060005260406000206000915091509054906101000a900460000b81565b6000600360089054906101000a900463ffffffff1663ffffffff168363ffffffff161115610fd857600080fd5b60008363ffffffff1611610feb57600080fd5b600360089054906101000a900463ffffffff1663ffffffff168263ffffffff16111561101657600080fd5b82600360006101000a81548163ffffffff021916908363ffffffff16021790555081600360046101000a81548163ffffffff021916908363ffffffff160217905550600360089054906101000a900463ffffffff1663ffffffff16600360049054906101000a900463ffffffff1663ffffffff16600360009054906101000a900463ffffffff1663ffffffff167fe77378573ac0f86c7fa8dd116b1fa17cf9c328a09a0c56a2c42d786103ac5bc360405160405180910390a46001905092915050565b60046020528060005260406000206000915054906101000a900460ff1681565b600360089054906101000a900463ffffffff1681565b6000600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1661119d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611194906123be565b60405180910390fd5b60008060008463ffffffff1663ffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460000b60000b1461124b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161124290612557565b60405180910390fd5b6000600160008463ffffffff1663ffffffff168152602001908152602001600020905060018160040160009054906101000a900460ff1660ff161461128f57600080fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000808360030160149054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908360000b60ff16021790555080600301601c81819054906101000a900463ffffffff168092919061135e906124df565b91906101000a81548163ffffffff021916908363ffffffff1602179055505061139a8160030160149054906101000a900463ffffffff166118ec565b5080600301601c9054906101000a900463ffffffff16915050919050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611470576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611467906123be565b60405180910390fd5b60001515600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16151514611503576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114fa9061242a565b60405180910390fd5b6001600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506003600881819054906101000a900463ffffffff168092919061157d906124df565b91906101000a81548163ffffffff021916908363ffffffff160217905550507f47d1c22a25bb3a5d4e481b9b1e6944c2eade3181a0a20b495ed61d35b5323f24826040516115cb91906120b5565b60405180910390a1600360089054906101000a900463ffffffff169050919050565b60008060016000600260149054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020019081526020016000209050600260149054906101000a900463ffffffff168160030160146101000a81548163ffffffff021916908363ffffffff160217905550848160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550858160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550838160030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082816000018190555060018160040160006101000a81548160ff021916908360ff1602179055506002601c81819054906101000a900463ffffffff168092919061176a906124df565b91906101000a81548163ffffffff021916908363ffffffff160217905550506002601481819054906101000a900463ffffffff16809291906117ab906124df565b91906101000a81548163ffffffff021916908363ffffffff160217905550508060030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168260010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f3ba7a259b57ae3d653287762394374c856528591f691ecd6494021fdcea00f2484600001548560030160149054906101000a900463ffffffff166040516118c4929190612577565b60405180910390a48060030160149054906101000a900463ffffffff16915050949350505050565b6000806000600160008563ffffffff1663ffffffff168152602001908152602001600020905060018160040160009054906101000a900460ff1660ff161015611939578192505050611c8a565b600360009054906101000a900463ffffffff1663ffffffff168160030160189054906101000a900463ffffffff1663ffffffff1610611a285760028160040160008282829054906101000a900460ff161792506101000a81548160ff021916908360ff16021790555080600301601c9054906101000a900463ffffffff1663ffffffff168160030160189054906101000a900463ffffffff1663ffffffff168260030160149054906101000a900463ffffffff1663ffffffff167f7a17acca3819c1012204b2d019c0ee13bb7e5cf151111030329219582ba83f3160405160405180910390a460019150611c84565b6000600360049054906101000a900463ffffffff1663ffffffff16118015611a825750600360049054906101000a900463ffffffff1663ffffffff1681600301601c9054906101000a900463ffffffff1663ffffffff1610155b15611b5b5760048160040160008282829054906101000a900460ff161792506101000a81548160ff021916908360ff160217905550611ad48160030160149054906101000a900463ffffffff16611c8f565b5080600301601c9054906101000a900463ffffffff1663ffffffff168160030160189054906101000a900463ffffffff1663ffffffff168260030160149054906101000a900463ffffffff1663ffffffff167f4bdd2d0e6caefafbf833eda0d32f2dcb0e7a621e3e7b87b2a17c12090edbc0d660405160405180910390a460019150611c83565b600360009054906101000a900463ffffffff1663ffffffff1681600301601c9054906101000a900463ffffffff16600360089054906101000a900463ffffffff16611ba69190612192565b63ffffffff161015611c825760048160040160008282829054906101000a900460ff161792506101000a81548160ff021916908360ff160217905550611bff8160030160149054906101000a900463ffffffff16611c8f565b5080600301601c9054906101000a900463ffffffff1663ffffffff168160030160189054906101000a900463ffffffff1663ffffffff168260030160149054906101000a900463ffffffff1663ffffffff167f3c478de516aa199022ddcd594a6e3b7f03a3e23bfcafd6143adceb687a8e38ea60405160405180910390a4600191505b5b5b81925050505b919050565b60006002601c81819054906101000a900463ffffffff1680929190611cb3906124b6565b91906101000a81548163ffffffff021916908363ffffffff1602179055505060006002601c9054906101000a900463ffffffff1663ffffffff161115611d9557600260189054906101000a900463ffffffff1663ffffffff168263ffffffff1603611d90576000611d246000610bbe565b905060008163ffffffff1603611d6c57600260149054906101000a900463ffffffff16600260186101000a81548163ffffffff021916908363ffffffff160217905550611d8e565b80600260186101000a81548163ffffffff021916908363ffffffff1602179055505b505b611dc9565b600260149054906101000a900463ffffffff16600260186101000a81548163ffffffff021916908363ffffffff1602179055505b600260189054906101000a900463ffffffff169050919050565b600063ffffffff82169050919050565b611dfc81611de3565b82525050565b6000602082019050611e176000830184611df3565b92915050565b600080fd5b611e2b81611de3565b8114611e3657600080fd5b50565b600081359050611e4881611e22565b92915050565b600060208284031215611e6457611e63611e1d565b5b6000611e7284828501611e39565b91505092915050565b6000819050919050565b611e8e81611e7b565b82525050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000611ebf82611e94565b9050919050565b611ecf81611eb4565b82525050565b600060ff82169050919050565b611eeb81611ed5565b82525050565b600061010082019050611f07600083018b611e85565b611f14602083018a611ec6565b611f216040830189611ec6565b611f2e6060830188611ec6565b611f3b6080830187611df3565b611f4860a0830186611df3565b611f5560c0830185611df3565b611f6260e0830184611ee2565b9998505050505050505050565b60008115159050919050565b611f8481611f6f565b82525050565b6000602082019050611f9f6000830184611f7b565b92915050565b611fae81611eb4565b8114611fb957600080fd5b50565b600081359050611fcb81611fa5565b92915050565b600060208284031215611fe757611fe6611e1d565b5b6000611ff584828501611fbc565b91505092915050565b6000806040838503121561201557612014611e1d565b5b600061202385828601611e39565b925050602061203485828601611fbc565b9150509250929050565b60008160000b9050919050565b6120548161203e565b82525050565b600060208201905061206f600083018461204b565b92915050565b6000806040838503121561208c5761208b611e1d565b5b600061209a85828601611e39565b92505060206120ab85828601611e39565b9150509250929050565b60006020820190506120ca6000830184611ec6565b92915050565b6120d981611e7b565b81146120e457600080fd5b50565b6000813590506120f6816120d0565b92915050565b6000806000806080858703121561211657612115611e1d565b5b600061212487828801611fbc565b945050602061213587828801611fbc565b935050604061214687828801611fbc565b9250506060612157878288016120e7565b91505092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061219d82611de3565b91506121a883611de3565b9250828203905063ffffffff8111156121c4576121c3612163565b5b92915050565b600082825260208201905092915050565b7f4552525f494e56414c49445f5245515545535400000000000000000000000000600082015250565b60006122116013836121ca565b915061221c826121db565b602082019050919050565b6000602082019050818103600083015261224081612204565b9050919050565b7f4552525f4e4f545f454e444f5253454400000000000000000000000000000000600082015250565b600061227d6010836121ca565b915061228882612247565b602082019050919050565b600060208201905081810360008301526122ac81612270565b9050919050565b60006060820190506122c86000830186611ec6565b6122d56020830185611ec6565b6122e26040830184611e85565b949350505050565b600081519050919050565b600081905092915050565b60005b8381101561231e578082015181840152602081019050612303565b60008484015250505050565b6000612335826122ea565b61233f81856122f5565b935061234f818560208601612300565b80840191505092915050565b6000612367828461232a565b915081905092915050565b7f4552525f41434345535300000000000000000000000000000000000000000000600082015250565b60006123a8600a836121ca565b91506123b382612372565b602082019050919050565b600060208201905081810360008301526123d78161239b565b9050919050565b7f4552525f4e4f54464f554e440000000000000000000000000000000000000000600082015250565b6000612414600c836121ca565b915061241f826123de565b602082019050919050565b6000602082019050818103600083015261244381612407565b9050919050565b7f4552525f5245445543455f5448524553484f4c445f4649525354000000000000600082015250565b6000612480601a836121ca565b915061248b8261244a565b602082019050919050565b600060208201905081810360008301526124af81612473565b9050919050565b60006124c182611de3565b9150600082036124d4576124d3612163565b5b600182039050919050565b60006124ea82611de3565b915063ffffffff8203612500576124ff612163565b5b600182019050919050565b7f4552525f414c5245414459564f54454400000000000000000000000000000000600082015250565b60006125416010836121ca565b915061254c8261250b565b602082019050919050565b6000602082019050818103600083015261257081612534565b9050919050565b600060408201905061258c6000830185611e85565b6125996020830184611df3565b939250505056fea2646970667358221220c7f87a03c6ca3c1220eb00c3d0852eaa8b387cd2ef01e44bdaa8ea969e9fb9c464736f6c63430008110033 -\ No newline at end of file +60806040523480156200001157600080fd5b5033600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600260146101000a81548163ffffffff021916908363ffffffff1602179055506001600260186101000a81548163ffffffff021916908363ffffffff160217905550620000b133620000d6640100000000026401000000009004565b50620000cf60016000620002ef640100000000026401000000009004565b50620005e7565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146200016b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620001629062000481565b60405180910390fd5b60001515600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615151462000201576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620001f890620004f3565b60405180910390fd5b6001600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506003600881819054906101000a900463ffffffff16809291906200027d9062000554565b91906101000a81548163ffffffff021916908363ffffffff160217905550507f6ff3aa2ea7b53070f6d9d07a445d338d89e8edef44250ffa8be19f53910d4a2e82604051620002cd9190620005ca565b60405180910390a1600360089054906101000a900463ffffffff169050919050565b6000600360089054906101000a900463ffffffff1663ffffffff168363ffffffff1611156200031d57600080fd5b60008363ffffffff16116200033157600080fd5b600360089054906101000a900463ffffffff1663ffffffff168263ffffffff1611156200035d57600080fd5b82600360006101000a81548163ffffffff021916908363ffffffff16021790555081600360046101000a81548163ffffffff021916908363ffffffff160217905550600360089054906101000a900463ffffffff1663ffffffff16600360049054906101000a900463ffffffff1663ffffffff16600360009054906101000a900463ffffffff1663ffffffff167fe77378573ac0f86c7fa8dd116b1fa17cf9c328a09a0c56a2c42d786103ac5bc360405160405180910390a46001905092915050565b600082825260208201905092915050565b7f4552525f41434345535300000000000000000000000000000000000000000000600082015250565b600062000469600a8362000420565b9150620004768262000431565b602082019050919050565b600060208201905081810360008301526200049c816200045a565b9050919050565b7f4552525f4e4f54464f554e440000000000000000000000000000000000000000600082015250565b6000620004db600c8362000420565b9150620004e882620004a3565b602082019050919050565b600060208201905081810360008301526200050e81620004cc565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff82169050919050565b6000620005618262000544565b915063ffffffff82036200057a576200057962000515565b5b600182019050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620005b28262000585565b9050919050565b620005c481620005a5565b82525050565b6000602082019050620005e16000830184620005b9565b92915050565b61270e80620005f76000396000f3fe608060405234801561001057600080fd5b5060043610610154576000357c010000000000000000000000000000000000000000000000000000000090048063614f427f116100d55780637ca548c6116100995780637ca548c6146103d65780637f4dbec1146103f45780638da5cb5b14610424578063da2824a814610442578063ed71262a14610472578063fdd33d68146104a257610154565b8063614f427f146102f8578063655c013114610316578063669cd53b1461034657806366a5267214610376578063736c0d5b146103a657610154565b80631703a0181161011c5780631703a0181461022c5780632b29ba231461024a578063476ce3ad1461027a5780635356dddc146102aa57806357ec347a146102da57610154565b806306661abd1461015957806308ae6377146101775780630ab469b0146101955780630ac94000146101cc57806310858c67146101fc575b600080fd5b6101616104d2565b60405161016e9190611f0d565b60405180910390f35b61017f6104e8565b60405161018c9190611f0d565b60405180910390f35b6101af60048036038101906101aa9190611f59565b610548565b6040516101c3989796959493929190611ffc565b60405180910390f35b6101e660048036038101906101e19190611f59565b61062d565b6040516101f39190612095565b60405180910390f35b61021660048036038101906102119190611f59565b610978565b6040516102239190611f0d565b60405180910390f35b610234610a5a565b6040516102419190611f0d565b60405180910390f35b610264600480360381019061025f91906120dc565b610a70565b6040516102719190612095565b60405180910390f35b610294600480360381019061028f9190611f59565b610ac6565b6040516102a19190611f0d565b60405180910390f35b6102c460048036038101906102bf91906120dc565b610d50565b6040516102d19190611f0d565b60405180910390f35b6102e261100c565b6040516102ef9190611f0d565b60405180910390f35b610300611032565b60405161030d9190611f0d565b60405180910390f35b610330600480360381019061032b9190612109565b611048565b60405161033d9190612165565b60405180910390f35b610360600480360381019061035b9190612180565b611077565b60405161036d9190612095565b60405180910390f35b610390600480360381019061038b91906121ec565b6111a5565b60405161039d9190612219565b60405180910390f35b6103c060048036038101906103bb91906120dc565b6111e4565b6040516103cd9190612095565b60405180910390f35b6103de611204565b6040516103eb9190611f0d565b60405180910390f35b61040e60048036038101906104099190611f59565b61121a565b60405161041b9190611f0d565b60405180910390f35b61042c6114c3565b6040516104399190612219565b60405180910390f35b61045c600480360381019061045791906120dc565b6114e9565b6040516104699190611f0d565b60405180910390f35b61048c60048036038101906104879190612234565b6116f8565b6040516104999190611f0d565b60405180910390f35b6104bc60048036038101906104b79190611f59565b6119f7565b6040516104c99190612095565b60405180910390f35b6002601c9054906101000a900463ffffffff1681565b600080600260189054906101000a900463ffffffff16600260149054906101000a900463ffffffff1661051b91906122ca565b63ffffffff160361052f5760009050610545565b600260189054906101000a900463ffffffff1690505b90565b60016020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030160149054906101000a900463ffffffff16908060030160189054906101000a900463ffffffff169080600301601c9054906101000a900463ffffffff16908060040160009054906101000a900460ff16905088565b600080600160008463ffffffff1663ffffffff168152602001908152602001600020905060008160030160149054906101000a900463ffffffff1663ffffffff16116106ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106a59061235f565b60405180910390fd5b60038160040160009054906101000a900460ff1660ff1614610705576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106fc906123cb565b60405180910390fd5b6107228160030160149054906101000a900463ffffffff16611d9a565b5060088160040160008282829054906101000a900460ff161792506101000a81548160ff021916908360ff1602179055506000808260030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168360010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168460020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1685600001546040516024016107f2939291906123eb565b6040516020818303038152906040527f23b872dd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161087c9190612493565b6000604051808303816000865af19150503d80600081146108b9576040519150601f19603f3d011682016040523d82523d6000602084013e6108be565b606091505b50915091508115610905577fa80d5e3445b11533e6c584c506299aa14168f2ad1fe65b0266e7d622c5461c30856040516108f89190611f0d565b60405180910390a161096d565b60108360040160008282829054906101000a900460ff161792506101000a81548160ff021916908360ff1602179055507f8f15e24c8a8ecaa6b067f0cd2c220532e6496f53b2ac3263129d1496cb6f192e856040516109649190611f0d565b60405180910390a15b819350505050919050565b6000806000600260189054906101000a900463ffffffff1690505b600260149054906101000a900463ffffffff1663ffffffff168163ffffffff161015610a4e576000600160008363ffffffff1663ffffffff168152602001908152602001600020905060008160040160009054906101000a900460ff1660ff161115610a3a578463ffffffff168363ffffffff1603610a2b578060030160149054906101000a900463ffffffff169350505050610a55565b8280610a36906124aa565b9350505b508080610a46906124aa565b915050610993565b5060009150505b919050565b600360009054906101000a900463ffffffff1681565b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b6000600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610b54576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b4b90612522565b60405180910390fd5b60008060008463ffffffff1663ffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460000b60000b14610c02576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bf99061258e565b60405180910390fd5b6000600160008463ffffffff1663ffffffff168152602001908152602001600020905060018160040160009054906101000a900460ff1660ff1614610c4657600080fd5b60016000808360030160149054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908360000b60ff16021790555080600301601881819054906101000a900463ffffffff1680929190610cf6906124aa565b91906101000a81548163ffffffff021916908363ffffffff16021790555050610d328160030160149054906101000a900463ffffffff166119f7565b508060030160189054906101000a900463ffffffff16915050919050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610de2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dd990612522565b60405180910390fd5b60011515600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16151514610e75576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e6c906125fa565b60405180910390fd5b600360009054906101000a900463ffffffff1663ffffffff16600360089054906101000a900463ffffffff1663ffffffff16118015610ee35750600360049054906101000a900463ffffffff1663ffffffff16600360089054906101000a900463ffffffff1663ffffffff16115b610f22576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f1990612666565b60405180910390fd5b6000600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506003600881819054906101000a900463ffffffff1680929190610f9c90612686565b91906101000a81548163ffffffff021916908363ffffffff160217905550507f86e5bbceda94081c32220d685f37cc4e3ea7bb0be2dfbf0cb703579505a5390e82604051610fea9190612219565b60405180910390a1600360089054906101000a900463ffffffff169050919050565b60006001600260149054906101000a900463ffffffff1661102d91906122ca565b905090565b600360049054906101000a900463ffffffff1681565b60006020528160005260406000206020528060005260406000206000915091509054906101000a900460000b81565b6000600360089054906101000a900463ffffffff1663ffffffff168363ffffffff1611156110a457600080fd5b60008363ffffffff16116110b757600080fd5b600360089054906101000a900463ffffffff1663ffffffff168263ffffffff1611156110e257600080fd5b82600360006101000a81548163ffffffff021916908363ffffffff16021790555081600360046101000a81548163ffffffff021916908363ffffffff160217905550600360089054906101000a900463ffffffff1663ffffffff16600360049054906101000a900463ffffffff1663ffffffff16600360009054906101000a900463ffffffff1663ffffffff167fe77378573ac0f86c7fa8dd116b1fa17cf9c328a09a0c56a2c42d786103ac5bc360405160405180910390a46001905092915050565b600581815481106111b557600080fd5b906000526020600020016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60046020528060005260406000206000915054906101000a900460ff1681565b600360089054906101000a900463ffffffff1681565b6000600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166112a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161129f90612522565b60405180910390fd5b60008060008463ffffffff1663ffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460000b60000b14611356576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161134d9061258e565b60405180910390fd5b6000600160008463ffffffff1663ffffffff168152602001908152602001600020905060018160040160009054906101000a900460ff1660ff161461139a57600080fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000808360030160149054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908360000b60ff16021790555080600301601c81819054906101000a900463ffffffff1680929190611469906124aa565b91906101000a81548163ffffffff021916908363ffffffff160217905550506114a58160030160149054906101000a900463ffffffff166119f7565b5080600301601c9054906101000a900463ffffffff16915050919050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461157b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161157290612522565b60405180910390fd5b60001515600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615151461160e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611605906125fa565b60405180910390fd5b6001600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506003600881819054906101000a900463ffffffff1680929190611688906124aa565b91906101000a81548163ffffffff021916908363ffffffff160217905550507f6ff3aa2ea7b53070f6d9d07a445d338d89e8edef44250ffa8be19f53910d4a2e826040516116d69190612219565b60405180910390a1600360089054906101000a900463ffffffff169050919050565b60008060016000600260149054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020019081526020016000209050600260149054906101000a900463ffffffff168160030160146101000a81548163ffffffff021916908363ffffffff160217905550848160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550858160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550838160030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082816000018190555060018160040160006101000a81548160ff021916908360ff1602179055506002601c81819054906101000a900463ffffffff1680929190611875906124aa565b91906101000a81548163ffffffff021916908363ffffffff160217905550506002601481819054906101000a900463ffffffff16809291906118b6906124aa565b91906101000a81548163ffffffff021916908363ffffffff160217905550508060030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168260010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f3ba7a259b57ae3d653287762394374c856528591f691ecd6494021fdcea00f2484600001548560030160149054906101000a900463ffffffff166040516119cf9291906126af565b60405180910390a48060030160149054906101000a900463ffffffff16915050949350505050565b6000806000600160008563ffffffff1663ffffffff168152602001908152602001600020905060018160040160009054906101000a900460ff1660ff161015611a44578192505050611d95565b600360009054906101000a900463ffffffff1663ffffffff168160030160189054906101000a900463ffffffff1663ffffffff1610611b335760028160040160008282829054906101000a900460ff161792506101000a81548160ff021916908360ff16021790555080600301601c9054906101000a900463ffffffff1663ffffffff168160030160189054906101000a900463ffffffff1663ffffffff168260030160149054906101000a900463ffffffff1663ffffffff167f7a17acca3819c1012204b2d019c0ee13bb7e5cf151111030329219582ba83f3160405160405180910390a460019150611d8f565b6000600360049054906101000a900463ffffffff1663ffffffff16118015611b8d5750600360049054906101000a900463ffffffff1663ffffffff1681600301601c9054906101000a900463ffffffff1663ffffffff1610155b15611c665760048160040160008282829054906101000a900460ff161792506101000a81548160ff021916908360ff160217905550611bdf8160030160149054906101000a900463ffffffff16611d9a565b5080600301601c9054906101000a900463ffffffff1663ffffffff168160030160189054906101000a900463ffffffff1663ffffffff168260030160149054906101000a900463ffffffff1663ffffffff167f4bdd2d0e6caefafbf833eda0d32f2dcb0e7a621e3e7b87b2a17c12090edbc0d660405160405180910390a460019150611d8e565b600360009054906101000a900463ffffffff1663ffffffff1681600301601c9054906101000a900463ffffffff16600360089054906101000a900463ffffffff16611cb191906122ca565b63ffffffff161015611d8d5760048160040160008282829054906101000a900460ff161792506101000a81548160ff021916908360ff160217905550611d0a8160030160149054906101000a900463ffffffff16611d9a565b5080600301601c9054906101000a900463ffffffff1663ffffffff168160030160189054906101000a900463ffffffff1663ffffffff168260030160149054906101000a900463ffffffff1663ffffffff167f3c478de516aa199022ddcd594a6e3b7f03a3e23bfcafd6143adceb687a8e38ea60405160405180910390a4600191505b5b5b81925050505b919050565b60006002601c81819054906101000a900463ffffffff1680929190611dbe90612686565b91906101000a81548163ffffffff021916908363ffffffff1602179055505060006002601c9054906101000a900463ffffffff1663ffffffff161115611ea057600260189054906101000a900463ffffffff1663ffffffff168263ffffffff1603611e9b576000611e2f6000610978565b905060008163ffffffff1603611e7757600260149054906101000a900463ffffffff16600260186101000a81548163ffffffff021916908363ffffffff160217905550611e99565b80600260186101000a81548163ffffffff021916908363ffffffff1602179055505b505b611ed4565b600260149054906101000a900463ffffffff16600260186101000a81548163ffffffff021916908363ffffffff1602179055505b600260189054906101000a900463ffffffff169050919050565b600063ffffffff82169050919050565b611f0781611eee565b82525050565b6000602082019050611f226000830184611efe565b92915050565b600080fd5b611f3681611eee565b8114611f4157600080fd5b50565b600081359050611f5381611f2d565b92915050565b600060208284031215611f6f57611f6e611f28565b5b6000611f7d84828501611f44565b91505092915050565b6000819050919050565b611f9981611f86565b82525050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000611fca82611f9f565b9050919050565b611fda81611fbf565b82525050565b600060ff82169050919050565b611ff681611fe0565b82525050565b600061010082019050612012600083018b611f90565b61201f602083018a611fd1565b61202c6040830189611fd1565b6120396060830188611fd1565b6120466080830187611efe565b61205360a0830186611efe565b61206060c0830185611efe565b61206d60e0830184611fed565b9998505050505050505050565b60008115159050919050565b61208f8161207a565b82525050565b60006020820190506120aa6000830184612086565b92915050565b6120b981611fbf565b81146120c457600080fd5b50565b6000813590506120d6816120b0565b92915050565b6000602082840312156120f2576120f1611f28565b5b6000612100848285016120c7565b91505092915050565b600080604083850312156121205761211f611f28565b5b600061212e85828601611f44565b925050602061213f858286016120c7565b9150509250929050565b60008160000b9050919050565b61215f81612149565b82525050565b600060208201905061217a6000830184612156565b92915050565b6000806040838503121561219757612196611f28565b5b60006121a585828601611f44565b92505060206121b685828601611f44565b9150509250929050565b6121c981611f86565b81146121d457600080fd5b50565b6000813590506121e6816121c0565b92915050565b60006020828403121561220257612201611f28565b5b6000612210848285016121d7565b91505092915050565b600060208201905061222e6000830184611fd1565b92915050565b6000806000806080858703121561224e5761224d611f28565b5b600061225c878288016120c7565b945050602061226d878288016120c7565b935050604061227e878288016120c7565b925050606061228f878288016121d7565b91505092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006122d582611eee565b91506122e083611eee565b9250828203905063ffffffff8111156122fc576122fb61229b565b5b92915050565b600082825260208201905092915050565b7f4552525f494e56414c49445f5245515545535400000000000000000000000000600082015250565b6000612349601383612302565b915061235482612313565b602082019050919050565b600060208201905081810360008301526123788161233c565b9050919050565b7f4552525f4e4f545f454e444f5253454400000000000000000000000000000000600082015250565b60006123b5601083612302565b91506123c08261237f565b602082019050919050565b600060208201905081810360008301526123e4816123a8565b9050919050565b60006060820190506124006000830186611fd1565b61240d6020830185611fd1565b61241a6040830184611f90565b949350505050565b600081519050919050565b600081905092915050565b60005b8381101561245657808201518184015260208101905061243b565b60008484015250505050565b600061246d82612422565b612477818561242d565b9350612487818560208601612438565b80840191505092915050565b600061249f8284612462565b915081905092915050565b60006124b582611eee565b915063ffffffff82036124cb576124ca61229b565b5b600182019050919050565b7f4552525f41434345535300000000000000000000000000000000000000000000600082015250565b600061250c600a83612302565b9150612517826124d6565b602082019050919050565b6000602082019050818103600083015261253b816124ff565b9050919050565b7f4552525f414c5245414459564f54454400000000000000000000000000000000600082015250565b6000612578601083612302565b915061258382612542565b602082019050919050565b600060208201905081810360008301526125a78161256b565b9050919050565b7f4552525f4e4f54464f554e440000000000000000000000000000000000000000600082015250565b60006125e4600c83612302565b91506125ef826125ae565b602082019050919050565b60006020820190508181036000830152612613816125d7565b9050919050565b7f4552525f5245445543455f5448524553484f4c445f4649525354000000000000600082015250565b6000612650601a83612302565b915061265b8261261a565b602082019050919050565b6000602082019050818103600083015261267f81612643565b9050919050565b600061269182611eee565b9150600082036126a4576126a361229b565b5b600182039050919050565b60006040820190506126c46000830185611f90565b6126d16020830184611efe565b939250505056fea2646970667358221220441ad54fe6f08f891580df338880b0f83cdbd00aaa43398c54418ae9d041b5cc64736f6c63430008110033 +\ No newline at end of file diff --git a/python/erc20_transfer_authorization/data/ERC20TransferAuthorization.json b/python/erc20_transfer_authorization/data/ERC20TransferAuthorization.json @@ -1 +1 @@ -[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"_serial","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"_yays","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"_nays","type":"uint32"}],"name":"Approved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"_serial","type":"uint32"}],"name":"Executed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_sender","type":"address"},{"indexed":true,"internalType":"address","name":"_recipient","type":"address"},{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"_serial","type":"uint32"}],"name":"NewRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"_quorum","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"_vetoThreshold","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"_signerCount","type":"uint32"}],"name":"QuorumSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"_serial","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"_yays","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"_nays","type":"uint32"}],"name":"Rejected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_signer","type":"address"}],"name":"SignerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_signer","type":"address"}],"name":"SignerRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"_serial","type":"uint32"}],"name":"TransferFail","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"_serial","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"_yays","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"_nays","type":"uint32"}],"name":"Vetoed","type":"event"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"addSigner","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_serial","type":"uint32"}],"name":"checkResult","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"count","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"createRequest","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_serial","type":"uint32"}],"name":"executeRequest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_idx","type":"uint32"}],"name":"getSerialAt","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastSerial","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_serial","type":"uint32"}],"name":"nay","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nextSerial","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quorum","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"removeSigner","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"requests","outputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"serial","type":"uint32"},{"internalType":"uint32","name":"yay","type":"uint32"},{"internalType":"uint32","name":"nay","type":"uint32"},{"internalType":"uint8","name":"result","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_quorum","type":"uint32"},{"internalType":"uint32","name":"_vetoThreshold","type":"uint32"}],"name":"setThresholds","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signerCount","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"signers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vetoThreshold","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"address","name":"","type":"address"}],"name":"vote","outputs":[{"internalType":"int8","name":"","type":"int8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_serial","type":"uint32"}],"name":"yay","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"}] +[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"_serial","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"_yays","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"_nays","type":"uint32"}],"name":"Approved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"_serial","type":"uint32"}],"name":"Executed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_sender","type":"address"},{"indexed":true,"internalType":"address","name":"_recipient","type":"address"},{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"_serial","type":"uint32"}],"name":"NewRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"_quorum","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"_vetoThreshold","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"_signerCount","type":"uint32"}],"name":"QuorumSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"_serial","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"_yays","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"_nays","type":"uint32"}],"name":"Rejected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"_serial","type":"uint32"}],"name":"TransferFail","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"_serial","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"_yays","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"_nays","type":"uint32"}],"name":"Vetoed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_signer","type":"address"}],"name":"WriterAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_signer","type":"address"}],"name":"WriterRemoved","type":"event"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"addWriter","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_serial","type":"uint32"}],"name":"checkResult","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"count","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"createRequest","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_serial","type":"uint32"}],"name":"executeRequest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_idx","type":"uint32"}],"name":"getSerialAt","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"isWriter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastSerial","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_serial","type":"uint32"}],"name":"nay","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nextSerial","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quorum","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"removeWriter","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"requests","outputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"serial","type":"uint32"},{"internalType":"uint32","name":"yay","type":"uint32"},{"internalType":"uint32","name":"nay","type":"uint32"},{"internalType":"uint8","name":"result","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_quorum","type":"uint32"},{"internalType":"uint32","name":"_vetoThreshold","type":"uint32"}],"name":"setThresholds","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signerCount","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"signers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vetoThreshold","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"address","name":"","type":"address"}],"name":"vote","outputs":[{"internalType":"int8","name":"","type":"int8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"writers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_serial","type":"uint32"}],"name":"yay","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"}] diff --git a/python/erc20_transfer_authorization/transfer_authorization.py b/python/erc20_transfer_authorization/transfer_authorization.py @@ -32,6 +32,28 @@ moddir = os.path.dirname(__file__) datadir = os.path.join(moddir, 'data') +class Request: + + def __init__(self, sender, recipient, value, token): + self.sender = sender + self.recipient = recipient + self.value = value + self.token = token + self.serial = 0 + self.yay = 0 + self.nay = 0 + + + @classmethod + def create(cls, sender, recipient, value, token, *args): + o = Request(sender, recipient, value, token) + if len(args) > 0: + o.serial = args[0] + o.yay = args[1] + o.nsy = args[2] + return o + + class TransferAuthorization(TxFactory): __abi = None @@ -61,6 +83,26 @@ class TransferAuthorization(TxFactory): return 2800000 + def __single_address_method(self, method, contract_address, sender_address, address, tx_format=TxFormat.JSONRPC): + enc = ABIContractEncoder() + enc.method(method) + enc.typ(ABIContractType.ADDRESS) + enc.address(address) + data = enc.get() + tx = self.template(sender_address, contract_address, use_nonce=True) + tx = self.set_code(tx, data) + tx = self.finalize(tx, tx_format) + return tx + + + def add_writer(self, contract_address, sender_address, address, tx_format=TxFormat.JSONRPC): + return self.__single_address_method('addWriter', contract_address, sender_address, address, tx_format) + + + def delete_writer(self, contract_address, sender_address, address, tx_format=TxFormat.JSONRPC): + return self.__single_address_method('deleteWriter', contract_address, sender_address, address, tx_format) + + def create_request(self, contract_address, sender_address, sender, recipient, token, value, tx_format=TxFormat.JSONRPC): enc = ABIContractEncoder() enc.method('createRequest') @@ -79,6 +121,50 @@ class TransferAuthorization(TxFactory): return tx + + def set_thresholds(self, contract_address, sender_address, quorum_threshold, veto_threshold, tx_format=TxFormat.JSONRPC): + enc = ABIContractEncoder() + enc.method('setThresholds') + enc.typ(ABIContractType.UINT32) + enc.typ(ABIContractType.UINT32) + enc.uintn(quorum_threshold, 32) + enc.uintn(veto_threshold, 32) + data = enc.get() + tx = self.template(sender_address, contract_address, use_nonce=True) + tx = self.set_code(tx, data) + tx = self.finalize(tx, tx_format) + return tx + + + def requests(self, contract_address, idx, sender_address=ZERO_ADDRESS, id_generator=None): + j = JSONRPCRequest(id_generator) + o = j.template() + o['method'] = 'eth_call' + enc = ABIContractEncoder() + enc.method('requests') + enc.typ(ABIContractType.UINT32) + enc.uintn(idx, 32) + data = add_0x(enc.get()) + tx = self.template(sender_address, contract_address) + tx = self.set_code(tx, data) + o['params'].append(self.normalize(tx)) + o['params'].append('latest') + o = j.finalize(o) + return o + + + def yay(self, contract_address, sender_address, serial, tx_format=TxFormat.JSONRPC): + enc = ABIContractEncoder() + enc.method('yay') + enc.typ(ABIContractType.UINT32) + enc.uintn(serial, 32) + data = enc.get() + tx = self.template(sender_address, contract_address, use_nonce=True) + tx = self.set_code(tx, data) + tx = self.finalize(tx, tx_format) + return tx + + def constructor(self, sender_address): code = TransferAuthorization.bytecode() tx = self.template(sender_address, None, use_nonce=True) @@ -86,7 +172,7 @@ class TransferAuthorization(TxFactory): return self.build(tx) - def signers(self, contract_address, signer_address, sender_address=ZERO_ADDRESS, id_generator=None): + def writers(self, contract_address, signer_address, sender_address=ZERO_ADDRESS, id_generator=None): j = JSONRPCRequest(id_generator) o = j.template() o['method'] = 'eth_call' @@ -103,8 +189,8 @@ class TransferAuthorization(TxFactory): return o - def have_signer(self, contract_address, signer_address, sender_address=ZERO_ADDRESS): - return self.signers(contract_address, signer_address, sender_address) + def is_writer(self, contract_address, signer_address, sender_address=ZERO_ADDRESS, id_generator=None): + return self.writers(contract_address, signer_address, sender_address) @classmethod @@ -145,6 +231,39 @@ class TransferAuthorization(TxFactory): r = dec.decode() return r + + @classmethod + def parse_request(self, v): + cursor = 0 + v = strip_0x(v) + d = ABIContractDecoder() + d.typ(ABIContractType.UINT256) + d.typ(ABIContractType.ADDRESS) + d.typ(ABIContractType.ADDRESS) + d.typ(ABIContractType.ADDRESS) + d.typ(ABIContractType.UINT32) + d.typ(ABIContractType.UINT32) + d.typ(ABIContractType.UINT32) + d.typ(ABIContractType.UINT32) + d.val(v[cursor:cursor+64]) + cursor += 64 + d.val(v[cursor:cursor+64]) + cursor += 64 + d.val(v[cursor:cursor+64]) + cursor += 64 + d.val(v[cursor:cursor+64]) + cursor += 64 + d.val(v[cursor:cursor+64]) + cursor += 64 + d.val(v[cursor:cursor+64]) + cursor += 64 + d.val(v[cursor:cursor+64]) + cursor += 64 + d.val(v[cursor:cursor+64]) + cursor += 64 + r = d.decode() + return Request.create(r[1], r[2], r[0], r[3], r[4], r[5], r[6]) + # # def last_serial(self): # return self.contract.functions.lastSerial().call() diff --git a/python/requirements.txt b/python/requirements.txt @@ -1,4 +1,4 @@ confini>=0.5.2,<0.7.0 #chainlib-eth>=0.1.0b1,<0.2.0 -chainlib-eth~=0.4.6 +chainlib-eth~=0.4.7 potaahto~=0.1.1 diff --git a/python/setup.cfg b/python/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = erc20-transfer-authorization -version = 0.4.0 +version = 0.4.1 description = Simple approval escrow for ERC20 spend approval author = Louis Holbrook author_email = dev@holbrook.no diff --git a/python/tests/test_app.py b/python/tests/test_app.py @@ -5,6 +5,7 @@ import logging # external imports from chainlib.eth.nonce import RPCNonceOracle +from chainlib.eth.tx import receipt # local imports from erc20_transfer_authorization import TransferAuthorization @@ -17,22 +18,43 @@ logg = logging.getLogger() testdir = os.path.dirname(__file__) -class ERC20TransferAuthorizationBasicTest(TestBase): +class TestBasic(TestBase): - def test_basic(self): - + def setUp(self): + super(TestBasic, self).setUp() nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) + self.c = TransferAuthorization(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) + (tx_hash_hex, o) = self.c.add_writer(self.address, self.accounts[0], self.accounts[1]) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.rpc.do(o) + self.assertEqual(r['status'], 1) + + (tx_hash_hex, o) = self.c.add_writer(self.address, self.accounts[0], self.accounts[2]) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.rpc.do(o) + self.assertEqual(r['status'], 1) + + + def test_basic(self): c = TransferAuthorization(self.chain_spec) - o = c.signers(self.address, self.accounts[0], sender_address=self.accounts[0]) + o = c.is_writer(self.address, self.accounts[0], sender_address=self.accounts[0]) r = self.rpc.do(o) self.assertTrue(c.parse_signers(r)) - o = c.signers(self.address, self.accounts[1], sender_address=self.accounts[0]) + o = c.is_writer(self.address, self.accounts[1], sender_address=self.accounts[0]) r = self.rpc.do(o) - self.assertFalse(c.parse_signers(r)) - + self.assertTrue(c.parse_signers(r)) + o = c.is_writer(self.address, self.accounts[2], sender_address=self.accounts[0]) + r = self.rpc.do(o) + self.assertTrue(c.parse_signers(r)) + + o = c.is_writer(self.address, self.accounts[3], sender_address=self.accounts[0]) + r = self.rpc.do(o) + self.assertFalse(c.parse_signers(r)) # def test_get(self): # w = self.w3.eth.contract(abi=self.abi_wallet, address=self.address_wallet) # t = self.w3.eth.contract(abi=self.abi_token, address=self.address_token) diff --git a/python/tests/test_quorum.py b/python/tests/test_quorum.py @@ -1,298 +1,76 @@ # standard imports -import logging +import os import unittest +import logging + +# external imports +from chainlib.eth.nonce import RPCNonceOracle +from chainlib.eth.address import is_same_address +from chainlib.eth.tx import receipt +from giftable_erc20_token import GiftableToken + +# local imports +from erc20_transfer_authorization import TransferAuthorization # testutil imports from tests.base_erc20transferauthorization import TestBase logg = logging.getLogger() -rejected_log_signature = '3d61d434b895790b08f040c45261fce3b3bec596278b3a0f25dd9f741d0ba469' -vetoed_log_signature = '1ad80b2541a1f52bdc838332d7c23606116a1188a8cbbc4c0948b4b56ce51d14' -approved_log_signature = '36ea04725f8aa40ee603224671681b753f9cba3cb5f67c5a0e24a3b39900c065' - - -class ERC20TransferAuthorizationQuorumTest(TestBase): - - @unittest.skip('must be ported to chainlib') - def test_vote_access(self): - w = self.w3.eth.contract(abi=self.abi_wallet, address=self.address_wallet) - t = self.w3.eth.contract(abi=self.abi_token, address=self.address_token) - - w.functions.addSigner(self.w3.eth.accounts[5]).transact({'from': self.w3.eth.accounts[0]}) - w.functions.setThresholds(2, 0).transact({'from': self.w3.eth.accounts[0]}) - - tx_hash = w.functions.createRequest(self.w3.eth.accounts[2], self.w3.eth.accounts[3], t.address, 10).transact({'from': self.w3.eth.accounts[9]}) - r = self.w3.eth.getTransactionReceipt(tx_hash) - - topic_match = 'b609ae609609ee99268d05bc1371102cafe8d6b964bf082439ab16be2a01c87c' - log = r.logs[0] - topic = log.topics[0] - self.assertEqual(topic.hex()[2:], topic_match) - serial = int(log.data[66:], 16) - - # only signers may vote - with self.assertRaises(Exception): - tx_hashh = w.functions.yay(serial).transact({'from': self.w3.eth.accounts[2]}) - - # only signers may vote - with self.assertRaises(Exception): - tx_hashh = w.functions.nay(serial).transact({'from': self.w3.eth.accounts[2]}) - - w.functions.yay(serial).transact({'from': self.w3.eth.accounts[0]}) - - # may not vote twice - with self.assertRaises(Exception): - tx_hashh = w.functions.yay(serial).transact({'from': self.w3.eth.accounts[0]}) - - # may not change vote - with self.assertRaises(Exception): - tx_hashh = w.functions.nay(serial).transact({'from': self.w3.eth.accounts[0]}) - - tx_hashh = w.functions.nay(serial).transact({'from': self.w3.eth.accounts[5]}) - - # may not vote twice - with self.assertRaises(Exception): - tx_hashh = w.functions.nay(serial).transact({'from': self.w3.eth.accounts[5]}) - - # may not change vote - with self.assertRaises(Exception): - tx_hashh = w.functions.yay(serial).transact({'from': self.w3.eth.accounts[5]}) - - - @unittest.skip('must be ported to chainlib') - def test_minimal_quorum(self): - w = self.w3.eth.contract(abi=self.abi_wallet, address=self.address_wallet) - t = self.w3.eth.contract(abi=self.abi_token, address=self.address_token) - - t.functions.approve(w.address, 10).transact({'from': self.w3.eth.accounts[2]}) - self.eth_tester.mine_block() - - tx_hash = w.functions.createRequest(self.w3.eth.accounts[2], self.w3.eth.accounts[3], t.address, 10).transact({'from': self.w3.eth.accounts[9]}) - r = self.w3.eth.getTransactionReceipt(tx_hash) - - topic_match = 'b609ae609609ee99268d05bc1371102cafe8d6b964bf082439ab16be2a01c87c' - log = r.logs[0] - topic = log.topics[0] - self.assertEqual(topic.hex()[2:], topic_match) - serial = int(log.data[66:], 16) - - with self.assertRaises(Exception): - w.functions.executeRequest(serial).transact({'from': self.w3.eth.accounts[0]}) - - # only signers may vote - with self.assertRaises(Exception): - tx_hashh = w.functions.yay(serial).transact({'from': self.w3.eth.accounts[2]}) - - tx_hashh = w.functions.yay(serial).transact({'from': self.w3.eth.accounts[0]}) - r = self.w3.eth.getTransactionReceipt(tx_hashh) - - topic_match = approved_log_signature - log = r.logs[0] - topic = log.topics[0] - self.assertEqual(topic.hex()[2:], topic_match) - - tx_hashh = w.functions.executeRequest(serial).transact({'from': self.w3.eth.accounts[0]}) - r = self.w3.eth.getTransactionReceipt(tx_hashh) - - topic_match = 'bcf6a68a2f901be4a23a41b53acd7697893a7e34def4e28acba584da75283b67' # Executed(serial) - log = r.logs[1] - topic = log.topics[0].hex()[2:] - self.assertEqual(topic, topic_match) - - self.assertEqual(t.functions.balanceOf(self.w3.eth.accounts[2]).call(), 90) - self.assertEqual(t.functions.balanceOf(self.w3.eth.accounts[3]).call(), 10) - - - @unittest.skip('must be ported to chainlib') - def test_simple_quorum(self): - w = self.w3.eth.contract(abi=self.abi_wallet, address=self.address_wallet) - t = self.w3.eth.contract(abi=self.abi_token, address=self.address_token) - - t.functions.approve(w.address, 10).transact({'from': self.w3.eth.accounts[2]}) - self.eth_tester.mine_block() - - w.functions.addSigner(self.w3.eth.accounts[5]).transact({'from': self.w3.eth.accounts[0]}) - w.functions.addSigner(self.w3.eth.accounts[6]).transact({'from': self.w3.eth.accounts[0]}) - w.functions.setThresholds(2, 0).transact({'from': self.w3.eth.accounts[0]}) - - tx_hash = w.functions.createRequest(self.w3.eth.accounts[2], self.w3.eth.accounts[3], t.address, 10).transact({'from': self.w3.eth.accounts[9]}) - r = self.w3.eth.getTransactionReceipt(tx_hash) - - topic_match = 'b609ae609609ee99268d05bc1371102cafe8d6b964bf082439ab16be2a01c87c' - log = r.logs[0] - topic = log.topics[0] - self.assertEqual(topic.hex()[2:], topic_match) - serial = int(log.data[66:], 16) - - tx_hashh = w.functions.yay(serial).transact({'from': self.w3.eth.accounts[0]}) - r = self.w3.eth.getTransactionReceipt(tx_hashh) - self.assertEqual(len(r.logs), 0) - - # attempt to execute fails - with self.assertRaises(Exception): - w.functions.executeRequest(serial).transact({'from': self.w3.eth.accounts[0]}) - - # dough is still there - self.assertEqual(t.functions.balanceOf(self.w3.eth.accounts[2]).call(), 100) - - w.functions.yay(serial).transact({'from': self.w3.eth.accounts[5]}) - - w.functions.executeRequest(serial).transact({'from': self.w3.eth.accounts[0]}) - - self.assertEqual(t.functions.balanceOf(self.w3.eth.accounts[2]).call(), 90) - self.assertEqual(t.functions.balanceOf(self.w3.eth.accounts[3]).call(), 10) - - # additional votes not possible - with self.assertRaises(Exception): - w.functions.yay(serial).transact({'from': self.w3.eth.accounts[6]}) - - with self.assertRaises(Exception): - w.functions.nay(serial).transact({'from': self.w3.eth.accounts[6]}) - - - @unittest.skip('must be ported to chainlib') - def test_minimal_rejection(self): - w = self.w3.eth.contract(abi=self.abi_wallet, address=self.address_wallet) - t = self.w3.eth.contract(abi=self.abi_token, address=self.address_token) - - tx_hash = w.functions.createRequest(self.w3.eth.accounts[2], self.w3.eth.accounts[3], t.address, 10).transact({'from': self.w3.eth.accounts[9]}) - r = self.w3.eth.getTransactionReceipt(tx_hash) - - topic_match = 'b609ae609609ee99268d05bc1371102cafe8d6b964bf082439ab16be2a01c87c' - log = r.logs[0] - topic = log.topics[0] - self.assertEqual(topic.hex()[2:], topic_match) - serial = int(log.data[66:], 16) - - tx_hashh = w.functions.nay(serial).transact({'from': self.w3.eth.accounts[0]}) - r = self.w3.eth.getTransactionReceipt(tx_hashh) - - topic_match = rejected_log_signature - log = r.logs[0] - topic = log.topics[0] - self.assertEqual(topic.hex()[2:], topic_match) - - # cannot execute - with self.assertRaises(Exception): - w.functions.executeRequest(serial).transact({'from': self.w3.eth.accounts[0]}) - - - @unittest.skip('must be ported to chainlib') - def test_simple_rejection(self): - w = self.w3.eth.contract(abi=self.abi_wallet, address=self.address_wallet) - t = self.w3.eth.contract(abi=self.abi_token, address=self.address_token) - - t.functions.approve(w.address, 10).transact({'from': self.w3.eth.accounts[2]}) - self.eth_tester.mine_block() - - w.functions.addSigner(self.w3.eth.accounts[5]).transact({'from': self.w3.eth.accounts[0]}) - w.functions.addSigner(self.w3.eth.accounts[6]).transact({'from': self.w3.eth.accounts[0]}) - w.functions.setThresholds(2, 0).transact({'from': self.w3.eth.accounts[0]}) - - tx_hash = w.functions.createRequest(self.w3.eth.accounts[2], self.w3.eth.accounts[3], t.address, 10).transact({'from': self.w3.eth.accounts[9]}) - r = self.w3.eth.getTransactionReceipt(tx_hash) - - topic_match = 'b609ae609609ee99268d05bc1371102cafe8d6b964bf082439ab16be2a01c87c' - log = r.logs[0] - topic = log.topics[0] - self.assertEqual(topic.hex()[2:], topic_match) - serial = int(log.data[66:], 16) - - tx_hashh = w.functions.nay(serial).transact({'from': self.w3.eth.accounts[0]}) - r = self.w3.eth.getTransactionReceipt(tx_hashh) - self.assertEqual(len(r.logs), 0) - - tx_hashh = w.functions.nay(serial).transact({'from': self.w3.eth.accounts[5]}) - r = self.w3.eth.getTransactionReceipt(tx_hashh) - - topic_match = rejected_log_signature - log = r.logs[0] - topic = log.topics[0] - self.assertEqual(topic.hex()[2:], topic_match) - - # cannot execute - with self.assertRaises(Exception): - w.functions.executeRequest(serial).transact({'from': self.w3.eth.accounts[0]}) - - # additional votes not possible - with self.assertRaises(Exception): - w.functions.yay(serial).transact({'from': self.w3.eth.accounts[6]}) - - with self.assertRaises(Exception): - w.functions.nay(serial).transact({'from': self.w3.eth.accounts[6]}) - - - @unittest.skip('must be ported to chainlib') - def test_veto(self): - w = self.w3.eth.contract(abi=self.abi_wallet, address=self.address_wallet) - t = self.w3.eth.contract(abi=self.abi_token, address=self.address_token) - - t.functions.approve(w.address, 10).transact({'from': self.w3.eth.accounts[2]}) - self.eth_tester.mine_block() - - w.functions.addSigner(self.w3.eth.accounts[5]).transact({'from': self.w3.eth.accounts[0]}) - w.functions.addSigner(self.w3.eth.accounts[6]).transact({'from': self.w3.eth.accounts[0]}) - w.functions.setThresholds(2, 1).transact({'from': self.w3.eth.accounts[0]}) - - tx_hash = w.functions.createRequest(self.w3.eth.accounts[2], self.w3.eth.accounts[3], t.address, 10).transact({'from': self.w3.eth.accounts[9]}) - r = self.w3.eth.getTransactionReceipt(tx_hash) - - topic_match = 'b609ae609609ee99268d05bc1371102cafe8d6b964bf082439ab16be2a01c87c' - log = r.logs[0] - topic = log.topics[0] - self.assertEqual(topic.hex()[2:], topic_match) - serial = int(log.data[66:], 16) - - w.functions.yay(serial).transact({'from': self.w3.eth.accounts[0]}) - tx_hashh = w.functions.nay(serial).transact({'from': self.w3.eth.accounts[5]}) - r = self.w3.eth.getTransactionReceipt(tx_hashh) - - topic_match = vetoed_log_signature - log = r.logs[0] - topic = log.topics[0] - self.assertEqual(topic.hex()[2:], topic_match) - - # cannot execute - with self.assertRaises(Exception): - w.functions.executeRequest(serial).transact({'from': self.w3.eth.accounts[0]}) - - # additional votes not possible - with self.assertRaises(Exception): - w.functions.yay(serial).transact({'from': self.w3.eth.accounts[6]}) - - with self.assertRaises(Exception): - w.functions.nay(serial).transact({'from': self.w3.eth.accounts[6]}) - - - @unittest.skip('must be ported to chainlib') - def test_inflight_change(self): - w = self.w3.eth.contract(abi=self.abi_wallet, address=self.address_wallet) - t = self.w3.eth.contract(abi=self.abi_token, address=self.address_token) - - w.functions.addSigner(self.w3.eth.accounts[5]).transact({'from': self.w3.eth.accounts[0]}) - w.functions.addSigner(self.w3.eth.accounts[6]).transact({'from': self.w3.eth.accounts[0]}) - w.functions.setThresholds(2, 0).transact({'from': self.w3.eth.accounts[0]}) - - tx_hash = w.functions.createRequest(self.w3.eth.accounts[2], self.w3.eth.accounts[3], t.address, 10).transact({'from': self.w3.eth.accounts[9]}) - r = self.w3.eth.getTransactionReceipt(tx_hash) - - topic_match = 'b609ae609609ee99268d05bc1371102cafe8d6b964bf082439ab16be2a01c87c' - log = r.logs[0] - topic = log.topics[0] - self.assertEqual(topic.hex()[2:], topic_match) - serial = int(log.data[66:], 16) - - w.functions.nay(serial).transact({'from': self.w3.eth.accounts[0]}) - w.functions.removeSigner(self.w3.eth.accounts[6]).transact({'from': self.w3.eth.accounts[0]}) - - tx_hashh = w.functions.checkResult(serial).transact({'from': self.w3.eth.accounts[6]}) - r = self.w3.eth.getTransactionReceipt(tx_hashh) - - topic_match = rejected_log_signature - log = r.logs[0] - topic = log.topics[0] - self.assertEqual(topic.hex()[2:], topic_match) +testdir = os.path.dirname(__file__) + + +class TestQuorum(TestBase): + + def setUp(self): + super(TestQuorum, self).setUp() + nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) + self.c = TransferAuthorization(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) + + for i in range(1, 5): + (tx_hash_hex, o) = self.c.add_writer(self.address, self.accounts[0], self.accounts[i]) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.rpc.do(o) + self.assertEqual(r['status'], 1) + + c = GiftableToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) + (tx_hash_hex, o) = c.mint_to(self.token_address, self.accounts[0], self.accounts[1], 10000) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.rpc.do(o) + self.assertEqual(r['status'], 1) + + + def test_yay(self): + (tx_hash_hex, o) = self.c.set_thresholds(self.address, self.accounts[0], 2, 2) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.rpc.do(o) + self.assertEqual(r['status'], 1) + + (tx_hash_hex, o) = self.c.create_request(self.address, self.accounts[0], self.accounts[1], self.accounts[2], self.token_address, 1024) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.rpc.do(o) + self.assertEqual(r['status'], 1) + + (tx_hash_hex, o) = self.c.yay(self.address, self.accounts[0], 1) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.rpc.do(o) + self.assertEqual(r['status'], 1) + + o = self.c.requests(self.address, 1, sender_address=self.accounts[0]) + r = self.rpc.do(o) + request = self.c.parse_request(r) + self.assertTrue(is_same_address(request.sender, self.accounts[1])) + self.assertTrue(is_same_address(request.recipient, self.accounts[2])) + self.assertTrue(is_same_address(request.token, self.token_address)) + self.assertEqual(request.value, 1024) + self.assertEqual(request.serial, 1) + self.assertEqual(request.yay, 1) + self.assertEqual(request.nay, 0) if __name__ == '__main__': diff --git a/python/tests/test_transfer.py b/python/tests/test_transfer.py @@ -1,47 +0,0 @@ -# standard imports -import logging -import unittest - -# testutil imports -from tests.base_erc20transferauthorization import TestBase - -logg = logging.getLogger() - - -class ERC20TransferAuthorizationTransferTest(TestBase): - - @unittest.skip('must be ported to chainlib') - def test_transfer(self): - w = self.w3.eth.contract(abi=self.abi_wallet, address=self.address_wallet) - t = self.w3.eth.contract(abi=self.abi_token, address=self.address_token) - - t.functions.approve(w.address, 10).transact({'from': self.w3.eth.accounts[2]}) - self.eth_tester.mine_block() - - tx_hash = w.functions.createRequest(self.w3.eth.accounts[2], self.w3.eth.accounts[3], t.address, 10).transact({'from': self.w3.eth.accounts[9]}) - r = self.w3.eth.getTransactionReceipt(tx_hash) - - topic_match = 'b609ae609609ee99268d05bc1371102cafe8d6b964bf082439ab16be2a01c87c' - log = r.logs[0] - topic = log.topics[0] - self.assertEqual(topic.hex()[2:], topic_match) - serial = int(log.data[66:], 16) - - w.functions.yay(serial).transact({'from': self.w3.eth.accounts[0]}) - w.functions.executeRequest(serial).transact({'from': self.w3.eth.accounts[0]}) - - self.assertEqual(t.functions.balanceOf(self.w3.eth.accounts[2]).call(), 90) - self.assertEqual(t.functions.balanceOf(self.w3.eth.accounts[3]).call(), 10) - - req = w.functions.requests(1).call() - self.assertEqual(req[7], self.w3.eth.blockNumber) - - serial_compare = w.functions.requestSenderIndex(self.w3.eth.accounts[2], 0).call() - self.assertEqual(serial_compare, req[0]) - - serial_compare = w.functions.requestRecipientIndex(self.w3.eth.accounts[3], 0).call() - self.assertEqual(serial_compare, req[0]) - - -if __name__ == '__main__': - unittest.main() diff --git a/solidity/ERC20TransferAuthorization.sol b/solidity/ERC20TransferAuthorization.sol @@ -34,13 +34,14 @@ contract ERC20TransferAuthorization { uint32 public signerCount; mapping(address => bool) public signers; + address[] public writers; event NewRequest(address indexed _sender, address indexed _recipient, address indexed _token, uint256 _value, uint32 _serial); event Executed(uint32 _serial); event TransferFail(uint32 _serial); event QuorumSet(uint32 indexed _quorum, uint32 indexed _vetoThreshold, uint32 indexed _signerCount); - event SignerAdded(address _signer); - event SignerRemoved(address _signer); + event WriterAdded(address _signer); + event WriterRemoved(address _signer); event Vetoed(uint32 indexed _serial, uint32 indexed _yays, uint32 indexed _nays); event Approved(uint32 indexed _serial, uint32 indexed _yays, uint32 indexed _nays); event Rejected(uint32 indexed _serial, uint32 indexed _yays, uint32 indexed _nays); @@ -49,21 +50,25 @@ contract ERC20TransferAuthorization { owner = msg.sender; hi = 1; lo = 1; - addSigner(msg.sender); + addWriter(msg.sender); setThresholds(1, 0); } - function addSigner(address _signer) public returns (uint32) { + function isWriter(address _signer) public view returns (bool) { + return signers[_signer]; + } + + function addWriter(address _signer) public returns (uint32) { require(msg.sender == owner, 'ERR_ACCESS'); require(signers[_signer] == false, 'ERR_NOTFOUND'); signers[_signer] = true; signerCount++; - emit SignerAdded(_signer); + emit WriterAdded(_signer); return signerCount; } - function removeSigner(address _signer) public returns (uint32) { + function removeWriter(address _signer) public returns (uint32) { //require(msg.sender == owner || msg.sender == _signer, 'ERR_ACCESS'); require(msg.sender == owner, 'ERR_ACCESS'); require(signers[_signer] == true, 'ERR_NOTFOUND'); @@ -71,7 +76,7 @@ contract ERC20TransferAuthorization { signers[_signer] = false; signerCount--; - emit SignerRemoved(_signer); + emit WriterRemoved(_signer); return signerCount; }