tensaikit
Version:
An autonomous DeFi AI Agent Kit on Katana enabling AI agents to plan and execute on-chain financial operations.
118 lines (117 loc) • 4.74 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.isNativeToken = exports.allowance = exports.applyGasMultiplier = exports.approve = void 0;
const viem_1 = require("viem");
const errors_1 = require("./common/errors");
const ERC20_ABI = [
{
inputs: [
{ name: "spender", type: "address" },
{ name: "amount", type: "uint256" },
],
name: "approve",
outputs: [{ name: "", type: "bool" }],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{ name: "owner", type: "address" },
{ name: "spender", type: "address" },
],
name: "allowance",
outputs: [{ name: "", type: "uint256" }],
stateMutability: "view",
type: "function",
},
];
/**
* Approves a spender to spend tokens on behalf of the owner.
*
* Encodes and sends an ERC-20 `approve` transaction using the provided wallet,
* allowing the specified spender to spend a given amount of tokens.
*
* @param wallet - The EVM wallet provider used to sign and send the transaction.
* @param tokenAddress - The ERC-20 token contract address.
* @param spenderAddress - The address being approved to spend tokens.
* @param amount - The amount of tokens to approve (in atomic units, e.g., wei).
* @returns A promise that resolves to a success or error message string.
*/
const approve = async (wallet, tokenAddress, spenderAddress, amount) => {
try {
const data = (0, viem_1.encodeFunctionData)({
abi: ERC20_ABI,
functionName: "approve",
args: [spenderAddress, amount],
});
const txHash = await wallet.sendTransaction({
to: tokenAddress,
data,
});
await wallet.waitForTransactionReceipt(txHash);
return `Approval successful: ${spenderAddress} is now allowed to spend up to ${amount.toString()} tokens.`;
}
catch (error) {
return `Error approving tokens for ${spenderAddress}: ${error.message || error}`;
}
};
exports.approve = approve;
/**
* Scales a gas estimate by a given multiplier.
*
* This function converts the gas estimate to a number, applies the multiplier,
* rounds the result to the nearest integer, and returns it as a bigint.
*
* @param gas - The original gas estimate as a bigint.
* @param multiplier - The factor by which to scale the estimate.
* @returns The adjusted gas estimate as a bigint.
*/
const applyGasMultiplier = (gas, multiplier) => {
return BigInt(Math.round(Number(gas) * multiplier));
};
exports.applyGasMultiplier = applyGasMultiplier;
/**
* Fetches the current token allowance for a spender set by the connected wallet.
*
* Calls the ERC-20 `allowance` function to determine how many tokens the
* `spenderAddress` is allowed to spend on behalf of the wallet's address.
*
* @param wallet - The EVM wallet provider used to get the owner's address and read from the contract
* @param tokenAddress - The address of the ERC-20 token contract
* @param spenderAddress - The address of the spender whose allowance is being queried
* @returns A promise that resolves to the allowance amount as a bigint
* @throws CONTRACT_ERROR if the read call fails
*/
const allowance = async (wallet, tokenAddress, spenderAddress) => {
try {
const ownerAddress = wallet.getAddress();
const allowanceAmount = await wallet.readContract({
address: tokenAddress,
abi: ERC20_ABI,
functionName: "allowance",
args: [ownerAddress, spenderAddress],
});
console.log(`[Token Allowance] Spender: ${spenderAddress} | Owner: ${ownerAddress} | Allowance: ${allowanceAmount.toString()}`);
return allowanceAmount;
}
catch (error) {
throw (0, errors_1.createError)(`Failed to fetch allowance from contract: ${error}`, errors_1.ErrorCode.CONTRACT_ERROR);
}
};
exports.allowance = allowance;
/**
* Checks if the provided token address represents a native token (e.g., ETH, MATIC).
*
* Considers two common placeholders used to represent native tokens:
* - `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` (commonly used in DeFi protocols)
* - `0x0000000000000000000000000000000000000000` (null address)
*
* @param tokenAddress - The token address to check
* @returns `true` if the address is a known native token placeholder, otherwise `false`
*/
const isNativeToken = (tokenAddress) => {
const normalized = tokenAddress.toLowerCase();
return (normalized === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" ||
normalized === "0x0000000000000000000000000000000000000000");
};
exports.isNativeToken = isNativeToken;