erc20-transfer-authorization

Simple approval escrow for ERC20 spending
Log | Files | Refs

commit 001d6b84517289cf3a2dd45a60afc77608aafc8b
parent 700edcab7369a45b20bfefa3c22b98c5047e3333
Author: nolash <dev@holbrook.no>
Date:   Tue, 16 Feb 2021 11:36:13 +0100

Rename package

Diffstat:
Dpython/erc20_approval_escrow/data/TransferApproval.bin | 2--
Dpython/erc20_approval_escrow/runnable/deploy.py | 103-------------------------------------------------------------------------------
Rpython/erc20_approval_escrow/__init__.py -> python/erc20_transfer_authorization/__init__.py | 0
Rpython/erc20_approval_escrow/approval.py -> python/erc20_transfer_authorization/approval.py | 0
Apython/erc20_transfer_authorization/data/ERC20TransferAuthorization.bin | 2++
Rpython/erc20_approval_escrow/data/TransferApproval.json -> python/erc20_transfer_authorization/data/ERC20TransferAuthorization.json | 0
Rpython/erc20_approval_escrow/data/GiftableToken.bin -> python/erc20_transfer_authorization/data/GiftableToken.bin | 0
Rpython/erc20_approval_escrow/data/GiftableToken.json -> python/erc20_transfer_authorization/data/GiftableToken.json | 0
Apython/erc20_transfer_authorization/runnable/deploy.py | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpython/setup.cfg | 16++++++++--------
Mpython/tests/base.py | 8++++----
Mpython/tests/test_app.py | 211+++++++++++++++----------------------------------------------------------------
Asolidity/ERC20TransferAuthorization.sol | 208+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msolidity/Makefile | 8++++----
Dsolidity/TransferApproval.bin | 2--
Dsolidity/TransferApproval.json | 1-
Dsolidity/TransferApproval.sol | 207-------------------------------------------------------------------------------
17 files changed, 367 insertions(+), 504 deletions(-)

diff --git a/python/erc20_approval_escrow/data/TransferApproval.bin b/python/erc20_approval_escrow/data/TransferApproval.bin @@ -1 +0,0 @@ -60806040523480156200001157600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060016003819055506001600481905550600160068190555060016008819055506200008760016000620000a060201b60201c565b5062000099336200012b60201b60201c565b50620003d2565b6000600854831115620000b257600080fd5b60008311620000c057600080fd5b600854821115620000d057600080fd5b82600681905550816007819055507f9f40cfd22fe91777c78f252bd21a710f3fb007dc2f321876891e7644ba0ae1756006546007546008546040516200011993929190620002da565b60405180910390a16001905092915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146200018857600080fd5b60001515600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16151514620001e657600080fd5b6001600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555060086000815480929190620002539062000355565b91905055507f47d1c22a25bb3a5d4e481b9b1e6944c2eade3181a0a20b495ed61d35b5323f2482604051620002899190620002bd565b60405180910390a16008549050919050565b620002a68162000317565b82525050565b620002b7816200034b565b82525050565b6000602082019050620002d460008301846200029b565b92915050565b6000606082019050620002f16000830186620002ac565b620003006020830185620002ac565b6200030f6040830184620002ac565b949350505050565b600062000324826200032b565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600062000362826200034b565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415620003985762000397620003a3565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b611a5b80620003e26000396000f3fe608060405234801561001057600080fd5b506004361061010b5760003560e01c8063614f427f116100a25780638da5cb5b116100715780638da5cb5b146102ff578063b0addede1461031d578063bac911ac1461034d578063e3064a771461037d578063eb12d61e146103ad5761010b565b8063614f427f146102485780636e417c6914610266578063736c0d5b1461029657806381d12c58146102c65761010b565b80631703a018116100de5780631703a018146101ac5780634797569a146101ca57806357ec347a146101fa57806358d71f82146102185761010b565b806302d947ef1461011057806306661abd1461014057806308ae63771461015e5780630e316ab71461017c575b600080fd5b61012a60048036038101906101259190611517565b6103dd565b6040516101379190611700565b60405180910390f35b61014861040c565b604051610155919061175b565b60405180910390f35b610166610412565b604051610173919061175b565b60405180910390f35b61019660048036038101906101919190611476565b61043d565b6040516101a3919061175b565b60405180910390f35b6101b4610638565b6040516101c1919061175b565b60405180910390f35b6101e460048036038101906101df91906114ee565b61063e565b6040516101f1919061175b565b60405180910390f35b610202610930565b60405161020f919061175b565b60405180910390f35b610232600480360381019061022d91906114ee565b610946565b60405161023f919061175b565b60405180910390f35b610250610b4b565b60405161025d919061175b565b60405180910390f35b610280600480360381019061027b91906114ee565b610b51565b60405161028d91906116e5565b60405180910390f35b6102b060048036038101906102ab9190611476565b610e2a565b6040516102bd91906116e5565b60405180910390f35b6102e060048036038101906102db91906114ee565b610e4a565b6040516102f69a99989796959493929190611776565b60405180910390f35b610307610f0b565b6040516103149190611693565b60405180910390f35b6103376004803603810190610332919061149f565b610f31565b604051610344919061175b565b60405180910390f35b610367600480360381019061036291906114ee565b61116f565b604051610374919061175b565b60405180910390f35b61039760048036038101906103929190611553565b6111ee565b6040516103a491906116e5565b60405180910390f35b6103c760048036038101906103c29190611476565b611274565b6040516103d4919061175b565b60405180910390f35b60006020528160005260406000206020528060005260406000206000915091509054906101000a900460000b81565b60055481565b6000806004546003546104259190611899565b1415610434576000905061043a565b60045490505b90565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141561049a57600080fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061052157508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b61052a57600080fd5b60011515600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615151461058757600080fd5b6000600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600860008154809291906105f290611955565b91905055507f3525e22824a8a7df2c9a6029941c824cf95b6447f1e13d5128fd3826d35afe8b826040516106269190611693565b60405180910390a16008549050919050565b60065481565b6000600960003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1661069657600080fd5b600080600084815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460000b60000b1461070257600080fd5b600060026000848152602001908152602001600020905060008160090160009054906101000a900460000b60000b1461073a57600080fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60008085815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908360000b60ff1602179055508060080160008154809291906107da9061197f565b9190505550806005015481600801546008546107f69190611899565b1415610881577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160090160006101000a81548160ff021916908360000b60ff160217905550610845836113de565b7f94064f919a02d0565c6790e0615fb4ba6cf1be1dd679f0161be914613a1b9bb583604051610874919061175b565b60405180910390a1610923565b6000816006015411801561089c575080600601548160080154145b15610922577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160090160006101000a81548160ff021916908360000b60ff1602179055506108ea836113de565b7f2ae00ba9813199478b6f22f0c9b606daa70f8efc319c8d2fa6af63f66ea3176383604051610919919061175b565b60405180910390a15b5b8060080154915050919050565b600060016003546109419190611899565b905090565b6000600960003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1661099e57600080fd5b600080600084815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460000b60000b14610a0a57600080fd5b600060026000848152602001908152602001600020905060008160090160009054906101000a900460000b60000b14610a4257600080fd5b600160008085815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908360000b60ff160217905550806007016000815480929190610ac39061197f565b919050555080600501548160070154600854610adf9190611899565b1415610b3e5760018160090160006101000a81548160ff021916908360000b60ff1602179055507f3ad93af63cb7967b23e4fb500b7d7d28b07516325dcf341f88bebf959d82c1cb83604051610b35919061175b565b60405180910390a15b8060070154915050919050565b60075481565b6000806002600084815260200190815260200160002090506000816000015411610bb0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ba79061171b565b60405180910390fd5b60018160090160009054906101000a900460000b60000b14610c07576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bfe9061173b565b60405180910390fd5b60028160090160006101000a81548160ff021916908360000b60ff1602179055506000808260030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168360010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168460020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168560040154604051602401610cc7939291906116ae565b6040516020818303038152906040527f23b872dd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610d51919061167c565b6000604051808303816000865af19150503d8060008114610d8e576040519150601f19603f3d011682016040523d82523d6000602084013e610d93565b606091505b5091509150610da583600001546113de565b8115610de7577fbcf6a68a2f901be4a23a41b53acd7697893a7e34def4e28acba584da75283b6785604051610dda919061175b565b60405180910390a1610e1f565b7fdab20a0fcd702cf875c2d715d5c3fc99af66a716c94b3405408c94b7311c99eb85604051610e16919061175b565b60405180910390a15b819350505050919050565b60096020528060005260406000206000915054906101000a900460ff1681565b60026020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060040154908060050154908060060154908060070154908060080154908060090160009054906101000a900460000b90508a565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060026000600354815260200190815260200160002090506003548160000181905550848160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550338160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550838160030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082816004018190555060065481600501819055506007548160060181905550600560008154809291906110519061197f565b9190505550600360008154809291906110699061197f565b91905055508060030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168260010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fb609ae609609ee99268d05bc1371102cafe8d6b964bf082439ab16be2a01c87c84600401548560000154604051611158929190611812565b60405180910390a480600001549150509392505050565b600080600060045490505b6003548110156111e25760006002600083815260200190815260200160002090506000816000015411156111ce57848314156111bf57806000015493505050506111e9565b82806111ca9061197f565b9350505b5080806111da9061197f565b91505061117a565b5060009150505b919050565b60006008548311156111ff57600080fd5b6000831161120c57600080fd5b60085482111561121b57600080fd5b82600681905550816007819055507f9f40cfd22fe91777c78f252bd21a710f3fb007dc2f321876891e7644ba0ae1756006546007546008546040516112629392919061183b565b60405180910390a16001905092915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146112d057600080fd5b60001515600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615151461132d57600080fd5b6001600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600860008154809291906113989061197f565b91905055507f47d1c22a25bb3a5d4e481b9b1e6944c2eade3181a0a20b495ed61d35b5323f24826040516113cc9190611693565b60405180910390a16008549050919050565b600560008154809291906113f190611955565b91905055506000600554111561143f5760045481141561143a576000611417600061116f565b9050600081141561143057600354600481905550611438565b806004819055505b505b611449565b6003546004819055505b50565b60008135905061145b816119f7565b92915050565b60008135905061147081611a0e565b92915050565b60006020828403121561148857600080fd5b60006114968482850161144c565b91505092915050565b6000806000606084860312156114b457600080fd5b60006114c28682870161144c565b93505060206114d38682870161144c565b92505060406114e486828701611461565b9150509250925092565b60006020828403121561150057600080fd5b600061150e84828501611461565b91505092915050565b6000806040838503121561152a57600080fd5b600061153885828601611461565b92505060206115498582860161144c565b9150509250929050565b6000806040838503121561156657600080fd5b600061157485828601611461565b925050602061158585828601611461565b9150509250929050565b611598816118cd565b82525050565b6115a7816118df565b82525050565b60006115b882611872565b6115c2818561187d565b93506115d2818560208601611922565b80840191505092915050565b6115e7816118eb565b82525050565b60006115fa601383611888565b91507f4552525f494e56414c49445f52455155455354000000000000000000000000006000830152602082019050919050565b600061163a601083611888565b91507f4552525f4e4f545f454e444f52534544000000000000000000000000000000006000830152602082019050919050565b61167681611918565b82525050565b600061168882846115ad565b915081905092915050565b60006020820190506116a8600083018461158f565b92915050565b60006060820190506116c3600083018661158f565b6116d0602083018561158f565b6116dd604083018461166d565b949350505050565b60006020820190506116fa600083018461159e565b92915050565b600060208201905061171560008301846115de565b92915050565b60006020820190508181036000830152611734816115ed565b9050919050565b600060208201905081810360008301526117548161162d565b9050919050565b6000602082019050611770600083018461166d565b92915050565b60006101408201905061178c600083018d61166d565b611799602083018c61158f565b6117a6604083018b61158f565b6117b3606083018a61158f565b6117c0608083018961166d565b6117cd60a083018861166d565b6117da60c083018761166d565b6117e760e083018661166d565b6117f561010083018561166d565b6118036101208301846115de565b9b9a5050505050505050505050565b6000604082019050611827600083018561166d565b611834602083018461166d565b9392505050565b6000606082019050611850600083018661166d565b61185d602083018561166d565b61186a604083018461166d565b949350505050565b600081519050919050565b600081905092915050565b600082825260208201905092915050565b60006118a482611918565b91506118af83611918565b9250828210156118c2576118c16119c8565b5b828203905092915050565b60006118d8826118f8565b9050919050565b60008115159050919050565b60008160000b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60005b83811015611940578082015181840152602081019050611925565b8381111561194f576000848401525b50505050565b600061196082611918565b91506000821415611974576119736119c8565b5b600182039050919050565b600061198a82611918565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156119bd576119bc6119c8565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b611a00816118cd565b8114611a0b57600080fd5b50565b611a1781611918565b8114611a2257600080fd5b5056fea2646970667358221220c17d0764fe33a9b1217529656b2598c39654db4c96db0c61f11c4057f0d608df64736f6c63430008000033 -\ No newline at end of file diff --git a/python/erc20_approval_escrow/runnable/deploy.py b/python/erc20_approval_escrow/runnable/deploy.py @@ -1,103 +0,0 @@ -"""Deploys erc20 approval escrow contract - -.. moduleauthor:: Louis Holbrook <dev@holbrook.no> -.. pgp:: 0826EDA1702D1E87C6E2875121D2E7BB88C2A746 - -""" - -# standard imports -import os -import json -import argparse -import logging - -# third-party imports -import web3 -from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer -from crypto_dev_signer.keystore import DictKeystore -from crypto_dev_signer.eth.helper import EthTxExecutor - -logging.basicConfig(level=logging.WARNING) -logg = logging.getLogger() - -logging.getLogger('web3').setLevel(logging.WARNING) -logging.getLogger('urllib3').setLevel(logging.WARNING) - -script_dir = os.path.dirname(__file__) -data_dir = os.path.join(script_dir, '..', 'data') - -argparser = argparse.ArgumentParser() -argparser.add_argument('-p', '--provider', dest='p', default='http://localhost:8545', type=str, help='Web3 provider url (http only)') -argparser.add_argument('-w', action='store_true', help='Wait for the last transaction to be confirmed') -argparser.add_argument('-ww', action='store_true', help='Wait for every transaction to be confirmed') -argparser.add_argument('-i', '--chain-spec', dest='i', type=str, default='Ethereum:1', help='Chain specification string') -argparser.add_argument('-a', '--signer-address', dest='a', type=str, help='Signer address') -argparser.add_argument('-y', '--key-file', dest='y', type=str, help='Ethereum keystore file to use for signing') -argparser.add_argument('--approver', action='append', type=str, help='approver to add') -argparser.add_argument('--abi-dir', dest='abi_dir', type=str, default=data_dir, help='Directory containing bytecode and abi (default: {})'.format(data_dir)) -argparser.add_argument('-v', action='store_true', help='Be verbose') -argparser.add_argument('-vv', action='store_true', help='Be more verbose') -args = argparser.parse_args() - -if args.vv: - logg.setLevel(logging.DEBUG) -elif args.v: - logg.setLevel(logging.INFO) - -block_last = args.w -block_all = args.ww - -w3 = web3.Web3(web3.Web3.HTTPProvider(args.p)) - -signer_address = None -keystore = DictKeystore() -if args.y != None: - logg.debug('loading keystore file {}'.format(args.y)) - signer_address = keystore.import_keystore_file(args.y) - logg.debug('now have key for signer address {}'.format(signer_address)) -signer = EIP155Signer(keystore) - -chain_pair = args.i.split(':') -chain_id = int(chain_pair[1]) - -helper = EthTxExecutor( - w3, - signer_address, - signer, - chain_id, - block=args.ww, - ) - - -def main(): - f = open(os.path.join(args.abi_dir, 'TransferApproval.json'), 'r') - abi = json.load(f) - f.close() - - f = open(os.path.join(args.abi_dir, 'TransferApproval.bin'), 'r') - bytecode = f.read() - f.close() - - c = w3.eth.contract(abi=abi, bytecode=bytecode) - - approvers = [signer_address] - if args.approver != None: - for a in args.approver: - approvers.append(a) - logg.info('add approver {}'.format(a)) - - #tx_hash = c.constructor(approvers).transact() - (tx_hash, rcpt) = helper.sign_and_send( - [ - c.constructor(approvers).buildTransaction - ], - force_wait=True, - ) - - address = rcpt.contractAddress - - print(address) - - -if __name__ == '__main__': - main() diff --git a/python/erc20_approval_escrow/__init__.py b/python/erc20_transfer_authorization/__init__.py diff --git a/python/erc20_approval_escrow/approval.py b/python/erc20_transfer_authorization/approval.py diff --git a/python/erc20_transfer_authorization/data/ERC20TransferAuthorization.bin b/python/erc20_transfer_authorization/data/ERC20TransferAuthorization.bin @@ -0,0 +1 @@ +60806040523480156200001157600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060016003819055506001600481905550600160068190555060016008819055506200008760016000620000a060201b60201c565b5062000099336200012b60201b60201c565b50620003d2565b6000600854831115620000b257600080fd5b60008311620000c057600080fd5b600854821115620000d057600080fd5b82600681905550816007819055507f9f40cfd22fe91777c78f252bd21a710f3fb007dc2f321876891e7644ba0ae1756006546007546008546040516200011993929190620002da565b60405180910390a16001905092915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146200018857600080fd5b60001515600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16151514620001e657600080fd5b6001600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555060086000815480929190620002539062000355565b91905055507f47d1c22a25bb3a5d4e481b9b1e6944c2eade3181a0a20b495ed61d35b5323f2482604051620002899190620002bd565b60405180910390a16008549050919050565b620002a68162000317565b82525050565b620002b7816200034b565b82525050565b6000602082019050620002d460008301846200029b565b92915050565b6000606082019050620002f16000830186620002ac565b620003006020830185620002ac565b6200030f6040830184620002ac565b949350505050565b600062000324826200032b565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600062000362826200034b565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415620003985762000397620003a3565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b611a8c80620003e26000396000f3fe608060405234801561001057600080fd5b506004361061010b5760003560e01c8063614f427f116100a25780638da5cb5b116100715780638da5cb5b146102ff578063b0addede1461031d578063bac911ac1461034d578063e3064a771461037d578063eb12d61e146103ad5761010b565b8063614f427f146102485780636e417c6914610266578063736c0d5b1461029657806381d12c58146102c65761010b565b80631703a018116100de5780631703a018146101ac5780634797569a146101ca57806357ec347a146101fa57806358d71f82146102185761010b565b806302d947ef1461011057806306661abd1461014057806308ae63771461015e5780630e316ab71461017c575b600080fd5b61012a60048036038101906101259190611548565b6103dd565b6040516101379190611731565b60405180910390f35b61014861040c565b604051610155919061178c565b60405180910390f35b610166610412565b604051610173919061178c565b60405180910390f35b610196600480360381019061019191906114a7565b61043d565b6040516101a3919061178c565b60405180910390f35b6101b4610638565b6040516101c1919061178c565b60405180910390f35b6101e460048036038101906101df919061151f565b61063e565b6040516101f1919061178c565b60405180910390f35b610202610930565b60405161020f919061178c565b60405180910390f35b610232600480360381019061022d919061151f565b610946565b60405161023f919061178c565b60405180910390f35b610250610b4b565b60405161025d919061178c565b60405180910390f35b610280600480360381019061027b919061151f565b610b51565b60405161028d9190611716565b60405180910390f35b6102b060048036038101906102ab91906114a7565b610e2a565b6040516102bd9190611716565b60405180910390f35b6102e060048036038101906102db919061151f565b610e4a565b6040516102f69a999897969594939291906117a7565b60405180910390f35b610307610f0b565b60405161031491906116c4565b60405180910390f35b610337600480360381019061033291906114d0565b610f31565b604051610344919061178c565b60405180910390f35b6103676004803603810190610362919061151f565b611190565b604051610374919061178c565b60405180910390f35b61039760048036038101906103929190611584565b61121f565b6040516103a49190611716565b60405180910390f35b6103c760048036038101906103c291906114a7565b6112a5565b6040516103d4919061178c565b60405180910390f35b60006020528160005260406000206020528060005260406000206000915091509054906101000a900460000b81565b60055481565b60008060045460035461042591906118ca565b1415610434576000905061043a565b60045490505b90565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141561049a57600080fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061052157508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b61052a57600080fd5b60011515600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615151461058757600080fd5b6000600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600860008154809291906105f290611986565b91905055507f3525e22824a8a7df2c9a6029941c824cf95b6447f1e13d5128fd3826d35afe8b8260405161062691906116c4565b60405180910390a16008549050919050565b60065481565b6000600960003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1661069657600080fd5b600080600084815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460000b60000b1461070257600080fd5b600060026000848152602001908152602001600020905060018160090160009054906101000a900460000b60000b1461073a57600080fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60008085815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908360000b60ff1602179055508060080160008154809291906107da906119b0565b9190505550806005015481600801546008546107f691906118ca565b1415610881577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160090160006101000a81548160ff021916908360000b60ff1602179055506108458361140f565b7f94064f919a02d0565c6790e0615fb4ba6cf1be1dd679f0161be914613a1b9bb583604051610874919061178c565b60405180910390a1610923565b6000816006015411801561089c575080600601548160080154145b15610922577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160090160006101000a81548160ff021916908360000b60ff1602179055506108ea8361140f565b7f2ae00ba9813199478b6f22f0c9b606daa70f8efc319c8d2fa6af63f66ea3176383604051610919919061178c565b60405180910390a15b5b8060080154915050919050565b6000600160035461094191906118ca565b905090565b6000600960003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1661099e57600080fd5b600080600084815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460000b60000b14610a0a57600080fd5b600060026000848152602001908152602001600020905060018160090160009054906101000a900460000b60000b14610a4257600080fd5b600160008085815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908360000b60ff160217905550806007016000815480929190610ac3906119b0565b919050555080600501548160070154600854610adf91906118ca565b1415610b3e5760028160090160006101000a81548160ff021916908360000b60ff1602179055507f3ad93af63cb7967b23e4fb500b7d7d28b07516325dcf341f88bebf959d82c1cb83604051610b35919061178c565b60405180910390a15b8060070154915050919050565b60075481565b6000806002600084815260200190815260200160002090506000816000015411610bb0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ba79061174c565b60405180910390fd5b60028160090160009054906101000a900460000b60000b14610c07576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bfe9061176c565b60405180910390fd5b60008160090160006101000a81548160ff021916908360000b60ff1602179055506000808260030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168360010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168460020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168560040154604051602401610cc7939291906116df565b6040516020818303038152906040527f23b872dd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610d5191906116ad565b6000604051808303816000865af19150503d8060008114610d8e576040519150601f19603f3d011682016040523d82523d6000602084013e610d93565b606091505b5091509150610da5836000015461140f565b8115610de7577fbcf6a68a2f901be4a23a41b53acd7697893a7e34def4e28acba584da75283b6785604051610dda919061178c565b60405180910390a1610e1f565b7fdab20a0fcd702cf875c2d715d5c3fc99af66a716c94b3405408c94b7311c99eb85604051610e16919061178c565b60405180910390a15b819350505050919050565b60096020528060005260406000206000915054906101000a900460ff1681565b60026020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060040154908060050154908060060154908060070154908060080154908060090160009054906101000a900460000b90508a565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060026000600354815260200190815260200160002090506003548160000181905550848160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550338160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550838160030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508281600401819055506006548160050181905550600754816006018190555060018160090160006101000a81548160ff021916908360000b60ff16021790555060056000815480929190611072906119b0565b91905055506003600081548092919061108a906119b0565b91905055508060030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168260010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fb609ae609609ee99268d05bc1371102cafe8d6b964bf082439ab16be2a01c87c84600401548560000154604051611179929190611843565b60405180910390a480600001549150509392505050565b600080600060045490505b60035481101561121357600060026000838152602001908152602001600020905060008160090160009054906101000a900460000b60000b13156111ff57848314156111f0578060000154935050505061121a565b82806111fb906119b0565b9350505b50808061120b906119b0565b91505061119b565b5060009150505b919050565b600060085483111561123057600080fd5b6000831161123d57600080fd5b60085482111561124c57600080fd5b82600681905550816007819055507f9f40cfd22fe91777c78f252bd21a710f3fb007dc2f321876891e7644ba0ae1756006546007546008546040516112939392919061186c565b60405180910390a16001905092915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461130157600080fd5b60001515600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615151461135e57600080fd5b6001600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600860008154809291906113c9906119b0565b91905055507f47d1c22a25bb3a5d4e481b9b1e6944c2eade3181a0a20b495ed61d35b5323f24826040516113fd91906116c4565b60405180910390a16008549050919050565b6005600081548092919061142290611986565b9190505550600060055411156114705760045481141561146b5760006114486000611190565b9050600081141561146157600354600481905550611469565b806004819055505b505b61147a565b6003546004819055505b50565b60008135905061148c81611a28565b92915050565b6000813590506114a181611a3f565b92915050565b6000602082840312156114b957600080fd5b60006114c78482850161147d565b91505092915050565b6000806000606084860312156114e557600080fd5b60006114f38682870161147d565b93505060206115048682870161147d565b925050604061151586828701611492565b9150509250925092565b60006020828403121561153157600080fd5b600061153f84828501611492565b91505092915050565b6000806040838503121561155b57600080fd5b600061156985828601611492565b925050602061157a8582860161147d565b9150509250929050565b6000806040838503121561159757600080fd5b60006115a585828601611492565b92505060206115b685828601611492565b9150509250929050565b6115c9816118fe565b82525050565b6115d881611910565b82525050565b60006115e9826118a3565b6115f381856118ae565b9350611603818560208601611953565b80840191505092915050565b6116188161191c565b82525050565b600061162b6013836118b9565b91507f4552525f494e56414c49445f52455155455354000000000000000000000000006000830152602082019050919050565b600061166b6010836118b9565b91507f4552525f4e4f545f454e444f52534544000000000000000000000000000000006000830152602082019050919050565b6116a781611949565b82525050565b60006116b982846115de565b915081905092915050565b60006020820190506116d960008301846115c0565b92915050565b60006060820190506116f460008301866115c0565b61170160208301856115c0565b61170e604083018461169e565b949350505050565b600060208201905061172b60008301846115cf565b92915050565b6000602082019050611746600083018461160f565b92915050565b600060208201905081810360008301526117658161161e565b9050919050565b600060208201905081810360008301526117858161165e565b9050919050565b60006020820190506117a1600083018461169e565b92915050565b6000610140820190506117bd600083018d61169e565b6117ca602083018c6115c0565b6117d7604083018b6115c0565b6117e4606083018a6115c0565b6117f1608083018961169e565b6117fe60a083018861169e565b61180b60c083018761169e565b61181860e083018661169e565b61182661010083018561169e565b61183461012083018461160f565b9b9a5050505050505050505050565b6000604082019050611858600083018561169e565b611865602083018461169e565b9392505050565b6000606082019050611881600083018661169e565b61188e602083018561169e565b61189b604083018461169e565b949350505050565b600081519050919050565b600081905092915050565b600082825260208201905092915050565b60006118d582611949565b91506118e083611949565b9250828210156118f3576118f26119f9565b5b828203905092915050565b600061190982611929565b9050919050565b60008115159050919050565b60008160000b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60005b83811015611971578082015181840152602081019050611956565b83811115611980576000848401525b50505050565b600061199182611949565b915060008214156119a5576119a46119f9565b5b600182039050919050565b60006119bb82611949565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156119ee576119ed6119f9565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b611a31816118fe565b8114611a3c57600080fd5b50565b611a4881611949565b8114611a5357600080fd5b5056fea26469706673582212209518b4dc715f5c2253f1cec97d24f2a17c9ec0cf4f89a44b63dee36379f7e3af64736f6c63430008000033 +\ No newline at end of file diff --git a/python/erc20_approval_escrow/data/TransferApproval.json b/python/erc20_transfer_authorization/data/ERC20TransferAuthorization.json diff --git a/python/erc20_approval_escrow/data/GiftableToken.bin b/python/erc20_transfer_authorization/data/GiftableToken.bin diff --git a/python/erc20_approval_escrow/data/GiftableToken.json b/python/erc20_transfer_authorization/data/GiftableToken.json diff --git a/python/erc20_transfer_authorization/runnable/deploy.py b/python/erc20_transfer_authorization/runnable/deploy.py @@ -0,0 +1,103 @@ +"""Deploys erc20 transfer authorization contract + +.. moduleauthor:: Louis Holbrook <dev@holbrook.no> +.. pgp:: 0826EDA1702D1E87C6E2875121D2E7BB88C2A746 + +""" + +# standard imports +import os +import json +import argparse +import logging + +# third-party imports +import web3 +from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer +from crypto_dev_signer.keystore import DictKeystore +from crypto_dev_signer.eth.helper import EthTxExecutor + +logging.basicConfig(level=logging.WARNING) +logg = logging.getLogger() + +logging.getLogger('web3').setLevel(logging.WARNING) +logging.getLogger('urllib3').setLevel(logging.WARNING) + +script_dir = os.path.dirname(__file__) +data_dir = os.path.join(script_dir, '..', 'data') + +argparser = argparse.ArgumentParser() +argparser.add_argument('-p', '--provider', dest='p', default='http://localhost:8545', type=str, help='Web3 provider url (http only)') +argparser.add_argument('-w', action='store_true', help='Wait for the last transaction to be confirmed') +argparser.add_argument('-ww', action='store_true', help='Wait for every transaction to be confirmed') +argparser.add_argument('-i', '--chain-spec', dest='i', type=str, default='Ethereum:1', help='Chain specification string') +argparser.add_argument('-a', '--signer-address', dest='a', type=str, help='Signer address') +argparser.add_argument('-y', '--key-file', dest='y', type=str, help='Ethereum keystore file to use for signing') +argparser.add_argument('--approver', action='append', type=str, help='approver to add') +argparser.add_argument('--abi-dir', dest='abi_dir', type=str, default=data_dir, help='Directory containing bytecode and abi (default: {})'.format(data_dir)) +argparser.add_argument('-v', action='store_true', help='Be verbose') +argparser.add_argument('-vv', action='store_true', help='Be more verbose') +args = argparser.parse_args() + +if args.vv: + logg.setLevel(logging.DEBUG) +elif args.v: + logg.setLevel(logging.INFO) + +block_last = args.w +block_all = args.ww + +w3 = web3.Web3(web3.Web3.HTTPProvider(args.p)) + +signer_address = None +keystore = DictKeystore() +if args.y != None: + logg.debug('loading keystore file {}'.format(args.y)) + signer_address = keystore.import_keystore_file(args.y) + logg.debug('now have key for signer address {}'.format(signer_address)) +signer = EIP155Signer(keystore) + +chain_pair = args.i.split(':') +chain_id = int(chain_pair[1]) + +helper = EthTxExecutor( + w3, + signer_address, + signer, + chain_id, + block=args.ww, + ) + + +def main(): + f = open(os.path.join(args.abi_dir, 'ERC20TransferAuthorization.json'), 'r') + abi = json.load(f) + f.close() + + f = open(os.path.join(args.abi_dir, 'ERC20TransferAuthorization.bin'), 'r') + bytecode = f.read() + f.close() + + c = w3.eth.contract(abi=abi, bytecode=bytecode) + + approvers = [signer_address] + if args.approver != None: + for a in args.approver: + approvers.append(a) + logg.info('add approver {}'.format(a)) + + #tx_hash = c.constructor(approvers).transact() + (tx_hash, rcpt) = helper.sign_and_send( + [ + c.constructor(approvers).buildTransaction + ], + force_wait=True, + ) + + address = rcpt.contractAddress + + print(address) + + +if __name__ == '__main__': + main() diff --git a/python/setup.cfg b/python/setup.cfg @@ -1,10 +1,10 @@ [metadata] -name = erc20-approval-escrow -version = 0.3.0a6 +name = erc20-transfer-authorization +version = 0.3.0a7 description = Simple approval escrow for ERC20 spend approval author = Louis Holbrook author_email = dev@holbrook.no -url = https://gitlab.com/nolash/simple-multisig +url = https://gitlab.com/nolash/erc20-transfer-authorization keywords = ethereum classifiers = @@ -24,17 +24,17 @@ licence_files = include_package_data = True python_requires = >= 3.6 packages = - erc20_approval_escrow - erc20_approval_escrow.runnable + erc20_transfer_authorization + erc20_transfer_authorization.runnable install_requires = web3==5.12.2 crypto-dev-signer~=0.4.13rc2 [options.package_data] * = - data/TransferApproval.json - data/TransferApproval.bin + data/TransferAuthorization.json + data/TransferAuthorization.bin [options.entry_points] console_scripts = - erc20-approval-escrow-deploy = erc20_approval_escrow.runnable.deploy:main + erc20-transfer-auth-deploy = erc20_transfer_authorization.runnable.deploy:main diff --git a/python/tests/base.py b/python/tests/base.py @@ -25,11 +25,11 @@ class TestBase(unittest.TestCase): 'gas_limit': 9000000, }) - f = open(os.path.join(testdir, '../erc20_approval_escrow/data/TransferApproval.bin'), 'r') + f = open(os.path.join(testdir, '../erc20_transfer_authorization/data/ERC20TransferAuthorization.bin'), 'r') bytecode = f.read() f.close() - f = open(os.path.join(testdir, '../erc20_approval_escrow/data/TransferApproval.json'), 'r') + f = open(os.path.join(testdir, '../erc20_transfer_authorization/data/ERC20TransferAuthorization.json'), 'r') self.abi_wallet = json.load(f) f.close() @@ -45,11 +45,11 @@ class TestBase(unittest.TestCase): self.address_wallet = r.contractAddress - f = open(os.path.join(testdir, '../erc20_approval_escrow/data/GiftableToken.bin'), 'r') + f = open(os.path.join(testdir, '../erc20_transfer_authorization/data/GiftableToken.bin'), 'r') bytecode = f.read() f.close() - f = open(os.path.join(testdir, '../erc20_approval_escrow/data/GiftableToken.json'), 'r') + f = open(os.path.join(testdir, '../erc20_transfer_authorization/data/GiftableToken.json'), 'r') self.abi_token = json.load(f) f.close() diff --git a/python/tests/test_app.py b/python/tests/test_app.py @@ -1,84 +1,24 @@ +# standard imports import os import unittest -import json import logging -import web3 -import eth_tester -import eth_abi +# testutil imports +from tests.base import TestBase -logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger() -logging.getLogger('web3').setLevel(logging.WARNING) -logging.getLogger('eth.vm').setLevel(logging.WARNING) - testdir = os.path.dirname(__file__) -class Test(unittest.TestCase): - - contract = None - - def setUp(self): - eth_params = eth_tester.backends.pyevm.main.get_default_genesis_params({ - 'gas_limit': 9000000, - }) - - f = open(os.path.join(testdir, '../erc20_approval_escrow/data/TransferApproval.bin'), 'r') - bytecode = f.read() - f.close() - - f = open(os.path.join(testdir, '../erc20_approval_escrow/data/TransferApproval.json'), 'r') - self.abi_wallet = json.load(f) - f.close() - - backend = eth_tester.PyEVMBackend(eth_params) - self.eth_tester = eth_tester.EthereumTester(backend) - provider = web3.Web3.EthereumTesterProvider(self.eth_tester) - self.w3 = web3.Web3(provider) - c = self.w3.eth.contract(abi=self.abi_wallet, bytecode=bytecode) - tx_hash = c.constructor().transact({'from': self.w3.eth.accounts[0]}) - - r = self.w3.eth.getTransactionReceipt(tx_hash) - - self.address_wallet = r.contractAddress - - - f = open(os.path.join(testdir, '../erc20_approval_escrow/data/GiftableToken.bin'), 'r') - bytecode = f.read() - f.close() - - f = open(os.path.join(testdir, '../erc20_approval_escrow/data/GiftableToken.json'), 'r') - self.abi_token = json.load(f) - f.close() - - c = self.w3.eth.contract(abi=self.abi_token, bytecode=bytecode) - tx_hash = c.constructor('Foo Token', 'FOO', 18).transact({'from': self.w3.eth.accounts[0]}) - - r = self.w3.eth.getTransactionReceipt(tx_hash) - - self.address_token = r.contractAddress - c = self.w3.eth.contract(abi=self.abi_token, address=self.address_token) - - tx_hash = c.functions.mint(1000).transact({'from': self.w3.eth.accounts[0]}) - tx_hash = c.functions.transfer(self.w3.eth.accounts[1], 100).transact({'from': self.w3.eth.accounts[0]}) - tx_hash = c.functions.transfer(self.w3.eth.accounts[2], 100).transact({'from': self.w3.eth.accounts[0]}) - tx_hash = c.functions.transfer(self.w3.eth.accounts[4], 100).transact({'from': self.w3.eth.accounts[0]}) - +class ERC20TransferAuthorizationBasicTest(TestBase): - def tearDown(self): - pass - - - @unittest.skip('foo') def test_basic(self): c = self.w3.eth.contract(abi=self.abi_wallet, address=self.address_wallet) self.assertTrue(c.functions.signers(self.w3.eth.accounts[0]).call()) self.assertFalse(c.functions.signers(self.w3.eth.accounts[1]).call()) - @unittest.skip('foo') 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) @@ -108,79 +48,6 @@ class Test(unittest.TestCase): assert (tqg[4] == 10*i) - - @unittest.skip('foo') - def test_approval_missing(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[3], t.address, 10).transact({'from': self.w3.eth.accounts[2]}) - r = self.w3.eth.getTransactionReceipt(tx_hash) - - topic_match = 'b609ae609609ee99268d05bc1371102cafe8d6b964bf082439ab16be2a01c87c' - log = r.logs[0] - topic = log.topics[0] - serial = int(log.data[66:], 16) - - #with self.assertRaises(eth_tester.exceptions.TransactionFailed): - with self.assertRaises(Exception): - w.functions.execute(serial).transact({'from': self.w3.eth.accounts[0]}) - - - @unittest.skip('foo') - def test_approval(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[3], t.address, 10).transact({'from': self.w3.eth.accounts[2]}) - 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(eth_tester.exceptions.TransactionFailed): - with self.assertRaises(Exception): - w.functions.execute(serial).transact({'from': self.w3.eth.accounts[3]}) - - tx_hashh = w.functions.executeRequest(serial).transact({'from': self.w3.eth.accounts[0]}) - r = self.w3.eth.getTransactionReceipt(tx_hashh) - - 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('foo') - def test_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() - - tx_hash = w.functions.createRequest(self.w3.eth.accounts[3], t.address, 10).transact({'from': self.w3.eth.accounts[2]}) - r = self.w3.eth.getTransactionReceipt(tx_hash) - - - topic_match = 'b609ae609609ee99268d05bc1371102cafe8d6b964bf082439ab16be2a01c87c' - log = r.logs[0] - topic = log.topics[0] - serial = int(log.data[66:], 16) - - tx_hash = w.functions.rejectRequest(serial).transact({'from': self.w3.eth.accounts[0]}) - r = self.w3.eth.getTransactionReceipt(tx_hash) - - self.assertEqual(t.functions.balanceOf(self.w3.eth.accounts[2]).call(), 100) - self.assertEqual(t.functions.balanceOf(self.w3.eth.accounts[3]).call(), 0) - self.assertEqual(t.functions.allowances(self.w3.eth.accounts[2], w.address).call(), 0) - - - @unittest.skip('foo') def test_indexes(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) @@ -189,18 +56,15 @@ class Test(unittest.TestCase): amount = 10*(i+1) sender = self.w3.eth.accounts[3+i]; tx_hash = w.functions.createRequest(sender, t.address, amount).transact({'from': self.w3.eth.accounts[2]}) - t.functions.approve(w.address, amount).transact({'from': sender}) - self.eth_tester.mine_block() - w.functions.rejectRequest(1).transact({'from': self.w3.eth.accounts[0]}) - w.functions.rejectRequest(4).transact({'from': self.w3.eth.accounts[0]}) + w.functions.nay(1).transact({'from': self.w3.eth.accounts[0]}) + w.functions.nay(4).transact({'from': self.w3.eth.accounts[0]}) assert w.functions.getSerialAt(0).call() == 2 assert w.functions.getSerialAt(1).call() == 3 assert w.functions.getSerialAt(2).call() == 5 - @unittest.skip('foo') def test_index_after_removal(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) @@ -209,43 +73,41 @@ class Test(unittest.TestCase): amount = 10*(i+1) sender = self.w3.eth.accounts[3+i]; tx_hash = w.functions.createRequest(sender, t.address, amount).transact({'from': self.w3.eth.accounts[2]}) - t.functions.approve(w.address, amount).transact({'from': sender}) - self.eth_tester.mine_block() tq_count = w.functions.count().call() - assert (tq_count == 4); - assert (w.functions.lastSerial().call() == 4) - assert (w.functions.nextSerial().call() == 1) + self.assertEqual(tq_count, 4); + self.assertEqual(w.functions.lastSerial().call(), 4) + self.assertEqual(w.functions.nextSerial().call(), 1) - w.functions.rejectRequest(2).transact({'from': self.w3.eth.accounts[0]}) - assert (w.functions.count(). call() == 3) - assert (w.functions.nextSerial().call() == 1) - assert (w.functions.lastSerial(). call() == 4) + w.functions.nay(2).transact({'from': self.w3.eth.accounts[0]}) + self.assertEqual(w.functions.count().call(), 3) + self.assertEqual(w.functions.nextSerial().call(), 1) + self.assertEqual(w.functions.lastSerial().call(), 4) - w.functions.rejectRequest(1).transact({'from': self.w3.eth.accounts[0]}) - assert (w.functions.count(). call() == 2) - assert (w.functions.nextSerial().call() == 3) - assert (w.functions.lastSerial(). call() == 4) + w.functions.nay(1).transact({'from': self.w3.eth.accounts[0]}) + self.assertEqual(w.functions.count().call(), 2) + self.assertEqual(w.functions.nextSerial().call(), 3) + self.assertEqual(w.functions.lastSerial().call(), 4) w.functions.createRequest(self.w3.eth.accounts[3], t.address, 42).transact({'from': self.w3.eth.accounts[2]}) - assert (w.functions.count(). call() == 3) - assert (w.functions.lastSerial(). call() == 5) - assert (w.functions.nextSerial(). call() == 3) + self.assertEqual(w.functions.count().call(), 3) + self.assertEqual(w.functions.lastSerial().call(), 5) + self.assertEqual(w.functions.nextSerial().call(), 3) - w.functions.rejectRequest(3).transact({'from': self.w3.eth.accounts[0]}) - assert (w.functions.count(). call() == 2) - assert (w.functions.lastSerial(). call() == 5) - assert (w.functions.nextSerial(). call() == 4) + w.functions.nay(3).transact({'from': self.w3.eth.accounts[0]}) + self.assertEqual(w.functions.count().call(), 2) + self.assertEqual(w.functions.lastSerial().call(), 5) + self.assertEqual(w.functions.nextSerial().call(), 4) - w.functions.rejectRequest(4).transact({'from': self.w3.eth.accounts[0]}) - assert (w.functions.count(). call() == 1) - assert (w.functions.nextSerial(). call() == 5) - assert (w.functions.lastSerial(). call() == 5) + w.functions.nay(4).transact({'from': self.w3.eth.accounts[0]}) + self.assertEqual(w.functions.count().call(), 1) + self.assertEqual(w.functions.nextSerial().call(), 5) + self.assertEqual(w.functions.lastSerial().call(), 5) - w.functions.rejectRequest(5).transact({'from': self.w3.eth.accounts[0]}) - assert (w.functions.count(). call() == 0) - assert (w.functions.nextSerial(). call() == 0) - assert (w.functions.lastSerial(). call() == 5) + w.functions.nay(5).transact({'from': self.w3.eth.accounts[0]}) + self.assertEqual(w.functions.count().call(), 0) + self.assertEqual(w.functions.nextSerial().call(), 0) + self.assertEqual(w.functions.lastSerial().call(), 5) def test_pass_on_insufficient_approve(self): @@ -255,6 +117,9 @@ class Test(unittest.TestCase): self.eth_tester.mine_block() w.functions.createRequest(self.w3.eth.accounts[3], t.address, 10).transact({'from': self.w3.eth.accounts[2]}) + w.functions.yay(1).transact({'from': self.w3.eth.accounts[0]}) + self.eth_tester.mine_block() + tx_hash = w.functions.executeRequest(1).transact({'from': self.w3.eth.accounts[0]}) r = self.w3.eth.getTransactionReceipt(tx_hash) @@ -265,10 +130,10 @@ class Test(unittest.TestCase): self.assertEqual(topic.hex()[2:], topic_match) serial = int(log.data[2:], 16) - assert serial == 1 + self.assertEqual(serial, 1) - assert w.functions.count().call() == 0 - assert w.functions.nextSerial().call() == 0 + self.assertEqual(w.functions.count().call(), 0) + self.assertEqual(w.functions.nextSerial().call(), 0) if __name__ == '__main__': diff --git a/solidity/ERC20TransferAuthorization.sol b/solidity/ERC20TransferAuthorization.sol @@ -0,0 +1,208 @@ +pragma solidity >0.6.11; + +// SPDX-License-Identifier: GPL-3.0-or-later + +contract ERC20ApprovalEscrow { + struct Transaction { + uint256 serial; + address sender; + address recipient; + address token; + uint256 value; + uint256 quorum; + uint256 vetoThreshold; + uint256 yay; + uint256 nay; + int8 result; // -1 rejected/vetoed, 0 = completed, 1 = voting, 2 = approved + } + + mapping ( uint256 => mapping ( address => int8 )) public vote; + address public owner; + mapping(uint256 => Transaction) public requests; + uint256 hi; + uint256 lo; + uint256 public count; + uint256 public quorum; + uint256 public vetoThreshold; + uint256 signerCount; + + mapping(address => bool) public signers; + + event NewRequest(address indexed _sender, address indexed _recipient, address indexed _token, uint256 _value, uint256 _serial); + event Executed(uint256 _serial); + event TransferFail(uint256 _serial); + event QuorumSet(uint256 _quorum, uint256 _vetoThreshold, uint256 _signerCount); + event SignerAdded(address _signer); + event SignerRemoved(address _signer); + event Vetoed(uint256 _serial); + event Approved(uint256 _serial); + event Rejected(uint256 _serial); + + constructor() public { + owner = msg.sender; + hi = 1; + lo = 1; + quorum = 1; + signerCount = 1; + setThresholds(1, 0); + addSigner(msg.sender); + } + + function addSigner(address _signer) public returns (uint256) { + require(msg.sender == owner); + require(signers[_signer] == false); + + signers[_signer] = true; + signerCount++; + emit SignerAdded(_signer); + return signerCount; + } + + function removeSigner(address _signer) public returns (uint256) { + require(_signer != owner); + require(msg.sender == owner || msg.sender == _signer); + require(signers[_signer] == true); + + signers[_signer] = false; + signerCount--; + emit SignerRemoved(_signer); + return signerCount; + } + + function setThresholds(uint256 _quorum, uint256 _vetoThreshold) public returns (bool) { + require(_quorum <= signerCount); + require(_quorum > 0); + require(_vetoThreshold <= signerCount); + + quorum = _quorum; + vetoThreshold = _vetoThreshold; + emit QuorumSet(quorum, vetoThreshold, signerCount); + return true; + } + + function createRequest(address _recipient, address _token, uint256 _value) public returns (uint256) { + Transaction storage txx = requests[hi]; + + txx.serial = hi; + txx.recipient = _recipient; + txx.sender = msg.sender; + txx.token = _token; + txx.value = _value; + txx.quorum = quorum; + txx.vetoThreshold = vetoThreshold; + txx.result = 1; + + count++; + hi++; + + emit NewRequest(txx.sender, txx.recipient, txx.token, txx.value, txx.serial); + + return txx.serial; + } + + function removeItem(uint256 serialToRemove) private { + count--; + + if (count > 0) { + if (serialToRemove == lo) { + uint256 i; + i = getSerialAt(0); + if (i == 0) { + lo = hi; + } else { + lo = i; + } + } + } else { + lo = hi; + } + } + + function lastSerial() public view returns ( uint256 ) { + return hi - 1; + } + + function nextSerial() public view returns ( uint256 ) { + if (hi - lo == 0) { + return 0; + } + return lo; + } + + function getSerialAt(uint256 _idx) public view returns ( uint256 ) { + uint256 i; + for (uint256 j = lo; j < hi; j++) { + Transaction storage txx = requests[j]; + if (txx.result > 0) { + if (i == _idx) { + return txx.serial; + } + i++; + } + } + return 0; + } + + function yay(uint256 _serial) public returns (uint256) { + require(signers[msg.sender]); + require(vote[_serial][msg.sender] == 0); + + Transaction storage txx = requests[_serial]; + require(txx.result == 1); + + vote[_serial][msg.sender] = 1; + txx.yay++; + + if (signerCount - txx.yay == txx.quorum) { + txx.result = 2; + emit Approved(_serial); + } + + return txx.yay; + } + + function nay(uint256 _serial) public returns (uint256) { + require(signers[msg.sender]); + require(vote[_serial][msg.sender] == 0); + + Transaction storage txx = requests[_serial]; + require(txx.result == 1); + + + vote[_serial][msg.sender] = -1; + txx.nay++; + + if (signerCount - txx.nay == txx.quorum) { + txx.result = -1; + removeItem(_serial); + emit Rejected(_serial); + } else if (txx.vetoThreshold > 0 && txx.nay == txx.vetoThreshold) { + txx.result = -1; + removeItem(_serial); + emit Vetoed(_serial); + } + + return txx.nay; + } + + function executeRequest(uint256 _serial) public returns (bool) { + Transaction storage txx = requests[_serial]; + + require(txx.serial > 0, 'ERR_INVALID_REQUEST'); + require(txx.result == 2, 'ERR_NOT_ENDORSED'); + + txx.result = 0; + + (bool success, bytes memory _r) = txx.token.call(abi.encodeWithSignature("transferFrom(address,address,uint256)", txx.sender, txx.recipient, txx.value)); + + removeItem(txx.serial); + + if (success) { + emit Executed(_serial); + } else { + emit TransferFail(_serial); + } + + return success; + } +} diff --git a/solidity/Makefile b/solidity/Makefile @@ -1,9 +1,9 @@ SOLC = /usr/bin/solc all: - $(SOLC) --bin TransferApproval.sol | awk 'NR>3' > TransferApproval.bin - truncate -s -1 TransferApproval.bin - $(SOLC) --abi TransferApproval.sol | awk 'NR>3' > TransferApproval.json + $(SOLC) --bin ERC20TransferAuthorization.sol | awk 'NR>3' > ERC20TransferAuthorization.bin + truncate -s -1 ERC20TransferAuthorization.bin + $(SOLC) --abi ERC20TransferAuthorization.sol | awk 'NR>3' > ERC20TransferAuthorization.json install: all - cp -v *{json,bin} ../python/erc20_approval_escrow/data/ + cp -v *{json,bin} ../python/erc20_transfer_authorization/data/ diff --git a/solidity/TransferApproval.bin b/solidity/TransferApproval.bin @@ -1 +0,0 @@ -60806040523480156200001157600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060016003819055506001600481905550600160068190555060016008819055506200008760016000620000a060201b60201c565b5062000099336200012b60201b60201c565b50620003d2565b6000600854831115620000b257600080fd5b60008311620000c057600080fd5b600854821115620000d057600080fd5b82600681905550816007819055507f9f40cfd22fe91777c78f252bd21a710f3fb007dc2f321876891e7644ba0ae1756006546007546008546040516200011993929190620002da565b60405180910390a16001905092915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146200018857600080fd5b60001515600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16151514620001e657600080fd5b6001600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555060086000815480929190620002539062000355565b91905055507f47d1c22a25bb3a5d4e481b9b1e6944c2eade3181a0a20b495ed61d35b5323f2482604051620002899190620002bd565b60405180910390a16008549050919050565b620002a68162000317565b82525050565b620002b7816200034b565b82525050565b6000602082019050620002d460008301846200029b565b92915050565b6000606082019050620002f16000830186620002ac565b620003006020830185620002ac565b6200030f6040830184620002ac565b949350505050565b600062000324826200032b565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600062000362826200034b565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415620003985762000397620003a3565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b611a5b80620003e26000396000f3fe608060405234801561001057600080fd5b506004361061010b5760003560e01c8063614f427f116100a25780638da5cb5b116100715780638da5cb5b146102ff578063b0addede1461031d578063bac911ac1461034d578063e3064a771461037d578063eb12d61e146103ad5761010b565b8063614f427f146102485780636e417c6914610266578063736c0d5b1461029657806381d12c58146102c65761010b565b80631703a018116100de5780631703a018146101ac5780634797569a146101ca57806357ec347a146101fa57806358d71f82146102185761010b565b806302d947ef1461011057806306661abd1461014057806308ae63771461015e5780630e316ab71461017c575b600080fd5b61012a60048036038101906101259190611517565b6103dd565b6040516101379190611700565b60405180910390f35b61014861040c565b604051610155919061175b565b60405180910390f35b610166610412565b604051610173919061175b565b60405180910390f35b61019660048036038101906101919190611476565b61043d565b6040516101a3919061175b565b60405180910390f35b6101b4610638565b6040516101c1919061175b565b60405180910390f35b6101e460048036038101906101df91906114ee565b61063e565b6040516101f1919061175b565b60405180910390f35b610202610930565b60405161020f919061175b565b60405180910390f35b610232600480360381019061022d91906114ee565b610946565b60405161023f919061175b565b60405180910390f35b610250610b4b565b60405161025d919061175b565b60405180910390f35b610280600480360381019061027b91906114ee565b610b51565b60405161028d91906116e5565b60405180910390f35b6102b060048036038101906102ab9190611476565b610e2a565b6040516102bd91906116e5565b60405180910390f35b6102e060048036038101906102db91906114ee565b610e4a565b6040516102f69a99989796959493929190611776565b60405180910390f35b610307610f0b565b6040516103149190611693565b60405180910390f35b6103376004803603810190610332919061149f565b610f31565b604051610344919061175b565b60405180910390f35b610367600480360381019061036291906114ee565b61116f565b604051610374919061175b565b60405180910390f35b61039760048036038101906103929190611553565b6111ee565b6040516103a491906116e5565b60405180910390f35b6103c760048036038101906103c29190611476565b611274565b6040516103d4919061175b565b60405180910390f35b60006020528160005260406000206020528060005260406000206000915091509054906101000a900460000b81565b60055481565b6000806004546003546104259190611899565b1415610434576000905061043a565b60045490505b90565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141561049a57600080fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061052157508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b61052a57600080fd5b60011515600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615151461058757600080fd5b6000600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600860008154809291906105f290611955565b91905055507f3525e22824a8a7df2c9a6029941c824cf95b6447f1e13d5128fd3826d35afe8b826040516106269190611693565b60405180910390a16008549050919050565b60065481565b6000600960003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1661069657600080fd5b600080600084815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460000b60000b1461070257600080fd5b600060026000848152602001908152602001600020905060008160090160009054906101000a900460000b60000b1461073a57600080fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60008085815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908360000b60ff1602179055508060080160008154809291906107da9061197f565b9190505550806005015481600801546008546107f69190611899565b1415610881577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160090160006101000a81548160ff021916908360000b60ff160217905550610845836113de565b7f94064f919a02d0565c6790e0615fb4ba6cf1be1dd679f0161be914613a1b9bb583604051610874919061175b565b60405180910390a1610923565b6000816006015411801561089c575080600601548160080154145b15610922577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160090160006101000a81548160ff021916908360000b60ff1602179055506108ea836113de565b7f2ae00ba9813199478b6f22f0c9b606daa70f8efc319c8d2fa6af63f66ea3176383604051610919919061175b565b60405180910390a15b5b8060080154915050919050565b600060016003546109419190611899565b905090565b6000600960003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1661099e57600080fd5b600080600084815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460000b60000b14610a0a57600080fd5b600060026000848152602001908152602001600020905060008160090160009054906101000a900460000b60000b14610a4257600080fd5b600160008085815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908360000b60ff160217905550806007016000815480929190610ac39061197f565b919050555080600501548160070154600854610adf9190611899565b1415610b3e5760018160090160006101000a81548160ff021916908360000b60ff1602179055507f3ad93af63cb7967b23e4fb500b7d7d28b07516325dcf341f88bebf959d82c1cb83604051610b35919061175b565b60405180910390a15b8060070154915050919050565b60075481565b6000806002600084815260200190815260200160002090506000816000015411610bb0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ba79061171b565b60405180910390fd5b60018160090160009054906101000a900460000b60000b14610c07576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bfe9061173b565b60405180910390fd5b60028160090160006101000a81548160ff021916908360000b60ff1602179055506000808260030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168360010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168460020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168560040154604051602401610cc7939291906116ae565b6040516020818303038152906040527f23b872dd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610d51919061167c565b6000604051808303816000865af19150503d8060008114610d8e576040519150601f19603f3d011682016040523d82523d6000602084013e610d93565b606091505b5091509150610da583600001546113de565b8115610de7577fbcf6a68a2f901be4a23a41b53acd7697893a7e34def4e28acba584da75283b6785604051610dda919061175b565b60405180910390a1610e1f565b7fdab20a0fcd702cf875c2d715d5c3fc99af66a716c94b3405408c94b7311c99eb85604051610e16919061175b565b60405180910390a15b819350505050919050565b60096020528060005260406000206000915054906101000a900460ff1681565b60026020528060005260406000206000915090508060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060040154908060050154908060060154908060070154908060080154908060090160009054906101000a900460000b90508a565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060026000600354815260200190815260200160002090506003548160000181905550848160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550338160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550838160030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082816004018190555060065481600501819055506007548160060181905550600560008154809291906110519061197f565b9190505550600360008154809291906110699061197f565b91905055508060030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168260010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fb609ae609609ee99268d05bc1371102cafe8d6b964bf082439ab16be2a01c87c84600401548560000154604051611158929190611812565b60405180910390a480600001549150509392505050565b600080600060045490505b6003548110156111e25760006002600083815260200190815260200160002090506000816000015411156111ce57848314156111bf57806000015493505050506111e9565b82806111ca9061197f565b9350505b5080806111da9061197f565b91505061117a565b5060009150505b919050565b60006008548311156111ff57600080fd5b6000831161120c57600080fd5b60085482111561121b57600080fd5b82600681905550816007819055507f9f40cfd22fe91777c78f252bd21a710f3fb007dc2f321876891e7644ba0ae1756006546007546008546040516112629392919061183b565b60405180910390a16001905092915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146112d057600080fd5b60001515600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615151461132d57600080fd5b6001600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600860008154809291906113989061197f565b91905055507f47d1c22a25bb3a5d4e481b9b1e6944c2eade3181a0a20b495ed61d35b5323f24826040516113cc9190611693565b60405180910390a16008549050919050565b600560008154809291906113f190611955565b91905055506000600554111561143f5760045481141561143a576000611417600061116f565b9050600081141561143057600354600481905550611438565b806004819055505b505b611449565b6003546004819055505b50565b60008135905061145b816119f7565b92915050565b60008135905061147081611a0e565b92915050565b60006020828403121561148857600080fd5b60006114968482850161144c565b91505092915050565b6000806000606084860312156114b457600080fd5b60006114c28682870161144c565b93505060206114d38682870161144c565b92505060406114e486828701611461565b9150509250925092565b60006020828403121561150057600080fd5b600061150e84828501611461565b91505092915050565b6000806040838503121561152a57600080fd5b600061153885828601611461565b92505060206115498582860161144c565b9150509250929050565b6000806040838503121561156657600080fd5b600061157485828601611461565b925050602061158585828601611461565b9150509250929050565b611598816118cd565b82525050565b6115a7816118df565b82525050565b60006115b882611872565b6115c2818561187d565b93506115d2818560208601611922565b80840191505092915050565b6115e7816118eb565b82525050565b60006115fa601383611888565b91507f4552525f494e56414c49445f52455155455354000000000000000000000000006000830152602082019050919050565b600061163a601083611888565b91507f4552525f4e4f545f454e444f52534544000000000000000000000000000000006000830152602082019050919050565b61167681611918565b82525050565b600061168882846115ad565b915081905092915050565b60006020820190506116a8600083018461158f565b92915050565b60006060820190506116c3600083018661158f565b6116d0602083018561158f565b6116dd604083018461166d565b949350505050565b60006020820190506116fa600083018461159e565b92915050565b600060208201905061171560008301846115de565b92915050565b60006020820190508181036000830152611734816115ed565b9050919050565b600060208201905081810360008301526117548161162d565b9050919050565b6000602082019050611770600083018461166d565b92915050565b60006101408201905061178c600083018d61166d565b611799602083018c61158f565b6117a6604083018b61158f565b6117b3606083018a61158f565b6117c0608083018961166d565b6117cd60a083018861166d565b6117da60c083018761166d565b6117e760e083018661166d565b6117f561010083018561166d565b6118036101208301846115de565b9b9a5050505050505050505050565b6000604082019050611827600083018561166d565b611834602083018461166d565b9392505050565b6000606082019050611850600083018661166d565b61185d602083018561166d565b61186a604083018461166d565b949350505050565b600081519050919050565b600081905092915050565b600082825260208201905092915050565b60006118a482611918565b91506118af83611918565b9250828210156118c2576118c16119c8565b5b828203905092915050565b60006118d8826118f8565b9050919050565b60008115159050919050565b60008160000b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60005b83811015611940578082015181840152602081019050611925565b8381111561194f576000848401525b50505050565b600061196082611918565b91506000821415611974576119736119c8565b5b600182039050919050565b600061198a82611918565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156119bd576119bc6119c8565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b611a00816118cd565b8114611a0b57600080fd5b50565b611a1781611918565b8114611a2257600080fd5b5056fea2646970667358221220c17d0764fe33a9b1217529656b2598c39654db4c96db0c61f11c4057f0d608df64736f6c63430008000033 -\ No newline at end of file diff --git a/solidity/TransferApproval.json b/solidity/TransferApproval.json @@ -1 +0,0 @@ -[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_serial","type":"uint256"}],"name":"Approved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_serial","type":"uint256"}],"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":"uint256","name":"_serial","type":"uint256"}],"name":"NewRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_quorum","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_vetoThreshold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_signerCount","type":"uint256"}],"name":"QuorumSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_serial","type":"uint256"}],"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":"uint256","name":"_serial","type":"uint256"}],"name":"TransferFail","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_serial","type":"uint256"}],"name":"Vetoed","type":"event"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"addSigner","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"count","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"createRequest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_serial","type":"uint256"}],"name":"executeRequest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_idx","type":"uint256"}],"name":"getSerialAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastSerial","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_serial","type":"uint256"}],"name":"nay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nextSerial","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quorum","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"removeSigner","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"requests","outputs":[{"internalType":"uint256","name":"serial","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"quorum","type":"uint256"},{"internalType":"uint256","name":"vetoThreshold","type":"uint256"},{"internalType":"uint256","name":"yay","type":"uint256"},{"internalType":"uint256","name":"nay","type":"uint256"},{"internalType":"int8","name":"result","type":"int8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_quorum","type":"uint256"},{"internalType":"uint256","name":"_vetoThreshold","type":"uint256"}],"name":"setThresholds","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","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":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"vote","outputs":[{"internalType":"int8","name":"","type":"int8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_serial","type":"uint256"}],"name":"yay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}] diff --git a/solidity/TransferApproval.sol b/solidity/TransferApproval.sol @@ -1,207 +0,0 @@ -pragma solidity >0.6.11; - -// SPDX-License-Identifier: GPL-3.0-or-later - -contract ERC20ApprovalEscrow { - struct Transaction { - uint256 serial; - address sender; - address recipient; - address token; - uint256 value; - uint256 quorum; - uint256 vetoThreshold; - uint256 yay; - uint256 nay; - int8 result; // -1 rejected/vetoed, 0 = voting, 1 = approved, 2 = completed - } - - mapping ( uint256 => mapping ( address => int8 )) public vote; - address public owner; - mapping(uint256 => Transaction) public requests; - uint256 hi; - uint256 lo; - uint256 public count; - uint256 public quorum; - uint256 public vetoThreshold; - uint256 signerCount; - - mapping(address => bool) public signers; - - event NewRequest(address indexed _sender, address indexed _recipient, address indexed _token, uint256 _value, uint256 _serial); - event Executed(uint256 _serial); - event TransferFail(uint256 _serial); - event QuorumSet(uint256 _quorum, uint256 _vetoThreshold, uint256 _signerCount); - event SignerAdded(address _signer); - event SignerRemoved(address _signer); - event Vetoed(uint256 _serial); - event Approved(uint256 _serial); - event Rejected(uint256 _serial); - - constructor() public { - owner = msg.sender; - hi = 1; - lo = 1; - quorum = 1; - signerCount = 1; - setThresholds(1, 0); - addSigner(msg.sender); - } - - function addSigner(address _signer) public returns (uint256) { - require(msg.sender == owner); - require(signers[_signer] == false); - - signers[_signer] = true; - signerCount++; - emit SignerAdded(_signer); - return signerCount; - } - - function removeSigner(address _signer) public returns (uint256) { - require(_signer != owner); - require(msg.sender == owner || msg.sender == _signer); - require(signers[_signer] == true); - - signers[_signer] = false; - signerCount--; - emit SignerRemoved(_signer); - return signerCount; - } - - function setThresholds(uint256 _quorum, uint256 _vetoThreshold) public returns (bool) { - require(_quorum <= signerCount); - require(_quorum > 0); - require(_vetoThreshold <= signerCount); - - quorum = _quorum; - vetoThreshold = _vetoThreshold; - emit QuorumSet(quorum, vetoThreshold, signerCount); - return true; - } - - function createRequest(address _recipient, address _token, uint256 _value) public returns (uint256) { - Transaction storage txx = requests[hi]; - - txx.serial = hi; - txx.recipient = _recipient; - txx.sender = msg.sender; - txx.token = _token; - txx.value = _value; - txx.quorum = quorum; - txx.vetoThreshold = vetoThreshold; - - count++; - hi++; - - emit NewRequest(txx.sender, txx.recipient, txx.token, txx.value, txx.serial); - - return txx.serial; - } - - function removeItem(uint256 serialToRemove) private { - count--; - - if (count > 0) { - if (serialToRemove == lo) { - uint256 i; - i = getSerialAt(0); - if (i == 0) { - lo = hi; - } else { - lo = i; - } - } - } else { - lo = hi; - } - } - - function lastSerial() public view returns ( uint256 ) { - return hi - 1; - } - - function nextSerial() public view returns ( uint256 ) { - if (hi - lo == 0) { - return 0; - } - return lo; - } - - function getSerialAt(uint256 _idx) public view returns ( uint256 ) { - uint256 i; - for (uint256 j = lo; j < hi; j++) { - Transaction storage txx = requests[j]; - if (txx.serial > 0) { - if (i == _idx) { - return txx.serial; - } - i++; - } - } - return 0; - } - - function yay(uint256 _serial) public returns (uint256) { - require(signers[msg.sender]); - require(vote[_serial][msg.sender] == 0); - - Transaction storage txx = requests[_serial]; - require(txx.result == 0); - - vote[_serial][msg.sender] = 1; - txx.yay++; - - if (signerCount - txx.yay == txx.quorum) { - txx.result = 1; - emit Approved(_serial); - } - - return txx.yay; - } - - function nay(uint256 _serial) public returns (uint256) { - require(signers[msg.sender]); - require(vote[_serial][msg.sender] == 0); - - Transaction storage txx = requests[_serial]; - require(txx.result == 0); - - - vote[_serial][msg.sender] = -1; - txx.nay++; - - if (signerCount - txx.nay == txx.quorum) { - txx.result = -1; - removeItem(_serial); - emit Rejected(_serial); - } else if (txx.vetoThreshold > 0 && txx.nay == txx.vetoThreshold) { - txx.result = -1; - removeItem(_serial); - emit Vetoed(_serial); - } - - return txx.nay; - } - - function executeRequest(uint256 _serial) public returns (bool) { - Transaction storage txx = requests[_serial]; - - require(txx.serial > 0, 'ERR_INVALID_REQUEST'); - require(txx.result == 1, 'ERR_NOT_ENDORSED'); - - txx.result = 2; - - (bool success, bytes memory _r) = txx.token.call(abi.encodeWithSignature("transferFrom(address,address,uint256)", txx.sender, txx.recipient, txx.value)); - - removeItem(txx.serial); - - if (success) { - emit Executed(_serial); - } else { - emit TransferFail(_serial); - } - - return success; - } -}