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

2 Answers 2

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
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.