diff --git a/src/app/api/chainhooks/stackingdao/deposit/route.ts b/src/app/api/chainhooks/stackingdao/deposit/route.ts index e0da5da..9ba5530 100644 --- a/src/app/api/chainhooks/stackingdao/deposit/route.ts +++ b/src/app/api/chainhooks/stackingdao/deposit/route.ts @@ -45,10 +45,10 @@ export async function POST(request: Request) { sender, action: "stackingdao-deposit", data: { - inAmount: BigInt(stxTransferEvent.data.amount), - inToken: "STX", - outAmount: BigInt(stStxMintEvent.data.amount), - outToken: stStxMintEvent.data.asset_identifier, + outAmount: BigInt(stxTransferEvent.data.amount), + outToken: "STX", + inAmount: BigInt(stStxMintEvent.data.amount), + inToken: stStxMintEvent.data.asset_identifier, }, } satisfies InsertTransaction; }); diff --git a/src/app/api/chainhooks/stackingdao/withdraw/route.ts b/src/app/api/chainhooks/stackingdao/withdraw/route.ts new file mode 100644 index 0000000..b628f17 --- /dev/null +++ b/src/app/api/chainhooks/stackingdao/withdraw/route.ts @@ -0,0 +1,72 @@ +import { db } from "@/db/db"; +import { type InsertTransaction, transactionTable } from "@/db/schema"; +import { conflictUpdateSetAllColumns } from "@/db/utils"; +import type { + ChainhookPayload, + ChainhookReceiptEventFTBurnEvent, + ChainhookReceiptEventSTXTransferEvent, +} from "@/lib/chainhooks"; +import { getOrInsertToken } from "@/lib/currencies"; + +export const dynamic = "force-dynamic"; + +export async function POST(request: Request) { + const data: ChainhookPayload = await request.json(); + + const transactionsToInsert = data.apply[0].transactions + .filter((transactionToProcess) => transactionToProcess.metadata.success) + .map((transactionToProcess) => { + const sender = transactionToProcess.metadata.sender; + const transferEvents = transactionToProcess.metadata.receipt.events + // Events are not always in order so we sort them by index + .sort((a, b) => a.position.index - b.position.index) + .filter( + ( + event, + ): event is + | ChainhookReceiptEventSTXTransferEvent + | ChainhookReceiptEventFTBurnEvent => + event.type === "STXTransferEvent" || event.type === "FTBurnEvent", + ); + const stxTransferEvent = transferEvents.filter( + (event) => + event.type === "STXTransferEvent" && event.data.recipient === sender, + )[0]; + const stStxBurnEvent = transferEvents.filter( + (event): event is ChainhookReceiptEventFTBurnEvent => + event.type === "FTBurnEvent", + )[0]; + + return { + txId: transactionToProcess.transaction_identifier.hash, + protocol: "stackingdao", + blockHeight: BigInt(data.apply[0].block_identifier.index), + timestamp: new Date(data.apply[0].timestamp * 1000), + sender, + action: "stackingdao-withdraw", + data: { + inAmount: BigInt(stxTransferEvent.data.amount), + inToken: "STX", + outAmount: BigInt(stStxBurnEvent.data.amount), + outToken: stStxBurnEvent.data.asset_identifier, + }, + } satisfies InsertTransaction; + }); + + for (const transaction of transactionsToInsert) { + await getOrInsertToken(transaction.data.inToken); + await getOrInsertToken(transaction.data.outToken); + } + + if (transactionsToInsert.length > 0) { + await db + .insert(transactionTable) + .values(transactionsToInsert) + .onConflictDoUpdate({ + target: transactionTable.txId, + set: conflictUpdateSetAllColumns(transactionTable), + }); + } + + return Response.json({ ok: true }); +} diff --git a/src/components/Transaction/Action/StackingDAO.tsx b/src/components/Transaction/Action/StackingDAO.tsx new file mode 100644 index 0000000..ca051bd --- /dev/null +++ b/src/components/Transaction/Action/StackingDAO.tsx @@ -0,0 +1,28 @@ +import type { + SelectTransactionActionStackingDAODeposit, + SelectTransactionActionStackingDAOWithdraw, +} from "@/db/transactions"; +import { displayPrice } from "@/lib/currencies"; +import { Text } from "@radix-ui/themes"; + +interface TransactionActionStackingDAOProps { + transaction: + | SelectTransactionActionStackingDAODeposit + | SelectTransactionActionStackingDAOWithdraw; +} + +export const TransactionActionStackingDAO = ({ + transaction, +}: TransactionActionStackingDAOProps) => { + return ( + <> + + {transaction.action === "stackingdao-deposit" ? "Deposit" : "Withdraw"} + {" "} + {displayPrice(transaction.data.outAmount, transaction.outToken.decimals)}{" "} + {transaction.outToken.symbol} for{" "} + {displayPrice(transaction.data.inAmount, transaction.inToken.decimals)}{" "} + {transaction.inToken.symbol} + + ); +}; diff --git a/src/components/Transaction/Action/StackingDAODeposit.tsx b/src/components/Transaction/Action/StackingDAODeposit.tsx deleted file mode 100644 index ab04000..0000000 --- a/src/components/Transaction/Action/StackingDAODeposit.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import type { SelectTransactionActionStackingDAODeposit } from "@/db/transactions"; -import { displayPrice } from "@/lib/currencies"; -import { Text } from "@radix-ui/themes"; - -interface TransactionActionStackingDAODepositProps { - transaction: SelectTransactionActionStackingDAODeposit; -} - -export const TransactionActionStackingDAODeposit = ({ - transaction, -}: TransactionActionStackingDAODepositProps) => { - console.log(transaction); - return ( - <> - Deposit{" "} - {displayPrice(transaction.data.outAmount, transaction.outToken.decimals)}{" "} - {transaction.inToken.symbol} for{" "} - {displayPrice(transaction.data.inAmount, transaction.inToken.decimals)}{" "} - {transaction.outToken.symbol} - - ); -}; diff --git a/src/components/Transaction/TransactionRow.tsx b/src/components/Transaction/TransactionRow.tsx index 45b616c..0b000fa 100644 --- a/src/components/Transaction/TransactionRow.tsx +++ b/src/components/Transaction/TransactionRow.tsx @@ -6,7 +6,7 @@ import Link from "next/link"; import { TimeAgo } from "../Shared/TimeAgo"; import { TransactionActionAddLiquidity } from "./Action/AddLiquidity"; import { TransactionActionRemoveLiquidity } from "./Action/RemoveLiquidity"; -import { TransactionActionStackingDAODeposit } from "./Action/StackingDAODeposit"; +import { TransactionActionStackingDAO } from "./Action/StackingDAO"; import { TransactionActionSwap } from "./Action/Swap"; interface TransactionRowProps { @@ -87,8 +87,9 @@ export const TransactionRow = ({ transaction }: TransactionRowProps) => { {transaction.action === "remove-liquidity" ? ( ) : null} - {transaction.action === "stackingdao-deposit" ? ( - + {transaction.action === "stackingdao-deposit" || + transaction.action === "stackingdao-withdraw" ? ( + ) : null} diff --git a/src/lib/chainhooks.ts b/src/lib/chainhooks.ts index 9ad3441..f160afd 100644 --- a/src/lib/chainhooks.ts +++ b/src/lib/chainhooks.ts @@ -54,6 +54,7 @@ type ChainhookReceiptEvent = | ChainhookReceiptEventSTXTransferEvent | ChainhookReceiptEventFTTransferEvent | ChainhookReceiptEventFTMintEvent + | ChainhookReceiptEventFTBurnEvent | ChainhookReceiptEventSmartContractEvent; export interface ChainhookReceiptEventSTXTransferEvent { @@ -93,6 +94,18 @@ export interface ChainhookReceiptEventFTMintEvent { type: "FTMintEvent"; } +export interface ChainhookReceiptEventFTBurnEvent { + data: { + amount: string; + asset_identifier: string; + recipient: string; + }; + position: { + index: number; + }; + type: "FTBurnEvent"; +} + export interface ChainhookReceiptEventSmartContractEvent { data: unknown; position: {