@wafermapxyz/cli 0.4.3 → 0.4.4
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/CHANGELOG.md +9 -0
- package/README.md +3 -1
- package/dist/cli.js +88 -2
- package/dist/index.js +62 -1
- package/dist/types/shared/pass.d.ts +21 -0
- package/dist/types/src/core.d.ts +12 -0
- package/dist/types/src/index.d.ts +2 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.4 (2 Nov 2026)
|
|
4
|
+
|
|
5
|
+
**$WAFERMAP holder tiers.**
|
|
6
|
+
|
|
7
|
+
- **Pro free calls.** A wallet holding 1,000,000 $WAFERMAP on Robinhood Chain gets 10 free calls a day (UTC) to Wafermap resources listed at $0.01 or less. `call()` (CLI `wafermap call`, MCP `wafermap_call`) sends a **holder pass** to Wafermap with each call; when the call is free, the result comes back with `receipt: null` and `free: {left, perDay}`, no payment is signed and nothing is recorded as spending. Otherwise the call is quoted and paid as before.
|
|
8
|
+
- **Holder pass.** A message the wallet signs (`personal_sign`: no transaction, no cost) that proves it holds the wallet, valid for 24 hours and reused until its last 10 minutes (`Wafermap.holderPass()`). It goes to Wafermap only: never with `pay()` to third-party services, and never to marketplace listings (`m/...`). The SDK exports `PASS_HEADER`, `passMessage`, `encodePass`, `decodePass`, `makePass`.
|
|
9
|
+
- **`wafermap holder`** shows what the wallet's $WAFERMAP unlocks: holder price, tier, free calls left today, x402 Tracker Pro. Needs no password (`holderInfo()` in the SDK).
|
|
10
|
+
- **`wafermap pass`** prints a pass for scripts, e.g. the x402 Tracker Pro API (`/api/x402/pro/movers`, `/api/x402/pro/export`, for wallets holding 100,000 $WAFERMAP).
|
|
11
|
+
|
|
3
12
|
## 0.4.3 (2 Nov 2026)
|
|
4
13
|
|
|
5
14
|
The two open points from the third public review by @whoiskn0why (8/10), thank you.
|
package/README.md
CHANGED
|
@@ -82,7 +82,9 @@ Pass `approve: (a) => boolean` to confirm each payment or swap yourself, and `le
|
|
|
82
82
|
|
|
83
83
|
## $WAFERMAP holder discount
|
|
84
84
|
|
|
85
|
-
A wallet that holds at least 100,000 $WAFERMAP on Robinhood Chain pays 50% less for Wafermap's own resources when it pays on an EVM network (Robinhood Chain, Base, Arbitrum, Polygon). Nothing to set up: `wafermap call` names the wallet to Wafermap and the quote comes back discounted; the server re-checks the balance of the wallet that signs. Marketplace listings and Solana payments keep the regular price. Check a wallet: https://wafermap.xyz/api/holder?address=0x
|
|
85
|
+
A wallet that holds at least 100,000 $WAFERMAP on Robinhood Chain pays 50% less for Wafermap's own resources when it pays on an EVM network (Robinhood Chain, Base, Arbitrum, Polygon). Nothing to set up: `wafermap call` names the wallet to Wafermap and the quote comes back discounted; the server re-checks the balance of the wallet that signs. Marketplace listings and Solana payments keep the regular price. Check a wallet: https://wafermap.xyz/api/holder?address=0x…, or run `wafermap holder`.
|
|
86
|
+
|
|
87
|
+
With 1,000,000 $WAFERMAP the wallet is **Pro**: 10 free calls a day (UTC) to resources listed at $0.01 or less. `wafermap call` sends a holder pass (a signed message, no transaction, valid 24 hours) to Wafermap only; when a call is free, nothing is signed for payment and it prints `✓ Free call`. Holders of 100,000 also unlock x402 Tracker Pro: `wafermap pass` prints a pass for its API. Details: https://wafermap.xyz/docs#holders
|
|
86
88
|
|
|
87
89
|
## Where the limits live
|
|
88
90
|
|
package/dist/cli.js
CHANGED
|
@@ -437,6 +437,47 @@ var init_x402client = __esm({
|
|
|
437
437
|
}
|
|
438
438
|
});
|
|
439
439
|
|
|
440
|
+
// shared/pass.ts
|
|
441
|
+
function passMessage(address, iat, exp) {
|
|
442
|
+
return [
|
|
443
|
+
"wafermap.xyz holder pass",
|
|
444
|
+
"",
|
|
445
|
+
`Wallet: ${address}`,
|
|
446
|
+
`Issued: ${new Date(iat * 1e3).toISOString()}`,
|
|
447
|
+
`Expires: ${new Date(exp * 1e3).toISOString()}`,
|
|
448
|
+
"",
|
|
449
|
+
"Proves you hold this wallet, so Wafermap can apply what your $WAFERMAP unlocks. It costs nothing and moves no funds."
|
|
450
|
+
].join("\n");
|
|
451
|
+
}
|
|
452
|
+
function decodePass(s) {
|
|
453
|
+
if (!s || s.length > 1e3 || !/^[A-Za-z0-9_-]+$/.test(s)) return null;
|
|
454
|
+
try {
|
|
455
|
+
const p = JSON.parse(unb64url(s));
|
|
456
|
+
if (p?.v !== 1 || typeof p.address !== "string" || !/^0x[0-9a-fA-F]{40}$/.test(p.address)) return null;
|
|
457
|
+
if (!Number.isInteger(p.iat) || !Number.isInteger(p.exp) || typeof p.sig !== "string" || !/^0x[0-9a-fA-F]{130}$/.test(p.sig)) return null;
|
|
458
|
+
return { v: 1, address: p.address, iat: p.iat, exp: p.exp, sig: p.sig };
|
|
459
|
+
} catch {
|
|
460
|
+
return null;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
async function makePass(signer, seconds = PASS_MAX_SECONDS, now = Math.floor(Date.now() / 1e3)) {
|
|
464
|
+
const iat = now;
|
|
465
|
+
const exp = now + Math.min(Math.max(60, seconds), PASS_MAX_SECONDS);
|
|
466
|
+
const sig = await signer.signMessage({ message: passMessage(signer.address, iat, exp) });
|
|
467
|
+
return { v: 1, address: signer.address, iat, exp, sig };
|
|
468
|
+
}
|
|
469
|
+
var PASS_HEADER, PASS_MAX_SECONDS, b64url, unb64url, encodePass;
|
|
470
|
+
var init_pass = __esm({
|
|
471
|
+
"shared/pass.ts"() {
|
|
472
|
+
"use strict";
|
|
473
|
+
PASS_HEADER = "x-wafermap-pass";
|
|
474
|
+
PASS_MAX_SECONDS = 86400;
|
|
475
|
+
b64url = (s) => btoa(unescape(encodeURIComponent(s))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
476
|
+
unb64url = (s) => decodeURIComponent(escape(atob(s.replace(/-/g, "+").replace(/_/g, "/"))));
|
|
477
|
+
encodePass = (p) => b64url(JSON.stringify(p));
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
|
|
440
481
|
// src/core.ts
|
|
441
482
|
var core_exports = {};
|
|
442
483
|
__export(core_exports, {
|
|
@@ -446,6 +487,7 @@ __export(core_exports, {
|
|
|
446
487
|
Wafermap: () => Wafermap,
|
|
447
488
|
WafermapError: () => WafermapError,
|
|
448
489
|
checkPayment: () => checkPayment,
|
|
490
|
+
holderInfo: () => holderInfo,
|
|
449
491
|
isNet: () => isNet,
|
|
450
492
|
listResources: () => listResources,
|
|
451
493
|
mergeLog: () => mergeLog
|
|
@@ -473,6 +515,15 @@ async function checkPayment(e, rpc) {
|
|
|
473
515
|
return "error";
|
|
474
516
|
}
|
|
475
517
|
}
|
|
518
|
+
async function holderInfo(address, baseUrl = "https://wafermap.xyz", timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
519
|
+
const host = new URL(baseUrl).host;
|
|
520
|
+
const r = await fetch(`${baseUrl.replace(/\/$/, "")}/api/holder?address=${encodeURIComponent(address)}`, { signal: AbortSignal.timeout(timeoutMs) }).catch((e) => {
|
|
521
|
+
throw timedOut(e) ? new WafermapError("timeout", `${host} did not answer within ${Math.round(timeoutMs / 1e3)} s.`) : new WafermapError("network_error", `${host}: ${e?.message ?? "request failed"}`);
|
|
522
|
+
});
|
|
523
|
+
const j = await r.json().catch(() => null);
|
|
524
|
+
if (!r.ok || !j) throw new WafermapError(j?.error?.code ?? "network_error", j?.error?.message ?? `${host} answered HTTP ${r.status}.`);
|
|
525
|
+
return j;
|
|
526
|
+
}
|
|
476
527
|
async function listResources(baseUrl = "https://wafermap.xyz", timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
477
528
|
const host = new URL(baseUrl).host;
|
|
478
529
|
const gaveUp = () => new WafermapError("timeout", `${host} did not answer within ${Math.round(timeoutMs / 1e3)} s. Nothing was paid.`);
|
|
@@ -494,6 +545,7 @@ var init_core = __esm({
|
|
|
494
545
|
init_swap();
|
|
495
546
|
init_solana();
|
|
496
547
|
init_x402client();
|
|
548
|
+
init_pass();
|
|
497
549
|
NETS = CHAIN_KEYS;
|
|
498
550
|
isNet = (v) => NETS.includes(v);
|
|
499
551
|
isSwapNet = (v) => v === "robinhood" || v === "base";
|
|
@@ -649,8 +701,19 @@ var init_core = __esm({
|
|
|
649
701
|
async resources() {
|
|
650
702
|
return listResources(this.baseUrl, this.timeoutMs);
|
|
651
703
|
}
|
|
704
|
+
passCache = null;
|
|
705
|
+
/** A holder pass (shared/pass.ts) signed by this wallet, valid 24 h and reused until its last 10 minutes. It
|
|
706
|
+
* proves the wallet to Wafermap for what its $WAFERMAP unlocks (Pro free calls, x402 Tracker Pro). Signing
|
|
707
|
+
* a message moves no funds. */
|
|
708
|
+
async holderPass() {
|
|
709
|
+
const p = decodePass(this.passCache);
|
|
710
|
+
if (this.passCache && p && p.exp - 600 > Date.now() / 1e3) return this.passCache;
|
|
711
|
+
this.passCache = encodePass(await makePass({ address: this.account.address, signMessage: (a) => this.account.signMessage(a) }));
|
|
712
|
+
return this.passCache;
|
|
713
|
+
}
|
|
652
714
|
async call(id, input = {}, o = {}) {
|
|
653
|
-
const
|
|
715
|
+
const pass = id.startsWith("m/") ? null : await this.holderPass();
|
|
716
|
+
const go = () => this.paidFetch("resource", id, `${this.baseUrl}/v1/${id}`, { method: "POST", headers: { "content-type": "application/json", "x-wafermap-payer": this.address, ...pass ? { [PASS_HEADER]: pass } : {} }, body: JSON.stringify(input) }, o.network);
|
|
654
717
|
const settle = (r2, out2) => {
|
|
655
718
|
if (!r2.paid || !r2.id) return;
|
|
656
719
|
const status = r2.res.status === 402 ? "refused" : r2.res.ok ? "ok" : "failed";
|
|
@@ -960,7 +1023,7 @@ var VERSION;
|
|
|
960
1023
|
var init_version = __esm({
|
|
961
1024
|
"src/version.ts"() {
|
|
962
1025
|
"use strict";
|
|
963
|
-
VERSION = "0.4.
|
|
1026
|
+
VERSION = "0.4.4";
|
|
964
1027
|
}
|
|
965
1028
|
});
|
|
966
1029
|
|
|
@@ -1515,6 +1578,8 @@ Wallet
|
|
|
1515
1578
|
Pay
|
|
1516
1579
|
wafermap resources [words] Wafermap's pay-per-call catalog
|
|
1517
1580
|
wafermap call <id> [field=value ...] run a resource and pay its price (--json '{...}' for complex input)
|
|
1581
|
+
wafermap holder what this wallet's $WAFERMAP unlocks: holder price, Pro free calls left today
|
|
1582
|
+
wafermap pass print a holder pass (X-Wafermap-Pass) for scripts and x402 Tracker Pro
|
|
1518
1583
|
wafermap discover <words> search third-party x402 services
|
|
1519
1584
|
wafermap pay <url> [field=value ...] call any x402 URL and pay it (--post to send a JSON body)
|
|
1520
1585
|
|
|
@@ -1630,6 +1695,26 @@ async function main() {
|
|
|
1630
1695
|
Caps: $0.10 per payment, $1 per day, $25 per swap. Change with \`wafermap limits\`.`);
|
|
1631
1696
|
return;
|
|
1632
1697
|
}
|
|
1698
|
+
case "holder": {
|
|
1699
|
+
const addr = keystoreAddress() ?? die("No wallet yet. Run `wafermap init`.");
|
|
1700
|
+
const j = await holderInfo(addr, process.env.WAFERMAP_URL, Number(process.env.WAFERMAP_TIMEOUT_MS) || void 0);
|
|
1701
|
+
if (!j.active) return console.log("The $WAFERMAP holder program is off.");
|
|
1702
|
+
const n = (v) => Math.floor(v).toLocaleString("en-US");
|
|
1703
|
+
const k = j.perks;
|
|
1704
|
+
console.log(`${addr}
|
|
1705
|
+
holds ${n(j.balance)} $WAFERMAP on Robinhood Chain`);
|
|
1706
|
+
console.log(` tier ${j.tier === "pro" ? "Pro" : j.tier === "holder" ? "Holder" : "none"}`);
|
|
1707
|
+
console.log(` price ${j.holder ? `${j.percent}% off Wafermap resources on EVM networks` : `regular (hold ${n(j.minTokens)} for ${j.percent}% off)`}`);
|
|
1708
|
+
if (k) console.log(` free ${j.tier === "pro" ? `${k.freeLeftToday ?? "?"} of ${k.freeCallsPerDay} free calls left today (resources up to $${k.freeMaxUsd}); \`wafermap call\` uses them first` : `hold ${n(k.proMinTokens)} for ${k.freeCallsPerDay} free calls a day`}`);
|
|
1709
|
+
return console.log(` tracker ${j.holder ? "x402 Tracker Pro unlocked: wafermap.xyz/x402 (or `wafermap pass` for the API)" : `x402 Tracker Pro needs ${n(j.minTokens)}`}`);
|
|
1710
|
+
}
|
|
1711
|
+
case "pass": {
|
|
1712
|
+
const wm = openWallet(await password());
|
|
1713
|
+
const v = await wm.holderPass();
|
|
1714
|
+
console.error(`Holder pass for ${wm.address}, valid 24 hours. It proves you hold the wallet and moves no funds; anyone who has it can use your free calls until it expires, so keep it private. Send it as X-Wafermap-Pass:`);
|
|
1715
|
+
console.error(` curl -H "X-Wafermap-Pass: $(wafermap pass)" https://wafermap.xyz/api/x402/pro/movers`);
|
|
1716
|
+
return console.log(v);
|
|
1717
|
+
}
|
|
1633
1718
|
case "address": {
|
|
1634
1719
|
const evm = keystoreAddress() ?? die("No wallet yet. Run `wafermap init`.");
|
|
1635
1720
|
let sol = keystoreSolana();
|
|
@@ -1711,6 +1796,7 @@ Total $${total.toFixed(4)} in ${pays.length} payments. From 0.3.3 every payment
|
|
|
1711
1796
|
const wm = openWallet(await password(), approver(yes));
|
|
1712
1797
|
const out = await wm.call(id, inputOf(a, 1), { network: net(a.flags.network) });
|
|
1713
1798
|
if (out.receipt) console.error(`\u2713 Paid $${out.receipt.amountUsd} ${out.receipt.asset} \xB7 ${EXPLORER(out.receipt.network)}/tx/${out.receipt.tx}`);
|
|
1799
|
+
else if (out.free) console.error(`\u2713 Free call ($WAFERMAP Pro) \xB7 ${out.free.left} of ${out.free.perDay} left today. Nothing was paid.`);
|
|
1714
1800
|
if (typeof a.flags.out === "string") await saveMedia(out.result, a.flags.out);
|
|
1715
1801
|
return printResult(out.result);
|
|
1716
1802
|
}
|
package/dist/index.js
CHANGED
|
@@ -407,6 +407,41 @@ async function x402fetch(url, init, opts) {
|
|
|
407
407
|
return { res, paid: { ...signed, tx: readSettlement(res)?.tx ?? null } };
|
|
408
408
|
}
|
|
409
409
|
|
|
410
|
+
// shared/pass.ts
|
|
411
|
+
var PASS_HEADER = "x-wafermap-pass";
|
|
412
|
+
var PASS_MAX_SECONDS = 86400;
|
|
413
|
+
function passMessage(address, iat, exp) {
|
|
414
|
+
return [
|
|
415
|
+
"wafermap.xyz holder pass",
|
|
416
|
+
"",
|
|
417
|
+
`Wallet: ${address}`,
|
|
418
|
+
`Issued: ${new Date(iat * 1e3).toISOString()}`,
|
|
419
|
+
`Expires: ${new Date(exp * 1e3).toISOString()}`,
|
|
420
|
+
"",
|
|
421
|
+
"Proves you hold this wallet, so Wafermap can apply what your $WAFERMAP unlocks. It costs nothing and moves no funds."
|
|
422
|
+
].join("\n");
|
|
423
|
+
}
|
|
424
|
+
var b64url = (s) => btoa(unescape(encodeURIComponent(s))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
425
|
+
var unb64url = (s) => decodeURIComponent(escape(atob(s.replace(/-/g, "+").replace(/_/g, "/"))));
|
|
426
|
+
var encodePass = (p) => b64url(JSON.stringify(p));
|
|
427
|
+
function decodePass(s) {
|
|
428
|
+
if (!s || s.length > 1e3 || !/^[A-Za-z0-9_-]+$/.test(s)) return null;
|
|
429
|
+
try {
|
|
430
|
+
const p = JSON.parse(unb64url(s));
|
|
431
|
+
if (p?.v !== 1 || typeof p.address !== "string" || !/^0x[0-9a-fA-F]{40}$/.test(p.address)) return null;
|
|
432
|
+
if (!Number.isInteger(p.iat) || !Number.isInteger(p.exp) || typeof p.sig !== "string" || !/^0x[0-9a-fA-F]{130}$/.test(p.sig)) return null;
|
|
433
|
+
return { v: 1, address: p.address, iat: p.iat, exp: p.exp, sig: p.sig };
|
|
434
|
+
} catch {
|
|
435
|
+
return null;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
async function makePass(signer, seconds = PASS_MAX_SECONDS, now = Math.floor(Date.now() / 1e3)) {
|
|
439
|
+
const iat = now;
|
|
440
|
+
const exp = now + Math.min(Math.max(60, seconds), PASS_MAX_SECONDS);
|
|
441
|
+
const sig = await signer.signMessage({ message: passMessage(signer.address, iat, exp) });
|
|
442
|
+
return { v: 1, address: signer.address, iat, exp, sig };
|
|
443
|
+
}
|
|
444
|
+
|
|
410
445
|
// src/core.ts
|
|
411
446
|
var NETS = CHAIN_KEYS;
|
|
412
447
|
var isSwapNet = (v) => v === "robinhood" || v === "base";
|
|
@@ -442,6 +477,15 @@ async function checkPayment(e, rpc) {
|
|
|
442
477
|
var DEFAULT_LIMITS = { perPayment: 0.1, perDay: 1, perSwap: 25 };
|
|
443
478
|
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
444
479
|
var timedOut = (e) => e?.name === "TimeoutError" || e?.cause?.name === "TimeoutError";
|
|
480
|
+
async function holderInfo(address, baseUrl = "https://wafermap.xyz", timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
481
|
+
const host = new URL(baseUrl).host;
|
|
482
|
+
const r = await fetch(`${baseUrl.replace(/\/$/, "")}/api/holder?address=${encodeURIComponent(address)}`, { signal: AbortSignal.timeout(timeoutMs) }).catch((e) => {
|
|
483
|
+
throw timedOut(e) ? new WafermapError("timeout", `${host} did not answer within ${Math.round(timeoutMs / 1e3)} s.`) : new WafermapError("network_error", `${host}: ${e?.message ?? "request failed"}`);
|
|
484
|
+
});
|
|
485
|
+
const j = await r.json().catch(() => null);
|
|
486
|
+
if (!r.ok || !j) throw new WafermapError(j?.error?.code ?? "network_error", j?.error?.message ?? `${host} answered HTTP ${r.status}.`);
|
|
487
|
+
return j;
|
|
488
|
+
}
|
|
445
489
|
async function listResources(baseUrl = "https://wafermap.xyz", timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
446
490
|
const host = new URL(baseUrl).host;
|
|
447
491
|
const gaveUp = () => new WafermapError("timeout", `${host} did not answer within ${Math.round(timeoutMs / 1e3)} s. Nothing was paid.`);
|
|
@@ -596,8 +640,19 @@ var Wafermap = class {
|
|
|
596
640
|
async resources() {
|
|
597
641
|
return listResources(this.baseUrl, this.timeoutMs);
|
|
598
642
|
}
|
|
643
|
+
passCache = null;
|
|
644
|
+
/** A holder pass (shared/pass.ts) signed by this wallet, valid 24 h and reused until its last 10 minutes. It
|
|
645
|
+
* proves the wallet to Wafermap for what its $WAFERMAP unlocks (Pro free calls, x402 Tracker Pro). Signing
|
|
646
|
+
* a message moves no funds. */
|
|
647
|
+
async holderPass() {
|
|
648
|
+
const p = decodePass(this.passCache);
|
|
649
|
+
if (this.passCache && p && p.exp - 600 > Date.now() / 1e3) return this.passCache;
|
|
650
|
+
this.passCache = encodePass(await makePass({ address: this.account.address, signMessage: (a) => this.account.signMessage(a) }));
|
|
651
|
+
return this.passCache;
|
|
652
|
+
}
|
|
599
653
|
async call(id, input = {}, o = {}) {
|
|
600
|
-
const
|
|
654
|
+
const pass = id.startsWith("m/") ? null : await this.holderPass();
|
|
655
|
+
const go = () => this.paidFetch("resource", id, `${this.baseUrl}/v1/${id}`, { method: "POST", headers: { "content-type": "application/json", "x-wafermap-payer": this.address, ...pass ? { [PASS_HEADER]: pass } : {} }, body: JSON.stringify(input) }, o.network);
|
|
601
656
|
const settle = (r2, out2) => {
|
|
602
657
|
if (!r2.paid || !r2.id) return;
|
|
603
658
|
const status = r2.res.status === 402 ? "refused" : r2.res.ok ? "ok" : "failed";
|
|
@@ -711,6 +766,7 @@ export {
|
|
|
711
766
|
DEFAULT_TIMEOUT_MS,
|
|
712
767
|
KYBER_ROUTER,
|
|
713
768
|
MAX_VALIDITY_SECONDS,
|
|
769
|
+
PASS_HEADER,
|
|
714
770
|
PAY_CHAINS,
|
|
715
771
|
SwapError,
|
|
716
772
|
Wafermap,
|
|
@@ -718,10 +774,15 @@ export {
|
|
|
718
774
|
X402Error,
|
|
719
775
|
checkPayment,
|
|
720
776
|
choose,
|
|
777
|
+
decodePass,
|
|
721
778
|
decodeSwap,
|
|
779
|
+
encodePass,
|
|
722
780
|
executeSwap,
|
|
781
|
+
holderInfo,
|
|
723
782
|
listResources,
|
|
783
|
+
makePass,
|
|
724
784
|
mergeLog,
|
|
785
|
+
passMessage,
|
|
725
786
|
quoteSwap,
|
|
726
787
|
readQuote,
|
|
727
788
|
signPayment,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const PASS_HEADER = "x-wafermap-pass";
|
|
2
|
+
export declare const PASS_MAX_SECONDS = 86400;
|
|
3
|
+
export type Pass = {
|
|
4
|
+
v: 1;
|
|
5
|
+
address: string;
|
|
6
|
+
iat: number;
|
|
7
|
+
exp: number;
|
|
8
|
+
sig: string;
|
|
9
|
+
};
|
|
10
|
+
/** The exact text the wallet signs. */
|
|
11
|
+
export declare function passMessage(address: string, iat: number, exp: number): string;
|
|
12
|
+
export declare const encodePass: (p: Pass) => string;
|
|
13
|
+
/** The pass's fields, or null when it is not a well-formed pass (the signature is not checked here). */
|
|
14
|
+
export declare function decodePass(s: string | undefined | null): Pass | null;
|
|
15
|
+
/** Signs a new pass with any signer that can personal_sign. Valid for `seconds` (at most a day). */
|
|
16
|
+
export declare function makePass(signer: {
|
|
17
|
+
address: string;
|
|
18
|
+
signMessage: (a: {
|
|
19
|
+
message: string;
|
|
20
|
+
}) => Promise<string>;
|
|
21
|
+
}, seconds?: number, now?: number): Promise<Pass>;
|
package/dist/types/src/core.d.ts
CHANGED
|
@@ -87,6 +87,8 @@ export declare function mergeLog(entries: SpendEntry[]): SpendEntry[];
|
|
|
87
87
|
export declare function checkPayment(e: Pick<SpendEntry, "network" | "payer" | "nonce" | "validBefore">, rpc?: string): Promise<"used" | "unused" | "pending" | "unknown" | "error">;
|
|
88
88
|
export declare const DEFAULT_LIMITS: Limits;
|
|
89
89
|
export declare const DEFAULT_TIMEOUT_MS = 60000;
|
|
90
|
+
/** What a wallet's $WAFERMAP unlocks (holder price, Pro free calls left today), from /api/holder. Needs no key. */
|
|
91
|
+
export declare function holderInfo(address: string, baseUrl?: string, timeoutMs?: number): Promise<any>;
|
|
90
92
|
/** Wafermap's resource catalog. Needs no wallet; gives up after `timeoutMs` like every other request. */
|
|
91
93
|
export declare function listResources(baseUrl?: string, timeoutMs?: number): Promise<any[]>;
|
|
92
94
|
export declare class Wafermap {
|
|
@@ -126,6 +128,11 @@ export declare class Wafermap {
|
|
|
126
128
|
private acquire;
|
|
127
129
|
private paidFetch;
|
|
128
130
|
resources(): Promise<any[]>;
|
|
131
|
+
private passCache;
|
|
132
|
+
/** A holder pass (shared/pass.ts) signed by this wallet, valid 24 h and reused until its last 10 minutes. It
|
|
133
|
+
* proves the wallet to Wafermap for what its $WAFERMAP unlocks (Pro free calls, x402 Tracker Pro). Signing
|
|
134
|
+
* a message moves no funds. */
|
|
135
|
+
holderPass(): Promise<string>;
|
|
129
136
|
call(id: string, input?: Record<string, unknown>, o?: {
|
|
130
137
|
network?: Net;
|
|
131
138
|
}): Promise<{
|
|
@@ -139,6 +146,11 @@ export declare class Wafermap {
|
|
|
139
146
|
tx: string;
|
|
140
147
|
ms: number;
|
|
141
148
|
} | null;
|
|
149
|
+
free?: {
|
|
150
|
+
wallet: string;
|
|
151
|
+
left: number;
|
|
152
|
+
perDay: number;
|
|
153
|
+
};
|
|
142
154
|
}>;
|
|
143
155
|
discover(query: string, limit?: number): Promise<{
|
|
144
156
|
url: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { Wafermap, WafermapError, DEFAULT_LIMITS, DEFAULT_TIMEOUT_MS, checkPayment, listResources, mergeLog } from "./core.js";
|
|
1
|
+
export { Wafermap, WafermapError, DEFAULT_LIMITS, DEFAULT_TIMEOUT_MS, checkPayment, holderInfo, listResources, mergeLog } from "./core.js";
|
|
2
|
+
export { PASS_HEADER, passMessage, encodePass, decodePass, makePass } from "../shared/pass";
|
|
2
3
|
export type { Approval, Limits, Net, PaymentStatus, SpendEntry, SwapQuote, Token, WafermapOptions } from "./core.js";
|
|
3
4
|
export { x402fetch, readQuote, choose, signPayment, PAY_CHAINS, MAX_VALIDITY_SECONDS, X402Error } from "../shared/x402client";
|
|
4
5
|
export { quoteSwap, executeSwap, decodeSwap, KYBER_ROUTER, SwapError } from "../shared/swap";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wafermapxyz/cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"description": "Wafermap for agents: an encrypted local wallet that pays x402 resources, discovers and pays third-party x402 services (USDG on Robinhood Chain; USDC on Solana, Base, Arbitrum, Polygon), and swaps on Robinhood Chain and Base. CLI, SDK and MCP server.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|