encode.py (7307B)
1 # SPDX-License-Identifier: GPL-3.0-or-later 2 3 # standard imports 4 import io 5 import sys 6 import os 7 import json 8 import argparse 9 import logging 10 import urllib 11 import sha3 12 13 # external imports 14 #from chainlib.cli import flag_reset 15 from chainlib.settings import ChainSettings 16 from funga.eth.signer import EIP155Signer 17 from funga.eth.keystore.dict import DictKeystore 18 from hexathon import ( 19 add_0x, 20 strip_0x, 21 ) 22 23 # local imports 24 import chainlib.eth.cli 25 from chainlib.eth.cli.arg import ( 26 Arg, 27 ArgFlag, 28 process_args, 29 ) 30 from chainlib.eth.cli.config import ( 31 Config, 32 process_config, 33 ) 34 from chainlib.eth.cli.log import process_log 35 from chainlib.eth.cli.encode import CLIEncoder 36 from chainlib.eth.constant import ZERO_ADDRESS 37 from chainlib.eth.address import to_checksum 38 from chainlib.eth.connection import EthHTTPConnection 39 from chainlib.eth.settings import process_settings 40 from chainlib.jsonrpc import ( 41 JSONRPCRequest, 42 IntSequenceGenerator, 43 ) 44 from chainlib.eth.tx import ( 45 TxFactory, 46 TxFormat, 47 raw, 48 ) 49 from chainlib.error import SignerMissingException 50 from chainlib.chain import ChainSpec 51 from chainlib.eth.jsonrpc import to_blockheight_param 52 from chainlib.eth.address import to_checksum_address 53 54 logging.basicConfig(level=logging.WARNING) 55 logg = logging.getLogger() 56 57 script_dir = os.path.dirname(os.path.realpath(__file__)) 58 config_dir = os.path.join(script_dir, '..', 'data', 'config') 59 60 61 def process_config_local(config, arg, args, flags): 62 config.add(args.signature, '_SIGNATURE', False) 63 config.add(args.contract_args, '_CONTRACT_ARGS', False) 64 # workaround to avoid rpc lookup of fee parameters when using arg mode 65 if args.mode == 'arg': 66 config.add(0, '_FEE_PRICE', True) 67 config.add(0, '_FEE_LIMIT', True) 68 return config 69 70 arg_flags = ArgFlag() 71 arg = Arg(arg_flags) 72 flags = arg_flags.STD_WRITE | arg_flags.EXEC | arg_flags.FEE | arg_flags.FMT_HUMAN | arg_flags.FMT_WIRE | arg_flags.FMT_RPC 73 74 argparser = chainlib.eth.cli.ArgumentParser() 75 argparser = process_args(argparser, arg, flags) 76 argparser.add_argument('--mode', type=str, choices=['tx', 'call', 'arg'], help='Mode of operation') 77 argparser.add_argument('--signature', type=str, help='Method signature to encode') 78 argparser.add_argument('contract_args', type=str, nargs='*', help='arguments to encode') 79 args = argparser.parse_args() 80 81 logg = process_log(args, logg) 82 83 config = Config() 84 config = process_config(config, arg, args, flags) 85 config = process_config_local(config, arg, args, flags) 86 logg.debug('config loaded:\n{}'.format(config)) 87 88 settings = ChainSettings() 89 settings = process_settings(settings, config) 90 logg.debug('settings loaded:\n{}'.format(settings)) 91 92 93 def main(): 94 95 signer_address = ZERO_ADDRESS 96 signer = None 97 conn = settings.get('CONN') 98 signer_address = settings.get('SENDER_ADDRESS') 99 100 code = '0x' 101 cli_encoder = CLIEncoder(signature=config.get('_SIGNATURE')) 102 103 for arg in config.get('_CONTRACT_ARGS'): 104 cli_encoder.add_from(arg) 105 106 code += cli_encoder.get() 107 108 exec_address = config.get('_EXEC_ADDRESS') 109 if exec_address: 110 exec_address = add_0x(to_checksum_address(exec_address)) 111 112 mode = args.mode 113 if mode == None: 114 if signer == None: 115 mode = 'call' 116 else: 117 mode = 'tx' 118 119 if not config.get('_SIGNATURE'): 120 if mode != 'arg': 121 logg.error('mode tx without contract method signature makes no sense. Use eth-get with --data instead.') 122 sys.exit(1) 123 124 if mode == 'arg': 125 print(strip_0x(code)) 126 return 127 elif not exec_address: 128 logg.error('exec address (-e) must be defined with mode "{}"'.format(args.mode)) 129 sys.exit(1) 130 131 if config.get('RPC_PROVIDER'): 132 logg.debug('provider {}'.format(config.get('RPC_PROVIDER'))) 133 if not config.get('_FEE_LIMIT') or not config.get('_FEE_PRICE'): 134 #gas_oracle = rpc.get_gas_oracle() 135 gas_oracle = settings.get('GAS_ORACLE') 136 (price, limit) = gas_oracle.get_gas() 137 if not config.get('_FEE_PRICE'): 138 config.add(price, '_FEE_PRICE') 139 if not config.get('_FEE_LIMIT'): 140 config.add(limit, '_FEE_LIMIT') 141 142 if mode == 'tx': 143 if not config.get('_NONCE'): 144 nonce_oracle = settings.get('NONCE_ORACLE') #rpc.get_nonce_oracle() 145 config.add(nonce_oracle.get_nonce(), '_NONCE') 146 else: 147 for arg in [ 148 '_FEE_PRICE', 149 '_FEE_LIMIT', 150 '_NONCE', 151 ]: 152 if not config.get(arg): 153 logg.error('--{} must be specified when no rpc provider has been set.'.format(arg.replace('_', '-').lower())) 154 sys.exit(1) 155 156 157 if mode == 'call': #signer == None or config.true('_NOTX'): 158 c = TxFactory(settings.get('CHAIN_SPEC')) 159 j = JSONRPCRequest(id_generator=settings.get('RPC_ID_GENERATOR')) 160 o = j.template() 161 gas_limit = add_0x(int.to_bytes(config.get('_FEE_LIMIT'), 8, byteorder='big').hex(), compact_value=True) 162 gas_price = add_0x(int.to_bytes(config.get('_FEE_PRICE'), 8, byteorder='big').hex(), compact_value=True) 163 o['method'] = 'eth_call' 164 o['params'].append({ 165 'to': exec_address, 166 'from': signer_address, 167 'value': '0x0', 168 'gas': gas_limit, # TODO: better get of network gas limit 169 'gasPrice': gas_price, 170 'data': add_0x(code), 171 }) 172 height = to_blockheight_param(config.get('_HEIGHT')) 173 o['params'].append(height) 174 o = j.finalize(o) 175 176 if settings.get('RPC_SEND'): 177 r = conn.do(o) 178 try: 179 print(strip_0x(r)) 180 return 181 except ValueError: 182 sys.stderr.write('query returned an empty value ({})\n'.format(r)) 183 sys.exit(1) 184 else: 185 print(o) 186 return 187 188 if settings.get('SIGNER') == None: 189 logg.error('mode "tx" without signer does not make sense. Please specify a key file with -y.') 190 sys.exit(1) 191 192 if settings.get('CHAIN_SPEC') == None: 193 raise ValueError('chain spec must be specified') 194 195 c = TxFactory( 196 settings.get('CHAIN_SPEC'), 197 signer=settings.get('SIGNER'), 198 gas_oracle=settings.get('FEE_ORACLE'), 199 nonce_oracle=settings.get('NONCE_ORACLE'), 200 ) 201 202 tx = c.template( 203 settings.get('SENDER_ADDRESS'), 204 settings.get('EXEC'), 205 use_nonce=True, 206 ) 207 tx = c.set_code(tx, code) 208 tx_format = TxFormat.JSONRPC 209 if config.get('_RAW'): 210 tx_format = TxFormat.RLP_SIGNED 211 (tx_hash_hex, o) = c.finalize(tx, tx_format=tx_format) 212 if settings.get('RPC_SEND'): 213 r = conn.do(o) 214 if settings.get('WAIT'): 215 r = conn.wait(tx_hash_hex) 216 if r['status'] == 0: 217 logg.critical('VM revert. Wish I could tell you more') 218 sys.exit(1) 219 print(tx_hash_hex) 220 else: 221 if config.get('_RAW'): 222 o = strip_0x(o) 223 print(o) 224 225 if __name__ == '__main__': 226 main()