From f856ca3f68c44cce25527c3f0323ec0602c24b38 Mon Sep 17 00:00:00 2001 From: William Luke Date: Tue, 26 Oct 2021 15:48:25 +0300 Subject: [PATCH] init graphene --- .envrc | 2 + apps/cic-eth/cic_eth/api/api_task.py | 8 +- apps/cic-eth/cic_eth/graphql/schema.py | 235 +++++++++++++++++++++++++ apps/cic-eth/requirements.txt | 1 + 4 files changed, 242 insertions(+), 4 deletions(-) create mode 100644 .envrc create mode 100644 apps/cic-eth/cic_eth/graphql/schema.py diff --git a/.envrc b/.envrc new file mode 100644 index 00000000..6ad52af5 --- /dev/null +++ b/.envrc @@ -0,0 +1,2 @@ +export COMPOSE_DOCKER_CLI_BUILD=1 +export DOCKER_BUILDKIT=1 \ No newline at end of file diff --git a/apps/cic-eth/cic_eth/api/api_task.py b/apps/cic-eth/cic_eth/api/api_task.py index b0ecf047..92b8f8dd 100644 --- a/apps/cic-eth/cic_eth/api/api_task.py +++ b/apps/cic-eth/cic_eth/api/api_task.py @@ -430,13 +430,13 @@ class Api(ApiBase): return t - def balance(self, address, token_symbol, include_pending=True): + def balance(self, address, token_symbols, include_pending=True): """Calls the provided callback with the current token balance of the given address. :param address: Ethereum address of holder :type address: str, 0x-hex - :param token_symbol: ERC20 token symbol of token to send - :type token_symbol: str + :param token_symbols: ERC20 token symbols of tokens to send + :type token_symbols: list[str] :param include_pending: If set, will include transactions that have not yet been fully processed :type include_pending: bool :returns: uuid of root task @@ -448,7 +448,7 @@ class Api(ApiBase): s_tokens = celery.signature( 'cic_eth.eth.erc20.resolve_tokens_by_symbol', [ - [token_symbol], + token_symbols, self.chain_spec.asdict(), ], queue=self.queue, diff --git a/apps/cic-eth/cic_eth/graphql/schema.py b/apps/cic-eth/cic_eth/graphql/schema.py new file mode 100644 index 00000000..3fbacc38 --- /dev/null +++ b/apps/cic-eth/cic_eth/graphql/schema.py @@ -0,0 +1,235 @@ +# standard imports +import json +import sys +import uuid + +import cic_eth.cli +import redis +from cic_eth.api.api_task import Api +from graphene import (Boolean, Field, Float, Int, List, Mutation, ObjectType, + Schema, String) + +arg_flags = cic_eth.cli.argflag_std_base +local_arg_flags = cic_eth.cli.argflag_local_taskcallback +argparser = cic_eth.cli.ArgumentParser(arg_flags) + +argparser.process_local_flags(local_arg_flags) +args = argparser.parse_args() +config = cic_eth.cli.Config.from_args(args, arg_flags, local_arg_flags) + +celery_app = cic_eth.cli.CeleryApp.from_config(config) + + +def call(method, *args): + chain_spec = config.get('CHAIN_SPEC') + redis_host = config.get('REDIS_HOST') + redis_port = config.get('REDIS_PORT') + redis_db = config.get('REDIS_DB') + celery_queue = config.get('CELERY_QUEUE') + + redis_channel = str(uuid.uuid4()) + + r = redis.Redis(redis_host, redis_port, redis_db) + + ps = r.pubsub() + ps.subscribe(redis_channel) + ps.get_message() # Subscription Object + + api = Api( + chain_spec, + queue=celery_queue, + callback_param='{}:{}:{}:{}'.format( + redis_host, redis_port, redis_db, redis_channel), + callback_task='cic_eth.callbacks.redis.redis', + callback_queue=celery_queue, + ) + print(args) + + getattr(api, method)(*args) + + ps.get_message() # returns None !? + try: + o = ps.get_message(timeout=config.get('REDIS_TIMEOUT')) + except TimeoutError as e: + sys.stderr.write( + 'got no new address from cic-eth before timeout: {}\n'.format(e)) + sys.exit(1) + ps.unsubscribe() + m = json.loads(o['data']) + return m["result"] + + +class Token(ObjectType): + symbol = String() + address = String() + name = String() + decimals = Int() + + +class TokenBalance(ObjectType): + address = String() + converters = List(String) + balance_network = Int() + balance_incoming = Int(default_value=0) + balance_outgoing = Int(default_value=0) + balance_available = Int(default_value=0) + + def resolve_balance_available(parent, info): + print(parent) + return (parent.balance_network + parent.balance_incoming) - parent.balance_outgoing + + +class Query(ObjectType): + default_token = Field(Token) + + def resolve_default_token(parent, info): + # always pass an object for `me` field + data = call('default_token') + print(data) + return Token(**data) + + balance = Field(List(TokenBalance), address=String(), + token_symbols=List(String), include_pending=Boolean()) + + def resolve_balance(root, info, address, token_symbols, include_pending=True): + data = call('balance', address, token_symbols, include_pending) + print(data) + #[{'address': '3ff776b6f888980def9d4220858803f9dc5e341e', 'converters': [], 'balance_network': 0}] + return map(lambda token: TokenBalance(**token), data) + + +class CreateAccount(Mutation): + address = String() + + class Arguments: + password = String(required=True) + register = Boolean() + + def mutate(root, info, password, register=True): + print(password, register) + + address = call('create_account', password, register) + return CreateAccount(address=f"0x{address}") + + +class Transfer(Mutation): + test = String(default_value="test") + + class Arguments: + from_address = String(required=True) + to_address = String(required=True) + value = Int(required=True) + token_symbol = String(required=True) + + def mutate(root, info, from_address, + to_address, + value, + token_symbol): + print(from_address, to_address, value, token_symbol) + + data = call('transfer', from_address, + to_address, + value, + token_symbol) + print(data) + return data +# 0x0000000000000000000000000000000000000000 + + +class TransferFrom(Mutation): + address = String() + + class Arguments: + from_address = String(required=True) + to_address = String(required=True) + value = Int(required=True) + token_symbol = String(required=True) + spender_address = String(required=True) + + def mutate(root, info, from_address, + to_address, + value, + token_symbol, spender_address): + + data = call('transfer_from', from_address, + to_address, + value, + token_symbol, spender_address) + return data + + +class MyMutations(ObjectType): + create_account = CreateAccount.Field() + transfer = Transfer.Field() + + +schema = Schema(query=Query, mutation=MyMutations) + + +query_with_argument = """ +{ + defaultToken{ + symbol + } +} + +""" +result = schema.execute(query_with_argument) +print(result) + + +mutation_with_argument = """ +mutation { + createAccount(password:"test"){ + address + } +} + +""" +m_result = schema.execute(mutation_with_argument) +print(m_result) + + +balance_query = """ +query { + balance(address:"0x82e66cf2766bf20672a605bbf5a6faaa12d5b907", tokenSymbols:["GFT"]){ + balanceNetwork + balanceIncoming + balanceOutgoing + balanceAvailable + } +} + +""" +balance_query_result = schema.execute(balance_query) +print(balance_query_result) + + +transfer_mutation = """ +mutation { + transfer(fromAddress :"0x0000000000000000000000000000000000000000", +toAddress: "0x82e66cf2766bf20672a605bbf5a6faaa12d5b907" +value: 5000 +tokenSymbol: "GFT" ){ + test + } +} + +""" +transfer_mutation_result = schema.execute(transfer_mutation) +print(transfer_mutation_result) + + +balance_query = """ +query { + balance(address:"0x82e66cf2766bf20672a605bbf5a6faaa12d5b907", tokenSymbols:["GFT"]){ + balanceNetwork + balanceIncoming + balanceOutgoing + balanceAvailable + } +} + +""" +balance_query_result = schema.execute(balance_query) +print(balance_query_result) diff --git a/apps/cic-eth/requirements.txt b/apps/cic-eth/requirements.txt index 823e02e1..74239a6c 100644 --- a/apps/cic-eth/requirements.txt +++ b/apps/cic-eth/requirements.txt @@ -3,3 +3,4 @@ chainlib-eth>=0.0.10a4,<0.1.0 semver==2.13.0 crypto-dev-signer>=0.4.15rc2,<0.5.0 uwsgi==2.0.19.1 +graphene>=2.0 \ No newline at end of file