@moonpay/cli 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-AH5VMN63.js +6608 -0
- package/dist/chunk-AH5VMN63.js.map +1 -0
- package/dist/chunk-V7MA7WNX.js +441 -0
- package/dist/chunk-V7MA7WNX.js.map +1 -0
- package/dist/index.js +145 -51
- package/dist/index.js.map +1 -1
- package/dist/{mcp-QLBMU7OH.js → mcp-VOEHXIOY.js} +66 -46
- package/dist/mcp-VOEHXIOY.js.map +1 -0
- package/dist/store-HCN56E6A.js +22 -0
- package/package.json +4 -2
- package/skills/moonpay-auth/SKILL.md +19 -28
- package/skills/moonpay-missions/SKILL.md +31 -38
- package/skills/moonpay-swap-tokens/SKILL.md +52 -42
- package/skills/moonpay-virtual-account/SKILL.md +18 -81
- package/dist/chains-R754DQM5.js +0 -13
- package/dist/chunk-AGDVU2O5.js +0 -168
- package/dist/chunk-AGDVU2O5.js.map +0 -1
- package/dist/chunk-DAQDHLPY.js +0 -2444
- package/dist/chunk-DAQDHLPY.js.map +0 -1
- package/dist/chunk-EEBB5MQP.js +0 -12
- package/dist/chunk-EEBB5MQP.js.map +0 -1
- package/dist/chunk-Z33PSOPD.js +0 -128
- package/dist/chunk-Z33PSOPD.js.map +0 -1
- package/dist/mcp-QLBMU7OH.js.map +0 -1
- package/dist/server-IUOCZFT7.js +0 -21
- package/dist/server-IUOCZFT7.js.map +0 -1
- /package/dist/{chains-R754DQM5.js.map → store-HCN56E6A.js.map} +0 -0
|
@@ -6,22 +6,20 @@ import {
|
|
|
6
6
|
defineToolSchema,
|
|
7
7
|
messageSign,
|
|
8
8
|
resolveBaseUrl,
|
|
9
|
-
resolveSigningKey,
|
|
10
9
|
schemas_default,
|
|
10
|
+
tokenSwap,
|
|
11
11
|
transactionSign,
|
|
12
|
+
virtualAccountWalletRegister,
|
|
12
13
|
walletCreate,
|
|
13
14
|
walletDelete,
|
|
14
15
|
walletImport,
|
|
15
16
|
walletList,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
walletUnlock
|
|
19
|
-
} from "./chunk-DAQDHLPY.js";
|
|
17
|
+
walletRetrieve
|
|
18
|
+
} from "./chunk-AH5VMN63.js";
|
|
20
19
|
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
import "./chunk-EEBB5MQP.js";
|
|
20
|
+
findWalletOrThrow,
|
|
21
|
+
resolveSigningKey
|
|
22
|
+
} from "./chunk-V7MA7WNX.js";
|
|
25
23
|
|
|
26
24
|
// src/mcp.ts
|
|
27
25
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -46,8 +44,18 @@ var x402RequestSchema = defineToolSchema({
|
|
|
46
44
|
description: "Make an HTTP request to an x402-protected endpoint. Automatically handles payment when a 402 Payment Required response is received, signing the payment transaction with the local wallet.",
|
|
47
45
|
input: z.object({
|
|
48
46
|
method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]).describe("HTTP method"),
|
|
49
|
-
url: z.string().url().
|
|
50
|
-
|
|
47
|
+
url: z.string().url().refine((u) => u.startsWith("https://"), { message: "URL must use HTTPS" }).refine(
|
|
48
|
+
(u) => {
|
|
49
|
+
try {
|
|
50
|
+
const host = new URL(u).hostname;
|
|
51
|
+
return !host.match(/^(localhost|127\.|10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.|169\.254\.|0\.0\.0\.0|\[::1\])/);
|
|
52
|
+
} catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{ message: "URL must not target private/internal addresses" }
|
|
57
|
+
).describe(
|
|
58
|
+
"Full HTTPS URL of the x402-protected endpoint (e.g., 'https://agents.moonpay.com/api/x402/tools/market_digest_retrieve')"
|
|
51
59
|
),
|
|
52
60
|
body: z.record(z.any()).nullable().describe("Request body (for POST, PUT, PATCH)"),
|
|
53
61
|
params: z.record(z.any()).nullable().describe("Query parameters"),
|
|
@@ -99,7 +107,7 @@ function createLocalX402Client(walletAddress, secretKey) {
|
|
|
99
107
|
var x402Request = createTool(
|
|
100
108
|
x402RequestSchema,
|
|
101
109
|
async ({ method, url, body, params, wallet: walletNameOrAddress }) => {
|
|
102
|
-
const walletMetadata =
|
|
110
|
+
const walletMetadata = findWalletOrThrow(walletNameOrAddress);
|
|
103
111
|
const { privateKey, address } = resolveSigningKey(walletMetadata, "solana");
|
|
104
112
|
const client = createLocalX402Client(address, privateKey);
|
|
105
113
|
let response;
|
|
@@ -137,12 +145,12 @@ var LOCAL_TOOLS = [
|
|
|
137
145
|
walletList,
|
|
138
146
|
walletRetrieve,
|
|
139
147
|
walletDelete,
|
|
140
|
-
walletLock,
|
|
141
|
-
walletUnlock,
|
|
142
148
|
transactionSign,
|
|
143
149
|
messageSign,
|
|
144
150
|
bitcoinBalanceRetrieve,
|
|
145
|
-
x402Request
|
|
151
|
+
x402Request,
|
|
152
|
+
tokenSwap,
|
|
153
|
+
virtualAccountWalletRegister
|
|
146
154
|
];
|
|
147
155
|
var localToolMap = new Map(LOCAL_TOOLS.map((t) => [t.schema.name, t]));
|
|
148
156
|
function resolveRemoteSchema(schema) {
|
|
@@ -198,43 +206,55 @@ async function startMcpServer() {
|
|
|
198
206
|
isError: true
|
|
199
207
|
};
|
|
200
208
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
params[key]
|
|
209
|
+
try {
|
|
210
|
+
const localTool = localToolMap.get(name);
|
|
211
|
+
if (localTool) {
|
|
212
|
+
const shape = localTool.schema.input.shape ?? {};
|
|
213
|
+
for (const [key, field] of Object.entries(shape)) {
|
|
214
|
+
if (params[key] === void 0 && field._def.typeName === "ZodNullable") {
|
|
215
|
+
params[key] = null;
|
|
216
|
+
}
|
|
207
217
|
}
|
|
218
|
+
const result2 = await localTool.handler(params);
|
|
219
|
+
return {
|
|
220
|
+
content: [
|
|
221
|
+
{ type: "text", text: JSON.stringify(result2, null, 2) }
|
|
222
|
+
]
|
|
223
|
+
};
|
|
208
224
|
}
|
|
209
|
-
const
|
|
225
|
+
const props = remotePropsMap.get(name) ?? {};
|
|
226
|
+
for (const [key, prop] of Object.entries(props)) {
|
|
227
|
+
if (params[key] === void 0) {
|
|
228
|
+
const nullable = Array.isArray(prop.type) ? prop.type.includes("null") : prop.anyOf?.some((t) => t.type === "null");
|
|
229
|
+
if (nullable) params[key] = null;
|
|
230
|
+
}
|
|
231
|
+
const isNum = prop.type === "number" || prop.type === "integer" || Array.isArray(prop.type) && prop.type.some(
|
|
232
|
+
(t) => t === "number" || t === "integer"
|
|
233
|
+
) || prop.anyOf?.some(
|
|
234
|
+
(t) => t.type === "number" || t.type === "integer"
|
|
235
|
+
);
|
|
236
|
+
if (isNum && typeof params[key] === "string") {
|
|
237
|
+
params[key] = Number(params[key]);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const baseUrl = resolveBaseUrl();
|
|
241
|
+
const result = await callTool(baseUrl, name, params);
|
|
210
242
|
return {
|
|
211
243
|
content: [
|
|
212
|
-
{ type: "text", text: JSON.stringify(
|
|
244
|
+
{ type: "text", text: JSON.stringify(result, null, 2) }
|
|
213
245
|
]
|
|
214
246
|
};
|
|
247
|
+
} catch (error) {
|
|
248
|
+
return {
|
|
249
|
+
content: [
|
|
250
|
+
{
|
|
251
|
+
type: "text",
|
|
252
|
+
text: error instanceof Error ? error.message : String(error)
|
|
253
|
+
}
|
|
254
|
+
],
|
|
255
|
+
isError: true
|
|
256
|
+
};
|
|
215
257
|
}
|
|
216
|
-
const props = remotePropsMap.get(name) ?? {};
|
|
217
|
-
for (const [key, prop] of Object.entries(props)) {
|
|
218
|
-
if (params[key] === void 0) {
|
|
219
|
-
const nullable = Array.isArray(prop.type) ? prop.type.includes("null") : prop.anyOf?.some((t) => t.type === "null");
|
|
220
|
-
if (nullable) params[key] = null;
|
|
221
|
-
}
|
|
222
|
-
const isNum = prop.type === "number" || prop.type === "integer" || Array.isArray(prop.type) && prop.type.some(
|
|
223
|
-
(t) => t === "number" || t === "integer"
|
|
224
|
-
) || prop.anyOf?.some(
|
|
225
|
-
(t) => t.type === "number" || t.type === "integer"
|
|
226
|
-
);
|
|
227
|
-
if (isNum && typeof params[key] === "string") {
|
|
228
|
-
params[key] = Number(params[key]);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
const baseUrl = resolveBaseUrl();
|
|
232
|
-
const result = await callTool(baseUrl, name, params);
|
|
233
|
-
return {
|
|
234
|
-
content: [
|
|
235
|
-
{ type: "text", text: JSON.stringify(result, null, 2) }
|
|
236
|
-
]
|
|
237
|
-
};
|
|
238
258
|
});
|
|
239
259
|
const transport = new StdioServerTransport();
|
|
240
260
|
await server.connect(transport);
|
|
@@ -242,4 +262,4 @@ async function startMcpServer() {
|
|
|
242
262
|
export {
|
|
243
263
|
startMcpServer
|
|
244
264
|
};
|
|
245
|
-
//# sourceMappingURL=mcp-
|
|
265
|
+
//# sourceMappingURL=mcp-VOEHXIOY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp.ts","../src/tools/x402/request/tool.ts","../src/tools/x402/request/schema.ts"],"sourcesContent":["import { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { z } from \"zod\";\nimport { zodToJsonSchema } from \"zod-to-json-schema\";\nimport { callTool } from \"./client\";\nimport { resolveBaseUrl } from \"./auth\";\nimport type { Tool } from \"./tools/shared\";\nimport { walletCreate } from \"./tools/wallet/create/tool\";\nimport { walletImport } from \"./tools/wallet/import/tool\";\nimport { walletList } from \"./tools/wallet/list/tool\";\nimport { walletRetrieve } from \"./tools/wallet/retrieve/tool\";\nimport { walletDelete } from \"./tools/wallet/delete/tool\";\nimport { transactionSign } from \"./tools/transaction/sign/tool\";\nimport { messageSign } from \"./tools/message/sign/tool\";\nimport { bitcoinBalanceRetrieve } from \"./tools/bitcoin/balance/tool\";\nimport { x402Request } from \"./tools/x402/request/tool\";\nimport { tokenSwap } from \"./tools/token/swap/tool\";\nimport { virtualAccountWalletRegister } from \"./tools/virtual-account/wallet/register/tool\";\nimport schemas from \"./generated/schemas.json\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst LOCAL_TOOLS: Tool<any>[] = [\n walletCreate,\n walletImport,\n walletList,\n walletRetrieve,\n walletDelete,\n transactionSign,\n messageSign,\n bitcoinBalanceRetrieve,\n x402Request,\n tokenSwap,\n virtualAccountWalletRegister,\n];\n\nconst localToolMap = new Map(LOCAL_TOOLS.map((t) => [t.schema.name, t]));\n\n/**\n * Resolve a remote schema's $ref to the actual properties object.\n */\nfunction resolveRemoteSchema(schema: (typeof schemas)[number]) {\n const input = schema.inputSchema as any;\n if (input.$ref && input.definitions) {\n const defName = input.$ref.replace(\"#/definitions/\", \"\");\n return input.definitions[defName] ?? input;\n }\n return input;\n}\n\nexport async function startMcpServer() {\n const server = new Server(\n { name: \"moonpay\", version: \"1.0.0\" },\n { capabilities: { tools: { listChanged: true } } },\n );\n\n // Build tool definitions — local tools use Zod→JSON, remote use JSON directly\n const toolDefs: Array<{\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n }> = LOCAL_TOOLS.map((tool) => ({\n name: tool.schema.name,\n description: tool.schema.description,\n inputSchema: zodToJsonSchema(tool.schema.input) as Record<string, unknown>,\n }));\n\n const remotePropsMap = new Map<string, Record<string, any>>();\n for (const schema of schemas) {\n if (localToolMap.has(schema.name)) continue;\n const resolved = resolveRemoteSchema(schema);\n remotePropsMap.set(\n schema.name,\n (resolved.properties ?? {}) as Record<string, any>,\n );\n toolDefs.push({\n name: schema.name,\n description: schema.description,\n inputSchema: {\n type: \"object\",\n properties: resolved.properties ?? {},\n ...(resolved.required ? { required: resolved.required } : {}),\n ...(resolved.additionalProperties !== undefined\n ? { additionalProperties: resolved.additionalProperties }\n : {}),\n },\n });\n }\n\n const toolDefMap = new Map(toolDefs.map((t) => [t.name, t]));\n\n // tools/list — return raw JSON schemas directly\n server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: toolDefs.map((t) => ({\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema,\n })),\n }));\n\n // tools/call\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: params = {} } = request.params;\n\n if (!toolDefMap.has(name)) {\n return {\n content: [{ type: \"text\" as const, text: `Unknown tool: ${name}` }],\n isError: true,\n };\n }\n\n try {\n // Local tool — coerce nullable fields then run handler\n const localTool = localToolMap.get(name);\n if (localTool) {\n // Fill missing nullable fields with null (MCP clients may omit them)\n const shape = (localTool.schema.input as z.ZodObject<z.ZodRawShape>).shape ?? {};\n for (const [key, field] of Object.entries(shape)) {\n if (\n params[key] === undefined &&\n (field as z.ZodTypeAny)._def.typeName === \"ZodNullable\"\n ) {\n params[key] = null;\n }\n }\n\n const result = await localTool.handler(params);\n return {\n content: [\n { type: \"text\" as const, text: JSON.stringify(result, null, 2) },\n ],\n };\n }\n\n // Remote tool — coerce types then call API\n const props = remotePropsMap.get(name) ?? {};\n for (const [key, prop] of Object.entries(props)) {\n if (params[key] === undefined) {\n const nullable = Array.isArray(prop.type)\n ? prop.type.includes(\"null\")\n : prop.anyOf?.some((t: any) => t.type === \"null\");\n if (nullable) params[key] = null;\n }\n const isNum =\n prop.type === \"number\" ||\n prop.type === \"integer\" ||\n (Array.isArray(prop.type) &&\n prop.type.some(\n (t: string) => t === \"number\" || t === \"integer\",\n )) ||\n prop.anyOf?.some(\n (t: any) => t.type === \"number\" || t.type === \"integer\",\n );\n if (isNum && typeof params[key] === \"string\") {\n params[key] = Number(params[key]);\n }\n }\n\n const baseUrl = resolveBaseUrl();\n const result = await callTool(baseUrl, name, params);\n return {\n content: [\n { type: \"text\" as const, text: JSON.stringify(result, null, 2) },\n ],\n };\n } catch (error) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: error instanceof Error ? error.message : String(error),\n },\n ],\n isError: true,\n };\n }\n });\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n","import { Keypair, VersionedTransaction, VersionedMessage } from \"@solana/web3.js\";\nimport axios from \"axios\";\nimport { wrapAxiosWithPayment } from \"@x402/axios\";\nimport { x402Client } from \"@x402/core/client\";\nimport { ExactSvmScheme } from \"@x402/svm\";\nimport type { Address } from \"@solana/addresses\";\nimport type { SignatureDictionary } from \"@solana/signers\";\nimport type { Transaction } from \"@solana/transactions\";\nimport { createTool } from \"../../shared\";\nimport { findWalletOrThrow, resolveSigningKey } from \"../../wallet/store\";\nimport { x402RequestSchema } from \"./schema\";\n\nconst SOLANA_NETWORK = \"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp\" as const;\n\nfunction createLocalX402Client(walletAddress: string, secretKey: Uint8Array) {\n const keypair = Keypair.fromSecretKey(secretKey);\n\n const signer = {\n address: walletAddress as Address,\n signTransactions: async (\n transactions: readonly Transaction[],\n ): Promise<readonly SignatureDictionary[]> => {\n return transactions.map((transaction) => {\n const messageBytes = new Uint8Array(transaction.messageBytes);\n const message = VersionedMessage.deserialize(messageBytes);\n const numSigs = Object.keys(transaction.signatures).length;\n const tx = new VersionedTransaction(\n message,\n new Array(numSigs).fill(new Uint8Array(64)),\n );\n\n tx.sign([keypair]);\n\n const signerIndex = message.staticAccountKeys.findIndex(\n (key) => key.toBase58() === walletAddress,\n );\n if (signerIndex === -1) {\n throw new Error(\n `Wallet ${walletAddress} is not a signer for this transaction`,\n );\n }\n\n return {\n [walletAddress]: tx.signatures[signerIndex],\n } as SignatureDictionary;\n });\n },\n };\n\n const client = new x402Client();\n const svmScheme = new ExactSvmScheme(signer);\n client.register(SOLANA_NETWORK, svmScheme);\n client.registerV1(\"solana\", svmScheme);\n\n return wrapAxiosWithPayment(axios.create(), client);\n}\n\nexport const x402Request = createTool(\n x402RequestSchema,\n async ({ method, url, body, params, wallet: walletNameOrAddress }) => {\n const walletMetadata = findWalletOrThrow(walletNameOrAddress);\n const { privateKey, address } = resolveSigningKey(walletMetadata, \"solana\");\n const client = createLocalX402Client(address, privateKey);\n\n let response;\n switch (method) {\n case \"GET\":\n response = await client.get(url, { params });\n break;\n case \"POST\":\n response = await client.post(url, body || {}, { params });\n break;\n case \"PUT\":\n response = await client.put(url, body || {}, { params });\n break;\n case \"PATCH\":\n response = await client.patch(url, body || {}, { params });\n break;\n case \"DELETE\":\n response = await client.delete(url, { params });\n break;\n default:\n throw new Error(`Unsupported HTTP method: ${method}`);\n }\n\n return {\n status: response.status,\n data: response.data,\n headers: response.headers as Record<string, string>,\n };\n },\n);\n","import { z } from \"zod\";\nimport { defineToolSchema } from \"../../shared\";\n\nexport const x402RequestSchema = defineToolSchema({\n name: \"x402_request\",\n description:\n \"Make an HTTP request to an x402-protected endpoint. Automatically handles payment when a 402 Payment Required response is received, signing the payment transaction with the local wallet.\",\n input: z.object({\n method: z\n .enum([\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\"])\n .describe(\"HTTP method\"),\n url: z\n .string()\n .url()\n .refine((u) => u.startsWith(\"https://\"), { message: \"URL must use HTTPS\" })\n .refine(\n (u) => {\n try {\n const host = new URL(u).hostname;\n return !host.match(/^(localhost|127\\.|10\\.|172\\.(1[6-9]|2\\d|3[01])\\.|192\\.168\\.|169\\.254\\.|0\\.0\\.0\\.0|\\[::1\\])/);\n } catch { return false; }\n },\n { message: \"URL must not target private/internal addresses\" },\n )\n .describe(\n \"Full HTTPS URL of the x402-protected endpoint (e.g., 'https://agents.moonpay.com/api/x402/tools/market_digest_retrieve')\",\n ),\n body: z\n .record(z.any())\n .nullable()\n .describe(\"Request body (for POST, PUT, PATCH)\"),\n params: z.record(z.any()).nullable().describe(\"Query parameters\"),\n wallet: z.string().describe(\"Wallet name or address to pay with\"),\n }),\n output: z.object({\n status: z.number().describe(\"HTTP status code\"),\n data: z.any().describe(\"Response data\"),\n headers: z.record(z.string()).describe(\"Response headers\"),\n }),\n});\n"],"mappings":"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","names":["result"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "module"; const require = __createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
addWallet,
|
|
4
|
+
findWallet,
|
|
5
|
+
findWalletOrThrow,
|
|
6
|
+
loadWallets,
|
|
7
|
+
mutateWallets,
|
|
8
|
+
removeWallet,
|
|
9
|
+
resolveSigningKey,
|
|
10
|
+
saveWallets
|
|
11
|
+
} from "./chunk-V7MA7WNX.js";
|
|
12
|
+
export {
|
|
13
|
+
addWallet,
|
|
14
|
+
findWallet,
|
|
15
|
+
findWalletOrThrow,
|
|
16
|
+
loadWallets,
|
|
17
|
+
mutateWallets,
|
|
18
|
+
removeWallet,
|
|
19
|
+
resolveSigningKey,
|
|
20
|
+
saveWallets
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=store-HCN56E6A.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moonpay/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
24
|
-
"@
|
|
24
|
+
"@noble/hashes": "^1.7.0",
|
|
25
|
+
"@scure/bip32": "^1.4.0",
|
|
25
26
|
"@scure/bip39": "^1.6.0",
|
|
26
27
|
"@solana/web3.js": "^1.98.4",
|
|
27
28
|
"@x402/axios": "^2.4.0",
|
|
@@ -35,6 +36,7 @@
|
|
|
35
36
|
"ed25519-hd-key": "^1.3.0",
|
|
36
37
|
"tiny-secp256k1": "^2.2.4",
|
|
37
38
|
"tweetnacl": "^1.0.3",
|
|
39
|
+
"viem": "^2.46.2",
|
|
38
40
|
"zod": "^3.25.76",
|
|
39
41
|
"zod-to-json-schema": "^3.25.1"
|
|
40
42
|
},
|
|
@@ -36,14 +36,17 @@ mp logout
|
|
|
36
36
|
|
|
37
37
|
## Local wallet management
|
|
38
38
|
|
|
39
|
-
The CLI manages local
|
|
39
|
+
The CLI manages local wallets stored encrypted in `~/.config/moonpay/wallets.json`. Private keys are encrypted with AES-256-GCM using a random key stored in your OS keychain. No password required — keys never leave the machine.
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
-
# Create a new wallet
|
|
42
|
+
# Create a new HD wallet (Solana, Ethereum, Bitcoin, Tron)
|
|
43
43
|
mp wallet create --name "my-wallet"
|
|
44
44
|
|
|
45
|
-
# Import from a
|
|
46
|
-
mp wallet import --name "
|
|
45
|
+
# Import from a mnemonic (all chains)
|
|
46
|
+
mp wallet import --name "restored" --mnemonic "word1 word2 ..."
|
|
47
|
+
|
|
48
|
+
# Import from a private key (single chain)
|
|
49
|
+
mp wallet import --name "imported" --key <hex-key> --chain ethereum
|
|
47
50
|
|
|
48
51
|
# List all local wallets
|
|
49
52
|
mp wallet list
|
|
@@ -51,6 +54,9 @@ mp wallet list
|
|
|
51
54
|
# Get wallet details (by name or address)
|
|
52
55
|
mp wallet retrieve --wallet "my-wallet"
|
|
53
56
|
|
|
57
|
+
# Export mnemonic/key (interactive only — agents cannot run this)
|
|
58
|
+
mp wallet export --wallet "my-wallet"
|
|
59
|
+
|
|
54
60
|
# Delete a wallet (irreversible)
|
|
55
61
|
mp wallet delete --wallet "my-wallet" --confirm
|
|
56
62
|
```
|
|
@@ -64,35 +70,20 @@ mp wallet delete --wallet "my-wallet" --confirm
|
|
|
64
70
|
|
|
65
71
|
## Config locations
|
|
66
72
|
|
|
73
|
+
- **Wallets:** `~/.config/moonpay/wallets.json` (encrypted, AES-256-GCM)
|
|
74
|
+
- **Encryption key:** OS keychain (`moonpay-cli` / `encryption-key`)
|
|
67
75
|
- **Credentials:** `~/.config/moonpay/credentials.json` (OAuth tokens)
|
|
68
76
|
- **Config:** `~/.config/moonpay/config.json` (base URL, client ID)
|
|
69
|
-
- **Wallets:** `~/.config/moonpay/wallets/` (local keypairs, 0600 permissions)
|
|
70
|
-
|
|
71
|
-
## Output formats
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
mp -f json wallet list # Pretty JSON (default)
|
|
75
|
-
mp -f compact wallet list # Single-line JSON
|
|
76
|
-
mp -f table wallet list # ASCII table
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Environment for scripts/agents
|
|
80
|
-
|
|
81
|
-
If running `mp` from a script or agent subprocess, ensure PATH includes the npm global bin:
|
|
82
|
-
|
|
83
|
-
```bash
|
|
84
|
-
export PATH="$(npm config get prefix)/bin:$PATH"
|
|
85
|
-
mp --version
|
|
86
|
-
```
|
|
87
77
|
|
|
88
|
-
##
|
|
78
|
+
## Security
|
|
89
79
|
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
-
|
|
93
|
-
-
|
|
80
|
+
- Wallet secrets are always encrypted on disk
|
|
81
|
+
- Encryption key is stored in macOS Keychain / Linux libsecret
|
|
82
|
+
- No password to remember — the OS handles authentication
|
|
83
|
+
- `wallet export` requires an interactive terminal (TTY) — agents and scripts cannot extract secrets
|
|
84
|
+
- 24-word BIP39 mnemonics (256-bit entropy)
|
|
94
85
|
|
|
95
86
|
## Related skills
|
|
96
87
|
|
|
97
|
-
- **moonpay-swap-tokens** — Swap tokens using local wallets.
|
|
88
|
+
- **moonpay-swap-tokens** — Swap or bridge tokens using local wallets.
|
|
98
89
|
- **moonpay-check-wallet** — Check wallet balances.
|
|
@@ -20,82 +20,75 @@ mp wallet list
|
|
|
20
20
|
If no wallets exist, create one:
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
mp wallet create --name "
|
|
23
|
+
mp wallet create --name "main"
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
Tell the user their email, wallet
|
|
26
|
+
Tell the user their email, all wallet addresses (Solana, Ethereum, Bitcoin, Tron), and that keys are encrypted locally with a random key in the OS keychain.
|
|
27
27
|
|
|
28
28
|
## Mission 2: Recon
|
|
29
29
|
|
|
30
30
|
**Goal:** See what's trending and research a token.
|
|
31
31
|
|
|
32
|
-
First, check what's hot:
|
|
33
|
-
|
|
34
32
|
```bash
|
|
35
33
|
mp token trending list --chain solana --limit 5 --page 1
|
|
36
34
|
```
|
|
37
35
|
|
|
38
|
-
Present the top trending tokens
|
|
39
|
-
|
|
40
|
-
Then ask the user to pick a token to research (or default to SOL):
|
|
36
|
+
Present the top trending tokens. Then ask the user to pick one to research:
|
|
41
37
|
|
|
42
38
|
```bash
|
|
43
39
|
mp token search --query "<token>" --chain solana
|
|
44
40
|
mp token retrieve --token <address-from-search> --chain solana
|
|
45
41
|
```
|
|
46
42
|
|
|
47
|
-
Present: name, symbol, price,
|
|
43
|
+
Present: name, symbol, price, market cap, liquidity, volume.
|
|
48
44
|
|
|
49
45
|
## Mission 3: Portfolio Check
|
|
50
46
|
|
|
51
|
-
**Goal:** See what's in the wallet.
|
|
47
|
+
**Goal:** See what's in the wallet across chains.
|
|
52
48
|
|
|
53
49
|
```bash
|
|
54
|
-
mp token balance list --wallet <address> --chain solana
|
|
50
|
+
mp token balance list --wallet <solana-address> --chain solana
|
|
51
|
+
mp token balance list --wallet <eth-address> --chain ethereum
|
|
52
|
+
mp bitcoin balance retrieve --wallet <btc-address>
|
|
55
53
|
```
|
|
56
54
|
|
|
57
|
-
Present holdings as a
|
|
55
|
+
Present holdings as a multi-chain portfolio report with USD values and total.
|
|
58
56
|
|
|
59
57
|
## Mission 4: Swap
|
|
60
58
|
|
|
61
|
-
**Goal:**
|
|
62
|
-
|
|
63
|
-
Pick a small swap based on what the wallet holds (e.g. 0.01 USDC → SOL). If the wallet has no USDC, pick any token pair that makes sense.
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
mp token swap build --input <input-mint> --output <output-mint> --amount <small-amount> --wallet <address>
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
Show the quote from the `message` field. Ask the user: **"Want to execute this swap?"**
|
|
59
|
+
**Goal:** Execute a swap end-to-end.
|
|
70
60
|
|
|
71
|
-
|
|
61
|
+
Pick a small swap based on what the wallet holds:
|
|
72
62
|
|
|
73
63
|
```bash
|
|
74
|
-
mp
|
|
75
|
-
|
|
64
|
+
mp token swap \
|
|
65
|
+
--from-wallet main --from-chain solana \
|
|
66
|
+
--from-token So11111111111111111111111111111111111111112 \
|
|
67
|
+
--from-amount 0.01 \
|
|
68
|
+
--to-token EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
|
|
76
69
|
```
|
|
77
70
|
|
|
78
|
-
|
|
71
|
+
This builds, signs locally, and broadcasts in one step. Show the result and explain: the transaction was built on the server, signed locally (key never left the machine), and submitted on-chain.
|
|
79
72
|
|
|
80
73
|
## Mission 5: Buy with Fiat
|
|
81
74
|
|
|
82
|
-
**Goal:** Generate a fiat checkout link
|
|
75
|
+
**Goal:** Generate a fiat checkout link.
|
|
83
76
|
|
|
84
77
|
```bash
|
|
85
|
-
mp buy --token sol --amount 1 --wallet <address> --email <email
|
|
78
|
+
mp buy --token sol --amount 1 --wallet <solana-address> --email <email>
|
|
86
79
|
```
|
|
87
80
|
|
|
88
|
-
|
|
81
|
+
Open the checkout URL. Explain: MoonPay's fiat gateway for buying crypto with card or bank transfer.
|
|
89
82
|
|
|
90
83
|
## Mission 6: Message Signing
|
|
91
84
|
|
|
92
85
|
**Goal:** Sign a message to prove wallet ownership.
|
|
93
86
|
|
|
94
87
|
```bash
|
|
95
|
-
mp message sign --wallet
|
|
88
|
+
mp message sign --wallet main --chain solana --message "I own this wallet"
|
|
96
89
|
```
|
|
97
90
|
|
|
98
|
-
Present the signature. Explain:
|
|
91
|
+
Present the signature. Explain: used for wallet verification (e.g. registering with virtual accounts, proving ownership to dApps).
|
|
99
92
|
|
|
100
93
|
## Mission 7: Virtual Account (optional)
|
|
101
94
|
|
|
@@ -105,28 +98,28 @@ Present the signature. Explain: this is used for wallet verification (e.g. regis
|
|
|
105
98
|
mp virtual-account retrieve
|
|
106
99
|
```
|
|
107
100
|
|
|
108
|
-
If they have one, show the status and next step. If not, explain what
|
|
101
|
+
If they have one, show the status and next step. If not, explain what it is and that they can set one up with `mp virtual-account create`.
|
|
109
102
|
|
|
110
103
|
## Mission 8: Skills
|
|
111
104
|
|
|
112
|
-
**Goal:** Show
|
|
105
|
+
**Goal:** Show what skills are available.
|
|
113
106
|
|
|
114
107
|
```bash
|
|
115
108
|
mp skill list
|
|
116
109
|
```
|
|
117
110
|
|
|
118
|
-
Explain: skills are guides that teach agents how to use the CLI.
|
|
111
|
+
Explain: skills are guides that teach agents how to use the CLI. Install them with `mp skill install`.
|
|
119
112
|
|
|
120
113
|
## Debrief
|
|
121
114
|
|
|
122
|
-
Summarize everything
|
|
123
|
-
-
|
|
115
|
+
Summarize everything:
|
|
116
|
+
- Set up a multi-chain HD wallet (encrypted, OS keychain secured)
|
|
124
117
|
- Searched and analyzed tokens
|
|
125
|
-
- Checked portfolio
|
|
126
|
-
-
|
|
118
|
+
- Checked portfolio across Solana, Ethereum, Bitcoin
|
|
119
|
+
- Executed a swap (built, signed locally, broadcast)
|
|
127
120
|
- Generated a fiat buy link
|
|
128
|
-
- Signed a message
|
|
121
|
+
- Signed a message for verification
|
|
129
122
|
- Explored virtual accounts
|
|
130
123
|
- Discovered skills
|
|
131
124
|
|
|
132
|
-
End with: "You're
|
|
125
|
+
End with: "You're all set. Run `mp --help` to see all commands, or ask me anything."
|
|
@@ -1,73 +1,83 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: moonpay-swap-tokens
|
|
3
|
-
description: Swap
|
|
3
|
+
description: Swap or bridge tokens across chains. Use when the user wants to swap, bridge, or move tokens between wallets or chains.
|
|
4
4
|
tags: [trading]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
# Swap tokens
|
|
7
|
+
# Swap or bridge tokens
|
|
8
8
|
|
|
9
9
|
## Goal
|
|
10
10
|
|
|
11
|
-
Swap tokens on
|
|
11
|
+
Swap tokens on any supported chain, or bridge tokens across chains. One command handles everything: builds the transaction via swaps.xyz, signs locally, broadcasts, and registers for tracking.
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Command
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
-
|
|
15
|
+
```bash
|
|
16
|
+
mp token swap \
|
|
17
|
+
--from-wallet <wallet-name> \
|
|
18
|
+
--from-chain <chain> \
|
|
19
|
+
--from-token <token-address> \
|
|
20
|
+
--from-amount <amount> \
|
|
21
|
+
--to-token <token-address> \
|
|
22
|
+
--to-chain <chain> # optional, defaults to from-chain
|
|
23
|
+
--to-wallet <wallet-name> # optional, defaults to from-wallet
|
|
24
|
+
```
|
|
18
25
|
|
|
19
|
-
##
|
|
26
|
+
## Examples
|
|
20
27
|
|
|
21
|
-
###
|
|
28
|
+
### Same-chain swap (SOL → USDC on Solana)
|
|
22
29
|
|
|
23
30
|
```bash
|
|
24
|
-
mp token swap
|
|
25
|
-
--
|
|
26
|
-
--
|
|
27
|
-
--amount
|
|
28
|
-
--
|
|
31
|
+
mp token swap \
|
|
32
|
+
--from-wallet main --from-chain solana \
|
|
33
|
+
--from-token So11111111111111111111111111111111111111112 \
|
|
34
|
+
--from-amount 0.1 \
|
|
35
|
+
--to-token EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
|
|
29
36
|
```
|
|
30
37
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
### 2. Sign the transaction locally
|
|
38
|
+
### Cross-chain bridge (ETH → USDC.e on Polygon)
|
|
34
39
|
|
|
35
40
|
```bash
|
|
36
|
-
mp
|
|
37
|
-
--
|
|
38
|
-
--
|
|
41
|
+
mp token swap \
|
|
42
|
+
--from-wallet funded --from-chain ethereum \
|
|
43
|
+
--from-token 0x0000000000000000000000000000000000000000 \
|
|
44
|
+
--from-amount 0.003 \
|
|
45
|
+
--to-chain polygon \
|
|
46
|
+
--to-token 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
|
|
39
47
|
```
|
|
40
48
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
### 3. Execute the swap
|
|
49
|
+
### ERC20 swap (auto-approves if needed)
|
|
44
50
|
|
|
45
51
|
```bash
|
|
46
|
-
mp token swap
|
|
47
|
-
--
|
|
48
|
-
--
|
|
52
|
+
mp token swap \
|
|
53
|
+
--from-wallet funded --from-chain polygon \
|
|
54
|
+
--from-token 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 \
|
|
55
|
+
--from-amount 5 \
|
|
56
|
+
--to-token 0x0000000000000000000000000000000000000000
|
|
49
57
|
```
|
|
50
58
|
|
|
51
|
-
|
|
59
|
+
## Supported chains
|
|
60
|
+
|
|
61
|
+
solana, ethereum, base, polygon, arbitrum, optimism, bnb, avalanche, bitcoin (bridges only)
|
|
52
62
|
|
|
53
|
-
##
|
|
63
|
+
## How it works
|
|
54
64
|
|
|
55
|
-
1.
|
|
56
|
-
2.
|
|
57
|
-
3.
|
|
58
|
-
4.
|
|
59
|
-
5.
|
|
60
|
-
6.
|
|
61
|
-
7. Return the transaction signature.
|
|
65
|
+
1. Resolves wallet name → address
|
|
66
|
+
2. Builds unsigned transaction via swaps.xyz (handles decimal conversion)
|
|
67
|
+
3. If ERC20 token needs approval, sends an approve transaction first, then re-builds
|
|
68
|
+
4. Signs locally — private key never leaves the machine
|
|
69
|
+
5. Broadcasts to the network
|
|
70
|
+
6. Registers for tracking
|
|
62
71
|
|
|
63
|
-
##
|
|
72
|
+
## Tips
|
|
64
73
|
|
|
65
|
-
- If the user provides token names/symbols, resolve to addresses with `mp token search
|
|
66
|
-
-
|
|
67
|
-
- The
|
|
74
|
+
- If the user provides token names/symbols, resolve to addresses with `mp token search --query "USDC" --chain solana`
|
|
75
|
+
- Check balances first with `mp token balance list --wallet <address> --chain <chain>`
|
|
76
|
+
- For cross-chain bridges, specify `--to-chain`. The tool detects it and routes through a bridge protocol.
|
|
77
|
+
- Native tokens use `0x0000000000000000000000000000000000000000` (EVM) or `So11111111111111111111111111111111111111112` (Solana)
|
|
68
78
|
|
|
69
79
|
## Related skills
|
|
70
80
|
|
|
71
|
-
- **moonpay-discover-tokens** — Search for token addresses
|
|
72
|
-
- **moonpay-check-wallet** — Check balances before swapping
|
|
73
|
-
- **moonpay-auth** — Set up wallets for signing
|
|
81
|
+
- **moonpay-discover-tokens** — Search for token addresses
|
|
82
|
+
- **moonpay-check-wallet** — Check balances before swapping
|
|
83
|
+
- **moonpay-auth** — Set up wallets for signing
|