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 about 1 month ago