deployCoin.tsā¢7.06 kB
import { Tool } from "@modelcontextprotocol/sdk/types.js";
import { getAptosClient, getCurrentNetwork } from "../../config.js";
import { getDefaultAccount } from "../../utils/account.js";
import { formatAddress } from "../../utils/format.js";
export const DEPLOY_COIN: Tool = {
name: "deploy_coin",
description: "Deploy a new custom coin/token on Aptos blockchain. This creates a new coin type that can be minted, transferred, and managed. Returns the coin type identifier and deployment transaction details.",
inputSchema: {
type: "object",
properties: {
name: {
type: "string",
description: "Name of the coin (e.g., 'My Token')",
},
symbol: {
type: "string",
description: "Symbol of the coin (e.g., 'MTK')",
},
decimals: {
type: "number",
description: "Number of decimal places for the coin (typically 6 or 8)",
default: 8,
minimum: 0,
maximum: 32,
},
icon_url: {
type: "string",
description: "URL to the coin icon/logo (optional)",
},
project_url: {
type: "string",
description: "URL to the project website (optional)",
},
max_gas_amount: {
type: "number",
description: "Maximum gas amount for the transaction (optional)",
default: 5000,
},
},
required: ["name", "symbol"],
},
};
/**
* Deploys a new custom coin on Aptos
* @param args The arguments containing coin details
* @returns The deployment transaction details
*/
export async function deployCoinHandler(args: Record<string, any> | undefined) {
if (!isDeployCoinArgs(args)) {
throw new Error("Invalid arguments for deploy_coin");
}
const {
name,
symbol,
decimals = 8,
icon_url,
project_url,
max_gas_amount = 5000
} = args;
try {
const results = await performDeployCoin(
name,
symbol,
decimals,
icon_url,
project_url,
max_gas_amount
);
return {
content: [{ type: "text", text: results }],
isError: false,
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Error deploying coin: ${error instanceof Error ? error.message : String(error)}`,
},
],
isError: true,
};
}
}
/**
* Deploys a new custom coin on Aptos
* @param name The name of the coin
* @param symbol The symbol of the coin
* @param decimals The number of decimal places
* @param iconUrl Optional icon URL
* @param projectUrl Optional project URL
* @param maxGasAmount Maximum gas amount for the transaction
* @returns The deployment transaction details as a formatted string
*/
export async function performDeployCoin(
name: string,
symbol: string,
decimals: number = 8,
iconUrl?: string,
projectUrl?: string,
maxGasAmount: number = 5000
): Promise<string> {
try {
const aptos = getAptosClient();
const deployerAccount = getDefaultAccount();
const deployerAddress = deployerAccount.accountAddress.toString();
// Validate inputs
if (!name || name.trim().length === 0) {
throw new Error("Coin name cannot be empty");
}
if (!symbol || symbol.trim().length === 0) {
throw new Error("Coin symbol cannot be empty");
}
if (symbol.length > 10) {
throw new Error("Coin symbol should be 10 characters or less");
}
if (decimals < 0 || decimals > 32) {
throw new Error("Decimals must be between 0 and 32");
}
// Create the coin deployment transaction
const transaction = await aptos.transaction.build.simple({
sender: deployerAccount.accountAddress,
data: {
function: "0x1::managed_coin::initialize",
typeArguments: [],
functionArguments: [
name.trim(),
symbol.trim().toUpperCase(),
decimals,
false, // monitor_supply
],
},
options: {
maxGasAmount,
},
});
// Sign and submit the transaction
const committedTxn = await aptos.signAndSubmitTransaction({
signer: deployerAccount,
transaction,
});
// Wait for transaction confirmation
const executedTxn = await aptos.waitForTransaction({
transactionHash: committedTxn.hash,
});
// Generate the coin type identifier
const coinType = `${deployerAddress}::coin::T`;
let result = `šŖ Coin Deployment Successful!
Coin Details:
Name: ${name}
Symbol: ${symbol}
Decimals: ${decimals}
Deployer: ${formatAddress(deployerAddress)}
Blockchain Information:
Coin Type: ${coinType}
Transaction Hash: ${committedTxn.hash}
Gas Used: ${executedTxn.gas_used}
Status: ${executedTxn.success ? 'Success' : 'Failed'}`;
if (iconUrl) {
result += `
Icon URL: ${iconUrl}`;
}
if (projectUrl) {
result += `
Project URL: ${projectUrl}`;
}
result += `
š Next Steps:
1. Mint coins using the mint_coin tool with coin type: ${coinType}
2. Register the coin for accounts that want to receive it
3. Transfer coins using the transfer_coin tool
ā ļø Important Notes:
- Save the coin type identifier: ${coinType}
- Only the deployer (${formatAddress(deployerAddress)}) can mint new coins
- Recipients must register for this coin type before receiving transfers
- This coin follows the Aptos Managed Coin standard
ā
Your custom coin is now live on Aptos ${getCurrentNetwork()}!`;
return result;
} catch (error) {
console.error('Error deploying coin:', error);
if (error instanceof Error) {
if (error.message.includes('insufficient')) {
throw new Error("Insufficient APT balance to pay for coin deployment transaction fees");
}
if (error.message.includes('already exists')) {
throw new Error("A coin with this configuration already exists for this account");
}
if (error.message.includes('invalid')) {
throw new Error("Invalid coin parameters. Check name, symbol, and decimals");
}
}
throw new Error(`Failed to deploy coin: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Checks if the provided arguments are valid for the deployCoin tool
* @param args The arguments to check
* @returns True if the arguments are valid, false otherwise
*/
export function isDeployCoinArgs(args: unknown): args is {
name: string;
symbol: string;
decimals?: number;
icon_url?: string;
project_url?: string;
max_gas_amount?: number;
} {
return (
typeof args === "object" &&
args !== null &&
"name" in args &&
typeof (args as any).name === "string" &&
"symbol" in args &&
typeof (args as any).symbol === "string" &&
(!(args as any).decimals || typeof (args as any).decimals === "number") &&
(!(args as any).icon_url || typeof (args as any).icon_url === "string") &&
(!(args as any).project_url || typeof (args as any).project_url === "string") &&
(!(args as any).max_gas_amount || typeof (args as any).max_gas_amount === "number")
);
}