tensaikit
Version:
An autonomous DeFi AI Agent Kit on Katana enabling AI agents to plan and execute on-chain financial operations.
121 lines (120 loc) • 5.48 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.prepareAndSendSwapTransaction = void 0;
const decimal_js_1 = __importDefault(require("decimal.js"));
const errors_1 = require("../../../common/errors");
const fetchTokenMetadata_1 = require("./fetchTokenMetadata");
const utlis_1 = require("../utlis");
const utils_1 = require("../../../utils");
const viem_1 = require("viem");
const network_1 = require("../../../network");
/**
* Prepares and sends a token swap transaction via the SushiSwap module using the provided wallet provider.
*
* This function handles the full lifecycle of a swap:
* 1. Validates network and chain information from the wallet provider.
* 2. Fetches token metadata to convert the input amount into base units.
* 3. Checks and sets token allowance if needed.
* 4. Fetches the swap calldata from the SushiSwap module.
* 5. Simulates the transaction using Viem’s `publicClient.call` (for dry-run).
* 6. Sends the transaction using the wallet provider and waits for confirmation.
*
* @param walletProvider - A Viem-compatible wallet provider to interact with the blockchain.
* @param args - Swap details:
* - tokenIn: Address of the input token.
* - tokenOut: Address of the output token.
* - maxSlippage: Maximum allowed slippage for the trade (in percent).
* - amount: Human-readable input amount (e.g., 1.5 ETH).
*
* @returns A promise resolving to the transaction hash if successful.
* If approval fails, returns an error string.
* @throws Throws a formatted error if any stage in the swap process fails.
*/
const prepareAndSendSwapTransaction = async (walletProvider, args) => {
try {
const network = walletProvider.getNetwork();
const chainId = network.chainId;
const networkId = network.networkId;
if (!chainId || !networkId) {
throw (0, errors_1.createError)("Invalid or missing network", errors_1.ErrorCode.INVALID_NETWORK);
}
const tokenMetadata = await (0, fetchTokenMetadata_1.fetchTokenMetadata)(chainId, args.tokenIn);
if (!tokenMetadata?.decimals) {
throw (0, errors_1.createError)("Failed to fetch token decimals", errors_1.ErrorCode.TOKEN_METADATA_ERROR);
}
const amountInBaseUnits = new decimal_js_1.default(args.amount)
.mul(new decimal_js_1.default(10).pow(tokenMetadata.decimals))
.toFixed(0);
const sushiSwapModule = await (0, utlis_1.SushiSwapModule)();
const typedChainId = chainId;
const spender = (0, utlis_1.getSpender)(typedChainId);
if (!(0, utils_1.isNativeToken)(args.tokenIn)) {
const currentAllowance = await (0, utils_1.allowance)(walletProvider, args.tokenIn, spender);
if (currentAllowance < BigInt(amountInBaseUnits)) {
const approvalResult = await (0, utils_1.approve)(walletProvider, args.tokenIn, spender, BigInt(amountInBaseUnits));
if (approvalResult.startsWith("Error")) {
return `Error approving SushiSwap as spender: ${approvalResult}`;
}
else {
console.log(approvalResult);
}
}
else {
console.log("Sufficient allowance. Skipping approval.");
}
}
else {
console.log("Native token detected. No approval needed.");
}
// Step 1: Get swap quote
const swapData = await sushiSwapModule.getSwap({
chainId: typedChainId,
tokenIn: args.tokenIn,
tokenOut: args.tokenOut,
amount: BigInt(amountInBaseUnits),
maxSlippage: args.maxSlippage,
sender: walletProvider.getAddress(),
});
if (swapData.status !== "Success") {
throw (0, errors_1.createError)("Swap quote generation failed", "SWAP_QUOTE_FAILED");
}
const { tx } = swapData;
// Step 2: Simulate swap
// TODO: Remove below code once Katana is available on Viem and is public
let publicClient;
if (chainId === "129399" || chainId === "747474") {
publicClient = (0, viem_1.createPublicClient)({
chain: walletProvider.getChain(),
transport: (0, viem_1.http)(),
});
}
else {
publicClient = (0, viem_1.createPublicClient)({
chain: network_1.NETWORK_ID_TO_VIEM_CHAIN[networkId],
transport: (0, viem_1.http)(),
});
}
const simulation = await publicClient.call({
account: tx.from,
to: tx.to,
data: tx.data,
value: tx.value,
});
console.log("Simulated output:", simulation);
// Step 3: Send transaction
const txHash = await walletProvider.sendTransaction({
to: tx.to,
data: tx.data,
value: tx.value,
});
await walletProvider.waitForTransactionReceipt(txHash);
return `Swap transaction successful. Transaction Hash: ${txHash}`;
}
catch (error) {
throw (0, errors_1.handleError)("Failed to prepare and send swap transaction", error);
}
};
exports.prepareAndSendSwapTransaction = prepareAndSendSwapTransaction;