agentwallet-mcp 1.14.5 → 1.14.7
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 +2 -2
- package/build/index.js +24 -7
- package/build/ledger.d.ts +5 -2
- package/build/local-solana.d.ts +10 -0
- package/build/local-solana.js +51 -21
- package/build/policy.js +7 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -256,7 +256,7 @@ pay_x402(
|
|
|
256
256
|
|
|
257
257
|
**Asset risk.** `check_token_risk` (and every `approve_token` result) reports honeypot, tax, owner-power, verified-source, holder-concentration and liquidity flags from GoPlus Security, with an on-chain fallback. A warning for the caller to weigh, never a block.
|
|
258
258
|
|
|
259
|
-
**Proof.** Real settlements are listed in [PAYMENTS.md](https://github.com/hifriendbot/agentwallet-mcp/blob/main/PAYMENTS.md); the first is a 0.02 USDC `exact` payment on Base with the facilitator paying the gas.
|
|
259
|
+
**Proof.** Real settlements are listed in [PAYMENTS.md](https://github.com/hifriendbot/agentwallet-mcp/blob/main/PAYMENTS.md); the first is a 0.02 USDC `exact` payment on Base with the facilitator paying the gas. The same list, rendered with Basescan links, is at [hifriendbot.com/wallet/payments](https://hifriendbot.com/wallet/payments/), and a five-minute walkthrough from install to a real settlement is at [hifriendbot.com/wallet/quickstart](https://hifriendbot.com/wallet/quickstart/). Security policy, fixed disclosures and the release history: [hifriendbot.com/security](https://hifriendbot.com/security/) and [hifriendbot.com/changelog](https://hifriendbot.com/changelog/).
|
|
260
260
|
|
|
261
261
|
## Pay any x402 API from Claude in three steps
|
|
262
262
|
|
|
@@ -374,7 +374,7 @@ A per-transaction cap bounds one signature. It cannot see that the five hundredt
|
|
|
374
374
|
```
|
|
375
375
|
|
|
376
376
|
- **`budget`**: rolling dollar budgets (last 24 hours, last 30 days, lifetime) across every chain, counting x402 payments, stablecoin transfers and stablecoin approvals in registry stablecoins. A spend the budget cannot price (a token outside the registry) is refused while a budget is set, unless `"unpriced_spends": "allow"`. An SPL send is priced at the mint's own decimals; a `token_decimals` hint that disagrees with the mint is refused before any request is made.
|
|
377
|
-
- **`native_budget`**: the same per chain, in the chain's own coin, counting native transfers and the native value sent into any contract (`wrap_eth`, `send_transaction` with value and calldata), including value carried on a token transfer or approval call (a payable token contract keeps it, so it is a second spend, to that contract).
|
|
377
|
+
- **`native_budget`**: the same per chain, in the chain's own coin, counting native transfers and the native value sent into any contract (`wrap_eth`, `send_transaction` with value and calldata), including value carried on a token transfer or approval call (a payable token contract keeps it, so it is a second spend, to that contract) and, in local Solana mode, the rent an SPL send pays to create the recipient's token account (the recipient owns that account and can close it for the lamports; the ledger records it as its own line, method `rent`, to the recipient, and `assets.allow` does not need to list `native` for it).
|
|
378
378
|
- **Approvals are spends.** An ERC-20 allowance (`approve_token`, `approve_permit2`, `increaseAllowance`, `approveAndCall`, Permit2 `approve`, or the same calldata through `send_transaction`) is what the spender will take later, so it is priced, checked and reserved on the ledger when it is granted, the spender is checked against the recipient lists, and an unlimited approval (2^128 base units or more) is refused outright, since no budget can count it; grant an exact amount. A zero-value call to any other contract (a router, a bridge) reserves nothing: it can only pull what an approval already granted.
|
|
379
379
|
- **`hosts`**, **`per_host`**: which endpoints `pay_x402` may pay, and how much per host per day, per month and per payment. A denied host is never contacted, not even for a quote. A host is matched by its canonical DNS name (lowercase, the root label's trailing dot removed), so `api.example.com.` and its percent-encoded spelling are `api.example.com` to every list and to the ledger's per-host sums.
|
|
380
380
|
- **`recipients`**: where funds may go (transfers, x402 `payTo`, approval spenders, contracts that receive native value). The allow list covers those funds destinations; the contract a zero-value call is aimed at (a token being approved, a router) is checked against the deny list and the chain list.
|
package/build/index.js
CHANGED
|
@@ -30,7 +30,7 @@ import { WRAPPED_NATIVE } from './wrapped-native.js';
|
|
|
30
30
|
import { buildUptoAuthorization, uptoPayload, permit2AllowanceCalldata, permit2ApproveCalldata, decodeUint, permit2Address, } from './x402-permit2.js';
|
|
31
31
|
import { assessTokenRisk } from './token-risk.js';
|
|
32
32
|
import { isLegacyAgentWalletAccept, requiredAmount, buildAuthorization, buildPaymentPayload, buildPaymentPayloadRaw, paymentHeaderFor, parsePaymentRequired, parseSettlement, pickOption, knownTokenDomain, decodeAbiString as decodeDomainString, parseEip7702Delegation, erc1271ProbeCalldata, classifyErc1271Probe, settlementVerdict, legacyReceiptAllowed, sanitizeRequired, } from './x402-eip3009.js';
|
|
33
|
-
import { isSolanaLocalMode, getSolanaAddress, solanaWalletRecord, localSolBalance, localSplBalance, localSolTransfer, localSplTransfer, resolveSolanaRpc, mintDecimalsStrict, } from './local-solana.js';
|
|
33
|
+
import { isSolanaLocalMode, getSolanaAddress, solanaWalletRecord, localSolBalance, localSplBalance, localSolTransfer, localSplTransfer, resolveSolanaRpc, mintDecimalsStrict, splAccountRent, } from './local-solana.js';
|
|
34
34
|
import { localSimulate } from './local-wallet.js';
|
|
35
35
|
import { loadPolicy, describePolicy, hostAllowed, recipientAllowed, targetAllowed, chainAllowed, assetAllowed, perHostRule, toolAllowed, hostOf, budgetReport, units as policyUnits, human as policyHuman, rawToUnits, } from './policy.js';
|
|
36
36
|
import { Ledger } from './ledger.js';
|
|
@@ -92,7 +92,10 @@ function reserveSpend(input) {
|
|
|
92
92
|
const chain = chainAllowed(p, input.chainId);
|
|
93
93
|
if (!chain.ok)
|
|
94
94
|
throw new Error(chain.reason + ' Nothing was signed.');
|
|
95
|
-
|
|
95
|
+
// Rent is SOL by nature, not by choice: the operator allowed the token, and
|
|
96
|
+
// the account that holds it is paid for in the chain's coin, so assets.allow
|
|
97
|
+
// does not have to list native for the rent line. native_budget counts it.
|
|
98
|
+
const asset = input.method === 'rent' ? { ok: true } : assetAllowed(p, input.chainId, input.asset);
|
|
96
99
|
if (!asset.ok)
|
|
97
100
|
throw new Error(asset.reason + ' Nothing was signed.');
|
|
98
101
|
const to = recipientAllowed(p, input.to);
|
|
@@ -105,7 +108,7 @@ function reserveSpend(input) {
|
|
|
105
108
|
/** The same checks with nothing recorded, for quotes and simulations. */
|
|
106
109
|
function spendVerdict(input) {
|
|
107
110
|
const p = POL();
|
|
108
|
-
for (const r of [chainAllowed(p, input.chainId), assetAllowed(p, input.chainId, input.asset), recipientAllowed(p, input.to)])
|
|
111
|
+
for (const r of [chainAllowed(p, input.chainId), input.method === 'rent' ? { ok: true } : assetAllowed(p, input.chainId, input.asset), recipientAllowed(p, input.to)])
|
|
109
112
|
if (!r.ok)
|
|
110
113
|
return r;
|
|
111
114
|
const limits = limitsFor(input.host);
|
|
@@ -141,7 +144,19 @@ async function describeSend(body, chainId) {
|
|
|
141
144
|
// reached the custodian (reported privately 2026-10-24, 1.14.5). The chain
|
|
142
145
|
// would have refused the TransferChecked, but the ledger was already wrong.
|
|
143
146
|
const given = Number.isInteger(d) && d >= 0 && d <= 36 ? d : undefined;
|
|
144
|
-
|
|
147
|
+
const to = String(body.to || '');
|
|
148
|
+
const decimals = await verifiedDecimals(chainId, mint, given);
|
|
149
|
+
// In local mode this process is the payer: when the recipient has no token
|
|
150
|
+
// account yet, the send creates one and the rent is native value leaving
|
|
151
|
+
// the wallet, reserved here from the same reading the signer will make.
|
|
152
|
+
// The hosted custodian pays its own rent and bounds it on its side.
|
|
153
|
+
let carried;
|
|
154
|
+
if (isSolanaLocalMode() && to) {
|
|
155
|
+
const rent = await splAccountRent(mint, to, chainId);
|
|
156
|
+
if (rent > 0n)
|
|
157
|
+
carried = { raw: rent.toString(), to, rent: true };
|
|
158
|
+
}
|
|
159
|
+
return { kind: 'spl', to, asset: mint, raw: String(body.value ?? '0'), decimals, ...(carried ? { carried } : {}) };
|
|
145
160
|
}
|
|
146
161
|
const data = String(body.data || '');
|
|
147
162
|
const to = String(body.to || '');
|
|
@@ -221,7 +236,9 @@ function assertSendTarget(d, chainId) {
|
|
|
221
236
|
* recipients.allow and .deny bind who may be allowed to pull; the native
|
|
222
237
|
* value of a contract call is a spend to that contract; the native value
|
|
223
238
|
* carried on a token or approval call is a second spend, native, to the
|
|
224
|
-
* called contract (1.14.4)
|
|
239
|
+
* called contract (1.14.4); the rent a local SPL send pays for the recipient's
|
|
240
|
+
* token account is a native spend to the recipient, method 'rent' (1.14.7).
|
|
241
|
+
* Throws for an unbounded approval under a policy.
|
|
225
242
|
*/
|
|
226
243
|
function spendInputsOf(d, chainId, tool, wallet, ctx = {}) {
|
|
227
244
|
if (d.kind === 'approval' && d.unbounded && POLICY.path) {
|
|
@@ -238,7 +255,7 @@ function spendInputsOf(d, chainId, tool, wallet, ctx = {}) {
|
|
|
238
255
|
});
|
|
239
256
|
}
|
|
240
257
|
if (d.carried) {
|
|
241
|
-
out.push({ ...base, asset: '', assetLabel: assetLabel(chainId, ''), raw: d.carried.raw, decimals: nativeDecimals(chainId), usd: null, to: d.carried.to, method: 'native' });
|
|
258
|
+
out.push({ ...base, asset: '', assetLabel: assetLabel(chainId, ''), raw: d.carried.raw, decimals: nativeDecimals(chainId), usd: null, to: d.carried.to, method: d.carried.rent ? 'rent' : 'native' });
|
|
242
259
|
}
|
|
243
260
|
return out;
|
|
244
261
|
}
|
|
@@ -1175,7 +1192,7 @@ function resolveChainId(network) {
|
|
|
1175
1192
|
const AddressSchema = z.string().regex(/^(0x[a-fA-F0-9]{40}|[1-9A-HJ-NP-Za-km-z]{32,44})$/, 'Must be a 0x-prefixed 40-hex EVM address or a base58 Solana address');
|
|
1176
1193
|
const server = new McpServer({
|
|
1177
1194
|
name: 'agentwallet',
|
|
1178
|
-
version: '1.14.
|
|
1195
|
+
version: '1.14.7',
|
|
1179
1196
|
}, {
|
|
1180
1197
|
instructions: `AgentWallet gives AI agents their own blockchain wallets. ${anyLocalMode()
|
|
1181
1198
|
? 'This server runs in LOCAL (self-custody) mode: the operator supplied the key, signing happens in this process, and the only spend guards are the environment caps (AGENTWALLET_MAX_TX_NATIVE / _TOKEN / _SOL per transaction, AGENTWALLET_MAX_AUTOPAY and AGENTWALLET_AUTOPAY_ASSETS for x402, AGENTWALLET_X402_MAX_TIMEOUT for authorization windows). There is no server-side pause, daily limit or approval email; pause_wallet, unpause_wallet and delete_wallet are refused.'
|
package/build/ledger.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { type Spent } from './policy.js';
|
|
2
|
-
/**
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* 'approval' is an ERC-20 allowance granted (approve, increaseAllowance, Permit2.approve): a spend the spender executes later, counted when granted.
|
|
4
|
+
* 'rent' is the SOL an SPL send pays to create the recipient's token account (1.14.7): native, to the recipient, who owns the account and can close it for the lamports.
|
|
5
|
+
*/
|
|
6
|
+
export type SpendMethod = 'eip3009' | 'permit2' | 'transfer' | 'native' | 'spl' | 'autopay' | 'approval' | 'rent';
|
|
4
7
|
export interface SpendEntry {
|
|
5
8
|
seq: number;
|
|
6
9
|
ts: string;
|
package/build/local-solana.d.ts
CHANGED
|
@@ -76,6 +76,16 @@ export declare function localSolTransfer(to: string, lamports: string, chainId?:
|
|
|
76
76
|
* not exist, using the idempotent instruction so a race cannot fail the send.
|
|
77
77
|
*/
|
|
78
78
|
export declare function localSplTransfer(mintStr: string, to: string, rawAmount: string, decimals: number, chainId?: number): Promise<LocalSolResult>;
|
|
79
|
+
/**
|
|
80
|
+
* The SOL an SPL send to `to` spends on creating the recipient's token
|
|
81
|
+
* account, in lamports; 0n when the account exists. The recipient owns that
|
|
82
|
+
* account and can close it to keep the lamports, so it is native value leaving
|
|
83
|
+
* the wallet and the spend policy reserves it against native_budget before the
|
|
84
|
+
* send is built (reported privately 2026-10-26: it was checked against the
|
|
85
|
+
* per-transaction SOL cap only, and fresh recipients took SOL past the daily
|
|
86
|
+
* budget while the ledger held token lines alone).
|
|
87
|
+
*/
|
|
88
|
+
export declare function splAccountRent(mintStr: string, to: string, chainId?: number): Promise<bigint>;
|
|
79
89
|
export declare function solanaWalletRecord(): {
|
|
80
90
|
id: string;
|
|
81
91
|
address: string;
|
package/build/local-solana.js
CHANGED
|
@@ -448,31 +448,15 @@ export async function localSplTransfer(mintStr, to, rawAmount, decimals, chainId
|
|
|
448
448
|
const mint = new PublicKey(mintStr);
|
|
449
449
|
const recipient = new PublicKey(to);
|
|
450
450
|
await assertRecipientIsWallet(conn, recipient);
|
|
451
|
-
const { tokenProgram,
|
|
451
|
+
const { tokenProgram, destAta, rent } = await destinationAccount(conn, mint, recipient);
|
|
452
452
|
const sourceAta = associatedTokenAddress(payer.publicKey, mint, tokenProgram);
|
|
453
|
-
const destAta = associatedTokenAddress(recipient, mint, tokenProgram);
|
|
454
453
|
const tx = new Transaction();
|
|
455
|
-
|
|
456
|
-
// The associated-account program creates into an address that already holds
|
|
457
|
-
// plain SOL (system-owned, no data): it tops up the rent, allocates and
|
|
458
|
-
// assigns. Only an address holding something else cannot become the token
|
|
459
|
-
// account (2026-10-04 round 2; the 1.13.5 refusal of any occupant let anyone
|
|
460
|
-
// block a recipient for the price of the rent-exempt minimum).
|
|
461
|
-
const prefunded = destInfo !== null && destInfo.owner.equals(SystemProgram.programId) && destInfo.data.length === 0;
|
|
462
|
-
if (destInfo && !destInfo.owner.equals(tokenProgram) && !prefunded) {
|
|
463
|
-
throw new Error(`Refusing to send: the recipient's token account address ${destAta.toBase58()} is occupied by an account owned by ${destInfo.owner.toBase58()}, so no token account can be created there.`);
|
|
464
|
-
}
|
|
465
|
-
if (!destInfo || prefunded) {
|
|
454
|
+
if (rent > 0n) {
|
|
466
455
|
// Creating the recipient's token account costs the payer rent in SOL, an
|
|
467
456
|
// outflow the SOL cap must see (0.002 SOL a time adds up over many sends).
|
|
468
|
-
//
|
|
469
|
-
//
|
|
470
|
-
|
|
471
|
-
// node says already sits at the address is not credited: both are numbers a
|
|
472
|
-
// lying RPC used to zero so the create went out under the cap (round 4).
|
|
473
|
-
const claimed = Number(await conn.getMinimumBalanceForRentExemption(ataSize));
|
|
474
|
-
const rent = Math.max(Number.isFinite(claimed) ? Math.trunc(claimed) : 0, (128 + ataSize) * 6960);
|
|
475
|
-
assertWithinSolCap(BigInt(rent));
|
|
457
|
+
// The policy reserved the same figure against native_budget before this
|
|
458
|
+
// call (1.14.7); the cap is the per-transaction floor under it.
|
|
459
|
+
assertWithinSolCap(rent);
|
|
476
460
|
tx.add(createAtaIdempotentIx(payer.publicKey, destAta, recipient, mint, tokenProgram));
|
|
477
461
|
}
|
|
478
462
|
tx.add(transferCheckedIx(tokenProgram, sourceAta, mint, destAta, payer.publicKey, BigInt(rawAmount), decimals));
|
|
@@ -487,6 +471,52 @@ export async function localSplTransfer(mintStr, to, rawAmount, decimals, chainId
|
|
|
487
471
|
signed_locally: true,
|
|
488
472
|
};
|
|
489
473
|
}
|
|
474
|
+
/**
|
|
475
|
+
* The recipient's associated account for a mint, and the rent the payer funds
|
|
476
|
+
* when it has to be created: 0 when it already exists. One reading shared by
|
|
477
|
+
* the send and by the policy's reservation, so the ledger line and the
|
|
478
|
+
* instruction carry the same figure.
|
|
479
|
+
*
|
|
480
|
+
* The associated-account program creates into an address that already holds
|
|
481
|
+
* plain SOL (system-owned, no data): it tops up the rent, allocates and
|
|
482
|
+
* assigns. Only an address holding something else cannot become the token
|
|
483
|
+
* account (2026-10-04 round 2; the 1.13.5 refusal of any occupant let anyone
|
|
484
|
+
* block a recipient for the price of the rent-exempt minimum).
|
|
485
|
+
*
|
|
486
|
+
* Rent follows the account's real size, which for Token-2022 is above 165;
|
|
487
|
+
* SOL already sitting at the address reduces what the payer tops up. The
|
|
488
|
+
* node's rent figure is floored at the cluster constant and the SOL the node
|
|
489
|
+
* says already sits at the address is not credited: both are numbers a lying
|
|
490
|
+
* RPC used to zero so the create went out under the cap (round 4).
|
|
491
|
+
*/
|
|
492
|
+
async function destinationAccount(conn, mint, recipient) {
|
|
493
|
+
const { tokenProgram, ataSize } = await mintLayout(conn, mint);
|
|
494
|
+
const destAta = associatedTokenAddress(recipient, mint, tokenProgram);
|
|
495
|
+
const destInfo = await conn.getAccountInfo(destAta);
|
|
496
|
+
const prefunded = destInfo !== null && destInfo.owner.equals(SystemProgram.programId) && destInfo.data.length === 0;
|
|
497
|
+
if (destInfo && !destInfo.owner.equals(tokenProgram) && !prefunded) {
|
|
498
|
+
throw new Error(`Refusing to send: the recipient's token account address ${destAta.toBase58()} is occupied by an account owned by ${destInfo.owner.toBase58()}, so no token account can be created there.`);
|
|
499
|
+
}
|
|
500
|
+
if (destInfo && !prefunded)
|
|
501
|
+
return { tokenProgram, destAta, rent: 0n };
|
|
502
|
+
const claimed = Number(await conn.getMinimumBalanceForRentExemption(ataSize));
|
|
503
|
+
const rent = Math.max(Number.isFinite(claimed) ? Math.trunc(claimed) : 0, (128 + ataSize) * 6960);
|
|
504
|
+
return { tokenProgram, destAta, rent: BigInt(rent) };
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* The SOL an SPL send to `to` spends on creating the recipient's token
|
|
508
|
+
* account, in lamports; 0n when the account exists. The recipient owns that
|
|
509
|
+
* account and can close it to keep the lamports, so it is native value leaving
|
|
510
|
+
* the wallet and the spend policy reserves it against native_budget before the
|
|
511
|
+
* send is built (reported privately 2026-10-26: it was checked against the
|
|
512
|
+
* per-transaction SOL cap only, and fresh recipients took SOL past the daily
|
|
513
|
+
* budget while the ledger held token lines alone).
|
|
514
|
+
*/
|
|
515
|
+
export async function splAccountRent(mintStr, to, chainId = 900) {
|
|
516
|
+
const conn = connection(chainId);
|
|
517
|
+
await assertCluster(conn, chainId);
|
|
518
|
+
return (await destinationAccount(conn, new PublicKey(mintStr), new PublicKey(to))).rent;
|
|
519
|
+
}
|
|
490
520
|
const TOKEN_ACCOUNT_SIZE = 165;
|
|
491
521
|
const MINT_SIZE = 82;
|
|
492
522
|
/** Token-2022 pads a mint to the token-account size and tags the next byte: 1 = mint, 2 = token account. */
|
package/build/policy.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { readFileSync } from 'node:fs';
|
|
15
15
|
import { createHash } from 'node:crypto';
|
|
16
|
+
import { dirname, isAbsolute, join } from 'node:path';
|
|
16
17
|
import { z } from 'zod';
|
|
17
18
|
const Dec = z.string().regex(/^\d+(\.\d+)?$/, 'a decimal number as a string, like "5" or "0.25"');
|
|
18
19
|
const Window = z.object({ daily: Dec.optional(), monthly: Dec.optional(), total: Dec.optional() }).strict();
|
|
@@ -118,12 +119,15 @@ export function loadPolicy(env = process.env) {
|
|
|
118
119
|
}
|
|
119
120
|
const policy = parsePolicy(text);
|
|
120
121
|
const hash = createHash('sha256').update(text).digest('hex');
|
|
121
|
-
|
|
122
|
+
// The ledger lives beside the policy file. dirname() gives '.' for a bare
|
|
123
|
+
// filename; a hand-rolled strip-after-last-slash left the filename itself as
|
|
124
|
+
// the directory, so AGENTWALLET_POLICY=policy.json could not start (1.14.6).
|
|
125
|
+
const dir = dirname(file);
|
|
122
126
|
let ledgerPath = ledgerEnv || null;
|
|
123
127
|
if (!ledgerPath && policy.ledger)
|
|
124
|
-
ledgerPath =
|
|
128
|
+
ledgerPath = isAbsolute(policy.ledger) ? policy.ledger : join(dir, policy.ledger);
|
|
125
129
|
if (!ledgerPath && needsLedger(policy))
|
|
126
|
-
ledgerPath =
|
|
130
|
+
ledgerPath = join(dir, 'agentwallet-ledger.jsonl');
|
|
127
131
|
return { policy, path: file, hash, ledgerPath };
|
|
128
132
|
}
|
|
129
133
|
/** A budget is only meaningful across restarts, so it needs a file. */
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/hifriendbot/agentwallet-mcp.git"
|
|
7
7
|
},
|
|
8
|
-
"version": "1.14.
|
|
8
|
+
"version": "1.14.7",
|
|
9
9
|
"description": "MCP server for AgentWallet: self-custody local signing on EVM and Solana, or hosted wallets. Sign, broadcast, pay x402 invoices, and accept x402 payments.",
|
|
10
10
|
"type": "module",
|
|
11
11
|
"main": "build/index.js",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"scripts": {
|
|
21
21
|
"build": "tsc",
|
|
22
22
|
"start": "node build/index.js",
|
|
23
|
-
"test": "node test/x402-payment.test.mjs && node test/eip3009.test.mjs && node test/permit2-risk.test.mjs && node test/token-cap.test.mjs && node test/spl-cap.test.mjs && node test/unknown-decimals-cap.test.mjs && node test/decimals-range-cap.test.mjs && node test/local-mode.test.mjs && node test/ssrf-guard.test.mjs && node test/x402-policy.test.mjs && node test/local-guard-shape.test.mjs && node test/allowance-total-cap.test.mjs && node test/autopay-scheme.test.mjs && node test/spl-recipient-guard.test.mjs && node test/approval-binding.test.mjs && node test/ata-rent-size.test.mjs && node test/final-url-guard.test.mjs && node test/audit-1135.test.mjs && node test/local-no-autopay.test.mjs && node test/audit-1136.test.mjs && node test/delete-confirm.test.mjs && node test/audit-1138.test.mjs && node test/audit-1139.test.mjs && node test/audit-11310.test.mjs && node test/audit-11311.test.mjs && node test/audit-11312.test.mjs && node test/audit-11313.test.mjs && node test/audit-11316.test.mjs && node test/spend-policy.test.mjs",
|
|
23
|
+
"test": "node test/x402-payment.test.mjs && node test/eip3009.test.mjs && node test/permit2-risk.test.mjs && node test/token-cap.test.mjs && node test/spl-cap.test.mjs && node test/unknown-decimals-cap.test.mjs && node test/decimals-range-cap.test.mjs && node test/local-mode.test.mjs && node test/ssrf-guard.test.mjs && node test/x402-policy.test.mjs && node test/local-guard-shape.test.mjs && node test/allowance-total-cap.test.mjs && node test/autopay-scheme.test.mjs && node test/spl-recipient-guard.test.mjs && node test/approval-binding.test.mjs && node test/ata-rent-size.test.mjs && node test/final-url-guard.test.mjs && node test/audit-1135.test.mjs && node test/local-no-autopay.test.mjs && node test/audit-1136.test.mjs && node test/delete-confirm.test.mjs && node test/audit-1138.test.mjs && node test/audit-1139.test.mjs && node test/audit-11310.test.mjs && node test/audit-11311.test.mjs && node test/audit-11312.test.mjs && node test/audit-11313.test.mjs && node test/audit-11316.test.mjs && node test/spend-policy.test.mjs && node test/policy-path-resolution.test.mjs",
|
|
24
24
|
"prepublishOnly": "npm run build"
|
|
25
25
|
},
|
|
26
26
|
"keywords": [
|