UNPKG

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.**

135 lines (134 loc) 5.08 kB
import { decodeEventLog, getContract, keccak256, parseEther, parseUnits, publicActions, toBytes, zeroAddress, } from "viem"; import { AddressConfig } from "../addressConfig.js"; import { unichain, unichainSepolia } from "viem/chains"; import { supportedChain } from "../chains/index.js"; import { uniMemeLauncherAbi } from "../lib/abi/uniMemeLauncherAbi.js"; import { publicClient, walletClient } from "../config.js"; import { Price, Token } from "@uniswap/sdk-core"; import { priceToClosestTick } from "@uniswap/v3-sdk"; import Decimal from "decimal.js"; import { genImg } from "./genImg.js"; import { uniderpLogin } from "../lib/uniderp.js"; export const UNIDERP_DOMAINS = { [unichain.id]: "api.uniderp.fun", [unichainSepolia.id]: "staging-capi.uniderp.fun", }; const TICK_SPACING = 60; const INITIAL_PRICE = 10130819768; const DEPLOY_FEE = 0.00069; const NATIVE_DECIMAL = 18; const token = ({ sortOrder, decimals = 18, chainId = 1, }) => { if (sortOrder > 9 || sortOrder % 1 !== 0) throw new Error("invalid sort order"); return new Token(chainId, `0x${new Array(40).fill(`${sortOrder}`).join("")}`, decimals, `T${sortOrder}`, `token${sortOrder}`); }; const getTokenAddressFromLogs = (logs) => { let tokenAddress = ""; for (const log of logs) { try { const decoded = decodeEventLog({ abi: uniMemeLauncherAbi, data: log.data, topics: log.topics, }); if (decoded.eventName === "TokenCreated") { tokenAddress = decoded.args.tokenAddress; } } catch { console.log(); } } return tokenAddress; }; export async function uniderpCreateMeme({ account, initialEthBuyAmount, tokenName, tokenSymbol, description, teleUrl, twitUrl, webUrl, discordUrl, youtubeUrl, imageUrl, }) { const domain = UNIDERP_DOMAINS[supportedChain.id]; const uniderpToken = await uniderpLogin(account); // Submit Onchain const value = parseUnits(new Decimal(initialEthBuyAmount).add(DEPLOY_FEE).toFixed(NATIVE_DECIMAL), NATIVE_DECIMAL); const client = walletClient(account).extend(publicActions); const contract = getContract({ address: AddressConfig.UniMemeLauncherContract, abi: uniMemeLauncherAbi, client, }); const token0 = token({ sortOrder: 0 }); const token1 = token({ sortOrder: 1 }); const tickIfToken0IsNewToken = Math.floor(priceToClosestTick(new Price(token0, token1, INITIAL_PRICE, 1)) / TICK_SPACING) * TICK_SPACING; const txHash = await contract.write.deployTokenWithEth([ { initialBuyConfig: { buyPairedAmount: parseEther(initialEthBuyAmount), minTokenAmount: 0, }, tokenConfig: { name: tokenName, symbol: tokenSymbol, salt: keccak256(toBytes(tokenSymbol + Math.floor(1000 * Math.random()))), }, poolConfig: { pairedToken: zeroAddress, tickIfToken0IsNewToken, }, referrer: zeroAddress, }, ], { value, }); const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash, }); if (receipt.status !== "success") { throw new Error("Deploy token failed"); } const tokenAddress = getTokenAddressFromLogs(receipt.logs); // Create Project const formData = new FormData(); formData.append("tokenName", tokenName); formData.append("tokenSymbol", tokenSymbol); formData.append("description", description); formData.append("tokenAddress", tokenAddress); if (teleUrl) { formData.append("teleUrl", teleUrl); } if (twitUrl) { formData.append("twitUrl", twitUrl); } if (webUrl) { formData.append("webUrl", webUrl); } if (discordUrl) { formData.append("discordUrl", discordUrl); } if (youtubeUrl) { formData.append("youtubeUrl", youtubeUrl); } if (imageUrl) { formData.append("imageUrl", imageUrl); } else { // Image const prompt = `Logo for this token: name = ${tokenName}, description = ${description}`; const base64String = await genImg(prompt); const byteCharacters = atob(base64String); const byteNumbers = new Array(byteCharacters.length) .fill(0) .map((_, i) => byteCharacters.charCodeAt(i)); const byteArray = new Uint8Array(byteNumbers); const file = new File([byteArray], tokenName + ".jpeg", { type: "image/jpeg", }); formData.append("file", file); } const createProjectRes = await fetch(`https://${domain}/v1/projects`, { method: "POST", headers: { Authorization: `Bearer ${uniderpToken}`, }, body: formData, }).then((res) => res.json()); if (createProjectRes.data && createProjectRes.data.tokenAddress) { return createProjectRes.data.tokenAddress; } }