From 5be31a697fad12392cd842b061ffe5fe2377b1ec Mon Sep 17 00:00:00 2001 From: nolash Date: Mon, 22 Mar 2021 14:56:27 +0100 Subject: [PATCH] Rehabilitate runnables --- python/giftable_erc20_token/__init__.py | 1 + python/giftable_erc20_token/factory.py | 19 +-- python/giftable_erc20_token/runnable/add.py | 80 ++++++------- .../giftable_erc20_token/runnable/deploy.py | 108 +++++++----------- python/giftable_erc20_token/runnable/gift.py | 84 +++++++------- 5 files changed, 135 insertions(+), 157 deletions(-) create mode 100644 python/giftable_erc20_token/__init__.py diff --git a/python/giftable_erc20_token/__init__.py b/python/giftable_erc20_token/__init__.py new file mode 100644 index 0000000..5b84fe5 --- /dev/null +++ b/python/giftable_erc20_token/__init__.py @@ -0,0 +1 @@ +from .factory import GiftableToken diff --git a/python/giftable_erc20_token/factory.py b/python/giftable_erc20_token/factory.py index 8e89bed..2158781 100644 --- a/python/giftable_erc20_token/factory.py +++ b/python/giftable_erc20_token/factory.py @@ -7,14 +7,12 @@ from chainlib.eth.tx import ( TxFactory, TxFormat, ) -from chainlib.eth.encoding import abi_encode_hex from chainlib.hash import keccak256_string_to_hex from chainlib.eth.contract import ( ABIContractEncoder, ABIContractType, ) - # local imports from giftable_erc20_token.data import data_dir @@ -26,15 +24,22 @@ class GiftableToken(TxFactory): __abi = None __bytecode = None - def constructor(self, sender_address, name, symbol, decimals): + def constructor(self, sender_address, name, symbol, decimals, tx_format=TxFormat.JSONRPC): code = GiftableToken.bytecode() - - tx = self.template(sender_address, '0x', use_nonce=True) - code += abi_encode_hex('(string,string,uint8)', [name, symbol, decimals]) + enc = ABIContractEncoder() + enc.string(name) + enc.string(symbol) + enc.uint256(decimals) + code += enc.get() + tx = self.template(sender_address, None, use_nonce=True) tx = self.set_code(tx, code) - return self.build(tx) + return self.finalize(tx, tx_format) + @staticmethod + def gas(code=None): + return 1200000 + @staticmethod def abi(): if GiftableToken.__abi == None: diff --git a/python/giftable_erc20_token/runnable/add.py b/python/giftable_erc20_token/runnable/add.py index 9a9b50e..aa84d92 100644 --- a/python/giftable_erc20_token/runnable/add.py +++ b/python/giftable_erc20_token/runnable/add.py @@ -16,19 +16,20 @@ import logging import time # third-party imports -import web3 -from eth_keys import keys +from chainlib.eth.connection import EthHTTPConnection 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 +from crypto_dev_signer.keystore.dict import DictKeystore +from chainlib.eth.nonce import RPCNonceOracle +from chainlib.eth.gas import RPCGasOracle from chainlib.chain import ChainSpec +from chainlib.eth.tx import receipt + +# local imports +from giftable_erc20_token import GiftableToken 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') @@ -40,68 +41,63 @@ argparser.add_argument('-ww', action='store_true', help='Wait for every transact argparser.add_argument('-i', '--chain-spec', dest='i', type=str, default='Ethereum:1', help='Chain specification string') argparser.add_argument('-a', '--token-address', required='True', dest='a', type=str, help='Giftable token address') argparser.add_argument('-y', '--key-file', dest='y', type=str, help='Ethereum keystore file to use for signing') -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') +argparser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration') argparser.add_argument('minter_address', type=str, help='Minter address to add') args = argparser.parse_args() -if args.v: +if args.vv: logg.setLevel(logging.DEBUG) +elif args.v: + logg.setLevel(logging.INFO) block_all = args.ww block_last = args.w or block_all -w3 = web3.Web3(web3.Web3.HTTPProvider(args.p)) +passphrase_env = 'ETH_PASSPHRASE' +if args.env_prefix != None: + passphrase_env = args.env_prefix + '_' + passphrase_env +passphrase = os.environ.get(passphrase_env) +if passphrase == None: + logg.warning('no passphrase given') + passphrase='' 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) + signer_address = keystore.import_keystore_file(args.y, password=passphrase) logg.debug('now have key for signer address {}'.format(signer_address)) signer = EIP155Signer(keystore) chain_spec = ChainSpec.from_chain_str(args.i) chain_id = chain_spec.network_id() -helper = EthTxExecutor( - w3, - signer_address, - signer, - chain_id, - block=args.ww, - ) +rpc = EthHTTPConnection(args.p) +nonce_oracle = RPCNonceOracle(signer_address, rpc) +gas_oracle = RPCGasOracle(rpc, code_callback=GiftableToken.gas) + +token_address = args.a +minter_address = args.minter_address def main(): + c = GiftableToken(signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle) + (tx_hash_hex, o) = c.add_minter(token_address, signer_address, minter_address) + rpc.do(o) + o = receipt(tx_hash_hex) + r = rpc.do(o) + if r['status'] == 0: + sys.stderr.write('EVM revert. Wish I had more to tell you') + sys.exit(1) - f = open(os.path.join(args.abi_dir, 'GiftableToken.json'), 'r') - abi = json.load(f) - f.close() - - gas_price = w3.eth.gasPrice - - last_tx = None - - nonce = w3.eth.getTransactionCount(signer_address, 'pending') - - c = w3.eth.contract(abi=abi, address=args.a) - - if not web3.Web3.isChecksumAddress(args.minter_address): - raise ValueError('Minter is not a valid address {}'.format(args.minter_address)) - - (tx_hash, rcpt) = helper.sign_and_send( - [ - c.functions.addMinter(args.minter_address).buildTransaction, - ], - ) - - logg.info('addMinter to {} tx {}'.format(signer_address, tx_hash)) + logg.info('add minter {} to {} tx {}'.format(minter_address, token_address, tx_hash_hex)) if block_last: - helper.wait_for() + rpc.wait(o) - print(tx_hash) + print(tx_hash_hex) sys.exit(0) diff --git a/python/giftable_erc20_token/runnable/deploy.py b/python/giftable_erc20_token/runnable/deploy.py index abaf759..fe1af53 100644 --- a/python/giftable_erc20_token/runnable/deploy.py +++ b/python/giftable_erc20_token/runnable/deploy.py @@ -17,18 +17,20 @@ import time from enum import Enum # external 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 +from crypto_dev_signer.keystore.dict import DictKeystore from chainlib.chain import ChainSpec +from chainlib.eth.nonce import RPCNonceOracle +from chainlib.eth.gas import RPCGasOracle +from chainlib.eth.connection import EthHTTPConnection +from chainlib.eth.tx import receipt + +# local imports +from giftable_erc20_token import GiftableToken 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') @@ -40,89 +42,65 @@ argparser.add_argument('-ww', action='store_true', help='Wait for every transact argparser.add_argument('-e', action='store_true', help='Treat all transactions as essential') argparser.add_argument('-i', '--chain-spec', dest='i', type=str, default='evm:ethereum:1', help='Chain specification string') argparser.add_argument('-y', '--key-file', dest='y', type=str, help='Ethereum keystore file to use for signing') -argparser.add_argument('--name', dest='n', default='Giftable Token', type=str, help='Token name') -argparser.add_argument('--symbol', dest='s', default='GFT', type=str, help='Token symbol') -argparser.add_argument('--decimals', dest='d', default=18, type=int, help='Token decimals') -argparser.add_argument('--account', action='append', type=str, help='Account to fund') -argparser.add_argument('--minter', action='append', type=str, help='Minter 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('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration') +argparser.add_argument('--name', default='Giftable Token', type=str, help='Token name') +argparser.add_argument('--symbol', default='GFT', type=str, help='Token symbol') +argparser.add_argument('--decimals', default=18, type=int, help='Token decimals') argparser.add_argument('-v', action='store_true', help='Be verbose') +argparser.add_argument('-vv', action='store_true', help='Be more verbose') argparser.add_argument('amount', type=int, help='Initial token supply (will be owned by contract creator)') args = argparser.parse_args() -if args.v: +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)) +passphrase_env = 'ETH_PASSPHRASE' +if args.env_prefix != None: + passphrase_env = args.env_prefix + '_' + passphrase_env +passphrase = os.environ.get(passphrase_env) +if passphrase == None: + logg.warning('no passphrase given') + passphrase='' 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) + signer_address = keystore.import_keystore_file(args.y, password=passphrase) logg.debug('now have key for signer address {}'.format(signer_address)) signer = EIP155Signer(keystore) chain_spec = ChainSpec.from_chain_str(args.i) chain_id = chain_spec.network_id() -helper = EthTxExecutor( - w3, - signer_address, - signer, - chain_id, - block=args.ww, - ) +rpc = EthHTTPConnection(args.p) +nonce_oracle = RPCNonceOracle(signer_address, rpc) +gas_oracle = RPCGasOracle(rpc, code_callback=GiftableToken.gas) + +token_name = args.name +token_symbol = args.symbol +token_decimals = args.decimals + def main(): - - f = open(os.path.join(args.abi_dir, 'GiftableToken.json'), 'r') - abi = json.load(f) - f.close() - - f = open(os.path.join(args.abi_dir, 'GiftableToken.bin'), 'r') - bytecode = f.read() - f.close() - - c = w3.eth.contract(abi=abi, bytecode=bytecode) - (tx_hash, rcpt) = helper.sign_and_send( - [ - c.constructor(args.n, args.s, args.d).buildTransaction - ], - force_wait=True, - ) - logg.debug('tx hash {} rcpt {}'.format(tx_hash, rcpt)) - - address = rcpt.contractAddress - logg.debug('token contract mined {} {} {} {}'.format(address, args.n, args.s, args.d)) - c = w3.eth.contract(abi=abi, address=address) - - balance = c.functions.balanceOf(signer_address).call() - logg.info('balance {}: {} {}'.format(signer_address, balance, tx_hash)) - - if args.minter != None: - for a in args.minter: - if a == signer_address: - continue - (tx_hash, rcpt) = helper.sign_and_send( - [ - c.functions.addMinter(a).buildTransaction, - ], - ) - - if args.account != None: - for a in args.account: - (tx_hash, rcpt) = helper.sign_and_send( - [ - c.functions.mintTo(a, args.amount).buildTransaction, - ], - ) + c = GiftableToken(signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle) + (tx_hash_hex, o) = c.constructor(signer_address, token_name, token_symbol, token_decimals) + rpc.do(o) + o = receipt(tx_hash_hex) + r = rpc.do(o) + if r['status'] == 0: + sys.stderr.write('EVM revert while deploying contract. Wish I had more to tell you') + sys.exit(1) + # TODO: pass through translator for keys (evm tester uses underscore instead of camelcase) + address = r['contractAddress'] if block_last: - helper.wait_for() + rpc.wait(tx_hash_hex) print(address) diff --git a/python/giftable_erc20_token/runnable/gift.py b/python/giftable_erc20_token/runnable/gift.py index 8ac71cf..a8d8b57 100644 --- a/python/giftable_erc20_token/runnable/gift.py +++ b/python/giftable_erc20_token/runnable/gift.py @@ -16,19 +16,20 @@ import logging import time # third-party imports -import web3 -from eth_keys import keys 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 +from crypto_dev_signer.keystore.dict import DictKeystore +from chainlib.eth.tx import receipt from chainlib.chain import ChainSpec +from chainlib.eth.nonce import RPCNonceOracle +from chainlib.eth.gas import RPCGasOracle +from chainlib.eth.connection import EthHTTPConnection + +# local imports +from giftable_erc20_token import GiftableToken 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') @@ -40,70 +41,67 @@ argparser.add_argument('-ww', action='store_true', help='Wait for every transact argparser.add_argument('-i', '--chain-spec', dest='i', type=str, default='Ethereum:1', help='Chain specification string') argparser.add_argument('-a', '--token-address', required='True', dest='a', type=str, help='Giftable token address') argparser.add_argument('-y', '--key-file', dest='y', type=str, help='Ethereum keystore file to use for signing') -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') +argparser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration') argparser.add_argument('--recipient', type=str, help='Recipient account address. If not set, tokens will be gifted to the keystore account') -argparser.add_argument('amount', type=int, help='Amount of tokens to mint and gift') +argparser.add_argument('value', type=int, help='Value of tokens to mint and gift') args = argparser.parse_args() -if args.v: +if args.vv: logg.setLevel(logging.DEBUG) +elif args.v: + logg.setLevel(logging.INFO) block_all = args.ww block_last = args.w or block_all -w3 = web3.Web3(web3.Web3.HTTPProvider(args.p)) +passphrase_env = 'ETH_PASSPHRASE' +if args.env_prefix != None: + passphrase_env = args.env_prefix + '_' + passphrase_env +passphrase = os.environ.get(passphrase_env) +if passphrase == None: + logg.warning('no passphrase given') + passphrase='' 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) + signer_address = keystore.import_keystore_file(args.y, password=passphrase) logg.debug('now have key for signer address {}'.format(signer_address)) signer = EIP155Signer(keystore) chain_spec = ChainSpec.from_chain_str(args.i) chain_id = chain_spec.network_id() -helper = EthTxExecutor( - w3, - signer_address, - signer, - chain_id, - block=args.ww, - ) +rpc = EthHTTPConnection(args.p) +nonce_oracle = RPCNonceOracle(signer_address, rpc) +gas_oracle = RPCGasOracle(rpc, code_callback=GiftableToken.gas) + +token_address = args.a +recipient_address = args.recipient +if recipient_address == None: + recipient_address = signer_address +token_value = args.value def main(): + c = GiftableToken(signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle) + (tx_hash_hex, o) = c.mint_to(token_address, signer_address, recipient_address, token_value) + rpc.do(o) + o = receipt(tx_hash_hex) + r = rpc.do(o) + if r['status'] == 0: + sys.stderr.write('EVM revert. Wish I had more to tell you') + sys.exit(1) - f = open(os.path.join(args.abi_dir, 'GiftableToken.json'), 'r') - abi = json.load(f) - f.close() - - gas_price = w3.eth.gasPrice - - last_tx = None - - nonce = w3.eth.getTransactionCount(signer_address, 'pending') - - c = w3.eth.contract(abi=abi, address=args.a) - - recipient = signer_address - if args.recipient != None: - recipient = args.recipient - - (tx_hash, rcpt) = helper.sign_and_send( - [ - c.functions.mintTo(args.recipient, args.amount).buildTransaction, - ], - ) - - logg.info('mint to {} tx {}'.format(signer_address, tx_hash)) + logg.info('mint to {} tx {}'.format(recipient_address, tx_hash_hex)) if block_last: helper.wait_for() - print(tx_hash) + print(tx_hash_hex) sys.exit(0)