chaind-eth/chaind_eth/cli/process.py
2021-09-08 17:17:49 +02:00

163 lines
5.1 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# standard imports
import logging
# external imports
from chaind.error import TxSourceError
from chainlib.eth.address import is_checksum_address
from chainlib.eth.tx import unpack
from chainlib.eth.gas import Gas
from hexathon import (
add_0x,
strip_0x,
)
from crypto_dev_signer.eth.transaction import EIP155Transaction
from eth_erc20 import ERC20
logg = logging.getLogger(__name__)
class Processor:
def __init__(self, sender, signer, source, chain_spec, gas_oracle, nonce_oracle, resolver=None):
self.sender = sender
self.signer = signer
self.source = source
self.processor = []
self.content = []
self.token = []
self.token_resolver = resolver
self.cursor = 0
self.gas_oracle = gas_oracle
self.nonce_oracle = nonce_oracle
self.nonce_start = None
self.gas_limit_start = None
self.gas_price_start = None
self.chain_spec = chain_spec
self.chain_id = chain_spec.chain_id()
def add_processor(self, processor):
self.processor.append(processor)
def load(self, process=True):
for processor in self.processor:
self.content = processor.load(self.source)
if self.content != None:
if process:
try:
self.process()
except Exception as e:
raise TxSourceError('invalid source contents: {}'.format(str(e)))
return self.content
raise TxSourceError('unparseable source')
# 0: recipient
# 1: amount
# 2: token identifier (optional, when not specified network gas token will be used)
# 3: gas amount (optional)
def process(self):
txs = []
for i, r in enumerate(self.content):
logg.debug('processing {}'.format(r))
if not is_checksum_address(r[0]):
raise ValueError('invalid checksum address {} in record {}'.format(r[0], i))
self.content[i][0] = add_0x(r[0])
try:
self.content[i][1] = int(r[1])
except ValueError:
self.content[i][1] = int(strip_0x(r[1]), 16)
native_token_value = 0
if self.token_resolver == None:
self.token.append(None)
else:
#self.content[i][2] = self.token_resolver.lookup(k)
token = self.token_resolver.lookup(r[2])
self.token.append(token)
if len(self.content[i]) == 3:
self.content[i].append(native_token_value)
def __iter__(self):
gas_data = self.gas_oracle.get_gas()
self.gas_price_start = gas_data[0]
self.gas_limit_start = gas_data[1]
self.cursor = 0
return self
def __next__(self):
if self.cursor == len(self.content):
raise StopIteration()
nonce = self.nonce_oracle.next_nonce()
token_factory = None
r = self.content[self.cursor]
token = self.token[self.cursor]
if token == None:
token_factory = Gas(self.chain_spec, signer=self.signer, gas_oracle=self.gas_oracle, nonce_oracle=self.nonce_oracle)
else:
token_factory = ERC20(self.chain_spec, signer=self.signer, gas_oracle=self.gas_oracle, nonce_oracle=self.nonce_oracle)
value = 0
gas_value = 0
data = '0x'
debug_destination = (r[2], token)
if debug_destination[1] == None:
debug_destination = (None, 'network gas token')
if isinstance(token_factory, ERC20):
(tx_hash_hex, o) = token_factory.transfer(token, self.sender, r[0], r[1])
logg.debug('tx {}'.format(o))
# TODO: allow chainlib to return data args only (TxFormat)
tx = unpack(bytes.fromhex(strip_0x(o['params'][0])), self.chain_spec)
data = tx['data']
try:
value = int(r[1])
except ValueError:
value = int(strip_0x(r[1]), 16)
try:
gas_value = int(r[3])
except:
gas_value = int(strip_0x(r[3]), 16)
else:
try:
value = int(r[1])
except ValueError:
value = int(strip_0x(r[1]), 16)
gas_value = value
logg.debug('token factory {} resolved sender {} recipient {} gas value {} token value {} token {}'.format(
str(token_factory),
self.sender,
r[0],
gas_value,
value,
debug_destination,
)
)
tx = {
'from': self.sender,
'to': r[0],
'value': gas_value,
'data': data,
'nonce': nonce,
'gasPrice': self.gas_price_start,
'gas': self.gas_limit_start,
}
tx_o = EIP155Transaction(tx, nonce, self.chain_id)
tx_bytes = self.signer.sign_transaction_to_wire(tx_o)
self.cursor += 1
return tx_bytes
def __str__(self):
names = []
for s in self.processor:
names.append(str(s))
return ','.join(names)