shinjuku-shielded 0.3.14 → 0.3.16
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/manifest.json +3 -3
- package/package.json +3 -3
- package/shinjuku-wallet.mjs +84 -42
package/manifest.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "carbon-shielded-wallet/bundle-manifest/v1",
|
|
3
3
|
"file": "shinjuku-wallet.mjs",
|
|
4
|
-
"sha256": "
|
|
5
|
-
"bytes":
|
|
6
|
-
"sourceCommit": "
|
|
4
|
+
"sha256": "b32bffc727e1e7e33fb134a3918638006259033511e1a2aaf455d037da1f70b3",
|
|
5
|
+
"bytes": 11124201,
|
|
6
|
+
"sourceCommit": "4b3c69bd892409a11b931e3a01f254a8b2f4af0f",
|
|
7
7
|
"sourceDirty": false,
|
|
8
8
|
"installRecordMatchesLockfile": true,
|
|
9
9
|
"releaseRule": "valid only when two fresh npm ci --ignore-scripts builds on different OSes give the same sha256; installRecordMatchesLockfile true means every entry npm installed equals its package-lock.json entry and every entry not marked optional, devOptional included, is installed: an optional entry (a package for another platform) may be absent",
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shinjuku-shielded",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.16",
|
|
4
4
|
"mcpName": "io.github.ShinjukuStaition/shinjuku-mcp",
|
|
5
5
|
"description": "Shinjuku Shielded, the private x402 facilitator on Solana: the self-custody wallet CLI and its MCP server. Shield, pay, and unshield USDC from any MCP agent, under caps you set.",
|
|
6
|
-
"shinjukuRelease": "
|
|
7
|
-
"shinjukuSha256": "
|
|
6
|
+
"shinjukuRelease": "b32bffc7",
|
|
7
|
+
"shinjukuSha256": "b32bffc727e1e7e33fb134a3918638006259033511e1a2aaf455d037da1f70b3",
|
|
8
8
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
9
9
|
"author": "Shinjuku Shielded",
|
|
10
10
|
"homepage": "https://github.com/ShinjukuStaition/shinjuku-mcp#readme",
|
package/shinjuku-wallet.mjs
CHANGED
|
@@ -58607,9 +58607,6 @@ async function prepareRelayedDepositLeased({ store, connection, programId, proof
|
|
|
58607
58607
|
const minimum = closing ? config.closingSourceMinimumAtomic : pocketIndex !== void 0 && config.pocketMinimumAtomic !== void 0 ? config.pocketMinimumAtomic : config.minimumAtomic;
|
|
58608
58608
|
if (legacySource && amount < minimum) throw legacyBelowMinimum(legacySource, amount, minimum);
|
|
58609
58609
|
if (amount < minimum) fail11(pocketIndex !== void 0 && config.pocketMinimumAtomic === void 0 ? "relay_pocket_reshield_not_offered" : "relay_amount_below_facilitator_minimum");
|
|
58610
|
-
if (!record && pocketIndex === void 0 && !legacySource && config.depositUnitAtomic !== void 0 && amount % config.depositUnitAtomic !== 0n) {
|
|
58611
|
-
fail11("relay_amount_not_whole_unit");
|
|
58612
|
-
}
|
|
58613
58610
|
const pool = await poolState(connection, id);
|
|
58614
58611
|
if (amount > pool.maxDepositValue) fail11("amount_above_pool_deposit_cap");
|
|
58615
58612
|
if (BigInt(pool.depositCount) >= BigInt(pool.maxDeposits)) fail11("pool_at_deposit_cap");
|
|
@@ -58713,7 +58710,6 @@ async function readRelayConfig({ serviceUrl: serviceUrl2, fetchImpl, id }) {
|
|
|
58713
58710
|
minimumAtomic: BigInt(config.minimumAtomic),
|
|
58714
58711
|
closesSource: config.sourceCloseAuthority !== void 0,
|
|
58715
58712
|
...config.pocketMinimumAtomic === void 0 ? {} : { pocketMinimumAtomic: BigInt(config.pocketMinimumAtomic) },
|
|
58716
|
-
...config.depositUnitAtomic === void 0 ? {} : { depositUnitAtomic: BigInt(config.depositUnitAtomic) },
|
|
58717
58713
|
...config.closingSourceMinimumAtomic === void 0 ? {} : { closingSourceMinimumAtomic: BigInt(config.closingSourceMinimumAtomic) }
|
|
58718
58714
|
};
|
|
58719
58715
|
}
|
|
@@ -61876,6 +61872,8 @@ var init_errorCodes = __esm({
|
|
|
61876
61872
|
"mcp_unshield_to_not_allowed",
|
|
61877
61873
|
"mcp_unshield_to_invalid",
|
|
61878
61874
|
"mcp_shield_cap_exceeded",
|
|
61875
|
+
"mcp_shield_above_balance_cap",
|
|
61876
|
+
"mcp_balance_unknown",
|
|
61879
61877
|
"mcp_unshield_cap_exceeded",
|
|
61880
61878
|
"mcp_request_id_reused",
|
|
61881
61879
|
"mcp_shield_failed",
|
|
@@ -62362,6 +62360,7 @@ var init_errorCodes = __esm({
|
|
|
62362
62360
|
"float_not_ready",
|
|
62363
62361
|
"float_seller_uses_our_facilitator",
|
|
62364
62362
|
"float_payment_in_flight",
|
|
62363
|
+
"float_quote_open",
|
|
62365
62364
|
"float_already_paid",
|
|
62366
62365
|
"float_paid",
|
|
62367
62366
|
"p03_payer_float_wallet_pool_mismatch",
|
|
@@ -90984,9 +90983,9 @@ async function payViaFloat({
|
|
|
90984
90983
|
});
|
|
90985
90984
|
} catch (error) {
|
|
90986
90985
|
if (seen.refusal) {
|
|
90987
|
-
if (seen.refusal.code
|
|
90986
|
+
if (REGENERATE_CODES.has(seen.refusal.code) && !regenerated && innerUnsent()) {
|
|
90988
90987
|
regenerated = true;
|
|
90989
|
-
const refundTo = await ownRefundAddress(store, connection);
|
|
90988
|
+
const refundTo = await (deps.ownRefundAddress ?? ownRefundAddress)(store, connection);
|
|
90990
90989
|
const body = canonicalBody({ requestId, resourceUrl: record.url, requirement: record.requirement, refundTo });
|
|
90991
90990
|
record = { ...record, floatId: body.floatId, bodyBase64: body.bodyBase64, refundTo };
|
|
90992
90991
|
store.writeWal(walName2, record);
|
|
@@ -91090,7 +91089,7 @@ function paidResult(record, replayed) {
|
|
|
91090
91089
|
float: { floatId: record.floatId }
|
|
91091
91090
|
};
|
|
91092
91091
|
}
|
|
91093
|
-
var import_web3109, FLOAT_PAYMENT_SCHEMA, FLOAT_PAYMENT_WAL_PREFIX, FLOAT_CONFIG_SCHEMA, FLOAT_PAY_PATH, MAX_BODY_BYTES, FLOAT_REFUND_ETA_SECONDS, REFUND_SETTLED_AFTER_MS, FINISHING_POLL_MS, FINISHING_LIMIT_MS, SELLER_TIMEOUT_MS, CONFIG_TIMEOUT_MS, DECIMAL3, POSITIVE, PENDING_CODES, hash9, fail18, floatPaymentWalName, plainText;
|
|
91092
|
+
var import_web3109, FLOAT_PAYMENT_SCHEMA, REGENERATE_CODES, FLOAT_PAYMENT_WAL_PREFIX, FLOAT_CONFIG_SCHEMA, FLOAT_PAY_PATH, MAX_BODY_BYTES, FLOAT_REFUND_ETA_SECONDS, REFUND_SETTLED_AFTER_MS, FINISHING_POLL_MS, FINISHING_LIMIT_MS, SELLER_TIMEOUT_MS, CONFIG_TIMEOUT_MS, DECIMAL3, POSITIVE, PENDING_CODES, hash9, fail18, floatPaymentWalName, plainText;
|
|
91094
91093
|
var init_floatPay = __esm({
|
|
91095
91094
|
"wallet/src/pay/floatPay.mjs"() {
|
|
91096
91095
|
"use strict";
|
|
@@ -91107,6 +91106,7 @@ var init_floatPay = __esm({
|
|
|
91107
91106
|
init_proxy();
|
|
91108
91107
|
init_payResource();
|
|
91109
91108
|
FLOAT_PAYMENT_SCHEMA = "carbon-shielded-wallet/float-payment/v1";
|
|
91109
|
+
REGENERATE_CODES = /* @__PURE__ */ new Set(["float_payment_in_flight", "float_quote_open"]);
|
|
91110
91110
|
FLOAT_PAYMENT_WAL_PREFIX = "float-";
|
|
91111
91111
|
FLOAT_CONFIG_SCHEMA = "carbon-shielded-x402/float-config/v1";
|
|
91112
91112
|
FLOAT_PAY_PATH = "/api/x402/float/pay/";
|
|
@@ -118735,6 +118735,8 @@ function snapshotFromRecovery({ state, programId, recovery, history, walStates,
|
|
|
118735
118735
|
});
|
|
118736
118736
|
const slot3 = history?.finalizedPoolSnapshot?.slot;
|
|
118737
118737
|
if (slot3 === void 0 || !canonicalAtomic(String(slot3))) throw new Error("balance_snapshot_slot_invalid");
|
|
118738
|
+
const anchorIndexes = Array.isArray(history?.finalizedPoolSnapshot?.anchors) ? history.finalizedPoolSnapshot.anchors.map((anchor) => BigInt(anchor.index)) : [];
|
|
118739
|
+
const anchorIndex = anchorIndexes.length ? anchorIndexes.reduce((a, b) => b > a ? b : a).toString() : void 0;
|
|
118738
118740
|
return {
|
|
118739
118741
|
schema: BALANCE_SNAPSHOT_SCHEMA,
|
|
118740
118742
|
pool: state.pool,
|
|
@@ -118742,6 +118744,7 @@ function snapshotFromRecovery({ state, programId, recovery, history, walStates,
|
|
|
118742
118744
|
refreshedAt: new Date(now).toISOString(),
|
|
118743
118745
|
slot: String(slot3),
|
|
118744
118746
|
poolIndex: String(recovery.poolIndex),
|
|
118747
|
+
...anchorIndex === void 0 ? {} : { anchorIndex },
|
|
118745
118748
|
fresh: fresh === true,
|
|
118746
118749
|
walStates: { ...walStates },
|
|
118747
118750
|
outputs
|
|
@@ -119021,7 +119024,8 @@ function computeBalance({ store, snapshotRead, source = "local", now = Date.now(
|
|
|
119021
119024
|
const reservedAtomic = unknownInputs ? unspentAtomic : sum2([...reserved].filter((commitment) => unspent.has(commitment)).map((commitment) => unspent.get(commitment).valueAtomic));
|
|
119022
119025
|
detail.reservedAtomic = reservedAtomic.toString();
|
|
119023
119026
|
const spendable = unspentAtomic - reservedAtomic;
|
|
119024
|
-
|
|
119027
|
+
const anchorIndex = canonicalAtomic(snapshot.anchorIndex) ? BigInt(snapshot.anchorIndex) : void 0;
|
|
119028
|
+
detail.fundedAccounts = unknownInputs ? 0 : [...unspent.values()].filter((output2) => output2.kind === "account" && BigInt(output2.valueAtomic) > 0n && !reserved.has(output2.commitment) && (anchorIndex === void 0 || BigInt(output2.leafIndex) < anchorIndex)).length;
|
|
119025
119029
|
const next = detail.inFlight.length ? "finish or cancel the work in detail.inFlight; the wallet runs one payment at a time" : pendingDeposits.length ? `deposit ${pendingDeposits[0].depositId} is not finished: rerun the same deposit command with --submit --service <facilitator URL>` : pocketsUnscanned ? scanPockets2 : unspentAtomic === 0n && successionMovableAtomic > 0n ? "this pool was succeeded by a new pool: its value moves there (a move per account, the facilitator pays the fee) and counts in this balance until then" : unspentAtomic === 0n ? "nothing to spend: deposit (shinjuku-wallet help deposit), or run balance --refresh if a payment to this wallet settled" : void 0;
|
|
119026
119030
|
return report("current", spendable + successionMovableAtomic, next);
|
|
119027
119031
|
}
|
|
@@ -124142,6 +124146,7 @@ function writeCache(key, record, ctx) {
|
|
|
124142
124146
|
// wallet/src/mcp/tools.mjs
|
|
124143
124147
|
init_pool_denomination();
|
|
124144
124148
|
init_serviceUrl();
|
|
124149
|
+
init_anchorClock();
|
|
124145
124150
|
var shownCaps = (caps) => Object.fromEntries(Object.entries(caps).map(([name, value]) => [name, String(value) === NO_LIMIT_ATOMIC2 ? "none" : value]));
|
|
124146
124151
|
var RESOURCE_PAYMENT_WAL_PREFIX2 = "resource-payment-";
|
|
124147
124152
|
var SELF_PAY_ORIGIN3 = "https://self-pay.invalid/";
|
|
@@ -124406,7 +124411,7 @@ async function readOwnPublicBalance({ session, store }) {
|
|
|
124406
124411
|
solLamports: String(solAccount?.lamports ?? 0)
|
|
124407
124412
|
};
|
|
124408
124413
|
}
|
|
124409
|
-
async function runShield({ session, depositId, amountAtomic,
|
|
124414
|
+
async function runShield({ session, depositId, amountAtomic, onStage, steps = {} }) {
|
|
124410
124415
|
const store = session.openStore();
|
|
124411
124416
|
const existing = store.readWal(`deposit-${depositId}`);
|
|
124412
124417
|
if (existing && !existing.relay) return runSelfBroadcastShield({ session, depositId, onStage });
|
|
@@ -124424,9 +124429,8 @@ async function runShield({ session, depositId, amountAtomic, unitAtomic, onStage
|
|
|
124424
124429
|
...common,
|
|
124425
124430
|
amountAtomic,
|
|
124426
124431
|
ownKey: true,
|
|
124427
|
-
// The CLI deposit's own admission check (shielded-wallet.mjs runSelfCustodyDeposit)
|
|
124432
|
+
// The CLI deposit's own admission check (shielded-wallet.mjs runSelfCustodyDeposit); any amount (no deposit unit).
|
|
124428
124433
|
checkAmount: ({ amount, pool, sourceAmount, vaultAmount }) => resolveAgentDepositAmount({
|
|
124429
|
-
denominationAtomic: unitAtomic,
|
|
124430
124434
|
requestedAtomic: amount,
|
|
124431
124435
|
walletBalanceAtomic: sourceAmount,
|
|
124432
124436
|
maxDepositValueAtomic: pool.maxDepositValue,
|
|
@@ -124469,7 +124473,7 @@ var usdcText = (atomic3, decimals = 6) => {
|
|
|
124469
124473
|
const text3 = formatAtomic(BigInt(atomic3), decimals);
|
|
124470
124474
|
return text3.includes(".") ? text3.replace(/0+$/, "").replace(/\.$/, "") : text3;
|
|
124471
124475
|
};
|
|
124472
|
-
async function runShieldFromElsewhere({ session, depositId, amountAtomic,
|
|
124476
|
+
async function runShieldFromElsewhere({ session, depositId, amountAtomic, onStage, steps = {} }) {
|
|
124473
124477
|
const store = session.openStore();
|
|
124474
124478
|
const common = {
|
|
124475
124479
|
store,
|
|
@@ -124486,9 +124490,8 @@ async function runShieldFromElsewhere({ session, depositId, amountAtomic, unitAt
|
|
|
124486
124490
|
await (steps.prepare ?? prepareRelayedDeposit)({
|
|
124487
124491
|
...common,
|
|
124488
124492
|
amountAtomic,
|
|
124489
|
-
// The CLI deposit --relay admission check
|
|
124493
|
+
// The CLI deposit --relay admission check (any amount, no deposit unit); the source is the one-time address.
|
|
124490
124494
|
checkAmount: ({ amount, pool, sourceAmount, vaultAmount }) => resolveAgentDepositAmount({
|
|
124491
|
-
denominationAtomic: unitAtomic,
|
|
124492
124495
|
requestedAtomic: amount,
|
|
124493
124496
|
walletBalanceAtomic: sourceAmount,
|
|
124494
124497
|
maxDepositValueAtomic: pool.maxDepositValue,
|
|
@@ -124716,10 +124719,13 @@ function localBalance(session) {
|
|
|
124716
124719
|
return null;
|
|
124717
124720
|
}
|
|
124718
124721
|
}
|
|
124722
|
+
var CAP_BALANCE_WAIT_MS = 35e3;
|
|
124723
|
+
var CAP_BALANCE_RETRY_MS = 5e3;
|
|
124719
124724
|
var REFRESH_RETRY_MS = 6e4;
|
|
124720
124725
|
var SWITCH_WAIT_MS = 4e4;
|
|
124721
124726
|
var ELICIT_TIMEOUT_MS = 5 * 6e4;
|
|
124722
124727
|
var POLL_SECONDS2 = 30;
|
|
124728
|
+
var MAX_SHIELDED_BALANCE_ATOMIC = 5000000n;
|
|
124723
124729
|
function createWalletTools({
|
|
124724
124730
|
session,
|
|
124725
124731
|
policy,
|
|
@@ -124731,7 +124737,9 @@ function createWalletTools({
|
|
|
124731
124737
|
client,
|
|
124732
124738
|
exportBackup,
|
|
124733
124739
|
balanceRefreshWaitMs = BALANCE_REFRESH_WAIT_MS,
|
|
124734
|
-
elicitTimeoutMs = ELICIT_TIMEOUT_MS
|
|
124740
|
+
elicitTimeoutMs = ELICIT_TIMEOUT_MS,
|
|
124741
|
+
capBalanceWaitMs = CAP_BALANCE_WAIT_MS,
|
|
124742
|
+
capBalanceRetryMs = CAP_BALANCE_RETRY_MS
|
|
124735
124743
|
}) {
|
|
124736
124744
|
const outDir = join26(dirname23(session.walletPath), "mcp-out");
|
|
124737
124745
|
const knownIds = /* @__PURE__ */ new Map();
|
|
@@ -125565,6 +125573,19 @@ function createWalletTools({
|
|
|
125565
125573
|
const again = (kind, job) => `call ${KINDS[kind].tool} again with request_id "${job.requestId}", amount_atomic "${job.amountAtomic}"${job.to ? `, and to "${job.to}"` : ""}`;
|
|
125566
125574
|
const unboundNext = (requestId, amountAtomic) => `Nothing was signed. Do not retry this request_id. Tell your owner: the self-payment of this unshield has no recipient bound to it, so this server will not choose one. The owner finishes it with the CLI: shinjuku-wallet unshield (the same --wallet, proof tools, --profile, --program, --facilitator) --unshield-id ${moneyId(requestId)} --amount ${amountAtomic} --to <recipient USDC account> --recipient-owner <recipient owner>`;
|
|
125567
125575
|
const preApproved = () => [...new Set(unshieldTo)];
|
|
125576
|
+
async function anchorWaitAfterDeposit() {
|
|
125577
|
+
try {
|
|
125578
|
+
const read = await underLease((store) => readBalanceSnapshot(store));
|
|
125579
|
+
const anchorIndex = read.snapshot?.anchorIndex;
|
|
125580
|
+
if (anchorIndex === void 0) return {};
|
|
125581
|
+
const waiting = read.snapshot.outputs.some((output2) => output2.kind === "account" && output2.spendStatus === "unspent" && BigInt(output2.leafIndex) >= BigInt(anchorIndex));
|
|
125582
|
+
if (!waiting) return {};
|
|
125583
|
+
noteAnchorOrigin(session.memoServiceUrl);
|
|
125584
|
+
return { spendableAtMs: Date.now() + nextAnchorWaitMs(Date.now(), 0) };
|
|
125585
|
+
} catch {
|
|
125586
|
+
return {};
|
|
125587
|
+
}
|
|
125588
|
+
}
|
|
125568
125589
|
function doneNext(kind, job) {
|
|
125569
125590
|
if (kind === "unshield") {
|
|
125570
125591
|
return `the USDC was sent to ${job.to}; tell the user (exitTransaction). wallet_balance shows the new shielded balance${job.result?.backupPath ? `. An encrypted backup of the wallet was saved at ${job.result.backupPath}` : ""}`;
|
|
@@ -125574,6 +125595,9 @@ function createWalletTools({
|
|
|
125574
125595
|
return `the deposit landed. The wallet now reads it from the chain so it becomes spendable: call wallet_balance in ${POLL_SECONDS2} s (x402_pay and wallet_unshield also wait for it by themselves)`;
|
|
125575
125596
|
}
|
|
125576
125597
|
if (!post.refreshed) return `the deposit landed; reading it from the chain failed (${post.refreshError}): call wallet_balance in a minute, it retries by itself`;
|
|
125598
|
+
if (post.spendableAtMs !== void 0 && post.spendableAtMs > Date.now()) {
|
|
125599
|
+
return `the deposit landed and is in the shielded balance. It is spendable after the next pool anchor, in about ${Math.ceil((post.spendableAtMs - Date.now()) / 1e3)} s: x402_pay and wallet_unshield wait for it by themselves, so call them now if the user wants to${post.backupPath ? `. An encrypted backup of the wallet was saved at ${post.backupPath}` : ""}`;
|
|
125600
|
+
}
|
|
125577
125601
|
return `the deposit landed and is in the shielded balance: x402_pay and wallet_unshield can spend it now${post.backupPath ? `. An encrypted backup of the wallet was saved at ${post.backupPath}` : ""}`;
|
|
125578
125602
|
}
|
|
125579
125603
|
const ELSEWHERE_PRIVACY = "the chain shows the other wallet paying this new one-time address, and that address depositing this amount into the pool (both public; the facilitator also sees the amount and time). Later payments from the shielded balance do not show which deposit paid them. With few depositors in the pool, an amount few other deposits share, or a payment soon after the deposit, is easier to pair";
|
|
@@ -125691,8 +125715,6 @@ function createWalletTools({
|
|
|
125691
125715
|
else if (/another_deposit_unresolved/.test(code)) {
|
|
125692
125716
|
const waiting = waitingElsewhereIds();
|
|
125693
125717
|
next = waiting.length > 0 ? `Nothing new was moved. A wallet_shield_from_elsewhere address of this wallet still waits for its USDC (request_id ${waiting.map((id) => `"${id}"`).join(", ")}), and the wallet runs one deposit at a time. Either fund it and call wallet_shield_from_elsewhere again with that request_id until it is done, or, if nothing was sent to it, close it: call wallet_shield_from_elsewhere with action "cancel" and request_id "${waiting[0]}" (it refuses when any USDC or any transaction already reached the address; then only the owner's CLI deposit-reclaim frees it). Then call this one again` : `Nothing new was moved. Another deposit of this wallet is not finished (a wallet_shield, or a wallet_shield_from_elsewhere): call that tool again with its request_id until it is done, then call this one again. If no tool knows it, tell your owner: ${code} (the CLI's deposit records show which one)`;
|
|
125694
|
-
} else if (/relay_amount_not_whole_unit/.test(code)) {
|
|
125695
|
-
next = `Nothing was moved and no address was made. This pool takes deposits in whole units of its pocket size (the facilitator's /api/x402/deposit shows depositUnitAtomic): call ${KINDS[kind].tool} with a NEW request_id and amount_atomic a whole multiple of it`;
|
|
125696
125718
|
} else if (kind === "shield" && /relay_amount_below_facilitator_minimum/.test(code)) {
|
|
125697
125719
|
next = "Nothing was moved. The facilitator does not relay a deposit this small: call wallet_shield with a NEW request_id and a larger amount_atomic";
|
|
125698
125720
|
} else if (kind === "shield" && /relay_not_offered|relay_config_mismatch|relay_config_invalid|relay_service_required|proof_tools_missing/.test(code)) {
|
|
@@ -125730,13 +125752,6 @@ function createWalletTools({
|
|
|
125730
125752
|
if (typeof amount !== "string" || !POSITIVE_ATOMIC4.test(amount)) {
|
|
125731
125753
|
return { refusal: ["mcp_argument_invalid", "amount_atomic must be a positive whole number of atomic units (USDC: 1000000 = 1 USDC)", 'pass amount_atomic as a string, like "1000000"'] };
|
|
125732
125754
|
}
|
|
125733
|
-
if (kind !== "unshield" && money.depositUnitAtomic && BigInt(amount) % BigInt(money.depositUnitAtomic) !== 0n) {
|
|
125734
|
-
return { refusal: [
|
|
125735
|
-
"mcp_argument_invalid",
|
|
125736
|
-
`amount_atomic must be a whole multiple of ${money.depositUnitAtomic} on this pool (whole deposit units); nothing was moved`,
|
|
125737
|
-
`pass a multiple of ${money.depositUnitAtomic}, like ${money.depositUnitAtomic}`
|
|
125738
|
-
] };
|
|
125739
|
-
}
|
|
125740
125755
|
if (kind === "unshield") {
|
|
125741
125756
|
let canonical5 = false;
|
|
125742
125757
|
try {
|
|
@@ -125902,6 +125917,41 @@ function createWalletTools({
|
|
|
125902
125917
|
const detail = `this MCP session already moved ${total} of its ${spec.capFlag} ${max}; ${amount} more is above it`;
|
|
125903
125918
|
return refuse9(spec.capCode, `${detail}; nothing ${record ? "more " : ""}was moved`, ownerNext(detail), { requestId: request.requestId });
|
|
125904
125919
|
}
|
|
125920
|
+
if (kind !== "unshield" && !record) {
|
|
125921
|
+
let stale;
|
|
125922
|
+
try {
|
|
125923
|
+
stale = shieldedUnknown(session.openStore());
|
|
125924
|
+
} catch {
|
|
125925
|
+
stale = true;
|
|
125926
|
+
}
|
|
125927
|
+
let one = stale ? null : localBalance(session);
|
|
125928
|
+
const unknown = () => one?.balanceAtomic === null || one?.balanceAtomic === void 0;
|
|
125929
|
+
for (const deadline = Date.now() + capBalanceWaitMs; unknown(); ) {
|
|
125930
|
+
await refreshShared().catch(() => {
|
|
125931
|
+
});
|
|
125932
|
+
one = localBalance(session);
|
|
125933
|
+
if (!unknown() || Date.now() + capBalanceRetryMs > deadline) break;
|
|
125934
|
+
await new Promise((resolve36) => setTimeout(resolve36, capBalanceRetryMs));
|
|
125935
|
+
}
|
|
125936
|
+
if (unknown()) {
|
|
125937
|
+
return refuse9(
|
|
125938
|
+
"mcp_balance_unknown",
|
|
125939
|
+
`the shielded balance could not be read just now (a payment from moments ago is not final yet, the chain read failed, or another wallet command holds this wallet), so the wallet cannot check the ${usdcText(MAX_SHIELDED_BALANCE_ATOMIC)} USDC balance cap; nothing was moved`,
|
|
125940
|
+
`call ${spec.tool} again with the same request_id and amount_atomic in ${POLL_SECONDS2} s`,
|
|
125941
|
+
{ requestId: request.requestId }
|
|
125942
|
+
);
|
|
125943
|
+
}
|
|
125944
|
+
const room = MAX_SHIELDED_BALANCE_ATOMIC - BigInt(one.balanceAtomic);
|
|
125945
|
+
if (BigInt(request.amountAtomic) > room) {
|
|
125946
|
+
const left = room > 0n ? room : 0n;
|
|
125947
|
+
return refuse9(
|
|
125948
|
+
"mcp_shield_above_balance_cap",
|
|
125949
|
+
`the shielded balance may hold at most ${usdcText(MAX_SHIELDED_BALANCE_ATOMIC)} USDC; it holds ${usdcText(one.balanceAtomic)} USDC, so at most ${usdcText(left)} USDC more can be shielded now; nothing was moved`,
|
|
125950
|
+
left > 0n ? `Tell the user the cap. Call ${spec.tool} with a NEW request_id and amount_atomic at most "${left}"` : "Tell the user the shielded balance is at its cap: spend some with x402_pay, or send some out with wallet_unshield, before shielding more",
|
|
125951
|
+
{ requestId: request.requestId, balanceAtomic: one.balanceAtomic, maxBalanceAtomic: MAX_SHIELDED_BALANCE_ATOMIC.toString(), roomAtomic: left.toString() }
|
|
125952
|
+
);
|
|
125953
|
+
}
|
|
125954
|
+
}
|
|
125905
125955
|
if (!deferCount) {
|
|
125906
125956
|
moved[spec.counter] += amount;
|
|
125907
125957
|
counted.set(key, amount);
|
|
@@ -126007,7 +126057,6 @@ function createWalletTools({
|
|
|
126007
126057
|
session,
|
|
126008
126058
|
depositId: moneyId(job.requestId),
|
|
126009
126059
|
amountAtomic: job.amountAtomic,
|
|
126010
|
-
unitAtomic: money.depositUnitAtomic,
|
|
126011
126060
|
onStage,
|
|
126012
126061
|
steps: { prepare: ops.prepareOwnRelayed, submit: ops.submitOwnRelayed }
|
|
126013
126062
|
});
|
|
@@ -126017,14 +126066,16 @@ function createWalletTools({
|
|
|
126017
126066
|
session,
|
|
126018
126067
|
depositId: elsewhereId(job.requestId),
|
|
126019
126068
|
amountAtomic: job.amountAtomic,
|
|
126020
|
-
unitAtomic: money.depositUnitAtomic,
|
|
126021
126069
|
onStage,
|
|
126022
126070
|
steps: { prepare: ops.prepareRelayed, submit: ops.submitRelayed }
|
|
126023
126071
|
});
|
|
126024
126072
|
}
|
|
126025
126073
|
function afterShield(job) {
|
|
126026
126074
|
job.post = { state: "running" };
|
|
126027
|
-
job.postPromise = refreshShared().then(
|
|
126075
|
+
job.postPromise = refreshShared().then(
|
|
126076
|
+
() => anchorWaitAfterDeposit().then((wait2) => ({ refreshed: true, ...wait2 })),
|
|
126077
|
+
(error) => ({ refreshed: false, refreshError: errorCode2(error, "mcp_refresh_failed") })
|
|
126078
|
+
).then((refresh) => underLease((store) => backupNow(store)).catch((error) => typeof exportBackup === "function" ? { backupPath: null, backupError: errorCode2(error, "wallet_locked") } : {}).then((backup) => {
|
|
126028
126079
|
job.post = { state: "done", ...refresh, ...backup };
|
|
126029
126080
|
})).finally(() => {
|
|
126030
126081
|
if (money.autoPockets === true) autoPockets.onShielded();
|
|
@@ -126158,11 +126209,11 @@ function createWalletTools({
|
|
|
126158
126209
|
const shield = {
|
|
126159
126210
|
name: "wallet_shield",
|
|
126160
126211
|
title: "Shield USDC (make it private)",
|
|
126161
|
-
description: `Use this when the user says "shield 5 USDC", "make my USDC private", or "add funds to my shielded balance": it moves amount_atomic of the plain public USDC on this wallet's own Solana key (wallet_balance unshieldedAtomic) into the SHIELDED balance, which x402_pay and wallet_unshield spend. The USDC stays the user's. Cost: no SOL. The wallet's key only signs an approval of the amount; the facilitator's relayer submits the deposit and pays every network fee and rent.
|
|
126212
|
+
description: `Use this when the user says "shield 5 USDC", "make my USDC private", or "add funds to my shielded balance": it moves amount_atomic of the plain public USDC on this wallet's own Solana key (wallet_balance unshieldedAtomic) into the SHIELDED balance, which x402_pay and wallet_unshield spend. The USDC stays the user's. Cost: no SOL. The wallet's key only signs an approval of the amount; the facilitator's relayer submits the deposit and pays every network fee and rent. Any amount from 0.01 USDC (amount_atomic 10000; the facilitator's minimum) works, cents included, while the shielded balance stays at most 5 USDC (mcp_shield_above_balance_cap says how much more fits). Privacy: the chain shows this key depositing this amount; later payments from the shielded balance do not show this wallet. It takes a few minutes: the first call starts it and answers stage (proving, submitting, done); call wallet_shield again with the SAME request_id and amount_atomic in ${POLL_SECONDS2} s for the status. When the deposit lands, the wallet reads it from the chain by itself (refreshing: true until it is spendable) and writes an encrypted backup (backupPath). The same request_id never deposits twice, also after a restart. One deposit at a time. An optional owner cap (--max-shield) may bound each call and this session (mcp_shield_cap_exceeded: tell the owner). Refusals: mcp_argument_invalid, mcp_request_id_reused, wallet_locked, mcp_tool_disabled, mcp_shield_failed, and the deposit's own p03_deposit_* codes.`,
|
|
126162
126213
|
inputSchema: {
|
|
126163
126214
|
type: "object",
|
|
126164
126215
|
properties: {
|
|
126165
|
-
amount_atomic: { type: "string", pattern: "^[1-9][0-9]*$", description: "USDC to shield, in atomic units (1000000 = 1 USDC
|
|
126216
|
+
amount_atomic: { type: "string", pattern: "^[1-9][0-9]*$", description: "USDC to shield, in atomic units (1000000 = 1 USDC, 370000 = 0.37 USDC): any amount from 10000 (0.01 USDC) while the balance stays at most 5 USDC." },
|
|
126166
126217
|
request_id: { type: "string", pattern: "^[A-Za-z0-9_-]{1,44}$", description: "Your stable name for this deposit, like shield-1; pass it again to read the status." }
|
|
126167
126218
|
},
|
|
126168
126219
|
required: ["amount_atomic", "request_id"],
|
|
@@ -126195,7 +126246,7 @@ function createWalletTools({
|
|
|
126195
126246
|
inputSchema: {
|
|
126196
126247
|
type: "object",
|
|
126197
126248
|
properties: {
|
|
126198
|
-
amount_atomic: { type: "string", pattern: "^[1-9][0-9]*$", description: "USDC to shield, in atomic units (1000000 = 1 USDC
|
|
126249
|
+
amount_atomic: { type: "string", pattern: "^[1-9][0-9]*$", description: "USDC to shield, in atomic units (1000000 = 1 USDC, 370000 = 0.37 USDC): any amount from 10000 (0.01 USDC) while the balance stays at most 5 USDC. Required unless action is cancel." },
|
|
126199
126250
|
request_id: { type: "string", pattern: "^[A-Za-z0-9_-]{1,44}$", description: "Your stable name for this deposit, like from-phantom-1; pass it again (with the same amount_atomic) to read the status." },
|
|
126200
126251
|
action: { type: "string", enum: ["deposit", "cancel"], description: "deposit (the default): start or read this deposit. cancel: close this request's one-time address while nothing at all reached it (no amount_atomic needed)." }
|
|
126201
126252
|
},
|
|
@@ -126772,8 +126823,7 @@ function moneyOptions({
|
|
|
126772
126823
|
exitProofToolsPath,
|
|
126773
126824
|
profilePath,
|
|
126774
126825
|
proofToolsPath,
|
|
126775
|
-
memoServiceUrl
|
|
126776
|
-
depositUnitAtomic
|
|
126826
|
+
memoServiceUrl
|
|
126777
126827
|
}, asText = (value) => value === void 0 || value === null ? "" : String(value)) {
|
|
126778
126828
|
if (noShield === true && allowShield === true) setupInvalid("--no-shield and --allow-shield contradict each other; pass one");
|
|
126779
126829
|
const shieldCap = asText(maxShieldAtomic);
|
|
@@ -126828,8 +126878,7 @@ function moneyOptions({
|
|
|
126828
126878
|
...shieldOn && shieldCap ? { maxShieldAtomic: shieldCap } : {},
|
|
126829
126879
|
allowUnshield: unshieldOn,
|
|
126830
126880
|
unshieldTo: Object.freeze([...new Set(addresses)]),
|
|
126831
|
-
...unshieldOn ? { ...unshieldCap ? { maxUnshieldAtomic: unshieldCap } : {}, exitProofTools, profile, facilitatorOrigin: facilitatorOrigin2 } : {}
|
|
126832
|
-
...depositUnitAtomic ? { depositUnitAtomic: asText(depositUnitAtomic) } : {}
|
|
126881
|
+
...unshieldOn ? { ...unshieldCap ? { maxUnshieldAtomic: unshieldCap } : {}, exitProofTools, profile, facilitatorOrigin: facilitatorOrigin2 } : {}
|
|
126833
126882
|
});
|
|
126834
126883
|
}
|
|
126835
126884
|
async function runMcpServer({ input = process.stdin, output: output2 = process.stdout, errorOutput = process.stderr, updateCheck, ...options } = {}) {
|
|
@@ -126876,7 +126925,6 @@ async function openWalletServer({
|
|
|
126876
126925
|
maxUnshieldAtomic,
|
|
126877
126926
|
exitProofToolsPath,
|
|
126878
126927
|
profilePath,
|
|
126879
|
-
depositUnitAtomic,
|
|
126880
126928
|
autoPockets = true,
|
|
126881
126929
|
readyPockets,
|
|
126882
126930
|
discoverWarmup = false,
|
|
@@ -126904,8 +126952,7 @@ async function openWalletServer({
|
|
|
126904
126952
|
exitProofToolsPath,
|
|
126905
126953
|
profilePath,
|
|
126906
126954
|
proofToolsPath,
|
|
126907
|
-
memoServiceUrl
|
|
126908
|
-
depositUnitAtomic
|
|
126955
|
+
memoServiceUrl
|
|
126909
126956
|
}, asText);
|
|
126910
126957
|
const live = {
|
|
126911
126958
|
...proofToolsPath ? { proofToolsPath: resolve23(proofToolsPath) } : {},
|
|
@@ -131995,8 +132042,6 @@ function mcpServerOptions(values, deps) {
|
|
|
131995
132042
|
...values.has("--max-unshield") ? { maxUnshieldAtomic: values.get("--max-unshield") } : {},
|
|
131996
132043
|
...values.has("--exit-proof-tools") ? { exitProofToolsPath: values.get("--exit-proof-tools") } : {},
|
|
131997
132044
|
...values.has("--profile") ? { profilePath: values.get("--profile") } : {},
|
|
131998
|
-
// A wallet_shield deposit takes whole units of this service's pools, as a relayed deposit does.
|
|
131999
|
-
...!values.has("--no-shield") && RELAYED_DEPOSIT_UNIT[pool] ? { depositUnitAtomic: RELAYED_DEPOSIT_UNIT[pool] } : {},
|
|
132000
132045
|
// Automatic pockets: on by default (they fill with the unshield inputs, which config.json from setup holds).
|
|
132001
132046
|
autoPockets: !values.has("--no-auto-pockets"),
|
|
132002
132047
|
...values.has("--ready-pockets") ? { readyPockets: values.get("--ready-pockets") } : {},
|
|
@@ -134491,9 +134536,6 @@ function relayDepositFailureHint(reason) {
|
|
|
134491
134536
|
if (/p03_deposit_token_balance_unreadable/.test(reason)) {
|
|
134492
134537
|
return "the RPC did not answer a USDC balance read (after 5 tries), so the wallet stopped: it never reads a failed read as 0. Do NOT send more USDC because of this; nothing was sent. Rerun the same command later, or use another --rpc";
|
|
134493
134538
|
}
|
|
134494
|
-
if (/p03_deposit_relay_amount_not_whole_unit/.test(reason)) {
|
|
134495
|
-
return "this pool takes deposits in whole units of its pocket size (GET <facilitator>/api/x402/deposit shows depositUnitAtomic), so no amount marks one depositor; nothing was recorded or sent. Rerun with --amount a whole multiple of it";
|
|
134496
|
-
}
|
|
134497
134539
|
if (/p03_deposit_relay_amount_below_facilitator_minimum/.test(reason)) {
|
|
134498
134540
|
return "the facilitator relays deposits of at least its minimum (GET <facilitator>/api/x402/deposit shows minimumAtomic); nothing was recorded. Rerun with a larger --amount";
|
|
134499
134541
|
}
|