diff --git a/src/main.ts b/src/main.ts index 8e3b168..f2d6796 100644 --- a/src/main.ts +++ b/src/main.ts @@ -30,6 +30,7 @@ import { chainIdToCdpNetworkId, chainIdToChain } from './chains.js'; import { baseMcpContractActionProvider } from './tools/contracts/index.js'; import { baseMcpTools, toolToHandler } from './tools/index.js'; import { baseMcpMorphoActionProvider } from './tools/morpho/index.js'; +import { baseMcpOnrampActionProvider } from './tools/onramp/index.js'; import { generateSessionId, getActionProvidersWithRequiredEnvVars, @@ -98,6 +99,7 @@ export async function main() { // Base MCP Action Providers baseMcpMorphoActionProvider(), baseMcpContractActionProvider(), + baseMcpOnrampActionProvider(), ], }); diff --git a/src/tools/index.ts b/src/tools/index.ts index 8cf89ba..35592fe 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -1,13 +1,10 @@ import { erc20BalanceTool, erc20TransferTool } from './erc20/index.js'; import { farcasterUsernameTool } from './farcaster/index.js'; import { listNftsTool, transferNftTool } from './nft/index.js'; -import { getOnrampAssetsTool, onrampTool } from './onramp/index.js'; import { buyOpenRouterCreditsTool } from './open-router/index.js'; import type { ToolHandler, ToolWithHandler } from './types.js'; export const baseMcpTools: ToolWithHandler[] = [ - getOnrampAssetsTool, - onrampTool, erc20BalanceTool, erc20TransferTool, listNftsTool, diff --git a/src/tools/onramp/handlers.ts b/src/tools/onramp/handlers.ts deleted file mode 100644 index a6926db..0000000 --- a/src/tools/onramp/handlers.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { getOnrampBuyUrl } from '@coinbase/onchainkit/fund'; -import type { PublicActions, WalletClient } from 'viem'; -import { base } from 'viem/chains'; -import type { z } from 'zod'; -import { checkToolSupportsChain } from '../utils/index.js'; -import type { GetOnrampAssetsSchema, OnrampSchema } from './schemas.js'; -import type { PatchedOnrampConfigResponseData } from './types.js'; - -export async function getOnrampAssetsHandler( - wallet: WalletClient & PublicActions, - args: z.infer, -): Promise { - checkToolSupportsChain({ - chainId: wallet.chain?.id, - supportedChains: [base], - }); - - const config: PatchedOnrampConfigResponseData = await fetch( - `https://api.developer.coinbase.com/onramp/v1/buy/options?country=${args.country}&subdivision=${args.subdivision}&networks=base`, - { - headers: { - Authorization: `Bearer ${process.env.COINBASE_PUBLIC_API_KEY}`, - }, - }, - ).then((res) => res.json()); - - return JSON.stringify(config); -} - -export async function onrampHandler( - wallet: WalletClient & PublicActions, - args: z.infer, -): Promise { - checkToolSupportsChain({ - chainId: wallet.chain?.id, - supportedChains: [base], - }); - - const { amountUsd, assetId } = args; - - if (!process.env.COINBASE_PROJECT_ID) { - throw new Error('COINBASE_PROJECT_ID is not set'); - } - - const address = wallet.account?.address; - - if (!address) { - throw new Error('No address found'); - } - - const onrampUrl = getOnrampBuyUrl({ - projectId: process.env.COINBASE_PROJECT_ID, - addresses: { [address]: ['base'] }, // Onramp only available on Base - assets: [assetId], - presetFiatAmount: amountUsd, - fiatCurrency: 'USD', - redirectUrl: '', - }); - - return onrampUrl; -} diff --git a/src/tools/onramp/index.ts b/src/tools/onramp/index.ts index f52e85c..0a62bdf 100644 --- a/src/tools/onramp/index.ts +++ b/src/tools/onramp/index.ts @@ -1,17 +1,78 @@ -import { generateTool } from '../../utils.js'; -import { getOnrampAssetsHandler, onrampHandler } from './handlers.js'; +import { + ActionProvider, + CreateAction, + EvmWalletProvider, + type Network, +} from '@coinbase/agentkit'; +import { getOnrampBuyUrl } from '@coinbase/onchainkit/fund'; +import { base } from 'viem/chains'; +import type { z } from 'zod'; import { GetOnrampAssetsSchema, OnrampSchema } from './schemas.js'; +import type { PatchedOnrampConfigResponseData } from './types.js'; -export const getOnrampAssetsTool = generateTool({ - name: 'get_onramp_assets', - description: 'Get the assets available for onramp', - inputSchema: GetOnrampAssetsSchema, - toolHandler: getOnrampAssetsHandler, -}); - -export const onrampTool = generateTool({ - name: 'onramp', - description: 'Onramp a specific asset', - inputSchema: OnrampSchema, - toolHandler: onrampHandler, -}); +export class BaseMcpOnrampActionProvider extends ActionProvider { + constructor() { + super('baseMcpOnramp', []); + } + + @CreateAction({ + name: 'get_onramp_assets', + description: 'Get the assets available for onramp', + schema: GetOnrampAssetsSchema, + }) + async getOnrampAssets( + walletProvider: EvmWalletProvider, + args: z.infer, + ) { + const config: PatchedOnrampConfigResponseData = await fetch( + `https://api.developer.coinbase.com/onramp/v1/buy/options?country=${args.country}&subdivision=${args.subdivision}&networks=base`, + { + headers: { + Authorization: `Bearer ${process.env.COINBASE_PUBLIC_API_KEY}`, + }, + }, + ).then((res) => res.json()); + + return JSON.stringify(config); + } + + @CreateAction({ + name: 'onramp', + description: 'Onramp a specific asset', + schema: OnrampSchema, + }) + async onramp( + walletProvider: EvmWalletProvider, + args: z.infer, + ) { + const { amountUsd, assetId } = args; + + if (!process.env.COINBASE_PROJECT_ID) { + throw new Error('COINBASE_PROJECT_ID is not set'); + } + + const address = walletProvider.getAddress(); + + if (!address) { + throw new Error('No address found'); + } + + const onrampUrl = getOnrampBuyUrl({ + projectId: process.env.COINBASE_PROJECT_ID, + addresses: { [address]: ['base'] }, // Onramp only available on Base + assets: [assetId], + presetFiatAmount: amountUsd, + fiatCurrency: 'USD', + redirectUrl: '', + }); + + return onrampUrl; + } + + supportsNetwork(network: Network): boolean { + return network.chainId === String(base.id); + } +} + +export const baseMcpOnrampActionProvider = () => + new BaseMcpOnrampActionProvider();