1

Let's take these two examples here, they are swaps done on VVS SINGLE/USDC Liquidity Pool:

Example 1: Buy USDC with SINGLE (i.e. SELL SINGLE) https://cronoscan.com/tx/0xbd958b205291355d681cf01fa01f2064078d7be3b1ba63be8a9d2dff72bcce48 enter image description here

Example 2: Buy SINGLE with USDC (i.e. BUY SINGLE) https://cronoscan.com/tx/0x4f8898c244bd7bc7f77d6d8aec7af670ff6d86f252d9d231860dc1528dacf91c enter image description here

If you follow steps to decode the transaction using contract.events.Transfer().processReceipt,

from typing import Dict
from web3 import Web3
from web3.exceptions import TransactionNotFound

cronos_mainnet_rpc = "https://evm.cronos.org" w3 = Web3(Web3.HTTPProvider(cronos_mainnet_rpc))

pool_address = Web3.toChecksumAddress("0x0fBAB8A90CAC61b481530AAd3a64fE17B322C25d") pool_abi = '... very long ...' pool_contract = w3.eth.contract(address=pool_address, abi=pool_abi)

trx_hash = '0xbd958b205291355d681cf01fa01f2064078d7be3b1ba63be8a9d2dff72bcce48' trx = w3.eth.getTransaction(trx_hash) # This only means you sent the transaction. It does not mean it succeeded. trx_block_number = trx.blockNumber trx_unix_ts = w3.eth.getBlock(trx_block_number).timestamp status : int = -1 while True: try: trx_receipt = w3.eth.getTransactionReceipt(trx_hash) status = trx_receipt['status'] if status == 0 or status == 1: logs_summary = []

        from web3._utils.events import EventLogErrorFlags
        logs = pool_contract.events.Transfer().processReceipt(trx_receipt, EventLogErrorFlags.Warn)
        for log in logs:
            transaction_type = log.event    
            log_index = log.logIndex # Each 'log' has different log_index, you can use it to determine which is first and which comes after.
            transaction_index = log.transactionIndex # But they have same transaction_index!
            sender_address = log.args['from']
            destination_address = log.args['to']
            amount = log.args['value']

            logs_summary.append( {
                'log_index' : log_index,
                'transaction_index' : transaction_index,
                'transaction_type' : transaction_type,
                'sender_address' : sender_address,
                'destination_address' : destination_address,
                'amount' : amount
            })

        break
except TransactionNotFound:
    # Transaction not found!
    pass

trx_status : str = "Pending" if status==1: trx_status = "Confirmmed" elif status==0: trx_status = "Reverted"

transaction_report : Dict = { 'trx_hash' : trx_hash, 'trx_block_number' : trx.blockNumber, 'status' : trx_status, 'trx_unix_ts' : trx_unix_ts, 'logs' : logs_summary }

There's nothing from "logs" which tells you whether you're buying? Or selling the SINGLE coin? enter image description here

Note

  • 0x0fBAB8A90CAC61b481530AAd3a64fE17B322C25d is SINGLE/USDC liquidity pool on VVS/Cronos chain.
  • 0x88D669588b50F3cAa21507Ee5A867f132F9db97C is the wallet address

Question is, from "logs" (Nothing under log.args definitely), I find nothing which can tell me whether the transaction is a BUY trade? or a SELL trade.

logs = pool_contract.events.Transfer().processReceipt(trx_receipt, EventLogErrorFlags.Warn)

This is important as in additional to the first objective, which is to be able to tell whether it's BUY vs SELL, this information will also help me to adjust "amount" using either USDC's decimal, or SINGLE's decimal. That'd be the second objective.

web3.py get_transaction status, amounts in/out, sender/receiver address, transaction_type (Swap? Mint? Burn?), gasUsed etc

user3761555
  • 171
  • 1
  • 7

2 Answers2

2

This cracked the case:

from web3 import Web3
from web3.logs import DISCARD

EIP20_ABI = '[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}]' # noqa w3_cro = Web3(Web3.HTTPProvider("https://evm.cronos.org")) generic_token_contract = w3_cro.eth.contract(abi=EIP20_ABI)

def get_swap_details(trx_hash): receipt = w3_cro.eth.get_transaction_receipt(trx_hash) sender = receipt["from"] print("##### Swap Trx Hash:", trx_hash, "#####") print("wallet:", sender) events = generic_token_contract.events transfers = events.Transfer().processReceipt(receipt, errors=DISCARD)

for t in transfers:
    args = t["args"]
    if args['_from'] == sender:
        direction = "SELLS"
    elif args['_to'] == sender:
        direction = "BUYS"
    else:
        continue
    token_address = t["address"]
    value = args["_value"]

    token_contract = w3_cro.eth.contract(address=token_address, abi=EIP20_ABI)
    token_symbol = token_contract.functions.symbol().call()
    token_decimals = token_contract.functions.decimals().call()

    print(direction, value / 10**token_decimals, token_symbol)

print()


if name == "main": # Example 1. Single-hop. Buy USDC with SINGLE https://cronoscan.com/tx/0xbd958b205291355d681cf01fa01f2064078d7be3b1ba63be8a9d2dff72bcce48 swap_trx_hash = "0xbd958b205291355d681cf01fa01f2064078d7be3b1ba63be8a9d2dff72bcce48" get_swap_details(swap_trx_hash) # Example 2. Single-hop. Buy SINGLE with USDC https://cronoscan.com/tx/0x4f8898c244bd7bc7f77d6d8aec7af670ff6d86f252d9d231860dc1528dacf91c swap_trx_hash = "0x4f8898c244bd7bc7f77d6d8aec7af670ff6d86f252d9d231860dc1528dacf91c" get_swap_details(swap_trx_hash) # Example 3. Two hops. Buy USDT with SINGLE https://cronoscan.com/tx/0x1b09a08c87a2015a34fa05883cf1005715ff64d90772c044b02f80e646a69951 swap_trx_hash = "0x1b09a08c87a2015a34fa05883cf1005715ff64d90772c044b02f80e646a69951" get_swap_details(swap_trx_hash) # Example 4. Two hops. Buy SINGLE with USDT https://cronoscan.com/tx/0x4eff6d10c7310d272dc999d8c0acffcf18ff43b6802411a069570c43564d5579 swap_trx_hash = "0x4eff6d10c7310d272dc999d8c0acffcf18ff43b6802411a069570c43564d5579" get_swap_details(swap_trx_hash)

Output - it will look same as what you see on crono explorer:

##### Swap Trx Hash: 0xbd958b205291355d681cf01fa01f2064078d7be3b1ba63be8a9d2dff72bcce48 #####
wallet: 0x88D669588b50F3cAa21507Ee5A867f132F9db97C
SELLS 8399.685204763235 SINGLE
BUYS 107.62197 USDC
Swap Trx Hash: 0x4f8898c244bd7bc7f77d6d8aec7af670ff6d86f252d9d231860dc1528dacf91c

wallet: 0x88D669588b50F3cAa21507Ee5A867f132F9db97C SELLS 250.0 USDC BUYS 19425.008235644043 SINGLE

Swap Trx Hash: 0x1b09a08c87a2015a34fa05883cf1005715ff64d90772c044b02f80e646a69951

wallet: 0x88D669588b50F3cAa21507Ee5A867f132F9db97C SELLS 500.0 SINGLE BUYS 6.393829 USDT

Swap Trx Hash: 0x4eff6d10c7310d272dc999d8c0acffcf18ff43b6802411a069570c43564d5579

wallet: 0x88D669588b50F3cAa21507Ee5A867f132F9db97C SELLS 6.393829 USDT BUYS 495.0314116207821 SINGLE

user3761555
  • 171
  • 1
  • 7
1

There is no concept of buy and sell on trade level. Both of the below are equivalent:

  • Buying SIMPLE with USDC
  • Selling USDC for SIMPLE

For the human readable buy and sell labels, you need to come up with your own condition how you define buy and sell. One such condition could be "does the swap increase or decrease USDC position".

These information is available on Swap event in amount0_out and amount1_out parameters.

Mikko Ohtamaa
  • 22,269
  • 6
  • 62
  • 127