How to get token transfer information

it looks like there is a sequence of events of type Transfer, Sync, Swap

so in first case you have the Transfer at logs[6] and in second case you have a transfer on logs[6] and after that Sync on logs[7] and Swap on logs[8] and after that a new Transfer on logs[9] followed by Sync and Swap

2 Likes

Hey,

For a little test app of mine, I would like to recreate exactly this information about swaps you screenshoted. I read through this feed, but it isn’t 100% clear to me how to get this information from the logs. The differing log size makes a generic implementation complicated, I feel like. Did you manage to reconstruct it? I would really appreciate some advice.
Thanks already for the support here :slight_smile:

1 Like

Yes it works as cryptokid suggested. They all follow same pattern of transfer,sync,swap so no matter how many logs there are the tokenTo (bottom) in the swap will be logs[length-2] (aka the last transfer) and the first token aka tokenFrom(top) will be logs[0]

2 Likes

Ok thanks, I’m fairly new to the whole web3 development space, since all the data is just available in hex form, how do you parse it and is the token type included here as well? Would you be willing to share the code snippet?

1 Like

For anyone also interested in this, the above tips are gold! I managed to get a version running, but wouldn’t call it production ready. One thing I noticed is that the described log order for indexing does not always apply. For example, I tried to use the same logic as above, which seems to be applicable for Uniswap clones on a sushi swap (I know also a clone but seems to give different logs / order) transaction. There it didn’t work as intended. I try to work around it by using the transferTopicHash as an identifier for the token transfers of the swap. Then just map the logs to transactions and parse the whole thing.
E.g. in Vue3 (see ref() function and addressing of variables with “.value”)
You can chain a lot of these, but I wanted to keep it step wise and understandable here. Thanks again for the tips from @Cryptokid above, they send me on a good track.

const transaction = ref()
const transferTopicHash = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
        async function getTransactionFromHash(hash) { 
            const options = {
                chain: "ropsten",
                transaction_hash: hash
            };
            let trxn = await Moralis.Web3API.native.getTransaction(options);
            transaction.value = trxn;
            // TODO (sanity checks)

            // decode token addresses and values from log sequence
            let transferLogs = transaction.value['logs'].filter(log => {return log.topic0 === transferTopicHash});
            let fromTransfer = transferLogs.find(log => {return "0x"+log.topic2.slice(2,).replace(/\b0+/g, "") !== currentUser.attributes.ethAddress});
            let toTransfer = transferLogs.find(log => {return "0x"+log.topic2.slice(2,).replace(/\b0+/g, "") === currentUser.attributes.ethAddress});
            let fromTokenAmount = parseInt(Number(fromTransfer['data']), 10);
            const fromTokenAddress = fromTransfer['address'];
            let toTokenAmount = parseInt(Number(toTransfer['data']), 10);
            const toTokenAddress = toTransfer['address'];
            // get token metadata
            const tokensMetadata = await Moralis.Web3API.token.getTokenMetadata( { chain: "ropsten", addresses: [fromTokenAddress, toTokenAddress] } );
            // assign metadata to token
            const fromTokenMeta = tokensMetadata.find(token => { return token.address === fromTokenAddress} );
            const toTokenMeta = tokensMetadata.find(token => { return token.address === toTokenAddress} );
            // adjust amount by tokens decimals
            fromTokenAmount = fromTokenAmount / Math.pow(10, fromTokenMeta.decimals);
            toTokenAmount = toTokenAmount / Math.pow(10, toTokenMeta.decimals);
            
            console.log(fromTokenAmount + " " + fromTokenMeta.symbol + " => " + toTokenAmount + " " + toTokenMeta.symbol);
        }
2 Likes

How would you go about retrieving the transaction hash info for a custom table? Here’s what I have so far (cloning the amazon clone project). I want to add transaction hash to the table

let result = await Moralis.transfer(options1);

//Save Transaction Details to DB

const Transaction = Moralis.Object.extend("Transaction");

const transaction = new Transaction();

transaction.set("Customer", account);

transaction.set("Delivery", delivery);

transaction.set("Product", book.name);

transaction.set("Spent", book.price);

This line may not be ok, and you also need to use .save at the end for that query to save the data

Yes i have the save.

ok, my table is named “Transaction”. you are saying to rename the table to a different name?

I’m saying that the syntax seems to be different in documentation for a basic query:

https://docs.moralis.io/moralis-server/database/queries

const query = new Moralis.Query(Monster);

3

query.equalTo(“ownerName”, “Aegon”);

4

const results = await query.find();

5

alert(“Successfully retrieved " + results.length + " monsters.”);

6

// Do something with the returned Moralis.Object values

7

for (let i = 0; i < results.length; i++) {

8

const object = results[i];

9

alert(object.id + ’ - ’ + object.get(‘ownerName’));

10

Maybe something like this but query the hash? I know all the info is stored on each transaction automatically. I need to have it “called” or “set” or “get” somehow aha

vs

const Monster = Moralis.Object.extend("Monster");
const query = new Moralis.Query(Monster);

that is what I noticed

would i have to query the “BscTransactions” table?

I don’t know, your example was only adding data with .set

you can see here how to format code on forum:

import {Select, Button, Modal, Input} from 'antd'

import {ShoppingCartOutlined} from "@ant-design/icons";

import { useState } from 'react';

import { useMoralis } from 'react-moralis';

const {Option} = Select;

function Purchase({book}) {

  const [isModalVisible, setIsModalVisible] = useState(false);

  const [delivery, setDelivery] = useState("");

  const {Moralis, Native, account, chainId} = useMoralis();

  const handleOk = async () => {

    //Get token price on PancakeSwap v2 BSC

    const options = {

      address: "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",

      chain: "bsc",

      exchange: "PancakeSwapv2",

    };

    const price = await Moralis.Web3API.token.getTokenPrice(options);

    const priceBNB = book.price / price.usdPrice;

   

    // Send Matic to book store owenr address

   

    const options1 = {

      type: "native",

      amount: Moralis.Units.ETH(priceBNB),

      receiver: "0xf435247364F38e7f182372fbfF58E50f0A90E88F"

     

    }

   

    let result = await Moralis.transfer(options1);

    //Save Transaction Details to DB

    const Transaction = Moralis.Object.extend("Transaction");

    const transaction = new Transaction();

   

    transaction.set("Customer", account);

    transaction.set("Delivery", delivery);

    transaction.set("Product", book.name);

    transaction.set("Spent", book.price);

    transaction.save()

    setIsModalVisible(false);

  }

  return (

    <>

      <span className="price"> ${book.price}</span>

      <p>No Import Fees & Free Shipping Included</p>

      <h1 style={{ color: "green" }}> In Stock </h1>

      <h3>Quantity</h3>

      <Select defaultValue={1} style={{ width: "100%" }}>

        <Option value={1}>1</Option>

        <Option value={2}>2</Option>

        <Option value={3}>3</Option>

        <Option value={4}>4</Option>

        <Option value={5}>5</Option>

      </Select>

      {chainId === "0x38" &&

      <Button

      className="login"

      style={{ width: "100%", marginTop: "50px" }}

      onClick={()=>setIsModalVisible(true)}

    >

      <ShoppingCartOutlined /> Buy Now

    </Button>

      }

     

      <Modal

        title="Purchase Product"

        visible={isModalVisible}

        onOk={handleOk}

        onCancel={()=>setIsModalVisible(false)}

      >

        <div style={{ display: "flex" }}>

          <img src={book.image} alt="product" style={{ width: "200px" }}></img>

          <div>

            <h3>{book.name}</h3>

            <h2>${book.price}</h2>

            <h4>Delivery Address</h4>

            <Input onChange={(value) => setDelivery(value.target.value)}></Input>

          </div>

        </div>

      </Modal>

    </>

  )

}

export default Purchase

ok thanks i edited it!

try to change this line to
const transaction = new Moralis.Query(Transaction);

do you get any error?
what doesn’t work?

better to create a separate forum thread with this problem

i tried to make a transaction with this change and it did not save to my custom “Transaction” table. Ok thanks will do

this thread started with a fantastic subject / inquiry! and then it got better… it got a solution!! …so, the solution is there in the open… thank you all for this. Cryptokid rules…
Now, following action… tigerwoooods decided to leave golf and ask an offtopic about saving data into a custom table!! … and even worst! i came and i posted this comment about nothing!, please close this thread… is declining. :rofl:

Also, thanks for that solution. It was exaclty what i was looking for!