From b6c285c02ae0a9851e44f529f31182f2e425a06d Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Thu, 20 Mar 2025 08:48:03 +0300 Subject: [PATCH] proto.eth.contract: relocate methods --- mmgen/proto/eth/contract.py | 97 ++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 49 deletions(-) diff --git a/mmgen/proto/eth/contract.py b/mmgen/proto/eth/contract.py index 8871fa57..bd75eaee 100755 --- a/mmgen/proto/eth/contract.py +++ b/mmgen/proto/eth/contract.py @@ -36,6 +36,9 @@ def parse_abi(s): class Contract: + def strip(self, s): + return ''.join([chr(b) for b in s if 32 <= b <= 127]).strip() + def create_method_id(self, sig): return self.keccak_256(sig.encode()).hexdigest()[:8] @@ -47,6 +50,9 @@ class Contract: int(parse_abi(data)[-1], 16) * self.base_unit, from_decimal = True) + async def code(self): + return (await self.rpc.call('eth_getCode', '0x'+self.addr))[2:] + async def do_call(self, method_sig, method_args='', *, toUnit=False): data = self.create_method_id(method_sig) + method_args if self.cfg.debug: @@ -60,14 +66,52 @@ class Contract: else: return ret + async def txsign(self, tx_in, key, from_addr, *, chain_id=None): + + from .pyethereum.transactions import Transaction + + if chain_id is None: + res = await self.rpc.call('eth_chainId') + chain_id = None if res is None else int(res, 16) + + etx = Transaction(**tx_in).sign(key, chain_id) + + if etx.sender.hex() != from_addr: + die(3, f'Sender address {from_addr!r} does not match address of key {etx.sender.hex()!r}!') + + if self.cfg.debug: + msg('TOKEN DATA:') + pp_msg(etx.to_dict()) + msg('PARSED ABI DATA:\n {}'.format( + '\n '.join(parse_abi(etx.data.hex())))) + + return namedtuple('signed_contract_transaction', ['etx', 'txhex', 'txid'])( + etx, + rlp.encode(etx).hex(), + CoinTxID(etx.hash.hex())) + + async def txsend(self, txhex): + return (await self.rpc.call('eth_sendRawTransaction', '0x'+txhex)).replace('0x', '', 1) + +class Token(Contract): + + def __init__(self, cfg, proto, addr, decimals, *, rpc=None): + if type(self).__name__ == 'Token': + from ...util2 import get_keccak + self.keccak_256 = get_keccak(cfg) + self.cfg = cfg + self.proto = proto + self.addr = TokenAddr(proto, addr) + assert isinstance(decimals, int), f'decimals param must be int instance, not {type(decimals)}' + self.decimals = decimals + self.base_unit = Decimal('10') ** -self.decimals + self.rpc = rpc + async def get_balance(self, acct_addr): return self.proto.coin_amt( await self.do_call('balanceOf(address)', acct_addr.rjust(64, '0'), toUnit=True), from_decimal = True) - def strip(self, s): - return ''.join([chr(b) for b in s if 32 <= b <= 127]).strip() - async def get_name(self): return self.strip(bytes.fromhex((await self.do_call('name()'))[2:])) @@ -94,9 +138,6 @@ class Contract: 'decimals:', self.decimals, 'total supply:', await self.get_total_supply()) - async def code(self): - return (await self.rpc.call('eth_getCode', '0x'+self.addr))[2:] - def create_data( self, to_addr, @@ -129,35 +170,7 @@ class Contract: 'nonce': nonce, 'data': bytes.fromhex(data)} - async def txsign(self, tx_in, key, from_addr, *, chain_id=None): - - from .pyethereum.transactions import Transaction - - if chain_id is None: - res = await self.rpc.call('eth_chainId') - chain_id = None if res is None else int(res, 16) - - etx = Transaction(**tx_in).sign(key, chain_id) - - if etx.sender.hex() != from_addr: - die(3, f'Sender address {from_addr!r} does not match address of key {etx.sender.hex()!r}!') - - if self.cfg.debug: - msg('TOKEN DATA:') - pp_msg(etx.to_dict()) - msg('PARSED ABI DATA:\n {}'.format( - '\n '.join(parse_abi(etx.data.hex())))) - - return namedtuple('signed_contract_transaction', ['etx', 'txhex', 'txid'])( - etx, - rlp.encode(etx).hex(), - CoinTxID(etx.hash.hex())) - -# The following are used for token deployment only: - - async def txsend(self, txhex): - return (await self.rpc.call('eth_sendRawTransaction', '0x'+txhex)).replace('0x', '', 1) - + # used for token deployment only: async def transfer( self, from_addr, @@ -178,20 +191,6 @@ class Contract: res = await self.txsign(tx_in, key, from_addr) return await self.txsend(res.txhex) -class Token(Contract): - - def __init__(self, cfg, proto, addr, decimals, *, rpc=None): - if type(self).__name__ == 'Token': - from ...util2 import get_keccak - self.keccak_256 = get_keccak(cfg) - self.cfg = cfg - self.proto = proto - self.addr = TokenAddr(proto, addr) - assert isinstance(decimals, int), f'decimals param must be int instance, not {type(decimals)}' - self.decimals = decimals - self.base_unit = Decimal('10') ** -self.decimals - self.rpc = rpc - class ResolvedToken(Token, metaclass=AsyncInit): async def __init__(self, cfg, proto, rpc, addr):