cotiv2-mcp
Version:
> A plug-and-play MCP tool server to **send COTI**, **transfer BEP-20 tokens**, **deploy tokens**, and **interact with smart contracts** on the **COTI v2 Network (COTI)** — built for **Claude Desktop**, **AI agents**, and **developers.**
122 lines (121 loc) • 4.44 kB
JavaScript
import { z } from "zod";
import { parseUnits, toEventSelector, decodeEventLog } from "viem";
import { getAccount, getCotiAccount, publicClient, walletClient, } from "../config.js";
import { AddressConfig } from "../addressConfig.js";
import { supportedChain } from "../chains/index.js";
import { portfolioTokenFactoryAbi } from "../lib/portfolioTokenFactoryAbi.js";
import { toField } from "../lib/coti.js";
const abiEvent = {
anonymous: false,
inputs: [
{
indexed: true,
internalType: "bool",
name: "isPrivate",
type: "bool",
},
{
indexed: true,
internalType: "address",
name: "owner",
type: "address",
},
{
indexed: false,
internalType: "address",
name: "newToken",
type: "address",
},
{
indexed: false,
internalType: "string",
name: "name",
type: "string",
},
{
indexed: false,
internalType: "string",
name: "symbol",
type: "string",
},
{
indexed: false,
internalType: "uint256",
name: "maxSupply",
type: "uint256",
},
],
name: "TokenDeployed",
type: "event",
};
export function registerCreatePrivateERC20Token(server) {
server.tool("Create_PrivateERC20_Token", "🔨Create a new ERC20 private token on COTI v2 network", {
name: z.string(),
symbol: z.string(),
intialSupply: z.string(),
maxSupply: z.string(),
amountPerMint: z.string(),
}, async ({ name, symbol, intialSupply, maxSupply, amountPerMint }) => {
try {
const contract = AddressConfig.PortfolioTokenFactoryContract;
const cotiAccount = await getCotiAccount();
const functionSelector = "0xbd81f4f5";
const itAmountValue = (await cotiAccount.encryptValue(parseUnits(intialSupply, 6), contract, functionSelector));
const itMaxSupplyValue = (await cotiAccount.encryptValue(parseUnits(maxSupply, 6), contract, functionSelector));
const itMintAmountValue = (await cotiAccount.encryptValue(parseUnits(amountPerMint, 6), contract, functionSelector));
const account = await getAccount();
const hash = await walletClient(account).writeContract({
account,
address: contract,
abi: portfolioTokenFactoryAbi,
functionName: "createPrivacyToken",
args: [
name,
symbol,
toField(itAmountValue),
toField(itMaxSupplyValue),
toField(itMintAmountValue),
],
});
const transaction = await publicClient.waitForTransactionReceipt({
hash: hash,
retryCount: 300,
retryDelay: 100,
});
if (transaction.status != "success") {
throw new Error("Transaction failed");
}
const targetTopic = toEventSelector(abiEvent);
const logData = transaction.logs.find((log) => log.topics.includes(targetTopic));
if (!logData) {
throw new Error("Log not found");
}
const decodedLog = decodeEventLog({
abi: [abiEvent],
data: logData.data,
topics: logData.topics,
});
return {
content: [
{
type: "text",
text: `Create token successfully. ${supportedChain.blockExplorers.default.url}/tx/${hash}, Token Address: ${decodedLog.args.newToken}`,
url: `${supportedChain.blockExplorers.default.url}/tx/${hash}`,
},
],
};
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
return {
content: [
{
type: "text",
text: `Transaction failed: ${errorMessage}. ${JSON.stringify(error)}`,
},
],
isError: true,
};
}
});
}