Compare commits
1 Commits
master
...
lash/new-t
Author | SHA1 | Date | |
---|---|---|---|
|
dc3461e48e |
@ -1 +1 @@
|
|||||||
Subproject commit 06c5f0fb0dca5992a7ffb12874b5cb0c9fdcd706
|
Subproject commit d2cb3a45558d7ca3a412c97c6aea794d9ac6c6f5
|
@ -1,194 +0,0 @@
|
|||||||
# standard imports
|
|
||||||
import logging
|
|
||||||
|
|
||||||
# third-party imports
|
|
||||||
import web3
|
|
||||||
import celery
|
|
||||||
from erc20_approval_escrow import TransferApproval
|
|
||||||
from cic_registry import CICRegistry
|
|
||||||
from cic_registry.chain import ChainSpec
|
|
||||||
|
|
||||||
# local imports
|
|
||||||
from cic_eth.db.models.tx import TxCache
|
|
||||||
from cic_eth.db.models.base import SessionBase
|
|
||||||
from cic_eth.eth import RpcClient
|
|
||||||
from cic_eth.eth.factory import TxFactory
|
|
||||||
from cic_eth.eth.task import sign_and_register_tx
|
|
||||||
from cic_eth.eth.util import unpack_signed_raw_tx
|
|
||||||
from cic_eth.eth.task import create_check_gas_and_send_task
|
|
||||||
from cic_eth.error import TokenCountError
|
|
||||||
|
|
||||||
celery_app = celery.current_app
|
|
||||||
logg = logging.getLogger()
|
|
||||||
|
|
||||||
contract_function_signatures = {
|
|
||||||
'request': 'b0addede',
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class TransferRequestTxFactory(TxFactory):
|
|
||||||
"""Factory for creating Transfer request transactions using the TransferApproval contract backend
|
|
||||||
"""
|
|
||||||
def request(
|
|
||||||
self,
|
|
||||||
token_address,
|
|
||||||
beneficiary_address,
|
|
||||||
amount,
|
|
||||||
chain_spec,
|
|
||||||
):
|
|
||||||
"""Create a new TransferApproval.request transaction
|
|
||||||
|
|
||||||
:param token_address: Token to create transfer request for
|
|
||||||
:type token_address: str, 0x-hex
|
|
||||||
:param beneficiary_address: Beneficiary of token transfer
|
|
||||||
:type beneficiary_address: str, 0x-hex
|
|
||||||
:param amount: Amount of tokens to transfer
|
|
||||||
:type amount: number
|
|
||||||
:param chain_spec: Chain spec
|
|
||||||
:type chain_spec: cic_registry.chain.ChainSpec
|
|
||||||
:returns: Transaction in standard Ethereum format
|
|
||||||
:rtype: dict
|
|
||||||
"""
|
|
||||||
transfer_approval = CICRegistry.get_contract(chain_spec, 'TransferApproval', 'TransferAuthorization')
|
|
||||||
fn = transfer_approval.function('createRequest')
|
|
||||||
tx_approval_buildable = fn(beneficiary_address, token_address, amount)
|
|
||||||
transfer_approval_gas = transfer_approval.gas('createRequest')
|
|
||||||
|
|
||||||
tx_approval = tx_approval_buildable.buildTransaction({
|
|
||||||
'from': self.address,
|
|
||||||
'gas': transfer_approval_gas,
|
|
||||||
'gasPrice': self.gas_price,
|
|
||||||
'chainId': chain_spec.chain_id(),
|
|
||||||
'nonce': self.next_nonce(),
|
|
||||||
})
|
|
||||||
return tx_approval
|
|
||||||
|
|
||||||
|
|
||||||
def unpack_transfer_approval_request(data):
|
|
||||||
"""Verifies that a transaction is an "TransferApproval.request" transaction, and extracts call parameters from it.
|
|
||||||
|
|
||||||
:param data: Raw input data from Ethereum transaction.
|
|
||||||
:type data: str, 0x-hex
|
|
||||||
:raises ValueError: Function signature does not match AccountRegister.add
|
|
||||||
:returns: Parsed parameters
|
|
||||||
:rtype: dict
|
|
||||||
"""
|
|
||||||
f = data[2:10]
|
|
||||||
if f != contract_function_signatures['request']:
|
|
||||||
raise ValueError('Invalid transfer request data ({})'.format(f))
|
|
||||||
|
|
||||||
d = data[10:]
|
|
||||||
return {
|
|
||||||
'to': web3.Web3.toChecksumAddress('0x' + d[64-40:64]),
|
|
||||||
'token': web3.Web3.toChecksumAddress('0x' + d[128-40:128]),
|
|
||||||
'amount': int(d[128:], 16)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@celery_app.task(bind=True)
|
|
||||||
def transfer_approval_request(self, tokens, holder_address, receiver_address, value, chain_str):
|
|
||||||
"""Creates a new transfer approval
|
|
||||||
|
|
||||||
:param tokens: Token to generate transfer request for
|
|
||||||
:type tokens: list with single token spec as dict
|
|
||||||
:param holder_address: Address to generate transfer on behalf of
|
|
||||||
:type holder_address: str, 0x-hex
|
|
||||||
:param receiver_address: Address to transfser tokens to
|
|
||||||
:type receiver_address: str, 0x-hex
|
|
||||||
:param value: Amount of tokens to transfer
|
|
||||||
:type value: number
|
|
||||||
:param chain_spec: Chain spec string representation
|
|
||||||
:type chain_spec: str
|
|
||||||
:raises cic_eth.error.TokenCountError: More than one token in tokens argument
|
|
||||||
:returns: Raw signed transaction
|
|
||||||
:rtype: list with transaction as only element
|
|
||||||
"""
|
|
||||||
|
|
||||||
if len(tokens) != 1:
|
|
||||||
raise TokenCountError
|
|
||||||
|
|
||||||
chain_spec = ChainSpec.from_chain_str(chain_str)
|
|
||||||
|
|
||||||
queue = self.request.delivery_info['routing_key']
|
|
||||||
|
|
||||||
t = tokens[0]
|
|
||||||
|
|
||||||
c = RpcClient(holder_address)
|
|
||||||
|
|
||||||
txf = TransferRequestTxFactory(holder_address, c)
|
|
||||||
|
|
||||||
tx_transfer = txf.request(t['address'], receiver_address, value, chain_spec)
|
|
||||||
(tx_hash_hex, tx_signed_raw_hex) = sign_and_register_tx(tx_transfer, chain_str, queue, 'cic_eth.eth.request.otx_cache_transfer_approval_request')
|
|
||||||
|
|
||||||
gas_budget = tx_transfer['gas'] * tx_transfer['gasPrice']
|
|
||||||
|
|
||||||
s = create_check_gas_and_send_task(
|
|
||||||
[tx_signed_raw_hex],
|
|
||||||
chain_str,
|
|
||||||
holder_address,
|
|
||||||
gas_budget,
|
|
||||||
[tx_hash_hex],
|
|
||||||
queue,
|
|
||||||
)
|
|
||||||
s.apply_async()
|
|
||||||
return [tx_signed_raw_hex]
|
|
||||||
|
|
||||||
|
|
||||||
@celery_app.task()
|
|
||||||
def otx_cache_transfer_approval_request(
|
|
||||||
tx_hash_hex,
|
|
||||||
tx_signed_raw_hex,
|
|
||||||
chain_str,
|
|
||||||
):
|
|
||||||
"""Generates and commits transaction cache metadata for an TransferApproval.request 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())
|
|
||||||
logg.debug('in otx acche transfer approval request')
|
|
||||||
(txc, cache_id) = cache_transfer_approval_request_data(tx_hash_hex, tx)
|
|
||||||
return txc
|
|
||||||
|
|
||||||
|
|
||||||
@celery_app.task()
|
|
||||||
def cache_transfer_approval_request_data(
|
|
||||||
tx_hash_hex,
|
|
||||||
tx,
|
|
||||||
):
|
|
||||||
"""Helper function for otx_cache_transfer_approval_request
|
|
||||||
|
|
||||||
:param tx_hash_hex: Transaction hash
|
|
||||||
:type tx_hash_hex: str, 0x-hex
|
|
||||||
:param tx: Signed raw transaction
|
|
||||||
:type tx: str, 0x-hex
|
|
||||||
:returns: Transaction hash and id of cache element in storage backend, respectively
|
|
||||||
:rtype: tuple
|
|
||||||
"""
|
|
||||||
tx_data = unpack_transfer_approval_request(tx['data'])
|
|
||||||
logg.debug('tx approval request data {}'.format(tx_data))
|
|
||||||
logg.debug('tx approval request {}'.format(tx))
|
|
||||||
|
|
||||||
session = SessionBase.create_session()
|
|
||||||
tx_cache = TxCache(
|
|
||||||
tx_hash_hex,
|
|
||||||
tx['from'],
|
|
||||||
tx_data['to'],
|
|
||||||
tx_data['token'],
|
|
||||||
tx_data['token'],
|
|
||||||
tx_data['amount'],
|
|
||||||
tx_data['amount'],
|
|
||||||
)
|
|
||||||
session.add(tx_cache)
|
|
||||||
session.commit()
|
|
||||||
cache_id = tx_cache.id
|
|
||||||
session.close()
|
|
||||||
return (tx_hash_hex, cache_id)
|
|
@ -55,62 +55,25 @@ SessionBase.connect(dsn)
|
|||||||
celery_app = celery.Celery(backend=config.get('CELERY_RESULT_URL'), broker=config.get('CELERY_BROKER_URL'))
|
celery_app = celery.Celery(backend=config.get('CELERY_RESULT_URL'), broker=config.get('CELERY_BROKER_URL'))
|
||||||
queue = args.q
|
queue = args.q
|
||||||
|
|
||||||
re_transfer_approval_request = r'^/transferrequest/?'
|
re_something = r'^/something/?'
|
||||||
|
|
||||||
chain_spec = ChainSpec.from_chain_str(config.get('CIC_CHAIN_SPEC'))
|
chain_spec = ChainSpec.from_chain_str(config.get('CIC_CHAIN_SPEC'))
|
||||||
|
|
||||||
|
|
||||||
def process_transfer_approval_request(session, env):
|
def process_something(session, env):
|
||||||
r = re.match(re_transfer_approval_request, env.get('PATH_INFO'))
|
r = re.match(re_something, env.get('PATH_INFO'))
|
||||||
if not r:
|
if not r:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if env.get('CONTENT_TYPE') != 'application/json':
|
#if env.get('CONTENT_TYPE') != 'application/json':
|
||||||
raise AttributeError('content type')
|
# raise AttributeError('content type')
|
||||||
|
|
||||||
if env.get('REQUEST_METHOD') != 'POST':
|
#if env.get('REQUEST_METHOD') != 'POST':
|
||||||
raise AttributeError('method')
|
# raise AttributeError('method')
|
||||||
|
|
||||||
post_data = json.load(env.get('wsgi.input'))
|
#post_data = json.load(env.get('wsgi.input'))
|
||||||
token_address = web3.Web3.toChecksumAddress(post_data['token_address'])
|
|
||||||
holder_address = web3.Web3.toChecksumAddress(post_data['holder_address'])
|
|
||||||
beneficiary_address = web3.Web3.toChecksumAddress(post_data['beneficiary_address'])
|
|
||||||
value = int(post_data['value'])
|
|
||||||
|
|
||||||
logg.debug('transfer approval request token {} to {} from {} value {}'.format(
|
#return ('text/plain', 'foo'.encode('utf-8'),)
|
||||||
token_address,
|
|
||||||
beneficiary_address,
|
|
||||||
holder_address,
|
|
||||||
value,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
s = celery.signature(
|
|
||||||
'cic_eth.eth.request.transfer_approval_request',
|
|
||||||
[
|
|
||||||
[
|
|
||||||
{
|
|
||||||
'address': token_address,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
holder_address,
|
|
||||||
beneficiary_address,
|
|
||||||
value,
|
|
||||||
config.get('CIC_CHAIN_SPEC'),
|
|
||||||
],
|
|
||||||
queue=queue,
|
|
||||||
)
|
|
||||||
t = s.apply_async()
|
|
||||||
r = t.get()
|
|
||||||
tx_raw_bytes = bytes.fromhex(r[0][2:])
|
|
||||||
tx = unpack_signed_raw_tx(tx_raw_bytes, chain_spec.chain_id())
|
|
||||||
for r in t.collect():
|
|
||||||
logg.debug('result {}'.format(r))
|
|
||||||
|
|
||||||
if not t.successful():
|
|
||||||
raise RuntimeError(tx['hash'])
|
|
||||||
|
|
||||||
return ('text/plain', tx['hash'].encode('utf-8'),)
|
|
||||||
|
|
||||||
|
|
||||||
# uwsgi application
|
# uwsgi application
|
||||||
@ -125,7 +88,7 @@ def application(env, start_response):
|
|||||||
|
|
||||||
session = SessionBase.create_session()
|
session = SessionBase.create_session()
|
||||||
for handler in [
|
for handler in [
|
||||||
process_transfer_approval_request,
|
process_something,
|
||||||
]:
|
]:
|
||||||
try:
|
try:
|
||||||
r = handler(session, env)
|
r = handler(session, env)
|
||||||
|
@ -9,8 +9,9 @@ alembic==1.4.2
|
|||||||
websockets==8.1
|
websockets==8.1
|
||||||
requests~=2.24.0
|
requests~=2.24.0
|
||||||
eth_accounts_index~=0.0.10a7
|
eth_accounts_index~=0.0.10a7
|
||||||
erc20-approval-escrow~=0.3.0a5
|
erc20-transfer-authorization~=0.3.0a7
|
||||||
erc20-single-shot-faucet~=0.2.0a6
|
erc20-single-shot-faucet~=0.2.0a6
|
||||||
|
eth-address-index~=0.1.0a8
|
||||||
rlp==2.0.1
|
rlp==2.0.1
|
||||||
uWSGI==2.0.19.1
|
uWSGI==2.0.19.1
|
||||||
semver==2.13.0
|
semver==2.13.0
|
||||||
|
@ -22,7 +22,7 @@ RUN echo Install confini schema files && \
|
|||||||
ENV CONFINI_DIR /usr/local/etc/cic
|
ENV CONFINI_DIR /usr/local/etc/cic
|
||||||
|
|
||||||
|
|
||||||
ARG cic_contracts_commit=698ef3a30fde8d7f2c498f1208fb0ff45d665501
|
ARG cic_contracts_commit=9933979e14484e826523df23a0b11480799f6380
|
||||||
ARG cic_contracts_url=https://gitlab.com/grassrootseconomics/cic-contracts.git/
|
ARG cic_contracts_url=https://gitlab.com/grassrootseconomics/cic-contracts.git/
|
||||||
RUN echo Install ABI collection for solidity interfaces used across all components && \
|
RUN echo Install ABI collection for solidity interfaces used across all components && \
|
||||||
git clone --depth 1 $cic_contracts_url cic-contracts && \
|
git clone --depth 1 $cic_contracts_url cic-contracts && \
|
||||||
@ -106,7 +106,7 @@ RUN cd cic-bancor/python && \
|
|||||||
pip install --extra-index-url $pip_extra_index_url .
|
pip install --extra-index-url $pip_extra_index_url .
|
||||||
|
|
||||||
RUN echo installing common python tooling
|
RUN echo installing common python tooling
|
||||||
ARG cic_python_commit=beecee783ceac2ea0fa711f888ce4c82f1a81490
|
ARG cic_python_commit=4573afb7ad4d635c2f3330b8b9b25806523b7e14
|
||||||
ARG cic_python_url=https://gitlab.com/grassrootseconomics/cic-python.git/
|
ARG cic_python_url=https://gitlab.com/grassrootseconomics/cic-python.git/
|
||||||
RUN echo Install sum of python dependencies across all components && \
|
RUN echo Install sum of python dependencies across all components && \
|
||||||
git clone --depth 1 $cic_python_url cic-python && \
|
git clone --depth 1 $cic_python_url cic-python && \
|
||||||
@ -126,8 +126,8 @@ RUN pip install --extra-index-url $pip_extra_index_url giftable-erc20-token==$gi
|
|||||||
ARG eth_accounts_index_version=0.0.10a6
|
ARG eth_accounts_index_version=0.0.10a6
|
||||||
RUN pip install --extra-index-url $pip_extra_index_url eth-accounts-index==$eth_accounts_index_version
|
RUN pip install --extra-index-url $pip_extra_index_url eth-accounts-index==$eth_accounts_index_version
|
||||||
|
|
||||||
ARG erc20_approval_escrow_version=0.3.0a4
|
ARG erc20_transfer_authorization_version=0.3.0a8
|
||||||
RUN pip install --extra-index-url $pip_extra_index_url erc20-approval-escrow==$erc20_approval_escrow_version
|
RUN pip install --extra-index-url $pip_extra_index_url erc20-transfer-authorization==$erc20_transfer_authorization_version
|
||||||
|
|
||||||
ARG erc20_single_shot_faucet_version=0.2.0a5
|
ARG erc20_single_shot_faucet_version=0.2.0a5
|
||||||
RUN pip install --extra-index-url $pip_extra_index_url erc20-single-shot-faucet==$erc20_single_shot_faucet_version
|
RUN pip install --extra-index-url $pip_extra_index_url erc20-single-shot-faucet==$erc20_single_shot_faucet_version
|
||||||
|
@ -9,7 +9,7 @@ ecuth==0.4.5a1
|
|||||||
eth-accounts-index==0.0.10a7
|
eth-accounts-index==0.0.10a7
|
||||||
eth-address-index==0.1.0a7
|
eth-address-index==0.1.0a7
|
||||||
eth-tester==0.5.0b3
|
eth-tester==0.5.0b3
|
||||||
erc20-approval-escrow==0.3.0a5
|
erc20-transfer-authorization==0.3.0a7
|
||||||
erc20-single-shot-faucet==0.2.0a6
|
erc20-single-shot-faucet==0.2.0a6
|
||||||
faker==4.17.1
|
faker==4.17.1
|
||||||
http-hoba-auth==0.2.0
|
http-hoba-auth==0.2.0
|
||||||
|
Loading…
Reference in New Issue
Block a user