Rehabilitate transfer, approve
Signed-off-by: nolash <dev@holbrook.no>
This commit is contained in:
parent
c245a29a6b
commit
3f61a2007e
@ -161,7 +161,7 @@ class NonceReservation(SessionBase):
|
|||||||
o = q.first()
|
o = q.first()
|
||||||
|
|
||||||
if o == None:
|
if o == None:
|
||||||
raise IntegrityError('nonce {} for key {} address {}: {}'.format(nonce, key, address))
|
raise IntegrityError('nonce {} for key {} address {}'.format(nonce, key, address))
|
||||||
SessionBase.release_session(session)
|
SessionBase.release_session(session)
|
||||||
|
|
||||||
session.delete(o)
|
session.delete(o)
|
||||||
|
@ -46,80 +46,8 @@ from cic_eth.queue.tx import (
|
|||||||
register_tx,
|
register_tx,
|
||||||
)
|
)
|
||||||
|
|
||||||
#logg = logging.getLogger(__name__)
|
|
||||||
logg = logging.getLogger()
|
logg = logging.getLogger()
|
||||||
celery_app = celery.current_app
|
celery_app = celery.current_app
|
||||||
#celery_app.log.setup_task_loggers(loglevel=logging.DEBUG)
|
|
||||||
#celery_app.log.redirect_stdouts_to_logger(logg, loglevel=logging.DEBUG)
|
|
||||||
|
|
||||||
|
|
||||||
#class AccountTxFactory(TxFactory):
|
|
||||||
# """Factory for creating account index contract transactions
|
|
||||||
# """
|
|
||||||
# def add(
|
|
||||||
# self,
|
|
||||||
# address,
|
|
||||||
# chain_spec,
|
|
||||||
# uuid,
|
|
||||||
# session=None,
|
|
||||||
# ):
|
|
||||||
# """Register an Ethereum account address with the on-chain account registry
|
|
||||||
#
|
|
||||||
# :param address: Ethereum account address to add
|
|
||||||
# :type address: str, 0x-hex
|
|
||||||
# :param chain_spec: Chain to build transaction for
|
|
||||||
# :type chain_spec: cic_registry.chain.ChainSpec
|
|
||||||
# :returns: Unsigned "AccountRegistry.add" transaction in standard Ethereum format
|
|
||||||
# :rtype: dict
|
|
||||||
# """
|
|
||||||
#
|
|
||||||
# c = self.registry.get_contract(chain_spec, 'AccountRegistry')
|
|
||||||
# f = c.function('add')
|
|
||||||
# tx_add_buildable = f(
|
|
||||||
# address,
|
|
||||||
# )
|
|
||||||
# gas = c.gas('add')
|
|
||||||
# tx_add = tx_add_buildable.buildTransaction({
|
|
||||||
# 'from': self.address,
|
|
||||||
# 'gas': gas,
|
|
||||||
# 'gasPrice': self.gas_price,
|
|
||||||
# 'chainId': chain_spec.chain_id(),
|
|
||||||
# 'nonce': self.next_nonce(uuid, session=session),
|
|
||||||
# 'value': 0,
|
|
||||||
# })
|
|
||||||
# return tx_add
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# def gift(
|
|
||||||
# self,
|
|
||||||
# address,
|
|
||||||
# chain_spec,
|
|
||||||
# uuid,
|
|
||||||
# session=None,
|
|
||||||
# ):
|
|
||||||
# """Trigger the on-chain faucet to disburse tokens to the provided Ethereum account
|
|
||||||
#
|
|
||||||
# :param address: Ethereum account address to gift to
|
|
||||||
# :type address: str, 0x-hex
|
|
||||||
# :param chain_spec: Chain to build transaction for
|
|
||||||
# :type chain_spec: cic_registry.chain.ChainSpec
|
|
||||||
# :returns: Unsigned "Faucet.giveTo" transaction in standard Ethereum format
|
|
||||||
# :rtype: dict
|
|
||||||
# """
|
|
||||||
#
|
|
||||||
# c = self.registry.get_contract(chain_spec, 'Faucet')
|
|
||||||
# f = c.function('giveTo')
|
|
||||||
# tx_add_buildable = f(address)
|
|
||||||
# gas = c.gas('add')
|
|
||||||
# tx_add = tx_add_buildable.buildTransaction({
|
|
||||||
# 'from': self.address,
|
|
||||||
# 'gas': gas,
|
|
||||||
# 'gasPrice': self.gas_price,
|
|
||||||
# 'chainId': chain_spec.chain_id(),
|
|
||||||
# 'nonce': self.next_nonce(uuid, session=session),
|
|
||||||
# 'value': 0,
|
|
||||||
# })
|
|
||||||
# return tx_add
|
|
||||||
|
|
||||||
|
|
||||||
def unpack_register(data):
|
def unpack_register(data):
|
||||||
@ -183,16 +111,11 @@ def create(self, password, chain_str):
|
|||||||
o = new_account()
|
o = new_account()
|
||||||
a = conn.do(o)
|
a = conn.do(o)
|
||||||
|
|
||||||
#try:
|
|
||||||
# a = c.w3.eth.personal.new_account(password)
|
|
||||||
#except FileNotFoundError:
|
|
||||||
# pass
|
|
||||||
if a == None:
|
if a == None:
|
||||||
raise SignerError('create account')
|
raise SignerError('create account')
|
||||||
logg.debug('created account {}'.format(a))
|
logg.debug('created account {}'.format(a))
|
||||||
|
|
||||||
# Initialize nonce provider record for account
|
# Initialize nonce provider record for account
|
||||||
#session = SessionBase.create_session()
|
|
||||||
session = self.create_session()
|
session = self.create_session()
|
||||||
Nonce.init(a, session=session)
|
Nonce.init(a, session=session)
|
||||||
session.commit()
|
session.commit()
|
||||||
@ -217,7 +140,6 @@ def register(self, account_address, chain_spec_dict, writer_address=None):
|
|||||||
chain_spec = ChainSpec.from_dict(chain_spec_dict)
|
chain_spec = ChainSpec.from_dict(chain_spec_dict)
|
||||||
|
|
||||||
session = self.create_session()
|
session = self.create_session()
|
||||||
#session = SessionBase.create_session()
|
|
||||||
if writer_address == None:
|
if writer_address == None:
|
||||||
writer_address = AccountRole.get_address('ACCOUNT_REGISTRY_WRITER', session=session)
|
writer_address = AccountRole.get_address('ACCOUNT_REGISTRY_WRITER', session=session)
|
||||||
|
|
||||||
@ -243,7 +165,6 @@ def register(self, account_address, chain_spec_dict, writer_address=None):
|
|||||||
(tx_hash_hex, tx_signed_raw_hex) = account_registry.add(account_registry_address, writer_address, account_address, tx_format=TxFormat.RLP_SIGNED)
|
(tx_hash_hex, tx_signed_raw_hex) = account_registry.add(account_registry_address, writer_address, account_address, tx_format=TxFormat.RLP_SIGNED)
|
||||||
# TODO: if cache task fails, task chain will not return
|
# TODO: if cache task fails, task chain will not return
|
||||||
cache_task = 'cic_eth.eth.account.cache_account_data'
|
cache_task = 'cic_eth.eth.account.cache_account_data'
|
||||||
cache_task = None
|
|
||||||
|
|
||||||
# add transaction to queue
|
# add transaction to queue
|
||||||
register_tx(tx_hash_hex, tx_signed_raw_hex, chain_spec, queue, cache_task=cache_task, session=session)
|
register_tx(tx_hash_hex, tx_signed_raw_hex, chain_spec, queue, cache_task=cache_task, session=session)
|
||||||
|
@ -10,6 +10,10 @@ from chainlib.chain import ChainSpec
|
|||||||
from chainlib.status import Status as TxStatus
|
from chainlib.status import Status as TxStatus
|
||||||
from chainlib.connection import RPCConnection
|
from chainlib.connection import RPCConnection
|
||||||
from chainlib.eth.erc20 import ERC20
|
from chainlib.eth.erc20 import ERC20
|
||||||
|
from chainlib.eth.tx import (
|
||||||
|
TxFormat,
|
||||||
|
unpack,
|
||||||
|
)
|
||||||
from cic_eth_registry.erc20 import ERC20Token
|
from cic_eth_registry.erc20 import ERC20Token
|
||||||
from hexathon import strip_0x
|
from hexathon import strip_0x
|
||||||
|
|
||||||
@ -20,15 +24,18 @@ from cic_eth.db.models.base import SessionBase
|
|||||||
from cic_eth.eth import RpcClient
|
from cic_eth.eth import RpcClient
|
||||||
from cic_eth.error import TokenCountError, PermanentTxError, OutOfGasError, NotLocalTxError
|
from cic_eth.error import TokenCountError, PermanentTxError, OutOfGasError, NotLocalTxError
|
||||||
from cic_eth.queue.tx import register_tx
|
from cic_eth.queue.tx import register_tx
|
||||||
from cic_eth.eth.gas import create_check_gas_task
|
from cic_eth.eth.gas import (
|
||||||
|
create_check_gas_task,
|
||||||
|
MaxGasOracle,
|
||||||
|
)
|
||||||
#from cic_eth.eth.factory import TxFactory
|
#from cic_eth.eth.factory import TxFactory
|
||||||
from cic_eth.eth.util import unpack_signed_raw_tx
|
|
||||||
from cic_eth.ext.address import translate_address
|
from cic_eth.ext.address import translate_address
|
||||||
from cic_eth.task import (
|
from cic_eth.task import (
|
||||||
CriticalSQLAlchemyTask,
|
CriticalSQLAlchemyTask,
|
||||||
CriticalWeb3Task,
|
CriticalWeb3Task,
|
||||||
CriticalSQLAlchemyAndSignerTask,
|
CriticalSQLAlchemyAndSignerTask,
|
||||||
)
|
)
|
||||||
|
from cic_eth.eth.nonce import CustodialTaskNonceOracle
|
||||||
|
|
||||||
celery_app = celery.current_app
|
celery_app = celery.current_app
|
||||||
logg = logging.getLogger()
|
logg = logging.getLogger()
|
||||||
@ -87,7 +94,7 @@ logg = logging.getLogger()
|
|||||||
# def transfer(
|
# def transfer(
|
||||||
# self,
|
# self,
|
||||||
# token_address,
|
# token_address,
|
||||||
# receiver_address,
|
# Receiver_address,
|
||||||
# value,
|
# value,
|
||||||
# chain_spec,
|
# chain_spec,
|
||||||
# uuid,
|
# uuid,
|
||||||
@ -125,68 +132,68 @@ logg = logging.getLogger()
|
|||||||
# return tx_transfer
|
# return tx_transfer
|
||||||
|
|
||||||
|
|
||||||
def unpack_transfer(data):
|
#def unpack_transfer(data):
|
||||||
"""Verifies that a transaction is an "ERC20.transfer" transaction, and extracts call parameters from it.
|
# """Verifies that a transaction is an "ERC20.transfer" transaction, and extracts call parameters from it.
|
||||||
|
#
|
||||||
:param data: Raw input data from Ethereum transaction.
|
# :param data: Raw input data from Ethereum transaction.
|
||||||
:type data: str, 0x-hex
|
# :type data: str, 0x-hex
|
||||||
:raises ValueError: Function signature does not match AccountRegister.add
|
# :raises ValueError: Function signature does not match AccountRegister.add
|
||||||
:returns: Parsed parameters
|
# :returns: Parsed parameters
|
||||||
:rtype: dict
|
# :rtype: dict
|
||||||
"""
|
# """
|
||||||
data = strip_0x(data)
|
# data = strip_0x(data)
|
||||||
f = data[:8]
|
# f = data[:8]
|
||||||
if f != contract_function_signatures['transfer']:
|
# if f != contract_function_signatures['transfer']:
|
||||||
raise ValueError('Invalid transfer data ({})'.format(f))
|
# raise ValueError('Invalid transfer data ({})'.format(f))
|
||||||
|
#
|
||||||
d = data[8:]
|
# d = data[8:]
|
||||||
return {
|
# return {
|
||||||
'to': web3.Web3.toChecksumAddress('0x' + d[64-40:64]),
|
# 'to': web3.Web3.toChecksumAddress('0x' + d[64-40:64]),
|
||||||
'amount': int(d[64:], 16)
|
# 'amount': int(d[64:], 16)
|
||||||
}
|
# }
|
||||||
|
|
||||||
|
|
||||||
def unpack_transferfrom(data):
|
#def unpack_transferfrom(data):
|
||||||
"""Verifies that a transaction is an "ERC20.transferFrom" transaction, and extracts call parameters from it.
|
# """Verifies that a transaction is an "ERC20.transferFrom" transaction, and extracts call parameters from it.
|
||||||
|
#
|
||||||
:param data: Raw input data from Ethereum transaction.
|
# :param data: Raw input data from Ethereum transaction.
|
||||||
:type data: str, 0x-hex
|
# :type data: str, 0x-hex
|
||||||
:raises ValueError: Function signature does not match AccountRegister.add
|
# :raises ValueError: Function signature does not match AccountRegister.add
|
||||||
:returns: Parsed parameters
|
# :returns: Parsed parameters
|
||||||
:rtype: dict
|
# :rtype: dict
|
||||||
"""
|
# """
|
||||||
data = strip_0x(data)
|
# data = strip_0x(data)
|
||||||
f = data[:8]
|
# f = data[:8]
|
||||||
if f != contract_function_signatures['transferfrom']:
|
# if f != contract_function_signatures['transferfrom']:
|
||||||
raise ValueError('Invalid transferFrom data ({})'.format(f))
|
# raise ValueError('Invalid transferFrom data ({})'.format(f))
|
||||||
|
#
|
||||||
d = data[8:]
|
# d = data[8:]
|
||||||
return {
|
# return {
|
||||||
'from': web3.Web3.toChecksumAddress('0x' + d[64-40:64]),
|
# 'from': web3.Web3.toChecksumAddress('0x' + d[64-40:64]),
|
||||||
'to': web3.Web3.toChecksumAddress('0x' + d[128-40:128]),
|
# 'to': web3.Web3.toChecksumAddress('0x' + d[128-40:128]),
|
||||||
'amount': int(d[128:], 16)
|
# 'amount': int(d[128:], 16)
|
||||||
}
|
# }
|
||||||
|
#
|
||||||
|
#
|
||||||
def unpack_approve(data):
|
#def unpack_approve(data):
|
||||||
"""Verifies that a transaction is an "ERC20.approve" transaction, and extracts call parameters from it.
|
# """Verifies that a transaction is an "ERC20.approve" transaction, and extracts call parameters from it.
|
||||||
|
#
|
||||||
:param data: Raw input data from Ethereum transaction.
|
# :param data: Raw input data from Ethereum transaction.
|
||||||
:type data: str, 0x-hex
|
# :type data: str, 0x-hex
|
||||||
:raises ValueError: Function signature does not match AccountRegister.add
|
# :raises ValueError: Function signature does not match AccountRegister.add
|
||||||
:returns: Parsed parameters
|
# :returns: Parsed parameters
|
||||||
:rtype: dict
|
# :rtype: dict
|
||||||
"""
|
# """
|
||||||
data = strip_0x(data)
|
# data = strip_0x(data)
|
||||||
f = data[:8]
|
# f = data[:8]
|
||||||
if f != contract_function_signatures['approve']:
|
# if f != contract_function_signatures['approve']:
|
||||||
raise ValueError('Invalid approval data ({})'.format(f))
|
# raise ValueError('Invalid approval data ({})'.format(f))
|
||||||
|
#
|
||||||
d = data[8:]
|
# d = data[8:]
|
||||||
return {
|
# return {
|
||||||
'to': web3.Web3.toChecksumAddress('0x' + d[64-40:64]),
|
# 'to': web3.Web3.toChecksumAddress('0x' + d[64-40:64]),
|
||||||
'amount': int(d[64:], 16)
|
# 'amount': int(d[64:], 16)
|
||||||
}
|
# }
|
||||||
|
|
||||||
|
|
||||||
@celery_app.task(base=CriticalWeb3Task)
|
@celery_app.task(base=CriticalWeb3Task)
|
||||||
@ -197,8 +204,8 @@ def balance(tokens, holder_address, chain_spec_dict):
|
|||||||
:type tokens: list of str, 0x-hex
|
:type tokens: list of str, 0x-hex
|
||||||
:param holder_address: Token holder address
|
:param holder_address: Token holder address
|
||||||
:type holder_address: str, 0x-hex
|
:type holder_address: str, 0x-hex
|
||||||
:param chain_str: Chain spec string representation
|
:param chain_spec_dict: Chain spec string representation
|
||||||
:type chain_str: str
|
:type chain_spec_dict: str
|
||||||
:return: List of balances
|
:return: List of balances
|
||||||
:rtype: list of int
|
:rtype: list of int
|
||||||
"""
|
"""
|
||||||
@ -218,7 +225,7 @@ def balance(tokens, holder_address, chain_spec_dict):
|
|||||||
|
|
||||||
|
|
||||||
@celery_app.task(bind=True, base=CriticalSQLAlchemyAndSignerTask)
|
@celery_app.task(bind=True, base=CriticalSQLAlchemyAndSignerTask)
|
||||||
def transfer(self, tokens, holder_address, receiver_address, value, chain_str):
|
def transfer(self, tokens, holder_address, receiver_address, value, chain_spec_dict):
|
||||||
"""Transfer ERC20 tokens between addresses
|
"""Transfer ERC20 tokens between addresses
|
||||||
|
|
||||||
First argument is a list of tokens, to enable the task to be chained to the symbol to token address resolver function. However, it accepts only one token as argument.
|
First argument is a list of tokens, to enable the task to be chained to the symbol to token address resolver function. However, it accepts only one token as argument.
|
||||||
@ -242,29 +249,31 @@ def transfer(self, tokens, holder_address, receiver_address, value, chain_str):
|
|||||||
# we only allow one token, one transfer
|
# we only allow one token, one transfer
|
||||||
if len(tokens) != 1:
|
if len(tokens) != 1:
|
||||||
raise TokenCountError
|
raise TokenCountError
|
||||||
|
|
||||||
chain_spec = ChainSpec.from_chain_str(chain_str)
|
|
||||||
|
|
||||||
queue = self.request.delivery_info['routing_key']
|
|
||||||
|
|
||||||
# retrieve the token interface
|
|
||||||
t = tokens[0]
|
t = tokens[0]
|
||||||
|
chain_spec = ChainSpec.from_dict(chain_spec_dict)
|
||||||
|
queue = self.request.delivery_info.get('routing_key')
|
||||||
|
|
||||||
c = RpcClient(chain_spec, holder_address=holder_address)
|
rpc = RPCConnection.connect(chain_spec, 'default')
|
||||||
registry = safe_registry(c.w3)
|
rpc_signer = RPCConnection.connect(chain_spec, 'signer')
|
||||||
|
|
||||||
txf = TokenTxFactory(holder_address, c, registry=registry)
|
session = self.create_session()
|
||||||
|
nonce_oracle = CustodialTaskNonceOracle(holder_address, self.request.root_id, session=session)
|
||||||
session = SessionBase.create_session()
|
gas_oracle = self.create_gas_oracle(rpc, MaxGasOracle.gas)
|
||||||
tx_transfer = txf.transfer(t['address'], receiver_address, value, chain_spec, self.request.root_id, session=session)
|
c = ERC20(signer=rpc_signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle, chain_id=chain_spec.chain_id())
|
||||||
(tx_hash_hex, tx_signed_raw_hex) = sign_and_register_tx(tx_transfer, chain_str, queue, cache_task='cic_eth.eth.token.otx_cache_transfer', session=session)
|
(tx_hash_hex, tx_signed_raw_hex) = c.transfer(t['address'], holder_address, receiver_address, value, tx_format=TxFormat.RLP_SIGNED)
|
||||||
|
cache_task = 'cic_eth.eth.erc20.cache_transfer_data'
|
||||||
|
|
||||||
|
register_tx(tx_hash_hex, tx_signed_raw_hex, chain_spec, queue, cache_task=cache_task, session=session)
|
||||||
|
session.commit()
|
||||||
session.close()
|
session.close()
|
||||||
|
|
||||||
gas_budget = tx_transfer['gas'] * tx_transfer['gasPrice']
|
gas_pair = gas_oracle.get_gas(tx_signed_raw_hex)
|
||||||
|
gas_budget = gas_pair[0] * gas_pair[1]
|
||||||
|
logg.debug('transfer tx {} {} {}'.format(tx_hash_hex, queue, gas_budget))
|
||||||
|
|
||||||
s = create_check_gas_and_send_task(
|
s = create_check_gas_task(
|
||||||
[tx_signed_raw_hex],
|
[tx_signed_raw_hex],
|
||||||
chain_str,
|
chain_spec,
|
||||||
holder_address,
|
holder_address,
|
||||||
gas_budget,
|
gas_budget,
|
||||||
[tx_hash_hex],
|
[tx_hash_hex],
|
||||||
@ -275,7 +284,7 @@ def transfer(self, tokens, holder_address, receiver_address, value, chain_str):
|
|||||||
|
|
||||||
|
|
||||||
@celery_app.task(bind=True, base=CriticalSQLAlchemyAndSignerTask)
|
@celery_app.task(bind=True, base=CriticalSQLAlchemyAndSignerTask)
|
||||||
def approve(self, tokens, holder_address, spender_address, value, chain_str):
|
def approve(self, tokens, holder_address, spender_address, value, chain_spec_dict):
|
||||||
"""Approve ERC20 transfer on behalf of holder address
|
"""Approve ERC20 transfer on behalf of holder address
|
||||||
|
|
||||||
First argument is a list of tokens, to enable the task to be chained to the symbol to token address resolver function. However, it accepts only one token as argument.
|
First argument is a list of tokens, to enable the task to be chained to the symbol to token address resolver function. However, it accepts only one token as argument.
|
||||||
@ -299,29 +308,30 @@ def approve(self, tokens, holder_address, spender_address, value, chain_str):
|
|||||||
# we only allow one token, one transfer
|
# we only allow one token, one transfer
|
||||||
if len(tokens) != 1:
|
if len(tokens) != 1:
|
||||||
raise TokenCountError
|
raise TokenCountError
|
||||||
|
|
||||||
chain_spec = ChainSpec.from_chain_str(chain_str)
|
|
||||||
|
|
||||||
queue = self.request.delivery_info['routing_key']
|
|
||||||
|
|
||||||
# retrieve the token interface
|
|
||||||
t = tokens[0]
|
t = tokens[0]
|
||||||
|
chain_spec = ChainSpec.from_dict(chain_spec_dict)
|
||||||
|
queue = self.request.delivery_info.get('routing_key')
|
||||||
|
|
||||||
c = RpcClient(chain_spec, holder_address=holder_address)
|
rpc = RPCConnection.connect(chain_spec, 'default')
|
||||||
registry = safe_registry(c.w3)
|
rpc_signer = RPCConnection.connect(chain_spec, 'signer')
|
||||||
|
|
||||||
txf = TokenTxFactory(holder_address, c, registry=registry)
|
session = self.create_session()
|
||||||
|
nonce_oracle = CustodialTaskNonceOracle(holder_address, self.request.root_id, session=session)
|
||||||
|
gas_oracle = self.create_gas_oracle(rpc, MaxGasOracle.gas)
|
||||||
|
c = ERC20(signer=rpc_signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle, chain_id=chain_spec.chain_id())
|
||||||
|
(tx_hash_hex, tx_signed_raw_hex) = c.approve(t['address'], holder_address, spender_address, value, tx_format=TxFormat.RLP_SIGNED)
|
||||||
|
cache_task = 'cic_eth.eth.erc20.cache_approve_data'
|
||||||
|
|
||||||
session = SessionBase.create_session()
|
register_tx(tx_hash_hex, tx_signed_raw_hex, chain_spec, queue, cache_task=cache_task, session=session)
|
||||||
tx_transfer = txf.approve(t['address'], spender_address, value, chain_spec, self.request.root_id, session=session)
|
session.commit()
|
||||||
(tx_hash_hex, tx_signed_raw_hex) = sign_and_register_tx(tx_transfer, chain_str, queue, cache_task='cic_eth.eth.token.otx_cache_approve', session=session)
|
|
||||||
session.close()
|
session.close()
|
||||||
|
|
||||||
gas_budget = tx_transfer['gas'] * tx_transfer['gasPrice']
|
gas_pair = gas_oracle.get_gas(tx_signed_raw_hex)
|
||||||
|
gas_budget = gas_pair[0] * gas_pair[1]
|
||||||
|
|
||||||
s = create_check_gas_and_send_task(
|
s = create_check_gas_task(
|
||||||
[tx_signed_raw_hex],
|
[tx_signed_raw_hex],
|
||||||
chain_str,
|
chain_spec,
|
||||||
holder_address,
|
holder_address,
|
||||||
gas_budget,
|
gas_budget,
|
||||||
[tx_hash_hex],
|
[tx_hash_hex],
|
||||||
@ -356,34 +366,11 @@ def resolve_tokens_by_symbol(token_symbols, chain_str):
|
|||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
|
|
||||||
@celery_app.task(base=CriticalSQLAlchemyTask)
|
|
||||||
def otx_cache_transfer(
|
|
||||||
tx_hash_hex,
|
|
||||||
tx_signed_raw_hex,
|
|
||||||
chain_str,
|
|
||||||
):
|
|
||||||
"""Generates and commits transaction cache metadata for an ERC20.transfer or ERC20.transferFrom transaction
|
|
||||||
|
|
||||||
:param tx_hash_hex: Transaction hash
|
|
||||||
:type tx_hash_hex: str, 0x-hex
|
|
||||||
:param tx_signed_raw_hex: Raw signed transaction
|
|
||||||
:type tx_signed_raw_hex: str, 0x-hex
|
|
||||||
:param chain_str: Chain spec string representation
|
|
||||||
:type chain_str: str
|
|
||||||
:returns: Transaction hash and id of cache element in storage backend, respectively
|
|
||||||
:rtype: tuple
|
|
||||||
"""
|
|
||||||
chain_spec = ChainSpec.from_chain_str(chain_str)
|
|
||||||
tx_signed_raw_bytes = bytes.fromhex(tx_signed_raw_hex[2:])
|
|
||||||
tx = unpack_signed_raw_tx(tx_signed_raw_bytes, chain_spec.chain_id())
|
|
||||||
(txc, cache_id) = cache_transfer_data(tx_hash_hex, tx)
|
|
||||||
return txc
|
|
||||||
|
|
||||||
|
|
||||||
@celery_app.task(base=CriticalSQLAlchemyTask)
|
@celery_app.task(base=CriticalSQLAlchemyTask)
|
||||||
def cache_transfer_data(
|
def cache_transfer_data(
|
||||||
tx_hash_hex,
|
tx_hash_hex,
|
||||||
tx,
|
tx_signed_raw_hex,
|
||||||
|
chain_spec_dict,
|
||||||
):
|
):
|
||||||
"""Helper function for otx_cache_transfer
|
"""Helper function for otx_cache_transfer
|
||||||
|
|
||||||
@ -394,19 +381,23 @@ def cache_transfer_data(
|
|||||||
:returns: Transaction hash and id of cache element in storage backend, respectively
|
:returns: Transaction hash and id of cache element in storage backend, respectively
|
||||||
:rtype: tuple
|
:rtype: tuple
|
||||||
"""
|
"""
|
||||||
tx_data = unpack_transfer(tx['data'])
|
chain_spec = ChainSpec.from_dict(chain_spec_dict)
|
||||||
logg.debug('tx data {}'.format(tx_data))
|
tx_signed_raw_bytes = bytes.fromhex(strip_0x(tx_signed_raw_hex))
|
||||||
logg.debug('tx {}'.format(tx))
|
tx = unpack(tx_signed_raw_bytes, chain_spec.chain_id())
|
||||||
|
|
||||||
|
tx_data = ERC20.parse_transfer_request(tx['data'])
|
||||||
|
recipient_address = tx_data[0]
|
||||||
|
token_value = tx_data[1]
|
||||||
|
|
||||||
session = SessionBase.create_session()
|
session = SessionBase.create_session()
|
||||||
tx_cache = TxCache(
|
tx_cache = TxCache(
|
||||||
tx_hash_hex,
|
tx_hash_hex,
|
||||||
tx['from'],
|
tx['from'],
|
||||||
tx_data['to'],
|
recipient_address,
|
||||||
tx['to'],
|
tx['to'],
|
||||||
tx['to'],
|
tx['to'],
|
||||||
tx_data['amount'],
|
token_value,
|
||||||
tx_data['amount'],
|
token_value,
|
||||||
session=session,
|
session=session,
|
||||||
)
|
)
|
||||||
session.add(tx_cache)
|
session.add(tx_cache)
|
||||||
@ -416,34 +407,11 @@ def cache_transfer_data(
|
|||||||
return (tx_hash_hex, cache_id)
|
return (tx_hash_hex, cache_id)
|
||||||
|
|
||||||
|
|
||||||
@celery_app.task(base=CriticalSQLAlchemyTask)
|
|
||||||
def otx_cache_approve(
|
|
||||||
tx_hash_hex,
|
|
||||||
tx_signed_raw_hex,
|
|
||||||
chain_str,
|
|
||||||
):
|
|
||||||
"""Generates and commits transaction cache metadata for an ERC20.approve transaction
|
|
||||||
|
|
||||||
:param tx_hash_hex: Transaction hash
|
|
||||||
:type tx_hash_hex: str, 0x-hex
|
|
||||||
:param tx_signed_raw_hex: Raw signed transaction
|
|
||||||
:type tx_signed_raw_hex: str, 0x-hex
|
|
||||||
:param chain_str: Chain spec string representation
|
|
||||||
:type chain_str: str
|
|
||||||
:returns: Transaction hash and id of cache element in storage backend, respectively
|
|
||||||
:rtype: tuple
|
|
||||||
"""
|
|
||||||
chain_spec = ChainSpec.from_chain_str(chain_str)
|
|
||||||
tx_signed_raw_bytes = bytes.fromhex(tx_signed_raw_hex[2:])
|
|
||||||
tx = unpack_signed_raw_tx(tx_signed_raw_bytes, chain_spec.chain_id())
|
|
||||||
(txc, cache_id) = cache_approve_data(tx_hash_hex, tx)
|
|
||||||
return txc
|
|
||||||
|
|
||||||
|
|
||||||
@celery_app.task(base=CriticalSQLAlchemyTask)
|
@celery_app.task(base=CriticalSQLAlchemyTask)
|
||||||
def cache_approve_data(
|
def cache_approve_data(
|
||||||
tx_hash_hex,
|
tx_hash_hex,
|
||||||
tx,
|
tx_signed_raw_hex,
|
||||||
|
chain_spec_dict,
|
||||||
):
|
):
|
||||||
"""Helper function for otx_cache_approve
|
"""Helper function for otx_cache_approve
|
||||||
|
|
||||||
@ -454,19 +422,23 @@ def cache_approve_data(
|
|||||||
:returns: Transaction hash and id of cache element in storage backend, respectively
|
:returns: Transaction hash and id of cache element in storage backend, respectively
|
||||||
:rtype: tuple
|
:rtype: tuple
|
||||||
"""
|
"""
|
||||||
tx_data = unpack_approve(tx['data'])
|
chain_spec = ChainSpec.from_dict(chain_spec_dict)
|
||||||
logg.debug('tx data {}'.format(tx_data))
|
tx_signed_raw_bytes = bytes.fromhex(strip_0x(tx_signed_raw_hex))
|
||||||
logg.debug('tx {}'.format(tx))
|
tx = unpack(tx_signed_raw_bytes, chain_spec.chain_id())
|
||||||
|
|
||||||
|
tx_data = ERC20.parse_approve_request(tx['data'])
|
||||||
|
recipient_address = tx_data[0]
|
||||||
|
token_value = tx_data[1]
|
||||||
|
|
||||||
session = SessionBase.create_session()
|
session = SessionBase.create_session()
|
||||||
tx_cache = TxCache(
|
tx_cache = TxCache(
|
||||||
tx_hash_hex,
|
tx_hash_hex,
|
||||||
tx['from'],
|
tx['from'],
|
||||||
tx_data['to'],
|
recipient_address,
|
||||||
tx['to'],
|
tx['to'],
|
||||||
tx['to'],
|
tx['to'],
|
||||||
tx_data['amount'],
|
token_value,
|
||||||
tx_data['amount'],
|
token_value,
|
||||||
session=session,
|
session=session,
|
||||||
)
|
)
|
||||||
session.add(tx_cache)
|
session.add(tx_cache)
|
||||||
|
@ -12,77 +12,83 @@ from cic_eth.db.models.base import SessionBase
|
|||||||
|
|
||||||
logg = logging.getLogger()
|
logg = logging.getLogger()
|
||||||
|
|
||||||
|
#
|
||||||
class GasOracle():
|
#class GasOracle():
|
||||||
"""Provides gas pricing for transactions.
|
# """Provides gas pricing for transactions.
|
||||||
|
#
|
||||||
:param w3: Web3 object
|
# :param w3: Web3 object
|
||||||
:type w3: web3.Web3
|
# :type w3: web3.Web3
|
||||||
"""
|
# """
|
||||||
|
#
|
||||||
__safe_threshold_amount_value = 2000000000 * 60000 * 3
|
# __safe_threshold_amount_value = 2000000000 * 60000 * 3
|
||||||
__refill_amount_value = __safe_threshold_amount_value * 5
|
# __refill_amount_value = __safe_threshold_amount_value * 5
|
||||||
default_gas_limit = 21000
|
# default_gas_limit = 21000
|
||||||
|
#
|
||||||
def __init__(self, conn):
|
# def __init__(self, conn):
|
||||||
o = price()
|
# o = price()
|
||||||
r = conn.do(o)
|
# r = conn.do(o)
|
||||||
b = bytes.from_hex(strip_0x(r))
|
# b = bytes.from_hex(strip_0x(r))
|
||||||
self.gas_price_current = int.from_bytes(b, 'big')
|
# self.gas_price_current = int.from_bytes(b, 'big')
|
||||||
|
#
|
||||||
#self.w3 = w3
|
# #self.w3 = w3
|
||||||
#self.gas_price_current = w3.eth.gas_price()
|
# #self.gas_price_current = w3.eth.gas_price()
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# def safe_threshold_amount(self):
|
||||||
|
# """The gas balance threshold under which a new gas refill transaction should be initiated.
|
||||||
|
#
|
||||||
|
# :returns: Gas token amount
|
||||||
|
# :rtype: number
|
||||||
|
# """
|
||||||
|
# g = GasOracle.__safe_threshold_amount_value
|
||||||
|
# logg.warning('gas safe threshold is currently hardcoded to {}'.format(g))
|
||||||
|
# return g
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# def refill_amount(self):
|
||||||
|
# """The amount of gas tokens to send in a gas refill transaction.
|
||||||
|
#
|
||||||
|
# :returns: Gas token amount
|
||||||
|
# :rtype: number
|
||||||
|
# """
|
||||||
|
# g = GasOracle.__refill_amount_value
|
||||||
|
# logg.warning('gas refill amount is currently hardcoded to {}'.format(g))
|
||||||
|
# return g
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# def gas_provider(self):
|
||||||
|
# """Gas provider address.
|
||||||
|
#
|
||||||
|
# :returns: Etheerum account address
|
||||||
|
# :rtype: str, 0x-hex
|
||||||
|
# """
|
||||||
|
# session = SessionBase.create_session()
|
||||||
|
# a = AccountRole.get_address('GAS_GIFTER', session)
|
||||||
|
# logg.debug('gasgifter {}'.format(a))
|
||||||
|
# session.close()
|
||||||
|
# return a
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# def gas_price(self, category='safe'):
|
||||||
|
# """Get projected gas price to use for a transaction at the current moment.
|
||||||
|
#
|
||||||
|
# When the category parameter is implemented, it can be used to control the priority of a transaction in the network.
|
||||||
|
#
|
||||||
|
# :param category: Bid level category to return price for. Currently has no effect.
|
||||||
|
# :type category: str
|
||||||
|
# :returns: Gas price
|
||||||
|
# :rtype: number
|
||||||
|
# """
|
||||||
|
# #logg.warning('gas price hardcoded to category "safe"')
|
||||||
|
# #g = 100
|
||||||
|
# #return g
|
||||||
|
# return self.gas_price_current
|
||||||
|
|
||||||
|
|
||||||
def safe_threshold_amount(self):
|
class MaxGasOracle:
|
||||||
"""The gas balance threshold under which a new gas refill transaction should be initiated.
|
|
||||||
|
|
||||||
:returns: Gas token amount
|
def gas(code=None):
|
||||||
:rtype: number
|
return 8000000
|
||||||
"""
|
|
||||||
g = GasOracle.__safe_threshold_amount_value
|
|
||||||
logg.warning('gas safe threshold is currently hardcoded to {}'.format(g))
|
|
||||||
return g
|
|
||||||
|
|
||||||
|
|
||||||
def refill_amount(self):
|
|
||||||
"""The amount of gas tokens to send in a gas refill transaction.
|
|
||||||
|
|
||||||
:returns: Gas token amount
|
|
||||||
:rtype: number
|
|
||||||
"""
|
|
||||||
g = GasOracle.__refill_amount_value
|
|
||||||
logg.warning('gas refill amount is currently hardcoded to {}'.format(g))
|
|
||||||
return g
|
|
||||||
|
|
||||||
|
|
||||||
def gas_provider(self):
|
|
||||||
"""Gas provider address.
|
|
||||||
|
|
||||||
:returns: Etheerum account address
|
|
||||||
:rtype: str, 0x-hex
|
|
||||||
"""
|
|
||||||
session = SessionBase.create_session()
|
|
||||||
a = AccountRole.get_address('GAS_GIFTER', session)
|
|
||||||
logg.debug('gasgifter {}'.format(a))
|
|
||||||
session.close()
|
|
||||||
return a
|
|
||||||
|
|
||||||
|
|
||||||
def gas_price(self, category='safe'):
|
|
||||||
"""Get projected gas price to use for a transaction at the current moment.
|
|
||||||
|
|
||||||
When the category parameter is implemented, it can be used to control the priority of a transaction in the network.
|
|
||||||
|
|
||||||
:param category: Bid level category to return price for. Currently has no effect.
|
|
||||||
:type category: str
|
|
||||||
:returns: Gas price
|
|
||||||
:rtype: number
|
|
||||||
"""
|
|
||||||
#logg.warning('gas price hardcoded to category "safe"')
|
|
||||||
#g = 100
|
|
||||||
#return g
|
|
||||||
return self.gas_price_current
|
|
||||||
|
|
||||||
|
|
||||||
def create_check_gas_task(tx_signed_raws_hex, chain_spec, holder_address, gas=None, tx_hashes_hex=None, queue=None):
|
def create_check_gas_task(tx_signed_raws_hex, chain_spec, holder_address, gas=None, tx_hashes_hex=None, queue=None):
|
||||||
|
@ -1,39 +1,39 @@
|
|||||||
# standard imports
|
# standard imports
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
# local imports
|
|
||||||
from cic_eth.eth.gas import GasOracle
|
|
||||||
|
|
||||||
logg = logging.getLogger()
|
logg = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class RpcClient(GasOracle):
|
class RpcClient:
|
||||||
"""RPC wrapper for web3 enabling gas calculation helpers and signer middleware.
|
pass
|
||||||
|
|
||||||
:param chain_spec: Chain spec
|
#class RpcClient(GasOracle):
|
||||||
:type chain_spec: cic_registry.chain.ChainSpec
|
# """RPC wrapper for web3 enabling gas calculation helpers and signer middleware.
|
||||||
:param holder_address: DEPRECATED Address of subject of the session.
|
#
|
||||||
:type holder_address: str, 0x-hex
|
# :param chain_spec: Chain spec
|
||||||
"""
|
# :type chain_spec: cic_registry.chain.ChainSpec
|
||||||
|
# :param holder_address: DEPRECATED Address of subject of the session.
|
||||||
signer_ipc_path = None
|
# :type holder_address: str, 0x-hex
|
||||||
"""Unix socket path to JSONRPC signer and keystore"""
|
# """
|
||||||
|
#
|
||||||
web3_constructor = None
|
# signer_ipc_path = None
|
||||||
"""Custom function to build a web3 object with middleware plugins"""
|
# """Unix socket path to JSONRPC signer and keystore"""
|
||||||
|
#
|
||||||
|
# web3_constructor = None
|
||||||
def __init__(self, chain_spec, holder_address=None):
|
# """Custom function to build a web3 object with middleware plugins"""
|
||||||
(self.provider, w3) = RpcClient.web3_constructor()
|
#
|
||||||
super(RpcClient, self).__init__(w3)
|
#
|
||||||
self.chain_spec = chain_spec
|
# def __init__(self, chain_spec, holder_address=None):
|
||||||
if holder_address != None:
|
# (self.provider, w3) = RpcClient.web3_constructor()
|
||||||
self.holder_address = holder_address
|
# super(RpcClient, self).__init__(w3)
|
||||||
logg.info('gasprice {}'.format(self.gas_price()))
|
# self.chain_spec = chain_spec
|
||||||
|
# if holder_address != None:
|
||||||
|
# self.holder_address = holder_address
|
||||||
@staticmethod
|
# logg.info('gasprice {}'.format(self.gas_price()))
|
||||||
def set_constructor(web3_constructor):
|
#
|
||||||
"""Sets the constructor to use for building the web3 object.
|
#
|
||||||
"""
|
# @staticmethod
|
||||||
RpcClient.web3_constructor = web3_constructor
|
# def set_constructor(web3_constructor):
|
||||||
|
# """Sets the constructor to use for building the web3 object.
|
||||||
|
# """
|
||||||
|
# RpcClient.web3_constructor = web3_constructor
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
pytest==6.0.1
|
pytest==6.0.1
|
||||||
pytest-celery==0.0.0a1
|
pytest-celery==0.0.0a1
|
||||||
pytest-mock==3.3.1
|
pytest-mock==3.3.1
|
||||||
py-eth==0.1.1
|
|
||||||
pytest-cov==2.10.1
|
pytest-cov==2.10.1
|
||||||
eth-tester==0.5.0b3
|
eth-tester==0.5.0b3
|
||||||
py-evm==0.3.0a20
|
py-evm==0.3.0a20
|
||||||
|
@ -9,6 +9,7 @@ sys.path.insert(0, root_dir)
|
|||||||
|
|
||||||
from tests.fixtures_config import *
|
from tests.fixtures_config import *
|
||||||
from tests.fixtures_database import *
|
from tests.fixtures_database import *
|
||||||
|
from tests.fixtures_celery import *
|
||||||
from tests.fixtures_role import *
|
from tests.fixtures_role import *
|
||||||
from chainlib.eth.pytest import *
|
from chainlib.eth.pytest import *
|
||||||
from contract_registry.pytest import *
|
from contract_registry.pytest import *
|
||||||
|
@ -11,6 +11,7 @@ logg = logging.getLogger()
|
|||||||
# celery fixtures
|
# celery fixtures
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
def celery_includes():
|
def celery_includes():
|
||||||
|
logg.debug('foooooooooooo ')
|
||||||
return [
|
return [
|
||||||
# 'cic_eth.eth.bancor',
|
# 'cic_eth.eth.bancor',
|
||||||
'cic_eth.eth.erc20',
|
'cic_eth.eth.erc20',
|
||||||
|
@ -18,14 +18,15 @@ logg = logging.getLogger()
|
|||||||
@pytest.fixture(scope='function')
|
@pytest.fixture(scope='function')
|
||||||
def custodial_roles(
|
def custodial_roles(
|
||||||
contract_roles,
|
contract_roles,
|
||||||
|
token_roles,
|
||||||
eth_accounts,
|
eth_accounts,
|
||||||
init_database,
|
init_database,
|
||||||
):
|
):
|
||||||
r = {}
|
r = {}
|
||||||
r.update(contract_roles)
|
r.update(contract_roles)
|
||||||
r.update({
|
r.update({
|
||||||
'DEFAULT': eth_accounts[0],
|
'GAS_GIFTER': eth_accounts[10],
|
||||||
'GAS_GIFTER': eth_accounts[3],
|
'FOO_TOKEN_GIFTER': token_roles['FOO_TOKEN_OWNER'],
|
||||||
})
|
})
|
||||||
for k in r.keys():
|
for k in r.keys():
|
||||||
role = AccountRole.set(k, r[k])
|
role = AccountRole.set(k, r[k])
|
||||||
|
@ -1,22 +1,65 @@
|
|||||||
|
# standard imports
|
||||||
|
import logging
|
||||||
|
|
||||||
# external imports
|
# external imports
|
||||||
|
import pytest
|
||||||
import celery
|
import celery
|
||||||
from chainlib.eth.erc20 import ERC20
|
from chainlib.eth.erc20 import ERC20
|
||||||
from chainlib.eth.nonce import RPCNonceOracle
|
from chainlib.eth.nonce import RPCNonceOracle
|
||||||
from chainlib.eth.tx import receipt
|
from chainlib.eth.tx import (
|
||||||
|
receipt,
|
||||||
|
TxFormat,
|
||||||
|
)
|
||||||
|
|
||||||
|
# local imports
|
||||||
|
from cic_eth.queue.tx import register_tx
|
||||||
|
|
||||||
|
logg = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
def test_erc20_balance(
|
def test_otx_cache_transfer(
|
||||||
default_chain_spec,
|
default_chain_spec,
|
||||||
foo_token,
|
foo_token,
|
||||||
token_roles,
|
token_roles,
|
||||||
agent_roles,
|
agent_roles,
|
||||||
eth_signer,
|
eth_signer,
|
||||||
eth_rpc,
|
eth_rpc,
|
||||||
celery_worker,
|
init_database,
|
||||||
|
celery_session_worker,
|
||||||
|
):
|
||||||
|
nonce_oracle = RPCNonceOracle(token_roles['FOO_TOKEN_OWNER'], eth_rpc)
|
||||||
|
c = ERC20(signer=eth_signer, nonce_oracle=nonce_oracle, chain_id=default_chain_spec.chain_id())
|
||||||
|
transfer_value = 100 * (10**6)
|
||||||
|
(tx_hash_hex, tx_signed_raw_hex) = c.transfer(foo_token, token_roles['FOO_TOKEN_OWNER'], agent_roles['ALICE'], transfer_value, tx_format=TxFormat.RLP_SIGNED)
|
||||||
|
register_tx(tx_hash_hex, tx_signed_raw_hex, default_chain_spec, None, session=init_database)
|
||||||
|
|
||||||
|
s = celery.signature(
|
||||||
|
'cic_eth.eth.erc20.cache_transfer_data',
|
||||||
|
[
|
||||||
|
tx_hash_hex,
|
||||||
|
tx_signed_raw_hex,
|
||||||
|
default_chain_spec.asdict(),
|
||||||
|
],
|
||||||
|
queue=None,
|
||||||
|
)
|
||||||
|
t = s.apply_async()
|
||||||
|
r = t.get()
|
||||||
|
|
||||||
|
assert r[0] == tx_hash_hex
|
||||||
|
|
||||||
|
|
||||||
|
def test_erc20_balance_task(
|
||||||
|
default_chain_spec,
|
||||||
|
foo_token,
|
||||||
|
token_roles,
|
||||||
|
agent_roles,
|
||||||
|
eth_signer,
|
||||||
|
eth_rpc,
|
||||||
|
celery_session_worker,
|
||||||
):
|
):
|
||||||
|
|
||||||
nonce_oracle = RPCNonceOracle(token_roles['FOO_TOKEN_OWNER'], eth_rpc)
|
nonce_oracle = RPCNonceOracle(token_roles['FOO_TOKEN_OWNER'], eth_rpc)
|
||||||
c = ERC20(signer=eth_signer, nonce_oracle=nonce_oracle)
|
c = ERC20(signer=eth_signer, nonce_oracle=nonce_oracle, chain_id=default_chain_spec.chain_id())
|
||||||
transfer_value = 100 * (10**6)
|
transfer_value = 100 * (10**6)
|
||||||
(tx_hash_hex, o) = c.transfer(foo_token, token_roles['FOO_TOKEN_OWNER'], agent_roles['ALICE'], transfer_value)
|
(tx_hash_hex, o) = c.transfer(foo_token, token_roles['FOO_TOKEN_OWNER'], agent_roles['ALICE'], transfer_value)
|
||||||
eth_rpc.do(o)
|
eth_rpc.do(o)
|
||||||
@ -41,3 +84,84 @@ def test_erc20_balance(
|
|||||||
r = t.get()
|
r = t.get()
|
||||||
assert r[0]['balance_network'] == transfer_value
|
assert r[0]['balance_network'] == transfer_value
|
||||||
|
|
||||||
|
|
||||||
|
def test_erc20_transfer_task(
|
||||||
|
default_chain_spec,
|
||||||
|
foo_token,
|
||||||
|
agent_roles,
|
||||||
|
custodial_roles,
|
||||||
|
eth_signer,
|
||||||
|
eth_rpc,
|
||||||
|
init_database,
|
||||||
|
celery_session_worker,
|
||||||
|
):
|
||||||
|
|
||||||
|
token_object = {
|
||||||
|
'address': foo_token,
|
||||||
|
}
|
||||||
|
transfer_value = 100 * (10 ** 6)
|
||||||
|
|
||||||
|
s_nonce = celery.signature(
|
||||||
|
'cic_eth.eth.tx.reserve_nonce',
|
||||||
|
[
|
||||||
|
[token_object],
|
||||||
|
custodial_roles['FOO_TOKEN_GIFTER'],
|
||||||
|
],
|
||||||
|
queue=None,
|
||||||
|
)
|
||||||
|
s_transfer = celery.signature(
|
||||||
|
'cic_eth.eth.erc20.transfer',
|
||||||
|
[
|
||||||
|
custodial_roles['FOO_TOKEN_GIFTER'],
|
||||||
|
agent_roles['ALICE'],
|
||||||
|
transfer_value,
|
||||||
|
default_chain_spec.asdict(),
|
||||||
|
],
|
||||||
|
queue=None,
|
||||||
|
)
|
||||||
|
s_nonce.link(s_transfer)
|
||||||
|
t = s_nonce.apply_async()
|
||||||
|
r = t.get_leaf()
|
||||||
|
|
||||||
|
logg.debug('result {}'.format(r))
|
||||||
|
|
||||||
|
|
||||||
|
def test_erc20_approve_task(
|
||||||
|
default_chain_spec,
|
||||||
|
foo_token,
|
||||||
|
agent_roles,
|
||||||
|
custodial_roles,
|
||||||
|
eth_signer,
|
||||||
|
eth_rpc,
|
||||||
|
init_database,
|
||||||
|
celery_session_worker,
|
||||||
|
):
|
||||||
|
|
||||||
|
token_object = {
|
||||||
|
'address': foo_token,
|
||||||
|
}
|
||||||
|
transfer_value = 100 * (10 ** 6)
|
||||||
|
|
||||||
|
s_nonce = celery.signature(
|
||||||
|
'cic_eth.eth.tx.reserve_nonce',
|
||||||
|
[
|
||||||
|
[token_object],
|
||||||
|
custodial_roles['FOO_TOKEN_GIFTER'],
|
||||||
|
],
|
||||||
|
queue=None,
|
||||||
|
)
|
||||||
|
s_transfer = celery.signature(
|
||||||
|
'cic_eth.eth.erc20.approve',
|
||||||
|
[
|
||||||
|
custodial_roles['FOO_TOKEN_GIFTER'],
|
||||||
|
agent_roles['ALICE'],
|
||||||
|
transfer_value,
|
||||||
|
default_chain_spec.asdict(),
|
||||||
|
],
|
||||||
|
queue=None,
|
||||||
|
)
|
||||||
|
s_nonce.link(s_transfer)
|
||||||
|
t = s_nonce.apply_async()
|
||||||
|
r = t.get_leaf()
|
||||||
|
|
||||||
|
logg.debug('result {}'.format(r))
|
||||||
|
Loading…
Reference in New Issue
Block a user