uniderp-mcp
Version:
> A plug-and-play MCP tool server to **send ETH**, **transfer ERC-20 tokens**, **deploy tokens**, and **interact with smart contracts** on the **UNICHAIN** — built for **Claude Desktop**, **AI agents**, and **developers.**
112 lines (111 loc) • 4.51 kB
JavaScript
import { getContract, parseUnits, isAddress, } from "viem";
import { erc20Abi, maxUint256 } from "viem";
import { CurrencyAmount, Token, TradeType, Percent, } from "@uniswap/sdk-core";
import { JsonRpcProvider } from "@ethersproject/providers";
import { publicClient, walletClient } from "../config.js";
import { erc20abi } from "../lib/abi/erc20Abi.js";
import { AlphaRouter, getApplicableV4FeesTickspacingsHooks, SwapType, } from "@uniswap/smart-order-router";
import { ChainNativeCurrency, supportedChain } from "../chains/index.js";
import { AddressConfig } from "../addressConfig.js";
import { UniversalRouterVersion } from "@uniswap/universal-router-sdk";
import { Protocol } from "@uniswap/router-sdk";
export const getToken = async (token) => {
if (token.toUpperCase() === "ETH") {
return new ChainNativeCurrency();
}
let address = token.toLowerCase();
let decimal;
const url = "https://raw.githubusercontent.com/Uniswap/default-token-list/refs/heads/add-unichain-tokens/src/tokens/unichain.json";
const resp = await fetch(url);
const tokens = await resp.json();
let symbol;
if (!isAddress(address)) {
const tokenInfo = tokens.find((item) => item.symbol.toLowerCase() === address);
if (!tokenInfo) {
throw new Error("Token not found");
}
address = tokenInfo.address;
decimal = tokenInfo.decimals;
symbol = tokenInfo.symbol;
}
else {
const tokenInfo = tokens.find((item) => item.address.toLowerCase() === address);
if (!tokenInfo) {
const contract = getContract({
address: address,
abi: erc20abi,
client: publicClient,
});
decimal = await contract.read.decimals();
symbol = await contract.read.symbol();
}
else {
decimal = tokenInfo.decimals;
symbol = tokenInfo.symbol;
}
}
return new Token(supportedChain.id, address, decimal, symbol);
};
export const uniswapTrade = async ({ account, inputToken, outputToken, amount, }) => {
let currencyA = await getToken(inputToken);
let currencyB = await getToken(outputToken);
let amountDecimal = currencyA.decimals;
const parseAmountIn = parseUnits(amount, amountDecimal);
const amountValue = CurrencyAmount.fromRawAmount(currencyA, parseAmountIn.toString());
const universalRouterAddress = AddressConfig.UniversalRouterContract;
// Routing
const swapParams = {
type: SwapType.UNIVERSAL_ROUTER,
version: UniversalRouterVersion.V2_0,
recipient: account.address,
slippageTolerance: new Percent(5000, 10_000),
};
const router = new AlphaRouter({
chainId: supportedChain.id,
provider: new JsonRpcProvider(supportedChain.rpcUrls.default.http[0]),
v4PoolParams: getApplicableV4FeesTickspacingsHooks(supportedChain.id).concat([[3000, 60, AddressConfig.UniderpHookContract]]),
});
const route = await router.route(amountValue, currencyB, TradeType.EXACT_INPUT, swapParams, {
protocols: [Protocol.V4],
});
if (!route || !route.methodParameters) {
// Handle failed request
throw new Error("No trading route found");
}
// Approve if token in is not native
if (!currencyA.isNative) {
const TokenContract = getContract({
address: currencyA.address,
abi: erc20Abi,
client: {
wallet: walletClient(account),
public: publicClient,
},
});
if (!TokenContract.write ||
!TokenContract.write.approve ||
!TokenContract.read.allowance) {
throw new Error("Unable to Swap Tokens");
}
const allowance = (await TokenContract.read.allowance([
account.address,
universalRouterAddress,
]));
if (allowance < parseAmountIn) {
const approveResult = await TokenContract.write.approve([
universalRouterAddress,
maxUint256,
]);
await publicClient.waitForTransactionReceipt({
hash: approveResult,
});
}
}
const txHash = await walletClient(account).sendTransaction({
data: route.methodParameters.calldata,
to: universalRouterAddress,
value: BigInt(route.methodParameters.value),
from: account.address,
});
return txHash;
};