Starknet NFT Purchase
This example uses function triggers to detect calls to the matchAskWithTakerBid
function, parses the related transaction and then emits the NFT purchase details.
{
"type": "TRIGGER_TYPE_FUNCTION",
"functionSignature": "0x03e2bd66aeb9284521dbba619e698cd99508e215c152bf788b608349e67bba61"
}
import { Contract, num, RpcProvider, shortString } from "https://cdn.jsdelivr.net/npm/[email protected]/+esm";
const providerString = "http://chain-provider";
const rpcProvider = new RpcProvider({ nodeUrl: providerString });
const flexContractAddr = "0x4b1b3fdf34d00288a7956e6342fb366a1510a9387d321c87f3301d990ac19d4";
export async function triggerHandler(context, data) {
if (context.dataType !== "DATA_TYPE_TRACE" || data.contract_address !== flexContractAddr) {
return;
}
// Flex is a PROXY contract and so has a library_call with the same method and arguments. We only parse the initial call.
if (data.call_type != "CALL") {
return;
}
// types explained here - https://docs.looksrare.org/developers/taker-orders
const takerOrder = getTakerOrder(data.calldata);
const makerOrder = getMakerOrder(data.calldata);
if (takerOrder.lowerTokenId !== makerOrder.lowerTokenId && takerOrder.higherTokenId !== makerOrder.higherTokenId) {
return {
error: "Expected to see the same tokenId in both orders",
taker: takerOrder,
maker: makerOrder,
context: context,
};
}
// The token that is used as a payment for the nft
const erc20ContractAddr = makerOrder.currency;
const paymentTokenInfo = await getPaymentTokenInfo(erc20ContractAddr, Number(context.blockNumber));
// The contract that manages the nft
const erc721ContractAddr = makerOrder.nftCollectionContract;
const nftInfo = await getNTFInfo(
erc721ContractAddr,
{ low: takerOrder.lowerTokenId, high: takerOrder.higherTokenId },
Number(context.blockNumber),
);
return {
transferData: {
paidToken: paymentTokenInfo.symbol,
price: takerOrder.price,
nftCollection: nftInfo.symbol,
tokenURI: nftInfo.uri,
taker: takerOrder.takerAddr,
maker: makerOrder.nftCollectionContract,
},
context: context,
};
}
function getTakerOrder(callData) {
const startIndex = 0;
return {
isOrderAsk: callData[startIndex],
takerAddr: callData[startIndex + 1],
price: callData[startIndex + 2],
lowerTokenId: callData[startIndex + 3], // two felt struct
higherTokenId: callData[startIndex + 4], // two felt struct
};
}
function getMakerOrder(callData) {
const startIndex = 7;
return {
isOrderAsk: callData[startIndex],
signer: callData[startIndex + 1],
nftCollectionContract: callData[startIndex + 2],
price: callData[startIndex + 3],
lowerTokenId: callData[startIndex + 4], // two felt struct
higherTokenId: callData[startIndex + 5], // two felt struct
amount: callData[startIndex + 6],
strategy: callData[startIndex + 7],
currency: callData[startIndex + 8],
};
}
async function getPaymentTokenInfo(contractAddress, blockNumber) {
const erc20Abi = [
{
name: "symbol",
type: "function",
inputs: [],
outputs: [
{
name: "symbol",
type: "felt",
},
],
stateMutability: "view",
},
];
const erc20Contract = new Contract(erc20Abi, contractAddress, rpcProvider);
return {
symbol: await erc20Contract
.symbol({ blockIdentifier: blockNumber })
.then((result) => shortString.decodeShortString(result.symbol)),
};
}
async function getNTFInfo(contractAddress, tokenId, blockNumber) {
const nftAbi = [
{
name: "Uint256",
size: 2,
type: "struct",
members: [
{
name: "low",
type: "felt",
offset: 0,
},
{
name: "high",
type: "felt",
offset: 1,
},
],
},
{
name: "tokenURI",
type: "function",
inputs: [
{
name: "tokenId",
type: "Uint256",
},
],
outputs: [
{
name: "tokenURI_len",
type: "felt",
},
{
name: "tokenURI",
type: "felt*",
},
],
stateMutability: "view",
},
{
name: "symbol",
type: "function",
inputs: [],
outputs: [
{
name: "symbol",
type: "felt",
},
],
stateMutability: "view",
},
];
const nftContract = new Contract(nftAbi, contractAddress, rpcProvider);
return {
uri: await nftContract
.tokenURI(tokenId, {
blockIdentifier: blockNumber,
})
.then((result) =>
result.tokenURI
.map((shortStr) => {
return shortString.decodeShortString(num.toHex(shortStr));
})
.join(""),
),
symbol: await nftContract
.symbol({ blockIdentifier: blockNumber })
.then((result) => shortString.decodeShortString(result.symbol)),
};
}
Updated 3 months ago