from logs it looks like one transaction made only one swap and the other transaction did 2 swaps, you could identify those two swap events or how many there are
Yes this additional swap comes from the point i made above - the router of Pancakeswap is figuring out that this route is better, thus going with it.
What i dont understand is how to identify all types of swap events - for example how can i know how many logs the swap will produce so that i use your logic above with specifying the exact log number (log[1]) for which i want to get the token address? If all swaps had exact same log structure, your solution will always work, but in this case i cannot figure out any way that it will work. Sometimes we will need log[8] to get the 2nd token address, other times it will be log[9]⌠it is quite confusing. Can you clarify? Thanks!
you will check all the logs and identify which one of them is a swap event:
Swap (index_topic_1 address sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, index_topic_2 address to)View Source
Topics
0 0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822
that 0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822 corresponds to that Swap function and it is computed as
x = Web3.utils.sha3('Swap(address,uint256,uint256,uint256,uint256,address)')
=>
'0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822'
Alright i understand what you mean!
One last thing - after i have identified this : how can i see which tokens were involved in the swap. Again this is a problem with logs number since for some swaps the token addresses will be in log[0] and log[7] but for other that will be, for example, log[0] and log [8]. I need to figure out a way not to hardcode those.
For example here - https://testnet.bscscan.com/tx/0x742f7e4bd25bbb07a4a19b21cfaade9cba60300da43d4c3c17dc258702f98e7e#eventlog
The token we want to swap into (WBNB) is on the 6th log place top to bottom, whereas here -
https://testnet.bscscan.com/tx/0xc1f597fe8ba8263cabe861a7465481c1b3d44a275816186030ca8ddd6b07f016#eventlog
The token we want to swap into (DAI) is on the 9th log place top to bottom. This is extremely confusing. Thanks for your time to deal with me <3. Appreciate your time.
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
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
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]
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?
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);
}
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:
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!