@quackai/q402-mcp 0.8.18 → 0.8.19
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/README.md +6 -2
- package/dist/index.js +16 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -156,7 +156,7 @@ Then export the values in `~/.zshrc` / `~/.bashrc`. See the [Codex config refere
|
|
|
156
156
|
|
|
157
157
|
## Tools exposed
|
|
158
158
|
|
|
159
|
-
**
|
|
159
|
+
**24 tools** — read-only by default; live mode needs an API key + signing path + `Q402_ENABLE_REAL_PAYMENTS=1`.
|
|
160
160
|
|
|
161
161
|
| Tool | Auth | Purpose |
|
|
162
162
|
|---|---|---|
|
|
@@ -180,8 +180,12 @@ Then export the values in `~/.zshrc` / `~/.bashrc`. See the [Codex config refere
|
|
|
180
180
|
| `q402_bridge_send` | live mode | Execute a CCIP bridge from the user's Agent Wallet. Mode C only (server-managed). Sandbox-by-default; `sandbox: false` + live Multichain key + `Q402_ENABLE_REAL_PAYMENTS=1` fires a real on-chain bridge. |
|
|
181
181
|
| `q402_bridge_history` | not yet wired | Pointer to the dashboard. Returns `{ implemented: false, dashboardUrl, dashboardPath }` — read-only guidance until owner-sig auth lands in MCP. |
|
|
182
182
|
| `q402_bridge_gas_tank` | not yet wired | Static guidance + dashboard pointer for the Bridge Gas Tank top-up flow. Live balance lookup needs owner-sig auth (dashboard for now). |
|
|
183
|
+
| `q402_yield_reserves` | none | List Q402 Yield (Aave V3) lending markets — protocol, chain, asset, market address, supply APY. BNB Chain only today. |
|
|
184
|
+
| `q402_yield_positions` | api key | Show the Agent Wallet's open Q402 Yield positions (balance, principal, accrued interest, APY) + total supplied in USD. Mode C. |
|
|
185
|
+
| `q402_yield_deposit` | live mode | Supply the Agent Wallet's USDC/USDT into Aave V3 (Q402 Yield) to earn supply APY. Mode C, BNB-only. Requires `confirm: true`; sandbox-by-default. |
|
|
186
|
+
| `q402_yield_withdraw` | live mode | Withdraw supplied USDC/USDT out of Aave V3 back to the Agent Wallet (`amount: "max"` = full position). Mode C, BNB-only. Requires `confirm: true`; sandbox-by-default. |
|
|
183
187
|
|
|
184
|
-
`q402_pay` + `q402_batch_pay` + `q402_bridge_send` require explicit in-chat confirmation. Batch confirmation = full batch, not per-row.
|
|
188
|
+
`q402_pay` + `q402_batch_pay` + `q402_bridge_send` + `q402_yield_deposit` + `q402_yield_withdraw` require explicit in-chat confirmation. Batch confirmation = full batch, not per-row.
|
|
185
189
|
|
|
186
190
|
> ℹ️ `q402_pay` expects a 0x address — ENS isn't resolved server-side. Resolve client-side first.
|
|
187
191
|
> Per-chain Gas Tank balances + full TX history live in the [dashboard](https://q402.quackai.ai/dashboard) (wallet-signature only).
|
package/dist/index.js
CHANGED
|
@@ -212,7 +212,7 @@ var isValidPrivateKey = (s) => typeof s === "string" && PRIVATE_KEY_RE.test(s);
|
|
|
212
212
|
// package.json
|
|
213
213
|
var package_default = {
|
|
214
214
|
name: "@quackai/q402-mcp",
|
|
215
|
-
version: "0.8.
|
|
215
|
+
version: "0.8.19",
|
|
216
216
|
description: "MCP server for Q402 \u2014 gasless USDC/USDT/RLUSD payments on 10 EVM chains + Chainlink CCIP USDC bridge on the eth/avax/arbitrum triangle, callable from Claude (Desktop / Code), OpenAI Codex CLI, and any other Model Context Protocol client.",
|
|
217
217
|
mcpName: "io.github.bitgett/q402-mcp",
|
|
218
218
|
keywords: [
|
|
@@ -3480,7 +3480,10 @@ async function runYieldPositions(input) {
|
|
|
3480
3480
|
};
|
|
3481
3481
|
}
|
|
3482
3482
|
const positions = data.positions ?? [];
|
|
3483
|
-
const
|
|
3483
|
+
const unavailableChains = Array.isArray(data.unavailableChains) ? data.unavailableChains : [];
|
|
3484
|
+
const hasUnavailable = data.unavailable === true || unavailableChains.length > 0;
|
|
3485
|
+
const unavailableNote = hasUnavailable ? ` Some chains could not be read this cycle${unavailableChains.length ? ` (${unavailableChains.join(", ")})` : ""} \u2014 this snapshot may be incomplete; retry before treating a balance as zero.` : "";
|
|
3486
|
+
const summary = positions.length ? `Total supplied: $${(data.totalSuppliedUsd ?? 0).toFixed(2)} across ${positions.length} position(s).${unavailableNote}` : hasUnavailable ? `No positions returned, but a read failure occurred${unavailableChains.length ? ` on ${unavailableChains.join(", ")}` : ""} \u2014 this is NOT a confirmed empty position; retry.` : "No open Q402 Yield positions for this wallet.";
|
|
3484
3487
|
return {
|
|
3485
3488
|
content: [
|
|
3486
3489
|
{ type: "text", text: summary },
|
|
@@ -3493,7 +3496,9 @@ async function runYieldPositions(input) {
|
|
|
3493
3496
|
supplyApyPct: Math.round(p.supplyApy * 100 * 100) / 100
|
|
3494
3497
|
})),
|
|
3495
3498
|
totalSuppliedUsd: data.totalSuppliedUsd ?? null,
|
|
3496
|
-
asOf: data.asOf ?? null
|
|
3499
|
+
asOf: data.asOf ?? null,
|
|
3500
|
+
unavailable: hasUnavailable,
|
|
3501
|
+
unavailableChains
|
|
3497
3502
|
}, null, 2)
|
|
3498
3503
|
}
|
|
3499
3504
|
]
|
|
@@ -3501,7 +3506,7 @@ async function runYieldPositions(input) {
|
|
|
3501
3506
|
}
|
|
3502
3507
|
|
|
3503
3508
|
// src/tools/yield-deposit.ts
|
|
3504
|
-
import {
|
|
3509
|
+
import { hexlify as hexlify2, randomBytes as randomBytes2 } from "ethers";
|
|
3505
3510
|
import { z as z16 } from "zod";
|
|
3506
3511
|
var YieldDepositInputSchema = z16.object({
|
|
3507
3512
|
chain: z16.enum(["bnb"]).default("bnb").describe("Chain the Aave market lives on. Q402 Yield is BNB-only today \u2014 only 'bnb' is accepted."),
|
|
@@ -3511,7 +3516,7 @@ var YieldDepositInputSchema = z16.object({
|
|
|
3511
3516
|
"Optional Agent Wallet address to supply from (max 10 per owner). Omit to use Q402_AGENT_WALLET_ADDRESS env, then the owner's default wallet (resolved server-side from the API key)."
|
|
3512
3517
|
),
|
|
3513
3518
|
idempotencyKey: z16.string().optional().describe(
|
|
3514
|
-
"Optional durable idempotency key for this logical deposit. When omitted the tool
|
|
3519
|
+
"Optional durable idempotency key for this logical deposit. When omitted the tool generates a FRESH random key per invocation, so each call executes a distinct deposit (two intentional same-amount deposits both run, and a re-deposit after a withdrawal is NOT replayed). Pass your own STABLE key only when you want retry-safety: re-calling with the same key replays the first result instead of double-supplying."
|
|
3515
3520
|
),
|
|
3516
3521
|
confirm: z16.boolean().optional().describe(
|
|
3517
3522
|
"MUST be true to actually supply funds. Set this only after the user has explicitly approved this exact deposit (amount, token, chain, wallet) in the conversation. When omitted or false the tool previews the action and does NOT move any funds."
|
|
@@ -3543,7 +3548,7 @@ var YIELD_DEPOSIT_TOOL = {
|
|
|
3543
3548
|
},
|
|
3544
3549
|
idempotencyKey: {
|
|
3545
3550
|
type: "string",
|
|
3546
|
-
description: "Optional durable idempotency key. Omit and the tool
|
|
3551
|
+
description: "Optional durable idempotency key. Omit and the tool generates a FRESH random key per invocation, so every call executes a distinct deposit. Pass your own STABLE key only for opt-in retry-safety \u2014 re-calling with the same key replays the first result instead of double-supplying."
|
|
3547
3552
|
},
|
|
3548
3553
|
confirm: {
|
|
3549
3554
|
type: "boolean",
|
|
@@ -3565,7 +3570,7 @@ async function runYieldDeposit(input) {
|
|
|
3565
3570
|
};
|
|
3566
3571
|
}
|
|
3567
3572
|
const walletId = typeof input.walletId === "string" && input.walletId.length > 0 ? input.walletId.toLowerCase() : CONFIG.walletId ?? void 0;
|
|
3568
|
-
const idempotencyKey = typeof input.idempotencyKey === "string" && input.idempotencyKey.length > 0 ? input.idempotencyKey :
|
|
3573
|
+
const idempotencyKey = typeof input.idempotencyKey === "string" && input.idempotencyKey.length > 0 ? input.idempotencyKey : hexlify2(randomBytes2(32));
|
|
3569
3574
|
if (input.confirm !== true) {
|
|
3570
3575
|
const walletDesc = walletId ? `wallet ${walletId}` : "your default Agent Wallet";
|
|
3571
3576
|
return {
|
|
@@ -3651,7 +3656,7 @@ async function runYieldDeposit(input) {
|
|
|
3651
3656
|
}
|
|
3652
3657
|
|
|
3653
3658
|
// src/tools/yield-withdraw.ts
|
|
3654
|
-
import {
|
|
3659
|
+
import { hexlify as hexlify3, randomBytes as randomBytes3 } from "ethers";
|
|
3655
3660
|
import { z as z17 } from "zod";
|
|
3656
3661
|
var YieldWithdrawInputSchema = z17.object({
|
|
3657
3662
|
chain: z17.enum(["bnb"]).default("bnb").describe("Chain the Aave market lives on. Q402 Yield is BNB-only today \u2014 only 'bnb' is accepted."),
|
|
@@ -3661,7 +3666,7 @@ var YieldWithdrawInputSchema = z17.object({
|
|
|
3661
3666
|
"Optional Agent Wallet address to withdraw to (max 10 per owner). Omit to use Q402_AGENT_WALLET_ADDRESS env, then the owner's default wallet (resolved server-side from the API key)."
|
|
3662
3667
|
),
|
|
3663
3668
|
idempotencyKey: z17.string().optional().describe(
|
|
3664
|
-
"Optional durable idempotency key for this logical withdrawal. When omitted the tool
|
|
3669
|
+
"Optional durable idempotency key for this logical withdrawal. When omitted the tool generates a FRESH random key per invocation, so each call executes a distinct withdrawal (a re-deposit followed by another `withdraw max` is NOT replayed). Pass your own STABLE key only when you want retry-safety: re-calling with the same key replays the first result instead of double-withdrawing."
|
|
3665
3670
|
),
|
|
3666
3671
|
confirm: z17.boolean().optional().describe(
|
|
3667
3672
|
"MUST be true to actually withdraw funds. Set this only after the user has explicitly approved this exact withdrawal (amount, token, chain, wallet) in the conversation. When omitted or false the tool previews the action and does NOT move any funds."
|
|
@@ -3693,7 +3698,7 @@ var YIELD_WITHDRAW_TOOL = {
|
|
|
3693
3698
|
},
|
|
3694
3699
|
idempotencyKey: {
|
|
3695
3700
|
type: "string",
|
|
3696
|
-
description: "Optional durable idempotency key. Omit and the tool
|
|
3701
|
+
description: "Optional durable idempotency key. Omit and the tool generates a FRESH random key per invocation, so every call executes a distinct withdrawal. Pass your own STABLE key only for opt-in retry-safety \u2014 re-calling with the same key replays the first result instead of double-withdrawing."
|
|
3697
3702
|
},
|
|
3698
3703
|
confirm: {
|
|
3699
3704
|
type: "boolean",
|
|
@@ -3715,7 +3720,7 @@ async function runYieldWithdraw(input) {
|
|
|
3715
3720
|
};
|
|
3716
3721
|
}
|
|
3717
3722
|
const walletId = typeof input.walletId === "string" && input.walletId.length > 0 ? input.walletId.toLowerCase() : CONFIG.walletId ?? void 0;
|
|
3718
|
-
const idempotencyKey = typeof input.idempotencyKey === "string" && input.idempotencyKey.length > 0 ? input.idempotencyKey :
|
|
3723
|
+
const idempotencyKey = typeof input.idempotencyKey === "string" && input.idempotencyKey.length > 0 ? input.idempotencyKey : hexlify3(randomBytes3(32));
|
|
3719
3724
|
const amountDesc = input.amount === "max" ? "the FULL position" : `${input.amount} ${input.token}`;
|
|
3720
3725
|
if (input.confirm !== true) {
|
|
3721
3726
|
const walletDesc = walletId ? `wallet ${walletId}` : "your default Agent Wallet";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quackai/q402-mcp",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.19",
|
|
4
4
|
"description": "MCP server for Q402 — gasless USDC/USDT/RLUSD payments on 10 EVM chains + Chainlink CCIP USDC bridge on the eth/avax/arbitrum triangle, callable from Claude (Desktop / Code), OpenAI Codex CLI, and any other Model Context Protocol client.",
|
|
5
5
|
"mcpName": "io.github.bitgett/q402-mcp",
|
|
6
6
|
"keywords": [
|