@piprail/sdk 1.21.0 → 1.21.1
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 +32 -0
- package/dist/index.cjs +58 -17
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +58 -17
- package/dist/{solana-4EMMGGDR.js → solana-IBVUZS54.js} +9 -0
- package/dist/{solana-CCVSMOKS.cjs → solana-WG7RGDSI.cjs} +9 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,38 @@ All notable changes to `@piprail/sdk` are documented here. The format
|
|
|
4
4
|
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the
|
|
5
5
|
versions follow [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [1.21.1] — 2026-06-13 — facilitator hardening + gasless auto-routing + agent-facing docs
|
|
8
|
+
|
|
9
|
+
A correctness/robustness patch over 1.21.0, after a full re-review and **live mainnet tests of the
|
|
10
|
+
facilitator path on both Solana and Base (EVM)**. Opt-in surface unchanged; `onchain-proof` still the
|
|
11
|
+
default everywhere.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- **Gasless auto-routing now works on Solana.** The Solana driver's `estimateCost` now reports the
|
|
15
|
+
`exact` rail as **~0 buyer gas** (the fee payer — a facilitator like PayAI, or your relayer —
|
|
16
|
+
broadcasts and pays the SOL fee), mirroring the EVM driver. Before, it reported the same fee as
|
|
17
|
+
`onchain-proof`, so `planPayment()`/`fetch({ autoRoute: true })` wouldn't prefer the gasless rail —
|
|
18
|
+
now they correctly pick it. (Live-proven: autoRoute chooses `exact` even when the buyer holds SOL.)
|
|
19
|
+
- **Buyer EIP-3009 domain read is resilient to a flaky RPC.** `payExactEvm` now retries the on-chain
|
|
20
|
+
EIP-712 domain read once before concluding a token "isn't EIP-3009", so a rate-limited public RPC can
|
|
21
|
+
no longer misreport real USDC as un-payable and block an otherwise-valid gasless payment. The error
|
|
22
|
+
message, if it still fails, now names the transient-RPC possibility instead of asserting non-EIP-3009.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
- **Permit2 can't be facilitator-settled — the gate now says so clearly.** A third-party facilitator
|
|
26
|
+
settles the standard EIP-3009 (EVM) / SVM (Solana) schemes, not PipRail's `x402ExactPermit2Proxy`. A
|
|
27
|
+
*forced* `exact: { method: 'permit2', settle: { facilitator } }` now throws a clear config error, and
|
|
28
|
+
an *auto*-selected Permit2 token is dropped to `onchain-proof`-only over a facilitator (rather than
|
|
29
|
+
advertising a rail it could never settle). Keyed off the resolved method, so Solana (`svm`) is unaffected.
|
|
30
|
+
- **Clearer facilitator-unreachable error.** When a Solana facilitator's `GET /supported` can't be read
|
|
31
|
+
at challenge time, the gate now explains the real cause (and points at `exact.settle.feePayer` /
|
|
32
|
+
`settle: 'self'`) instead of the misleading "none of the offered rails support it".
|
|
33
|
+
- **`PIPRAIL_AGENT_GUIDE` now teaches the gasless `exact` rail** — the two rails, that it's operator-opt-in,
|
|
34
|
+
that the on-chain method is auto-selected, and that on a timeout the `exact` `.ref` is an authorization
|
|
35
|
+
**nonce** (re-present the same authorization, never re-sign). Plus docs: the "whole model in 30 seconds"
|
|
36
|
+
(gas vs `onchain-proof` vs `exact`'s three methods), a "when the facilitator fails" breakdown, and
|
|
37
|
+
agent-toolkit/MCP gasless guidance.
|
|
38
|
+
|
|
7
39
|
## [1.21.0] — 2026-06-13 — standard `exact` rail on Solana (SVM) + fully-gasless facilitator mode
|
|
8
40
|
|
|
9
41
|
Opt-in, defaults unchanged. `onchain-proof` stays the default on every chain and is byte-identical.
|
package/dist/index.cjs
CHANGED
|
@@ -666,10 +666,14 @@ async function payExactEvm(input) {
|
|
|
666
666
|
`exact buyer rail requires an EOA signer; ${account.address} is a contract / EIP-1271 / EIP-7702-delegated account (no recoverable ECDSA signature). Pay via onchain-proof.`
|
|
667
667
|
);
|
|
668
668
|
}
|
|
669
|
-
|
|
669
|
+
let domain = await readExactDomain(publicClient, accept.asset);
|
|
670
|
+
if (!domain) {
|
|
671
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
672
|
+
domain = await readExactDomain(publicClient, accept.asset);
|
|
673
|
+
}
|
|
670
674
|
if (!domain) {
|
|
671
675
|
throw new (0, _chunkPA6YD3HLcjs.UnsupportedSchemeError)(
|
|
672
|
-
`exact: ${accept.asset} on ${accept.network} isn't an EIP-3009 token (USDT needs Permit2; native
|
|
676
|
+
`exact: couldn't derive the EIP-712 domain for ${accept.asset} on ${accept.network}. Either it isn't an EIP-3009 token (USDT needs Permit2; native/plain ERC-20 aren't exact-payable) \u2014 pay via onchain-proof \u2014 OR your RPC couldn't read it (transient): if the gate advertised eip3009, pass a reliable rpcUrl and retry.`
|
|
673
677
|
);
|
|
674
678
|
}
|
|
675
679
|
const g = globalThis.crypto;
|
|
@@ -1791,7 +1795,7 @@ var loaders = {
|
|
|
1791
1795
|
solana: async () => {
|
|
1792
1796
|
let mod;
|
|
1793
1797
|
try {
|
|
1794
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./solana-
|
|
1798
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./solana-WG7RGDSI.cjs")));
|
|
1795
1799
|
} catch (cause) {
|
|
1796
1800
|
throw new (0, _chunkPA6YD3HLcjs.MissingDriverError)(
|
|
1797
1801
|
`Solana selected, but its packages aren't installed. Run: npm install @solana/web3.js @solana/spl-token bs58`,
|
|
@@ -3647,6 +3651,18 @@ straight from your wallet to the server; PipRail custodies nothing. Follow this.
|
|
|
3647
3651
|
and return the result.
|
|
3648
3652
|
Always plan before you pay so you never commit to a payment you cannot finish.
|
|
3649
3653
|
|
|
3654
|
+
## Gasless \u2014 the exact rail (zero gas for you)
|
|
3655
|
+
A 402 may offer up to two rails; you don't choose per payment \u2014 the client does, automatically:
|
|
3656
|
+
- onchain-proof (PipRail's default): you broadcast the payment yourself and pay the network gas
|
|
3657
|
+
(the native coin \u2014 ETH/SOL/\u2026). Works on every chain.
|
|
3658
|
+
- exact (the ratified x402 rail, opt-in): you only SIGN; the server \u2014 or a facilitator it chose
|
|
3659
|
+
(e.g. PayAI) \u2014 broadcasts it, so you pay ZERO gas (you need only the token, no native coin). It
|
|
3660
|
+
works on EVM + Solana, and the on-chain method (EIP-3009 / Permit2 / SVM) is picked automatically.
|
|
3661
|
+
When the exact scheme is enabled AND balance-aware routing is on, paying picks the cheapest
|
|
3662
|
+
settleable rail \u2014 i.e. the gasless exact one. Nothing changes in your loop: quote \u2192 plan \u2192 pay is
|
|
3663
|
+
identical. The exact scheme is OPT-IN by the operator (MCP: PIPRAIL_SCHEMES=onchain-proof,exact);
|
|
3664
|
+
you can't enable it yourself, but you can report when a 402 needs it (see UNSUPPORTED_SCHEME below).
|
|
3665
|
+
|
|
3650
3666
|
## Reading a refusal \u2014 never crash, never double-spend
|
|
3651
3667
|
A failed pay returns a STRUCTURED object, never a thrown error you must catch:
|
|
3652
3668
|
{ ok:false, code, reason, explain, ref?, reasonCode?, declined? }
|
|
@@ -3664,9 +3680,13 @@ Branch on \`code\` (always reliable). Key cases:
|
|
|
3664
3680
|
- code:'INSUFFICIENT_FUNDS' \u2014 top up the wallet (token and/or native gas), retry.
|
|
3665
3681
|
- code:'PAYMENT_TIMEOUT' / 'MAX_RETRIES_EXCEEDED' / 'CONFIRMATION_TIMEOUT' \u2014 the
|
|
3666
3682
|
payment may ALREADY be on-chain. Recover using the proof on \`.ref\` (re-verify
|
|
3667
|
-
or re-submit it); never re-pay \u2014 a fresh payment would double-spend.
|
|
3683
|
+
or re-submit it); never re-pay \u2014 a fresh payment would double-spend. On a gasless
|
|
3684
|
+
exact rail \`.ref\` is the authorization NONCE, not a tx hash: re-present the SAME
|
|
3685
|
+
signed authorization, never sign a fresh one (that would risk a double-spend).
|
|
3668
3686
|
- code:'NO_COMPATIBLE_ACCEPT' / 'UNSUPPORTED_SCHEME' \u2014 the 402 isn't payable on
|
|
3669
3687
|
your chain/scheme; \`explain\` says whether it's the wrong chain or a scheme to enable.
|
|
3688
|
+
If it's a standard x402 server offering an exact rail, that's a config fix the operator makes
|
|
3689
|
+
once (enable the exact scheme); report it, don't retry the same call blindly.
|
|
3670
3690
|
|
|
3671
3691
|
## Knowing your leash \u2014 call piprail_budget
|
|
3672
3692
|
piprail_budget tells you how much budget and time you have left, per
|
|
@@ -4199,6 +4219,7 @@ function createPaymentGate(options) {
|
|
|
4199
4219
|
if (resolved) return resolved;
|
|
4200
4220
|
const p = (async () => {
|
|
4201
4221
|
const accepts = normaliseAccepts(options);
|
|
4222
|
+
const exactSkips = [];
|
|
4202
4223
|
const specs = await Promise.all(
|
|
4203
4224
|
accepts.map(async (a) => {
|
|
4204
4225
|
const net = await resolveNetwork2({ chain: a.chain, rpcUrl: _nullishCoalesce(a.rpcUrl, () => ( options.rpcUrl)) });
|
|
@@ -4212,13 +4233,17 @@ function createPaymentGate(options) {
|
|
|
4212
4233
|
const { asset, decimals, symbol } = net.resolveToken(a.token);
|
|
4213
4234
|
const amountBase = _chunkPA6YD3HLcjs.parseUnits.call(void 0, a.amount, decimals);
|
|
4214
4235
|
const spec = { net, asset, decimals, symbol, amountBase, amountFormatted: a.amount, payTo };
|
|
4215
|
-
if (options.exact)
|
|
4236
|
+
if (options.exact) {
|
|
4237
|
+
const outcome = await resolveExactRail(net, asset);
|
|
4238
|
+
if (outcome.rail) spec.exact = outcome.rail;
|
|
4239
|
+
else if (outcome.skipReason) exactSkips.push(outcome.skipReason);
|
|
4240
|
+
}
|
|
4216
4241
|
return spec;
|
|
4217
4242
|
})
|
|
4218
4243
|
);
|
|
4219
4244
|
if (options.exact && !specs.some((s) => s.exact)) {
|
|
4220
4245
|
throw new Error(
|
|
4221
|
-
"requirePayment: `exact` was requested but none of the offered rails support it. The standard `exact` rail is EVM ERC-20 (EIP-3009 \u2014 USDC / EURC \u2014 or Permit2, e.g. Binance-Peg USDC on BNB) or a Solana SPL token (SVM) \u2014 NOT native coins, NOT families without a standard `exact` scheme. Offer an EVM ERC-20 / Solana SPL token, or drop `exact`."
|
|
4246
|
+
"requirePayment: `exact` was requested but none of the offered rails support it. " + (exactSkips.length > 0 ? exactSkips.join(" ") : "The standard `exact` rail is EVM ERC-20 (EIP-3009 \u2014 USDC / EURC \u2014 or Permit2, e.g. Binance-Peg USDC on BNB) or a Solana SPL token (SVM) \u2014 NOT native coins, NOT families without a standard `exact` scheme. Offer an EVM ERC-20 / Solana SPL token, or drop `exact`.")
|
|
4222
4247
|
);
|
|
4223
4248
|
}
|
|
4224
4249
|
return specs;
|
|
@@ -4231,10 +4256,11 @@ function createPaymentGate(options) {
|
|
|
4231
4256
|
}
|
|
4232
4257
|
async function resolveExactRail(net, asset) {
|
|
4233
4258
|
const cfg = options.exact;
|
|
4234
|
-
|
|
4259
|
+
const settle = cfg.settle;
|
|
4260
|
+
if (!net.resolveExactRail) return {};
|
|
4235
4261
|
let relayer;
|
|
4236
4262
|
let feePayer;
|
|
4237
|
-
if (
|
|
4263
|
+
if (settle === "self") {
|
|
4238
4264
|
if (cfg.relayer === void 0) {
|
|
4239
4265
|
throw new Error(
|
|
4240
4266
|
"requirePayment: exact `settle: 'self'` needs a `relayer` wallet (the gas-paying key that broadcasts the settle), e.g. exact: { settle: 'self', relayer: { privateKey } }."
|
|
@@ -4242,21 +4268,36 @@ function createPaymentGate(options) {
|
|
|
4242
4268
|
}
|
|
4243
4269
|
relayer = net.bindWallet(cfg.relayer);
|
|
4244
4270
|
} else {
|
|
4245
|
-
feePayer =
|
|
4271
|
+
feePayer = settle.feePayer;
|
|
4246
4272
|
}
|
|
4247
4273
|
const method = _nullishCoalesce(cfg.method, () => ( "auto"));
|
|
4248
4274
|
let info = await net.resolveExactRail({ asset, method, relayer, feePayer });
|
|
4249
|
-
if (!info &&
|
|
4250
|
-
const discovered = await fetchFacilitatorFeePayer(
|
|
4251
|
-
if (discovered)
|
|
4275
|
+
if (!info && settle !== "self" && !feePayer && asset !== "native") {
|
|
4276
|
+
const discovered = await fetchFacilitatorFeePayer(settle.facilitator, net.network);
|
|
4277
|
+
if (!discovered) {
|
|
4278
|
+
return {
|
|
4279
|
+
skipReason: `${net.network}: couldn't read a fee payer from the facilitator (${settle.facilitator}/supported) \u2014 it may be down, or may not sponsor this network. Set \`exact.settle.feePayer\` explicitly to remove the runtime dependency, switch to \`settle: 'self'\` with your own relayer, or retry.`
|
|
4280
|
+
};
|
|
4281
|
+
}
|
|
4282
|
+
info = await net.resolveExactRail({ asset, method, relayer, feePayer: discovered });
|
|
4283
|
+
}
|
|
4284
|
+
if (!info) return {};
|
|
4285
|
+
if (settle !== "self" && info.method === "permit2") {
|
|
4286
|
+
if (cfg.method === "permit2") {
|
|
4287
|
+
throw new Error(
|
|
4288
|
+
"requirePayment: exact `method: 'permit2'` can't be settled by a third-party facilitator \u2014 facilitators settle the standard EIP-3009 (EVM) / SVM (Solana) schemes, not PipRail\u2019s Permit2 proxy. Use an EIP-3009 token (USDC / EURC) with the facilitator, or `settle: 'self'` (your own relayer) to settle Permit2 yourself."
|
|
4289
|
+
);
|
|
4290
|
+
}
|
|
4291
|
+
return {
|
|
4292
|
+
skipReason: `${net.network}: this token isn't EIP-3009 (auto-selected Permit2), which a third-party facilitator can't settle \u2014 it would serve onchain-proof only here. Use an EIP-3009 token (USDC / EURC) with the facilitator, or \`settle: 'self'\` to settle Permit2 yourself.`
|
|
4293
|
+
};
|
|
4252
4294
|
}
|
|
4253
|
-
|
|
4254
|
-
const mode = cfg.settle === "self" ? { kind: "self", relayer } : {
|
|
4295
|
+
const mode = settle === "self" ? { kind: "self", relayer } : {
|
|
4255
4296
|
kind: "facilitator",
|
|
4256
|
-
url:
|
|
4257
|
-
...
|
|
4297
|
+
url: settle.facilitator,
|
|
4298
|
+
...settle.authHeaders ? { authHeaders: settle.authHeaders } : {}
|
|
4258
4299
|
};
|
|
4259
|
-
return { method: info.method, ...info.extra ? { extra: info.extra } : {}, mode };
|
|
4300
|
+
return { rail: { method: info.method, ...info.extra ? { extra: info.extra } : {}, mode } };
|
|
4260
4301
|
}
|
|
4261
4302
|
const hasCustomStore = Boolean(options.isUsed || options.markUsed);
|
|
4262
4303
|
const localUsed = /* @__PURE__ */ new Map();
|
package/dist/index.d.cts
CHANGED
|
@@ -5545,7 +5545,7 @@ declare function formatSpendReport(summary: SpendSummary): string;
|
|
|
5545
5545
|
* literally, so a wrong name or order actively misleads. A test pins the load-
|
|
5546
5546
|
* bearing phrases.
|
|
5547
5547
|
*/
|
|
5548
|
-
declare const PIPRAIL_AGENT_GUIDE = "# Paying with PipRail \u2014 the agent contract\n\nYou can pay for x402 \"402 Payment Required\" resources autonomously. Money moves\nstraight from your wallet to the server; PipRail custodies nothing. Follow this.\n\n## The loop: quote \u2192 plan \u2192 pay\n1. piprail_quote_payment(url) \u2014 PRICE it. Returns the amount, token, chain, and\n whether it is within your spend policy. No funds move. Use it to decide if a\n resource is worth buying.\n2. piprail_plan_payment(url) \u2014 can I afford it NOW? Reads your balance, native gas,\n and recipient-readiness across every rail, and returns { payable, best,\n fundingHint, session? }. If payable is false, do NOT attempt the payment \u2014\n fundingHint says exactly what to fix.\n3. piprail_pay_request(url, method?, body?) \u2014 PAY (only if the plan was payable)\n and return the result.\nAlways plan before you pay so you never commit to a payment you cannot finish.\n\n## Reading a refusal \u2014 never crash, never double-spend\nA failed pay returns a STRUCTURED object, never a thrown error you must catch:\n { ok:false, code, reason, explain, ref?, reasonCode?, declined? }\nBranch on `code` (always reliable). Key cases:\n- declined:true with reasonCode:'SESSION_EXPIRED' \u2014 your time budget is over. This\n is TERMINAL: STOP. Do not retry ANY payment this process; it cannot be undone\n without a restart / a longer TTL.\n- declined:true with reasonCode:'APPROVAL' \u2014 a human (or hook) declined this\n payment. Terminal for this pay: do NOT auto-retry \u2014 they said no, or no one\n answered.\n- declined:true with reasonCode:'OUTSIDE_WINDOW' \u2014 your rolling rate-limit is\n exhausted. Wait for it to free, then retry; do not raise the amount.\n- declined:true with reasonCode:'POLICY' or 'BUDGET' \u2014 a spend cap or allowlist\n refused it. Don't retry the same payment; pick a cheaper/allowed one.\n- code:'INSUFFICIENT_FUNDS' \u2014 top up the wallet (token and/or native gas), retry.\n- code:'PAYMENT_TIMEOUT' / 'MAX_RETRIES_EXCEEDED' / 'CONFIRMATION_TIMEOUT' \u2014 the\n payment may ALREADY be on-chain. Recover using the proof on `.ref` (re-verify\n or re-submit it); never re-pay \u2014 a fresh payment would double-spend.\n- code:'NO_COMPATIBLE_ACCEPT' / 'UNSUPPORTED_SCHEME' \u2014 the 402 isn't payable on\n your chain/scheme; `explain` says whether it's the wrong chain or a scheme to enable.\n\n## Knowing your leash \u2014 call piprail_budget\npiprail_budget tells you how much budget and time you have left, per\n(network, asset), plus your spend so far. Read-only; moves no funds. Use it in\nMode A to self-check before paying.\n\n## Two modes\n- Mode A (headless, default): you run FREE inside a pre-set budget + time\n envelope. The policy IS the consent \u2014 there is no per-payment prompt. Stay\n inside it; piprail_budget shows what's left.\n- Mode B (supervised): the host may ask a human to approve each payment. A\n decline/cancel/timeout comes back as declined:true (reasonCode:'APPROVAL') \u2014\n do NOT retry it as if it were a transient error.\n\n## Hard facts\n- Spend caps are PER (network, asset). There is no single cross-token dollar cap \u2014\n budgets aren't summed across tokens (no price oracle).\n- Spend totals and the time envelope live IN-MEMORY for THIS process; they reset on restart\n (a convenience, not a durable ledger).\n";
|
|
5548
|
+
declare const PIPRAIL_AGENT_GUIDE = "# Paying with PipRail \u2014 the agent contract\n\nYou can pay for x402 \"402 Payment Required\" resources autonomously. Money moves\nstraight from your wallet to the server; PipRail custodies nothing. Follow this.\n\n## The loop: quote \u2192 plan \u2192 pay\n1. piprail_quote_payment(url) \u2014 PRICE it. Returns the amount, token, chain, and\n whether it is within your spend policy. No funds move. Use it to decide if a\n resource is worth buying.\n2. piprail_plan_payment(url) \u2014 can I afford it NOW? Reads your balance, native gas,\n and recipient-readiness across every rail, and returns { payable, best,\n fundingHint, session? }. If payable is false, do NOT attempt the payment \u2014\n fundingHint says exactly what to fix.\n3. piprail_pay_request(url, method?, body?) \u2014 PAY (only if the plan was payable)\n and return the result.\nAlways plan before you pay so you never commit to a payment you cannot finish.\n\n## Gasless \u2014 the exact rail (zero gas for you)\nA 402 may offer up to two rails; you don't choose per payment \u2014 the client does, automatically:\n- onchain-proof (PipRail's default): you broadcast the payment yourself and pay the network gas\n (the native coin \u2014 ETH/SOL/\u2026). Works on every chain.\n- exact (the ratified x402 rail, opt-in): you only SIGN; the server \u2014 or a facilitator it chose\n (e.g. PayAI) \u2014 broadcasts it, so you pay ZERO gas (you need only the token, no native coin). It\n works on EVM + Solana, and the on-chain method (EIP-3009 / Permit2 / SVM) is picked automatically.\nWhen the exact scheme is enabled AND balance-aware routing is on, paying picks the cheapest\nsettleable rail \u2014 i.e. the gasless exact one. Nothing changes in your loop: quote \u2192 plan \u2192 pay is\nidentical. The exact scheme is OPT-IN by the operator (MCP: PIPRAIL_SCHEMES=onchain-proof,exact);\nyou can't enable it yourself, but you can report when a 402 needs it (see UNSUPPORTED_SCHEME below).\n\n## Reading a refusal \u2014 never crash, never double-spend\nA failed pay returns a STRUCTURED object, never a thrown error you must catch:\n { ok:false, code, reason, explain, ref?, reasonCode?, declined? }\nBranch on `code` (always reliable). Key cases:\n- declined:true with reasonCode:'SESSION_EXPIRED' \u2014 your time budget is over. This\n is TERMINAL: STOP. Do not retry ANY payment this process; it cannot be undone\n without a restart / a longer TTL.\n- declined:true with reasonCode:'APPROVAL' \u2014 a human (or hook) declined this\n payment. Terminal for this pay: do NOT auto-retry \u2014 they said no, or no one\n answered.\n- declined:true with reasonCode:'OUTSIDE_WINDOW' \u2014 your rolling rate-limit is\n exhausted. Wait for it to free, then retry; do not raise the amount.\n- declined:true with reasonCode:'POLICY' or 'BUDGET' \u2014 a spend cap or allowlist\n refused it. Don't retry the same payment; pick a cheaper/allowed one.\n- code:'INSUFFICIENT_FUNDS' \u2014 top up the wallet (token and/or native gas), retry.\n- code:'PAYMENT_TIMEOUT' / 'MAX_RETRIES_EXCEEDED' / 'CONFIRMATION_TIMEOUT' \u2014 the\n payment may ALREADY be on-chain. Recover using the proof on `.ref` (re-verify\n or re-submit it); never re-pay \u2014 a fresh payment would double-spend. On a gasless\n exact rail `.ref` is the authorization NONCE, not a tx hash: re-present the SAME\n signed authorization, never sign a fresh one (that would risk a double-spend).\n- code:'NO_COMPATIBLE_ACCEPT' / 'UNSUPPORTED_SCHEME' \u2014 the 402 isn't payable on\n your chain/scheme; `explain` says whether it's the wrong chain or a scheme to enable.\n If it's a standard x402 server offering an exact rail, that's a config fix the operator makes\n once (enable the exact scheme); report it, don't retry the same call blindly.\n\n## Knowing your leash \u2014 call piprail_budget\npiprail_budget tells you how much budget and time you have left, per\n(network, asset), plus your spend so far. Read-only; moves no funds. Use it in\nMode A to self-check before paying.\n\n## Two modes\n- Mode A (headless, default): you run FREE inside a pre-set budget + time\n envelope. The policy IS the consent \u2014 there is no per-payment prompt. Stay\n inside it; piprail_budget shows what's left.\n- Mode B (supervised): the host may ask a human to approve each payment. A\n decline/cancel/timeout comes back as declined:true (reasonCode:'APPROVAL') \u2014\n do NOT retry it as if it were a transient error.\n\n## Hard facts\n- Spend caps are PER (network, asset). There is no single cross-token dollar cap \u2014\n budgets aren't summed across tokens (no price oracle).\n- Spend totals and the time envelope live IN-MEMORY for THIS process; they reset on restart\n (a convenience, not a durable ledger).\n";
|
|
5549
5549
|
/** Returns {@link PIPRAIL_AGENT_GUIDE} (a parity accessor for callers that prefer a function). */
|
|
5550
5550
|
declare function agentGuide(): string;
|
|
5551
5551
|
|
package/dist/index.d.ts
CHANGED
|
@@ -5545,7 +5545,7 @@ declare function formatSpendReport(summary: SpendSummary): string;
|
|
|
5545
5545
|
* literally, so a wrong name or order actively misleads. A test pins the load-
|
|
5546
5546
|
* bearing phrases.
|
|
5547
5547
|
*/
|
|
5548
|
-
declare const PIPRAIL_AGENT_GUIDE = "# Paying with PipRail \u2014 the agent contract\n\nYou can pay for x402 \"402 Payment Required\" resources autonomously. Money moves\nstraight from your wallet to the server; PipRail custodies nothing. Follow this.\n\n## The loop: quote \u2192 plan \u2192 pay\n1. piprail_quote_payment(url) \u2014 PRICE it. Returns the amount, token, chain, and\n whether it is within your spend policy. No funds move. Use it to decide if a\n resource is worth buying.\n2. piprail_plan_payment(url) \u2014 can I afford it NOW? Reads your balance, native gas,\n and recipient-readiness across every rail, and returns { payable, best,\n fundingHint, session? }. If payable is false, do NOT attempt the payment \u2014\n fundingHint says exactly what to fix.\n3. piprail_pay_request(url, method?, body?) \u2014 PAY (only if the plan was payable)\n and return the result.\nAlways plan before you pay so you never commit to a payment you cannot finish.\n\n## Reading a refusal \u2014 never crash, never double-spend\nA failed pay returns a STRUCTURED object, never a thrown error you must catch:\n { ok:false, code, reason, explain, ref?, reasonCode?, declined? }\nBranch on `code` (always reliable). Key cases:\n- declined:true with reasonCode:'SESSION_EXPIRED' \u2014 your time budget is over. This\n is TERMINAL: STOP. Do not retry ANY payment this process; it cannot be undone\n without a restart / a longer TTL.\n- declined:true with reasonCode:'APPROVAL' \u2014 a human (or hook) declined this\n payment. Terminal for this pay: do NOT auto-retry \u2014 they said no, or no one\n answered.\n- declined:true with reasonCode:'OUTSIDE_WINDOW' \u2014 your rolling rate-limit is\n exhausted. Wait for it to free, then retry; do not raise the amount.\n- declined:true with reasonCode:'POLICY' or 'BUDGET' \u2014 a spend cap or allowlist\n refused it. Don't retry the same payment; pick a cheaper/allowed one.\n- code:'INSUFFICIENT_FUNDS' \u2014 top up the wallet (token and/or native gas), retry.\n- code:'PAYMENT_TIMEOUT' / 'MAX_RETRIES_EXCEEDED' / 'CONFIRMATION_TIMEOUT' \u2014 the\n payment may ALREADY be on-chain. Recover using the proof on `.ref` (re-verify\n or re-submit it); never re-pay \u2014 a fresh payment would double-spend.\n- code:'NO_COMPATIBLE_ACCEPT' / 'UNSUPPORTED_SCHEME' \u2014 the 402 isn't payable on\n your chain/scheme; `explain` says whether it's the wrong chain or a scheme to enable.\n\n## Knowing your leash \u2014 call piprail_budget\npiprail_budget tells you how much budget and time you have left, per\n(network, asset), plus your spend so far. Read-only; moves no funds. Use it in\nMode A to self-check before paying.\n\n## Two modes\n- Mode A (headless, default): you run FREE inside a pre-set budget + time\n envelope. The policy IS the consent \u2014 there is no per-payment prompt. Stay\n inside it; piprail_budget shows what's left.\n- Mode B (supervised): the host may ask a human to approve each payment. A\n decline/cancel/timeout comes back as declined:true (reasonCode:'APPROVAL') \u2014\n do NOT retry it as if it were a transient error.\n\n## Hard facts\n- Spend caps are PER (network, asset). There is no single cross-token dollar cap \u2014\n budgets aren't summed across tokens (no price oracle).\n- Spend totals and the time envelope live IN-MEMORY for THIS process; they reset on restart\n (a convenience, not a durable ledger).\n";
|
|
5548
|
+
declare const PIPRAIL_AGENT_GUIDE = "# Paying with PipRail \u2014 the agent contract\n\nYou can pay for x402 \"402 Payment Required\" resources autonomously. Money moves\nstraight from your wallet to the server; PipRail custodies nothing. Follow this.\n\n## The loop: quote \u2192 plan \u2192 pay\n1. piprail_quote_payment(url) \u2014 PRICE it. Returns the amount, token, chain, and\n whether it is within your spend policy. No funds move. Use it to decide if a\n resource is worth buying.\n2. piprail_plan_payment(url) \u2014 can I afford it NOW? Reads your balance, native gas,\n and recipient-readiness across every rail, and returns { payable, best,\n fundingHint, session? }. If payable is false, do NOT attempt the payment \u2014\n fundingHint says exactly what to fix.\n3. piprail_pay_request(url, method?, body?) \u2014 PAY (only if the plan was payable)\n and return the result.\nAlways plan before you pay so you never commit to a payment you cannot finish.\n\n## Gasless \u2014 the exact rail (zero gas for you)\nA 402 may offer up to two rails; you don't choose per payment \u2014 the client does, automatically:\n- onchain-proof (PipRail's default): you broadcast the payment yourself and pay the network gas\n (the native coin \u2014 ETH/SOL/\u2026). Works on every chain.\n- exact (the ratified x402 rail, opt-in): you only SIGN; the server \u2014 or a facilitator it chose\n (e.g. PayAI) \u2014 broadcasts it, so you pay ZERO gas (you need only the token, no native coin). It\n works on EVM + Solana, and the on-chain method (EIP-3009 / Permit2 / SVM) is picked automatically.\nWhen the exact scheme is enabled AND balance-aware routing is on, paying picks the cheapest\nsettleable rail \u2014 i.e. the gasless exact one. Nothing changes in your loop: quote \u2192 plan \u2192 pay is\nidentical. The exact scheme is OPT-IN by the operator (MCP: PIPRAIL_SCHEMES=onchain-proof,exact);\nyou can't enable it yourself, but you can report when a 402 needs it (see UNSUPPORTED_SCHEME below).\n\n## Reading a refusal \u2014 never crash, never double-spend\nA failed pay returns a STRUCTURED object, never a thrown error you must catch:\n { ok:false, code, reason, explain, ref?, reasonCode?, declined? }\nBranch on `code` (always reliable). Key cases:\n- declined:true with reasonCode:'SESSION_EXPIRED' \u2014 your time budget is over. This\n is TERMINAL: STOP. Do not retry ANY payment this process; it cannot be undone\n without a restart / a longer TTL.\n- declined:true with reasonCode:'APPROVAL' \u2014 a human (or hook) declined this\n payment. Terminal for this pay: do NOT auto-retry \u2014 they said no, or no one\n answered.\n- declined:true with reasonCode:'OUTSIDE_WINDOW' \u2014 your rolling rate-limit is\n exhausted. Wait for it to free, then retry; do not raise the amount.\n- declined:true with reasonCode:'POLICY' or 'BUDGET' \u2014 a spend cap or allowlist\n refused it. Don't retry the same payment; pick a cheaper/allowed one.\n- code:'INSUFFICIENT_FUNDS' \u2014 top up the wallet (token and/or native gas), retry.\n- code:'PAYMENT_TIMEOUT' / 'MAX_RETRIES_EXCEEDED' / 'CONFIRMATION_TIMEOUT' \u2014 the\n payment may ALREADY be on-chain. Recover using the proof on `.ref` (re-verify\n or re-submit it); never re-pay \u2014 a fresh payment would double-spend. On a gasless\n exact rail `.ref` is the authorization NONCE, not a tx hash: re-present the SAME\n signed authorization, never sign a fresh one (that would risk a double-spend).\n- code:'NO_COMPATIBLE_ACCEPT' / 'UNSUPPORTED_SCHEME' \u2014 the 402 isn't payable on\n your chain/scheme; `explain` says whether it's the wrong chain or a scheme to enable.\n If it's a standard x402 server offering an exact rail, that's a config fix the operator makes\n once (enable the exact scheme); report it, don't retry the same call blindly.\n\n## Knowing your leash \u2014 call piprail_budget\npiprail_budget tells you how much budget and time you have left, per\n(network, asset), plus your spend so far. Read-only; moves no funds. Use it in\nMode A to self-check before paying.\n\n## Two modes\n- Mode A (headless, default): you run FREE inside a pre-set budget + time\n envelope. The policy IS the consent \u2014 there is no per-payment prompt. Stay\n inside it; piprail_budget shows what's left.\n- Mode B (supervised): the host may ask a human to approve each payment. A\n decline/cancel/timeout comes back as declined:true (reasonCode:'APPROVAL') \u2014\n do NOT retry it as if it were a transient error.\n\n## Hard facts\n- Spend caps are PER (network, asset). There is no single cross-token dollar cap \u2014\n budgets aren't summed across tokens (no price oracle).\n- Spend totals and the time envelope live IN-MEMORY for THIS process; they reset on restart\n (a convenience, not a durable ledger).\n";
|
|
5549
5549
|
/** Returns {@link PIPRAIL_AGENT_GUIDE} (a parity accessor for callers that prefer a function). */
|
|
5550
5550
|
declare function agentGuide(): string;
|
|
5551
5551
|
|
package/dist/index.js
CHANGED
|
@@ -666,10 +666,14 @@ async function payExactEvm(input) {
|
|
|
666
666
|
`exact buyer rail requires an EOA signer; ${account.address} is a contract / EIP-1271 / EIP-7702-delegated account (no recoverable ECDSA signature). Pay via onchain-proof.`
|
|
667
667
|
);
|
|
668
668
|
}
|
|
669
|
-
|
|
669
|
+
let domain = await readExactDomain(publicClient, accept.asset);
|
|
670
|
+
if (!domain) {
|
|
671
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
672
|
+
domain = await readExactDomain(publicClient, accept.asset);
|
|
673
|
+
}
|
|
670
674
|
if (!domain) {
|
|
671
675
|
throw new UnsupportedSchemeError(
|
|
672
|
-
`exact: ${accept.asset} on ${accept.network} isn't an EIP-3009 token (USDT needs Permit2; native
|
|
676
|
+
`exact: couldn't derive the EIP-712 domain for ${accept.asset} on ${accept.network}. Either it isn't an EIP-3009 token (USDT needs Permit2; native/plain ERC-20 aren't exact-payable) \u2014 pay via onchain-proof \u2014 OR your RPC couldn't read it (transient): if the gate advertised eip3009, pass a reliable rpcUrl and retry.`
|
|
673
677
|
);
|
|
674
678
|
}
|
|
675
679
|
const g = globalThis.crypto;
|
|
@@ -1791,7 +1795,7 @@ var loaders = {
|
|
|
1791
1795
|
solana: async () => {
|
|
1792
1796
|
let mod;
|
|
1793
1797
|
try {
|
|
1794
|
-
mod = await import("./solana-
|
|
1798
|
+
mod = await import("./solana-IBVUZS54.js");
|
|
1795
1799
|
} catch (cause) {
|
|
1796
1800
|
throw new MissingDriverError(
|
|
1797
1801
|
`Solana selected, but its packages aren't installed. Run: npm install @solana/web3.js @solana/spl-token bs58`,
|
|
@@ -3647,6 +3651,18 @@ straight from your wallet to the server; PipRail custodies nothing. Follow this.
|
|
|
3647
3651
|
and return the result.
|
|
3648
3652
|
Always plan before you pay so you never commit to a payment you cannot finish.
|
|
3649
3653
|
|
|
3654
|
+
## Gasless \u2014 the exact rail (zero gas for you)
|
|
3655
|
+
A 402 may offer up to two rails; you don't choose per payment \u2014 the client does, automatically:
|
|
3656
|
+
- onchain-proof (PipRail's default): you broadcast the payment yourself and pay the network gas
|
|
3657
|
+
(the native coin \u2014 ETH/SOL/\u2026). Works on every chain.
|
|
3658
|
+
- exact (the ratified x402 rail, opt-in): you only SIGN; the server \u2014 or a facilitator it chose
|
|
3659
|
+
(e.g. PayAI) \u2014 broadcasts it, so you pay ZERO gas (you need only the token, no native coin). It
|
|
3660
|
+
works on EVM + Solana, and the on-chain method (EIP-3009 / Permit2 / SVM) is picked automatically.
|
|
3661
|
+
When the exact scheme is enabled AND balance-aware routing is on, paying picks the cheapest
|
|
3662
|
+
settleable rail \u2014 i.e. the gasless exact one. Nothing changes in your loop: quote \u2192 plan \u2192 pay is
|
|
3663
|
+
identical. The exact scheme is OPT-IN by the operator (MCP: PIPRAIL_SCHEMES=onchain-proof,exact);
|
|
3664
|
+
you can't enable it yourself, but you can report when a 402 needs it (see UNSUPPORTED_SCHEME below).
|
|
3665
|
+
|
|
3650
3666
|
## Reading a refusal \u2014 never crash, never double-spend
|
|
3651
3667
|
A failed pay returns a STRUCTURED object, never a thrown error you must catch:
|
|
3652
3668
|
{ ok:false, code, reason, explain, ref?, reasonCode?, declined? }
|
|
@@ -3664,9 +3680,13 @@ Branch on \`code\` (always reliable). Key cases:
|
|
|
3664
3680
|
- code:'INSUFFICIENT_FUNDS' \u2014 top up the wallet (token and/or native gas), retry.
|
|
3665
3681
|
- code:'PAYMENT_TIMEOUT' / 'MAX_RETRIES_EXCEEDED' / 'CONFIRMATION_TIMEOUT' \u2014 the
|
|
3666
3682
|
payment may ALREADY be on-chain. Recover using the proof on \`.ref\` (re-verify
|
|
3667
|
-
or re-submit it); never re-pay \u2014 a fresh payment would double-spend.
|
|
3683
|
+
or re-submit it); never re-pay \u2014 a fresh payment would double-spend. On a gasless
|
|
3684
|
+
exact rail \`.ref\` is the authorization NONCE, not a tx hash: re-present the SAME
|
|
3685
|
+
signed authorization, never sign a fresh one (that would risk a double-spend).
|
|
3668
3686
|
- code:'NO_COMPATIBLE_ACCEPT' / 'UNSUPPORTED_SCHEME' \u2014 the 402 isn't payable on
|
|
3669
3687
|
your chain/scheme; \`explain\` says whether it's the wrong chain or a scheme to enable.
|
|
3688
|
+
If it's a standard x402 server offering an exact rail, that's a config fix the operator makes
|
|
3689
|
+
once (enable the exact scheme); report it, don't retry the same call blindly.
|
|
3670
3690
|
|
|
3671
3691
|
## Knowing your leash \u2014 call piprail_budget
|
|
3672
3692
|
piprail_budget tells you how much budget and time you have left, per
|
|
@@ -4199,6 +4219,7 @@ function createPaymentGate(options) {
|
|
|
4199
4219
|
if (resolved) return resolved;
|
|
4200
4220
|
const p = (async () => {
|
|
4201
4221
|
const accepts = normaliseAccepts(options);
|
|
4222
|
+
const exactSkips = [];
|
|
4202
4223
|
const specs = await Promise.all(
|
|
4203
4224
|
accepts.map(async (a) => {
|
|
4204
4225
|
const net = await resolveNetwork2({ chain: a.chain, rpcUrl: a.rpcUrl ?? options.rpcUrl });
|
|
@@ -4212,13 +4233,17 @@ function createPaymentGate(options) {
|
|
|
4212
4233
|
const { asset, decimals, symbol } = net.resolveToken(a.token);
|
|
4213
4234
|
const amountBase = parseUnits(a.amount, decimals);
|
|
4214
4235
|
const spec = { net, asset, decimals, symbol, amountBase, amountFormatted: a.amount, payTo };
|
|
4215
|
-
if (options.exact)
|
|
4236
|
+
if (options.exact) {
|
|
4237
|
+
const outcome = await resolveExactRail(net, asset);
|
|
4238
|
+
if (outcome.rail) spec.exact = outcome.rail;
|
|
4239
|
+
else if (outcome.skipReason) exactSkips.push(outcome.skipReason);
|
|
4240
|
+
}
|
|
4216
4241
|
return spec;
|
|
4217
4242
|
})
|
|
4218
4243
|
);
|
|
4219
4244
|
if (options.exact && !specs.some((s) => s.exact)) {
|
|
4220
4245
|
throw new Error(
|
|
4221
|
-
"requirePayment: `exact` was requested but none of the offered rails support it. The standard `exact` rail is EVM ERC-20 (EIP-3009 \u2014 USDC / EURC \u2014 or Permit2, e.g. Binance-Peg USDC on BNB) or a Solana SPL token (SVM) \u2014 NOT native coins, NOT families without a standard `exact` scheme. Offer an EVM ERC-20 / Solana SPL token, or drop `exact`."
|
|
4246
|
+
"requirePayment: `exact` was requested but none of the offered rails support it. " + (exactSkips.length > 0 ? exactSkips.join(" ") : "The standard `exact` rail is EVM ERC-20 (EIP-3009 \u2014 USDC / EURC \u2014 or Permit2, e.g. Binance-Peg USDC on BNB) or a Solana SPL token (SVM) \u2014 NOT native coins, NOT families without a standard `exact` scheme. Offer an EVM ERC-20 / Solana SPL token, or drop `exact`.")
|
|
4222
4247
|
);
|
|
4223
4248
|
}
|
|
4224
4249
|
return specs;
|
|
@@ -4231,10 +4256,11 @@ function createPaymentGate(options) {
|
|
|
4231
4256
|
}
|
|
4232
4257
|
async function resolveExactRail(net, asset) {
|
|
4233
4258
|
const cfg = options.exact;
|
|
4234
|
-
|
|
4259
|
+
const settle = cfg.settle;
|
|
4260
|
+
if (!net.resolveExactRail) return {};
|
|
4235
4261
|
let relayer;
|
|
4236
4262
|
let feePayer;
|
|
4237
|
-
if (
|
|
4263
|
+
if (settle === "self") {
|
|
4238
4264
|
if (cfg.relayer === void 0) {
|
|
4239
4265
|
throw new Error(
|
|
4240
4266
|
"requirePayment: exact `settle: 'self'` needs a `relayer` wallet (the gas-paying key that broadcasts the settle), e.g. exact: { settle: 'self', relayer: { privateKey } }."
|
|
@@ -4242,21 +4268,36 @@ function createPaymentGate(options) {
|
|
|
4242
4268
|
}
|
|
4243
4269
|
relayer = net.bindWallet(cfg.relayer);
|
|
4244
4270
|
} else {
|
|
4245
|
-
feePayer =
|
|
4271
|
+
feePayer = settle.feePayer;
|
|
4246
4272
|
}
|
|
4247
4273
|
const method = cfg.method ?? "auto";
|
|
4248
4274
|
let info = await net.resolveExactRail({ asset, method, relayer, feePayer });
|
|
4249
|
-
if (!info &&
|
|
4250
|
-
const discovered = await fetchFacilitatorFeePayer(
|
|
4251
|
-
if (discovered)
|
|
4275
|
+
if (!info && settle !== "self" && !feePayer && asset !== "native") {
|
|
4276
|
+
const discovered = await fetchFacilitatorFeePayer(settle.facilitator, net.network);
|
|
4277
|
+
if (!discovered) {
|
|
4278
|
+
return {
|
|
4279
|
+
skipReason: `${net.network}: couldn't read a fee payer from the facilitator (${settle.facilitator}/supported) \u2014 it may be down, or may not sponsor this network. Set \`exact.settle.feePayer\` explicitly to remove the runtime dependency, switch to \`settle: 'self'\` with your own relayer, or retry.`
|
|
4280
|
+
};
|
|
4281
|
+
}
|
|
4282
|
+
info = await net.resolveExactRail({ asset, method, relayer, feePayer: discovered });
|
|
4283
|
+
}
|
|
4284
|
+
if (!info) return {};
|
|
4285
|
+
if (settle !== "self" && info.method === "permit2") {
|
|
4286
|
+
if (cfg.method === "permit2") {
|
|
4287
|
+
throw new Error(
|
|
4288
|
+
"requirePayment: exact `method: 'permit2'` can't be settled by a third-party facilitator \u2014 facilitators settle the standard EIP-3009 (EVM) / SVM (Solana) schemes, not PipRail\u2019s Permit2 proxy. Use an EIP-3009 token (USDC / EURC) with the facilitator, or `settle: 'self'` (your own relayer) to settle Permit2 yourself."
|
|
4289
|
+
);
|
|
4290
|
+
}
|
|
4291
|
+
return {
|
|
4292
|
+
skipReason: `${net.network}: this token isn't EIP-3009 (auto-selected Permit2), which a third-party facilitator can't settle \u2014 it would serve onchain-proof only here. Use an EIP-3009 token (USDC / EURC) with the facilitator, or \`settle: 'self'\` to settle Permit2 yourself.`
|
|
4293
|
+
};
|
|
4252
4294
|
}
|
|
4253
|
-
|
|
4254
|
-
const mode = cfg.settle === "self" ? { kind: "self", relayer } : {
|
|
4295
|
+
const mode = settle === "self" ? { kind: "self", relayer } : {
|
|
4255
4296
|
kind: "facilitator",
|
|
4256
|
-
url:
|
|
4257
|
-
...
|
|
4297
|
+
url: settle.facilitator,
|
|
4298
|
+
...settle.authHeaders ? { authHeaders: settle.authHeaders } : {}
|
|
4258
4299
|
};
|
|
4259
|
-
return { method: info.method, ...info.extra ? { extra: info.extra } : {}, mode };
|
|
4300
|
+
return { rail: { method: info.method, ...info.extra ? { extra: info.extra } : {}, mode } };
|
|
4260
4301
|
}
|
|
4261
4302
|
const hasCustomStore = Boolean(options.isUsed || options.markUsed);
|
|
4262
4303
|
const localUsed = /* @__PURE__ */ new Map();
|
|
@@ -624,6 +624,15 @@ function makeSolanaNetwork(preset, rpcUrl) {
|
|
|
624
624
|
return { height: String(info.slot) };
|
|
625
625
|
},
|
|
626
626
|
async estimateCost(accept) {
|
|
627
|
+
if (accept.scheme === "exact") {
|
|
628
|
+
return nativeCost({
|
|
629
|
+
symbol: "SOL",
|
|
630
|
+
decimals: SOL_DECIMALS,
|
|
631
|
+
fee: 0n,
|
|
632
|
+
basis: "estimated",
|
|
633
|
+
detail: "gasless \u2014 the fee payer (facilitator/relayer) broadcasts and pays the SOL fee"
|
|
634
|
+
});
|
|
635
|
+
}
|
|
627
636
|
const base = 5000n;
|
|
628
637
|
if (accept.asset === "native") {
|
|
629
638
|
return nativeCost({
|
|
@@ -624,6 +624,15 @@ function makeSolanaNetwork(preset, rpcUrl) {
|
|
|
624
624
|
return { height: String(info.slot) };
|
|
625
625
|
},
|
|
626
626
|
async estimateCost(accept) {
|
|
627
|
+
if (accept.scheme === "exact") {
|
|
628
|
+
return _chunkPA6YD3HLcjs.nativeCost.call(void 0, {
|
|
629
|
+
symbol: "SOL",
|
|
630
|
+
decimals: SOL_DECIMALS,
|
|
631
|
+
fee: 0n,
|
|
632
|
+
basis: "estimated",
|
|
633
|
+
detail: "gasless \u2014 the fee payer (facilitator/relayer) broadcasts and pays the SOL fee"
|
|
634
|
+
});
|
|
635
|
+
}
|
|
627
636
|
const base = 5000n;
|
|
628
637
|
if (accept.asset === "native") {
|
|
629
638
|
return _chunkPA6YD3HLcjs.nativeCost.call(void 0, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@piprail/sdk",
|
|
3
|
-
"version": "1.21.
|
|
3
|
+
"version": "1.21.1",
|
|
4
4
|
"description": "Accept x402 crypto payments across 29 chains — every major EVM chain plus Solana, TON, Tron, NEAR, Sui, Aptos, Algorand, Stellar & XRPL — in a couple of lines. No backend, no database, no fee; payments settle straight to your wallet.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|