new class: ETCAmt; ETHAmt -> proto.coin_amt

This commit is contained in:
The MMGen Project 2022-12-03 17:40:43 +00:00
commit 8b6bdc72ca
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
12 changed files with 45 additions and 39 deletions

View file

@ -191,3 +191,6 @@ class ETHAmt(CoinAmt):
def toWei(self):
return int(Decimal(self) // self.wei)
class ETCAmt(ETHAmt):
coin = 'ETC'

View file

@ -17,6 +17,7 @@ from ..eth.params import mainnet
class mainnet(mainnet):
chain_names = ['classic','ethereum_classic']
max_tx_fee = '0.005'
coin_amt = 'ETCAmt'
ignore_daemon_version = False
class testnet(mainnet):

View file

@ -29,7 +29,6 @@ from ...globalvars import g
from ...base_obj import AsyncInit
from ...obj import MMGenObject,CoinTxID
from ...addr import CoinAddr,TokenAddr
from ...amt import ETHAmt
def parse_abi(s):
return [s[:8]] + [s[8+x*64:8+(x+1)*64] for x in range(len(s[8:])//64)]
@ -43,7 +42,7 @@ class TokenCommon(MMGenObject):
return CoinAddr(self.proto,parse_abi(data)[1][-40:])
def transferdata2amt(self,data): # online
return ETHAmt(int(parse_abi(data)[-1],16) * self.base_unit)
return self.proto.coin_amt(int(parse_abi(data)[-1],16) * self.base_unit)
async def do_call(self,method_sig,method_args='',toUnit=False):
data = self.create_method_id(method_sig) + method_args
@ -59,7 +58,7 @@ class TokenCommon(MMGenObject):
return ret
async def get_balance(self,acct_addr):
return ETHAmt(await self.do_call('balanceOf(address)',acct_addr.rjust(64,'0'),toUnit=True))
return self.proto.coin_amt(await self.do_call('balanceOf(address)',acct_addr.rjust(64,'0'),toUnit=True))
def strip(self,s):
return ''.join([chr(b) for b in s if 32 <= b <= 127]).strip()

View file

@ -23,7 +23,6 @@ proto.eth.tw.ctl: Ethereum tracking wallet control class
from ....util import msg,ymsg,die
from ....tw.ctl import TwCtl,write_mode
from ....addr import is_coin_addr,is_mmgen_id
from ....amt import ETHAmt
from ..contract import Token,TokenResolve
class EthereumTwCtl(TwCtl):
@ -82,7 +81,7 @@ class EthereumTwCtl(TwCtl):
msg(f'{self.desc} upgraded successfully!')
async def rpc_get_balance(self,addr):
return ETHAmt(int(await self.rpc.call('eth_getBalance','0x'+addr,'latest'),16),'wei')
return self.proto.coin_amt(int(await self.rpc.call('eth_getBalance','0x'+addr,'latest'),16),'wei')
@write_mode
async def batch_import_address(self,args_list):

View file

@ -143,5 +143,4 @@ class EthereumTwJSON(TwJSON):
@property
async def total(self):
from ....amt import ETHAmt
return sum(ETHAmt(i.amount) for i in self.entries['accounts']) or ETHAmt('0')
return sum(self.proto.coin_amt(i.amount) for i in self.entries['accounts']) or self.proto.coin_amt('0')

View file

@ -15,7 +15,6 @@ proto.eth.tx.base: Ethereum base transaction class
from collections import namedtuple
import mmgen.tx.base as TxBase
from ....amt import ETHAmt
from ....obj import HexStr,Int
from ....util import dmsg
@ -24,23 +23,23 @@ class Base(TxBase.Base):
rel_fee_desc = 'gas price'
rel_fee_disp = 'gas price in Gwei'
txobj = None # ""
gas = ETHAmt(21000,'wei') # an approximate number, used for fee estimation purposes
start_gas = ETHAmt(21000,'wei') # the actual startgas amt used in the transaction
# for simple sends with no data, gas = start_gas = 21000
dfl_gas = 21000 # an approximate number, used for fee estimation purposes
dfl_start_gas = 21000 # the actual startgas amt used in the transaction
# for simple sends with no data, gas = start_gas = 21000
contract_desc = 'contract'
usr_contract_data = HexStr('')
disable_fee_check = False
# given absolute fee in ETH, return gas price in Gwei using self.gas
def fee_abs2rel(self,abs_fee,to_unit='Gwei'):
ret = ETHAmt(int(abs_fee.toWei() // self.gas.toWei()),'wei')
ret = self.proto.coin_amt(int(abs_fee.toWei() // self.gas.toWei()),'wei')
dmsg(f'fee_abs2rel() ==> {ret} ETH')
return ret if to_unit == 'eth' else ret.to_unit(to_unit,show_decimal=True)
# given rel fee (gasPrice) in wei, return absolute fee using self.gas (Ethereum-only method)
def fee_gasPrice2abs(self,rel_fee):
assert isinstance(rel_fee,int), f'{rel_fee!r}: incorrect type for fee estimate (not an integer)'
return ETHAmt(rel_fee * self.gas.toWei(),'wei')
return self.proto.coin_amt(rel_fee * self.gas.toWei(),'wei')
def is_replaceable(self):
return True
@ -54,7 +53,7 @@ class Base(TxBase.Base):
status = Int(rx['status'],16), # zero is failure, non-zero success
gas_sent = Int(tx['gas'],16),
gas_used = Int(rx['gasUsed'],16),
gas_price = ETHAmt(int(tx['gasPrice'],16),from_unit='wei'),
gas_price = self.proto.coin_amt(int(tx['gasPrice'],16),from_unit='wei'),
contract_addr = self.proto.coin_addr(rx['contractAddress'][2:]) if rx['contractAddress'] else None,
tx = tx,
rx = rx,
@ -64,6 +63,6 @@ class Base(TxBase.Base):
return True
class TokenBase(Base):
gas = ETHAmt(52000,'wei')
start_gas = ETHAmt(60000,'wei')
dfl_gas = 52000
dfl_start_gas = 60000
contract_desc = 'token contract'

View file

@ -15,7 +15,6 @@ proto.eth.tx.bump: Ethereum transaction bump class
import mmgen.tx.bump as TxBase
from .completed import Completed,TokenCompleted
from .new import New,TokenNew
from ....amt import ETHAmt
from decimal import Decimal
class Bump(Completed,New,TxBase.Bump):
@ -23,7 +22,7 @@ class Bump(Completed,New,TxBase.Bump):
@property
def min_fee(self):
return ETHAmt(self.fee * Decimal('1.101'))
return self.proto.coin_amt(self.fee * Decimal('1.101'))
def bump_fee(self,idx,fee):
self.txobj['gasPrice'] = self.fee_abs2rel(fee,to_unit='eth')

View file

@ -18,6 +18,13 @@ from .base import Base,TokenBase
class Completed(Base,TxBase.Completed):
fn_fee_unit = 'Mwei'
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
self.gas = self.proto.coin_amt(self.dfl_gas,'wei')
self.start_gas = self.proto.coin_amt(self.dfl_start_gas,'wei')
@property
def send_amt(self):
return self.outputs[0].amt if self.outputs else self.proto.coin_amt('0')

View file

@ -18,7 +18,6 @@ import mmgen.tx.new as TxBase
from .base import Base,TokenBase
from ....opts import opt
from ....obj import Int,ETHNonce,MMGenTxID,Str,HexStr
from ....amt import ETHAmt
from ....util import msg,is_int,is_hex_str,make_chksum_6
from ....tw.ctl import TwCtl
from ....addr import is_mmgen_id,is_coin_addr
@ -36,7 +35,11 @@ class New(Base,TxBase.New):
super().__init__(*args,**kwargs)
if opt.gas:
self.gas = self.start_gas = ETHAmt(int(opt.gas),'wei')
self.gas = self.start_gas = self.proto.coin_amt(int(opt.gas),'wei')
else:
self.gas = self.proto.coin_amt(self.dfl_gas,'wei')
self.start_gas = self.proto.coin_amt(self.dfl_start_gas,'wei')
if opt.contract_data:
m = "'--contract-data' option may not be used with token transaction"
assert not 'Token' in type(self).__name__, m
@ -51,7 +54,7 @@ class New(Base,TxBase.New):
self.txobj = {
'from': self.inputs[0].addr,
'to': self.outputs[0].addr if self.outputs else Str(''),
'amt': self.outputs[0].amt if self.outputs else ETHAmt('0'),
'amt': self.outputs[0].amt if self.outputs else self.proto.coin_amt('0'),
'gasPrice': self.fee_abs2rel(self.usr_fee,to_unit='eth'),
'startGas': self.start_gas,
'nonce': await self.get_nonce(),
@ -111,8 +114,8 @@ class New(Base,TxBase.New):
# given rel fee and units, return absolute fee using self.gas
def fee_rel2abs(self,tx_size,units,amt,unit):
return ETHAmt(
ETHAmt(amt,units[unit]).toWei() * self.gas.toWei(),
return self.proto.coin_amt(
self.proto.coin_amt(amt,units[unit]).toWei() * self.gas.toWei(),
from_unit='wei'
)
@ -139,7 +142,7 @@ class New(Base,TxBase.New):
def update_change_output(self,funds_left):
if self.outputs and self.outputs[0].is_chg:
self.update_output_amt(0,ETHAmt(funds_left))
self.update_output_amt(0,self.proto.coin_amt(funds_left))
async def get_input_addrs_from_cmdline(self):
ret = []
@ -165,7 +168,7 @@ class New(Base,TxBase.New):
def final_inputs_ok_msg(self,funds_left):
chg = '0' if (self.outputs and self.outputs[0].is_chg) else funds_left
return 'Transaction leaves {} {} in the sender’s account'.format(
ETHAmt(chg).hl(),
self.proto.coin_amt(chg).hl(),
self.proto.coin
)
@ -200,7 +203,7 @@ class TokenNew(TokenBase,New):
def final_inputs_ok_msg(self,funds_left):
token_bal = (
ETHAmt('0') if self.outputs[0].is_chg
self.proto.coin_amt('0') if self.outputs[0].is_chg
else self.inputs[0].amt - self.outputs[0].amt
)
return "Transaction leaves ≈{} {} and {} {} in the sender's account".format(

View file

@ -17,7 +17,6 @@ from .completed import Completed,TokenCompleted
from ..contract import Token
from ....obj import Str,CoinTxID,ETHNonce,HexStr
from ....addr import CoinAddr,TokenAddr
from ....amt import ETHAmt
class Signed(Completed,TxBase.Signed):
@ -35,9 +34,9 @@ class Signed(Completed,TxBase.Signed):
'from': CoinAddr(self.proto,d['sender']),
# NB: for token, 'to' is token address
'to': CoinAddr(self.proto,d['to']) if d['to'] else Str(''),
'amt': ETHAmt(d['value'],'wei'),
'gasPrice': ETHAmt(d['gasprice'],'wei'),
'startGas': ETHAmt(d['startgas'],'wei'),
'amt': self.proto.coin_amt(d['value'],'wei'),
'gasPrice': self.proto.coin_amt(d['gasprice'],'wei'),
'startGas': self.proto.coin_amt(d['startgas'],'wei'),
'nonce': ETHNonce(d['nonce']),
'data': HexStr(d['data']) }
if o['data'] and not o['to']: # token- or contract-creating transaction

View file

@ -20,7 +20,6 @@ from ..contract import Token
from ....util import msg,msg_r,ymsg
from ....obj import Str,CoinTxID,ETHNonce,Int,HexStr
from ....addr import CoinAddr,TokenAddr
from ....amt import ETHAmt
class Unsigned(Completed,TxBase.Unsigned):
desc = 'unsigned transaction'
@ -32,9 +31,9 @@ class Unsigned(Completed,TxBase.Unsigned):
'from': CoinAddr(self.proto,d['from']),
# NB: for token, 'to' is sendto address
'to': CoinAddr(self.proto,d['to']) if d['to'] else Str(''),
'amt': ETHAmt(d['amt']),
'gasPrice': ETHAmt(d['gasPrice']),
'startGas': ETHAmt(d['startGas']),
'amt': self.proto.coin_amt(d['amt']),
'gasPrice': self.proto.coin_amt(d['gasPrice']),
'startGas': self.proto.coin_amt(d['startGas']),
'nonce': ETHNonce(d['nonce']),
'chainId': None if d['chainId'] == 'None' else Int(d['chainId']),
'data': HexStr(d['data']) }

View file

@ -28,7 +28,6 @@ from subprocess import run,PIPE,DEVNULL
from mmgen.globalvars import g
from mmgen.opts import opt
from mmgen.util import die
from mmgen.amt import ETHAmt
from mmgen.protocol import CoinProtocol
from ..include.common import *
from .common import *
@ -40,8 +39,6 @@ dfl_sid = '98831F3A'
dfl_devaddr = '00a329c0648769a73afac7f9381e08fb43dbea72'
dfl_devkey = '4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7'
prealloc_amt = ETHAmt('1_000_000_000')
burn_addr = 'deadbeef'*5
burn_addr2 = 'beadcafe'*5
@ -509,6 +506,8 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared):
imsg(cyan('Initializing Genesis Block:'))
prealloc_amt = self.proto.coin_amt('1_000_000_000')
make_key()
signer_addr = self.keystore_data['address']
self.write_to_tmpfile( 'signer_addr', signer_addr + '\n' )
@ -989,8 +988,8 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared):
usr_addrs[i],
amt,
dfl_devkey,
start_gas = ETHAmt(60000,'wei'),
gasPrice = ETHAmt(8,'Gwei') )
start_gas = self.proto.coin_amt(60000,'wei'),
gasPrice = self.proto.coin_amt(8,'Gwei') )
if self.daemon.id == 'geth': # yet another Geth bug
await asyncio.sleep(0.5)
if (await self.get_tx_receipt(txid)).status == 0: