import { DZapClient, Services, TxnStatus, ApprovalModes } from "@dzapio/sdk";
import type { TradeQuotesRequestData, TradeBuildTxnRequest, TradeBuildTxnRequestData } from "@dzapio/sdk";
const NATIVE = "0x0000000000000000000000000000000000000000";
async function batchSwap(
signer: any,
userAddress: `0x${string}`,
chainId: number,
swaps: Array<{
srcToken: string;
srcDecimals: number;
destToken: string;
destDecimals: number;
amount: string;
}>
) {
const dZap = DZapClient.getInstance();
const quoteReq: TradeQuotesRequestData[] = swaps.map((s) => ({
amount: s.amount,
srcToken: s.srcToken,
srcDecimals: s.srcDecimals,
destToken: s.destToken,
destDecimals: s.destDecimals,
toChain: chainId,
slippage: 0.5,
}));
const quotes = await dZap.getTradeQuotes({
fromChain: chainId,
data: quoteReq,
account: userAddress,
});
const buildData: TradeBuildTxnRequestData[] = [];
for (const [pairKey, pairQuotes] of Object.entries(quotes)) {
const source = pairQuotes.recommendedSource ?? pairQuotes.bestReturnSource;
if (!source || !pairQuotes.quoteRates?.[source]) continue;
const q = pairQuotes.quoteRates[source];
buildData.push({
amount: q.srcAmount,
srcToken: q.srcToken.address,
srcDecimals: q.srcToken.decimals,
destToken: q.destToken.address,
destDecimals: q.destToken.decimals,
toChain: chainId,
protocol: source,
recipient: userAddress,
slippage: 0.5,
});
}
const tokensForApproval = buildData
.filter((d) => d.srcToken.toLowerCase() !== NATIVE.toLowerCase())
.map((d) => ({ address: d.srcToken as `0x${string}`, amount: d.amount }));
if (tokensForApproval.length > 0) {
const allowanceRes = await dZap.getAllowance({
chainId,
sender: userAddress,
tokens: tokensForApproval,
service: Services.trade,
mode: ApprovalModes.Default,
});
const allowanceMap = allowanceRes.data ?? {};
const needsApproval = tokensForApproval.filter(
(t) => allowanceMap[t.address]?.approvalNeeded
);
if (needsApproval.length > 0) {
const approveRes = await dZap.approve({
chainId,
signer,
sender: userAddress,
tokens: needsApproval,
service: Services.trade,
mode: ApprovalModes.Default,
});
if (approveRes.status !== TxnStatus.success) throw new Error("Approval failed");
}
}
const tradeReq: TradeBuildTxnRequest = {
sender: userAddress,
refundee: userAddress,
fromChain: chainId,
gasless: false,
data: buildData,
};
let tradeRes = await dZap.trade({ request: tradeReq, signer });
if (tradeRes.status !== TxnStatus.success && tradeRes.action === "TRY_ANOTHER_ROUTE") {
const pairKeys = Object.keys(quotes);
const fallbackData = buildData.map((d, i) => {
const fallbackSource = quotes[pairKeys[i]]?.bestReturnSource;
return fallbackSource ? { ...d, protocol: fallbackSource } : d;
});
tradeRes = await dZap.trade({
request: { ...tradeReq, data: fallbackData },
signer,
});
}
if (tradeRes.status !== TxnStatus.success) {
throw new Error(tradeRes.errorMsg ?? "Trade failed");
}
return tradeRes.txnHash ?? null;
}