UniversalDeFi AI
Official
by McpCrypto
import { ethers, JsonRpcProvider, Wallet } from "ethers";
import { GetWalletDetailsSchema, TransferNativeTokenSchema, DeployContractSchema, CallContractSchema } from "./schemas.js";
import { z } from "zod";
import { constructTransactionUrl } from "../../utils/index.js";
import { compileSourceString } from "solc-typed-ast";
import { Abi, AbiFunction } from "viem";
export async function getWalletDetailsHandler(wallet: Wallet, provider: JsonRpcProvider, args: z.infer<typeof GetWalletDetailsSchema>): Promise<string> {
const balance = await provider.getBalance(wallet.address);
return JSON.stringify({
chain: provider.getNetwork().then(network => network.name),
address: wallet.address,
balance: ethers.formatEther(balance)
});
}
export async function transferNativeTokenHandler(
wallet: Wallet,
provider: JsonRpcProvider,
args: z.infer<typeof TransferNativeTokenSchema>
): Promise<string> {
const hash = await wallet.sendTransaction({
to: args.toAddress,
value: ethers.parseEther(args.amount)
});
return JSON.stringify({
hash: hash,
from: wallet.address,
to: args.toAddress,
amount: args.amount,
scanUrl: constructTransactionUrl('bsc', hash.hash)
});
}
export async function deployContractHandler(
wallet: Wallet,
provider: JsonRpcProvider,
args: z.infer<typeof DeployContractSchema>
): Promise<string> {
const sourceCode = args.sourceCode;
const contractName = args.contractName;
const compileResult = await compileSourceString(contractName, sourceCode, "auto");
const contractFile = Object.keys(compileResult.data.contracts).find((file) =>
Object.keys(compileResult.data.contracts[file]).includes(contractName)
);
if (!contractFile) {
throw new Error(`Contract ${contractName} not found in source code`);
}
const targetContract = compileResult.data.contracts[contractFile][contractName];
const abi = targetContract.abi;
const bytecode = "0x" + targetContract.evm.bytecode.object;
const factory = new ethers.ContractFactory(
abi, // ABI will be generated from source
bytecode, // Bytecode from source
wallet // Signer
);
// Deploy the contract
const contract = await factory.deploy(...(args.constructorArgs || []));
await contract.waitForDeployment();
const address = await contract.getAddress();
const deployTx = contract.deploymentTransaction();
if (!deployTx) {
throw new Error("Deployment transaction not found");
}
return JSON.stringify({
contractAddress: address,
deploymentHash: deployTx.hash,
from: wallet.address,
network: provider.getNetwork().then(network => network.name),
transactionUrl: constructTransactionUrl('bsc', deployTx.hash)
});
}
export async function callContractHandler(
wallet: Wallet,
provider: JsonRpcProvider,
args: z.infer<typeof CallContractSchema>
) {
let abiString: string = args.abi;
let abi: Abi = JSON.parse(abiString) as Abi;
if (!ethers.isAddress(args.contractAddress)) {
throw new Error(`Invalid contract address: ${args.contractAddress}`);
}
const contract = new ethers.Contract(args.contractAddress, abiString, wallet);
let functionAbi: AbiFunction | undefined;
try {
functionAbi = abi.find(
(item) => "name" in item && item.name === args.functionName,
) as AbiFunction;
} catch (error) {
throw new Error(`Invalid function name: ${args.functionName}`);
}
if (
functionAbi.stateMutability === "view" ||
functionAbi.stateMutability === "pure"
) {
return await contract.getFunction(args.functionName)(...args.args);
}
const contractFunction = contract.getFunction(args.functionName);
const txResponse = await contractFunction(...args.args);
const txReceipt = await txResponse.wait();
return JSON.stringify({
hash: txReceipt.hash,
transactionUrl: constructTransactionUrl('bsc', txReceipt.hash),
});
}