@dexterai/x402 3.9.0 → 3.9.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/README.md +6 -2
- package/dist/adapters/index.cjs +1 -1
- package/dist/adapters/index.d.cts +1 -1
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.js +1 -1
- package/dist/client/index.cjs +1 -1
- package/dist/client/index.d.cts +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +1 -1
- package/dist/{constants-qU-4U3L-.d.cts → constants-D41hDAG6.d.cts} +13 -1
- package/dist/{constants-qU-4U3L-.d.ts → constants-D41hDAG6.d.ts} +13 -1
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.js +1 -1
- package/dist/server/index.cjs +3 -3
- package/dist/server/index.d.cts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +3 -3
- package/dist/tab/adapters/solana/index.cjs +1 -0
- package/dist/tab/adapters/solana/index.d.cts +123 -0
- package/dist/tab/adapters/solana/index.d.ts +123 -0
- package/dist/tab/adapters/solana/index.js +1 -0
- package/dist/tab/index.cjs +6 -0
- package/dist/tab/index.d.cts +29 -0
- package/dist/tab/index.d.ts +29 -0
- package/dist/tab/index.js +6 -0
- package/dist/tab/seller/index.cjs +6 -0
- package/dist/tab/seller/index.d.cts +291 -0
- package/dist/tab/seller/index.d.ts +291 -0
- package/dist/tab/seller/index.js +6 -0
- package/dist/types-DIrmhiD-.d.cts +234 -0
- package/dist/types-DIrmhiD-.d.ts +234 -0
- package/dist/utils/index.cjs +1 -1
- package/dist/utils/index.d.cts +10 -1
- package/dist/utils/index.d.ts +10 -1
- package/dist/utils/index.js +1 -1
- package/package.json +18 -1
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
var m=class extends Error{constructor(n,r){super(`Invalid voucher: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidVoucherError"}};import{PublicKey as X}from"@solana/web3.js";import j from"tweetnacl";import{sha256 as fe}from"@noble/hashes/sha256";import{p256 as be}from"@noble/curves/p256";import{PublicKey as E}from"@solana/web3.js";var ie=(()=>{let e=new Uint8Array(32);return e.set(new TextEncoder().encode("OTS_SESSION_REGISTER_V1"),0),e})(),se=(()=>{let e=new Uint8Array(32);return e.set(new TextEncoder().encode("OTS_SESSION_REVOKE_V1"),0),e})();function U(e){if(e.channelId.length!==32)throw new Error(`channelId must be 32 bytes, got ${e.channelId.length}`);let t=new Uint8Array(44),n=new DataView(t.buffer),r=0;if(t.set(e.channelId,r),r+=32,n.setBigUint64(r,e.cumulativeAmount,!0),r+=8,n.setUint32(r,e.sequenceNumber>>>0,!0),r+=4,r!==44)throw new Error(`internal: voucher payload wrong length ${r}, expected 44`);return t}import{PublicKey as I,TransactionInstruction as ce}from"@solana/web3.js";var v=new I("Hg3wRaydFtJhYrdvYrKECacpJYDsC9Px7yKmpncj2fhc"),le=new I("Secp256r1SigVerify1111111111111111111111111"),me=new I("Sysvar1nstructions1111111111111111111111111"),de=new Uint8Array([69,94,60,44,49,199,183,233]),pe=new Uint8Array([81,192,32,110,104,116,144,151]);var T="OTS_SESSION_REGISTER_V1",d=class extends Error{constructor(n,r){super(`Invalid registration: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidRegistrationError"}};function k(e){if(e.length!==180)throw new d("wrong_length",`expected 180, got ${e.length}`);let t=new TextDecoder().decode(e.slice(0,T.length));if(t!==T)throw new d("wrong_domain",`got "${t}"`);for(let s=T.length;s<32;s++)if(e[s]!==0)throw new d("wrong_domain",`non-NUL padding at byte ${s}`);let n=new DataView(e.buffer,e.byteOffset,e.byteLength),r=new E(e.slice(32,64)),i=new E(e.slice(64,96)),u=e.slice(96,128),p=n.getBigUint64(128,!0),g=n.getBigInt64(136,!0),o=new E(e.slice(144,176)),a=n.getUint32(176,!0);if(!r.equals(v))throw new d("wrong_program",`${r.toBase58()} is not ${v.toBase58()}`);if(p===0n)throw new d("cap_zero");let l=BigInt(Math.floor(Date.now()/1e3));if(g<=l)throw new d("expiry_in_past",`expires_at=${g}, now=${l}`);return{programId:r,vaultPda:i,sessionPubkey:new Uint8Array(u),maxAmount:p,expiresAt:g,allowedCounterparty:o,nonce:a}}var M=10,f=class extends Error{constructor(n,r){super(`On-chain verification failed: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="OnChainVerificationError"}};async function L(e,t){let n=await e.getAccountInfo(t,"finalized");if(!n)throw new f("vault_not_found",t.toBase58());if(!n.owner.equals(v))throw new f("wrong_program",`owner ${n.owner.toBase58()} is not the vault program`);let r=n.data,i=new Uint8Array(r.slice(M,M+33)),a=84+(r[83]===1?48:0)+32+32;if(r[a]!==1)return{passkeyPubkey:i,activeSessionPubkey:null};let s=a+1,y=new Uint8Array(r.slice(s,s+32));return{passkeyPubkey:i,activeSessionPubkey:y}}async function _(e,t){let n=await L(e,t.vaultPda);if(n.activeSessionPubkey===null)throw new f("session_not_active","vault has no active_session \u2014 was it revoked?");if(!J(n.activeSessionPubkey,t.sessionPubkey))throw new f("session_pubkey_mismatch",`on-chain ${q(n.activeSessionPubkey)} != registration ${q(t.sessionPubkey)}`);return{passkeyPubkey:n.passkeyPubkey}}var h=class extends Error{constructor(t){super(`Invalid voucher signature${t?`: ${t}`:""}`),this.name="InvalidVoucherSignatureError"}};function R(e,t){if(t.length!==32)throw new h(`channelIdBytes must be 32 bytes, got ${t.length}`);if(e.sessionPublicKey.length!==32)throw new h(`sessionPublicKey must be 32 bytes, got ${e.sessionPublicKey.length}`);if(e.sessionSignature.length!==64)throw new h(`sessionSignature must be 64 bytes, got ${e.sessionSignature.length}`);let n=U({channelId:t,cumulativeAmount:BigInt(e.payload.cumulativeAmount),sequenceNumber:e.payload.sequenceNumber});if(!j.sign.detached.verify(n,e.sessionSignature,e.sessionPublicKey))throw new h("ed25519 verify rejected")}var c=class extends Error{constructor(n,r){super(`Scope violation: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="ScopeViolationError"}};function V(e){let t=BigInt(e.voucher.payload.cumulativeAmount);if(t>e.registration.maxAmount)throw new c("cumulative_exceeds_cap",`${t} > ${e.registration.maxAmount}`);let n=BigInt(Math.floor(Date.now()/1e3));if(n>=e.registration.expiresAt)throw new c("session_expired",`now=${n} >= expiresAt=${e.registration.expiresAt}`);if(!e.registration.allowedCounterparty.equals(e.expectedCounterparty))throw new c("wrong_counterparty",`${e.registration.allowedCounterparty.toBase58()} != ${e.expectedCounterparty.toBase58()}`);if(e.previousCumulativeAtomic!==void 0){let r=BigInt(e.previousCumulativeAtomic);if(t<=r)throw new c("non_monotonic",`cumulative=${t} not > previous=${r}`)}}function J(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(e[n]!==t[n])return!1;return!0}function q(e){let t="";for(let n of e)t+=n.toString(16).padStart(2,"0");return t}import{promises as w}from"fs";import{join as G,dirname as Y}from"path";function W(e){return{payload:e.payload,sessionPublicKey:C(e.sessionPublicKey),sessionRegistration:C(e.sessionRegistration),sessionSignature:C(e.sessionSignature)}}function Z(e){return{payload:e.payload,sessionPublicKey:$(e.sessionPublicKey),sessionRegistration:$(e.sessionRegistration),sessionSignature:$(e.sessionSignature)}}function C(e){let t="";for(let n of e)t+=n.toString(16).padStart(2,"0");return t}function $(e){if(e.length%2!==0)throw new Error(`hex length must be even, got ${e.length}`);let t=new Uint8Array(e.length/2);for(let n=0;n<t.length;n++)t[n]=parseInt(e.substr(n*2,2),16);return t}var b=class{map=new Map;async get(t){return this.map.get(t)??null}async set(t,n){this.map.set(t,n)}async delete(t){this.map.delete(t)}},K=class{constructor(t){this.dir=t}pathFor(t){if(!/^[a-z0-9_-]+$/i.test(t))throw new Error(`unsafe channelId for filesystem: ${t}`);return G(this.dir,`${t}.json`)}async get(t){try{let n=await w.readFile(this.pathFor(t),"utf8");return Z(JSON.parse(n))}catch(n){if(n?.code==="ENOENT")return null;throw n}}async set(t,n){let r=this.pathFor(t);await w.mkdir(Y(r),{recursive:!0});let i=`${r}.tmp`;await w.writeFile(i,JSON.stringify(W(n))),await w.rename(i,r)}async delete(t){try{await w.unlink(this.pathFor(t))}catch(n){if(n?.code!=="ENOENT")throw n}}};import{PublicKey as He}from"@solana/web3.js";import{bytesToHex as qe}from"@noble/hashes/utils";import _e from"tweetnacl";import{sha256 as Ce}from"@noble/hashes/sha256";var z=6;function A(e,t=z){if(!/^\d+(\.\d+)?$/.test(e))throw new Error(`amount must be a non-negative decimal string, got "${e}"`);let[n,r=""]=e.split(".");if(r.length>t)throw new Error(`amount "${e}" has more than ${t} decimals`);let i=r.padEnd(t,"0"),u=`${n}${i}`.replace(/^0+(?=\d)/,"");return u===""?"0":u}function S(e,t=z){if(!/^\d+$/.test(e))throw new Error(`atomic must be a non-negative integer string, got "${e}"`);let n=e.padStart(t+1,"0"),r=n.slice(0,-t).replace(/^0+(?=\d)/,"")||"0",i=n.slice(-t).replace(/0+$/,"");return i?`${r}.${i}`:r}var N="x-tab-voucher",O=class{map=new Map;get(t){return this.map.get(t)}set(t,n){this.map.set(t,n)}update(t,n){let r=this.map.get(t);r&&(r.lastCumulativeAtomic=n)}delete(t){this.map.delete(t)}},B=class{constructor(t,n,r,i){this.chargeImpl=i;this.channelId=t,this.network=n,this.cumulativeAtomic=r}channelId;network;sessionPublicKey=null;cumulativeAtomic;cumulative(){return S(this.cumulativeAtomic.toString())}bumpCumulative(t){this.cumulativeAtomic=t}setSessionPublicKey(t){this.sessionPublicKey=t}async charge(t){return this.chargeImpl(t)}};function Q(e){if(typeof e!="string"||e.length===0)throw new m("signature_invalid",`missing ${N} header`);let t;try{t=Buffer.from(e,"base64").toString("utf8")}catch{throw new m("signature_invalid","malformed base64")}let n;try{n=JSON.parse(t)}catch{throw new m("signature_invalid","malformed JSON")}if(!n||typeof n!="object"||!n.payload||!n.sessionPublicKey)throw new m("signature_invalid","missing required fields");return{payload:n.payload,sessionPublicKey:x(n.sessionPublicKey),sessionRegistration:x(n.sessionRegistration),sessionSignature:x(n.sessionSignature)}}function x(e){if(typeof e!="string"||e.length%2!==0)throw new m("signature_invalid",`bad hex: ${typeof e}`);let t=new Uint8Array(e.length/2);for(let n=0;n<t.length;n++)t[n]=parseInt(e.substr(n*2,2),16);return t}function ee(e){if(!/^[0-9a-f]{64}$/i.test(e))throw new m("signature_invalid",`channelId must be 64-char hex, got "${e}"`);return x(e)}function te(e){let t=e.store??new b,n=new O,r=typeof e.sellerPubkey=="string"?new X(e.sellerPubkey):e.sellerPubkey,i=e.maxPerVoucherAtomic?BigInt(e.maxPerVoucherAtomic):BigInt(A(e.perUnit))*100n;return async(u,p,g)=>{try{let o=Q(u.headers[N]),a=o.payload.channelId,l=ee(a),s=n.get(a);if(!s){let P=k(o.sessionRegistration);await _(e.connection,P),s={registration:P,lastCumulativeAtomic:"0"},n.set(a,s)}R(o,l),V({registration:s.registration,voucher:o,expectedCounterparty:r,previousCumulativeAtomic:s.lastCumulativeAtomic});let y=BigInt(o.payload.cumulativeAmount),F=BigInt(s.lastCumulativeAtomic),D=y-F;if(D>i)throw new c("cumulative_exceeds_cap",`single voucher increment ${D} exceeds maxPerVoucherAtomic ${i}`);await t.set(a,o),n.update(a,o.payload.cumulativeAmount);let H=new B(a,e.network,y,async P=>{throw new Error("SellerTab.charge() is not driven by the route handler; the buyer presents a fresh voucher per chunk. Use openSse(res, tab) for the metered-stream pattern.")});H.setSessionPublicKey(o.sessionPublicKey),u.tab=H,g()}catch(o){if(o instanceof m||o instanceof d||o instanceof f||o instanceof h||o instanceof c){p.status(402).json({error:"invalid_voucher",reason:o.reason??"unknown",detail:o.message});return}g(o)}}}function ne(e){if(!e.tab)throw new Error("req.tab is missing \u2014 did tabMiddleware run on this route?");return e.tab}function re(e,t){if(!t.tab)throw new Error("openSse requires options.tab");e.headersSent||(e.setHeader("Content-Type","text/event-stream"),e.setHeader("Cache-Control","no-cache"),e.setHeader("Connection","keep-alive"),typeof e.flushHeaders=="function"&&e.flushHeaders());let n=t.tab,r=BigInt(A(n.cumulative())),i=t.perUnit?BigInt(A(t.perUnit)):null,u=0n,p=!1;function g(l=1){if(p)return Promise.reject(new Error("meter ended"));if(i===null)return Promise.reject(new Error("charge() needs options.perUnit"));let s=i*BigInt(l),y=u+s;return y>r?Promise.reject(new c("cumulative_exceeds_cap",`chunk would push request total to ${S(y.toString())} beyond voucher-authorized budget ${S(r.toString())}`)):(u=y,Promise.resolve())}function o(l){if(p)throw new Error("meter ended");let y=(typeof l=="string"?l:Buffer.from(l).toString("utf8")).replace(/\n/g,"\\n");e.write(`data: ${y}
|
|
2
|
+
|
|
3
|
+
`)}function a(){p||(p=!0,e.write(`event: end
|
|
4
|
+
data: {"chargedAtomic":"${u}"}
|
|
5
|
+
|
|
6
|
+
`),e.end())}return{charge:g,send:o,end:a}}export{K as FileVoucherStore,b as InMemoryVoucherStore,d as InvalidRegistrationError,m as InvalidVoucherError,h as InvalidVoucherSignatureError,f as OnChainVerificationError,c as ScopeViolationError,N as TAB_VOUCHER_HEADER,V as enforceScope,re as openSse,k as parseRegistration,L as readVaultState,ne as requireTab,te as tabMiddleware,_ as verifyRegistrationOnChain,R as verifyVoucherSignature};
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @dexterai/x402/tab — type contract for the OTS-backed streaming payment module.
|
|
3
|
+
*
|
|
4
|
+
* Peer of `batch-settlement`. Where `batch-settlement` is for N discrete paid
|
|
5
|
+
* requests against one escrow channel, `tab` is for *continuous metered
|
|
6
|
+
* consumption* — tokens, bytes, frames, seconds — settled on close.
|
|
7
|
+
*
|
|
8
|
+
* Full design: see `docs/DESIGN-tab-streaming.md`. This file is the contract
|
|
9
|
+
* lock for Phase 1: the public types and option shapes that downstream phases
|
|
10
|
+
* must implement against without drift.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* CAIP-2-style network identifier. The buyer-side `openTab` accepts a string
|
|
14
|
+
* here so future networks (EVM L2s) require no API change — only a new
|
|
15
|
+
* VaultAdapter implementation.
|
|
16
|
+
*/
|
|
17
|
+
type TabNetworkId = 'solana:mainnet' | (string & {});
|
|
18
|
+
/**
|
|
19
|
+
* Atomic-unit cumulative amount the seller is asking the buyer to authorize
|
|
20
|
+
* for a single voucher. Strings to avoid bigint JSON-serialization headaches
|
|
21
|
+
* across language boundaries.
|
|
22
|
+
*/
|
|
23
|
+
type AtomicAmount = string;
|
|
24
|
+
/**
|
|
25
|
+
* Human-readable amount (e.g. "0.001" USDC). Used at SDK boundaries; converted
|
|
26
|
+
* to atomic units internally per the vault's token decimals.
|
|
27
|
+
*/
|
|
28
|
+
type HumanAmount = string;
|
|
29
|
+
/**
|
|
30
|
+
* Scope of a session key — the limits the passkey embeds into its
|
|
31
|
+
* registration signature. The on-chain program (via Swig) and the seller's
|
|
32
|
+
* middleware (locally) both enforce these.
|
|
33
|
+
*/
|
|
34
|
+
interface SessionScope {
|
|
35
|
+
/** The specific tab this session is bound to. */
|
|
36
|
+
channelId: string;
|
|
37
|
+
/** Cumulative cap, atomic units. The session-key cannot sign beyond this. */
|
|
38
|
+
maxAmountAtomic: AtomicAmount;
|
|
39
|
+
/** Wall-clock expiry (unix seconds). Hard deadline regardless of usage. */
|
|
40
|
+
expiresAtUnix: number;
|
|
41
|
+
/** Counterparty restriction — typically the seller's address. */
|
|
42
|
+
allowedCounterparty: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* In-memory session key. NEVER persisted to disk. A crashed process forfeits
|
|
46
|
+
* the session and re-prompts the passkey on the next attempt — this is the
|
|
47
|
+
* right default because a session key on disk is a real attack surface.
|
|
48
|
+
*/
|
|
49
|
+
interface SessionKey {
|
|
50
|
+
/** Public key the seller verifies signatures against. */
|
|
51
|
+
publicKey: Uint8Array;
|
|
52
|
+
/** Private key — in-memory only. */
|
|
53
|
+
privateKey: Uint8Array;
|
|
54
|
+
/** Limits this session may operate within. */
|
|
55
|
+
scope: SessionScope;
|
|
56
|
+
/** The passkey signature authorizing this session. The seller verifies it
|
|
57
|
+
* against the vault's registered passkey on every voucher. */
|
|
58
|
+
registration: Uint8Array;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* What the buyer signs per stream chunk, and what the seller verifies before
|
|
62
|
+
* delivering. Cumulative-amount semantics: each voucher represents the TOTAL
|
|
63
|
+
* owed so far, not the incremental amount. Replay-resistant because vouchers
|
|
64
|
+
* monotonically increase.
|
|
65
|
+
*/
|
|
66
|
+
interface VoucherPayload {
|
|
67
|
+
channelId: string;
|
|
68
|
+
/** Total owed so far, atomic units. Must strictly exceed the prior voucher. */
|
|
69
|
+
cumulativeAmount: AtomicAmount;
|
|
70
|
+
/** Monotonic sequence number. Replay protection within a tab. */
|
|
71
|
+
sequenceNumber: number;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The full voucher as sent over the wire: payload + session signature +
|
|
75
|
+
* the registration that authorizes the signing session key. The seller's
|
|
76
|
+
* middleware verifies the registration's passkey signature once per session,
|
|
77
|
+
* caches the result, and verifies only the session-key signature per chunk.
|
|
78
|
+
*/
|
|
79
|
+
interface SignedVoucher {
|
|
80
|
+
payload: VoucherPayload;
|
|
81
|
+
sessionPublicKey: Uint8Array;
|
|
82
|
+
sessionRegistration: Uint8Array;
|
|
83
|
+
sessionSignature: Uint8Array;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Adapter for a specific chain's OTS vault implementation. The SDK calls into
|
|
87
|
+
* `authorizeSession()` ONCE per tab and `signWithSession()` many times. The
|
|
88
|
+
* adapter owns the chain-specific wiring (Solana passkey via WebAuthn or
|
|
89
|
+
* noble-curves, EVM passkey via 7212-aware smart account, etc.).
|
|
90
|
+
*
|
|
91
|
+
* IMPORTANT: this interface must remain stable across vault chains. New
|
|
92
|
+
* chains add adapters; the SDK call site does not change.
|
|
93
|
+
*/
|
|
94
|
+
interface VaultAdapter {
|
|
95
|
+
/** Which chain this adapter operates on. */
|
|
96
|
+
network: TabNetworkId;
|
|
97
|
+
/** Wallet holding the buyer's funds. */
|
|
98
|
+
swigAddress: string;
|
|
99
|
+
/** Program/contract account holding the OTS gate state. */
|
|
100
|
+
vaultPda: string;
|
|
101
|
+
/**
|
|
102
|
+
* Use the ROOT signer (passkey) to authorize a fresh session key. This is
|
|
103
|
+
* the only call that prompts the user. Returns a session that can be passed
|
|
104
|
+
* to `signWithSession` freely until the scope's cap or expiry is reached.
|
|
105
|
+
*/
|
|
106
|
+
authorizeSession(scope: SessionScope): Promise<SessionKey>;
|
|
107
|
+
/**
|
|
108
|
+
* Use the session key to sign a voucher. Cheap. Never prompts. The seller
|
|
109
|
+
* verifies against the session's registration; the session's registration
|
|
110
|
+
* was passkey-signed by `authorizeSession`.
|
|
111
|
+
*/
|
|
112
|
+
signWithSession(session: SessionKey, payload: VoucherPayload): Promise<SignedVoucher>;
|
|
113
|
+
/**
|
|
114
|
+
* Authorize tab open on chain. Posted through the facilitator, which calls
|
|
115
|
+
* `settle_voucher(amount: 0, increment: true)` with the recorded authority.
|
|
116
|
+
*/
|
|
117
|
+
signOpenTab(session: SessionKey, channelId: string): Promise<Uint8Array>;
|
|
118
|
+
/**
|
|
119
|
+
* Authorize tab close on chain. Carries the final cumulative amount; the
|
|
120
|
+
* facilitator settles via `settle_voucher(amount, increment: false)`.
|
|
121
|
+
*/
|
|
122
|
+
signCloseTab(session: SessionKey, channelId: string, cumulativeAmount: AtomicAmount): Promise<Uint8Array>;
|
|
123
|
+
}
|
|
124
|
+
/** Live state of a buyer's tab. All amounts human units. */
|
|
125
|
+
interface TabState {
|
|
126
|
+
/** Whether the tab is currently open (on chain) and accepting vouchers. */
|
|
127
|
+
isOpen: boolean;
|
|
128
|
+
/** Cumulative amount spent against this tab so far. */
|
|
129
|
+
spent: HumanAmount;
|
|
130
|
+
/** Remaining headroom under the session's cap. */
|
|
131
|
+
remaining: HumanAmount;
|
|
132
|
+
/** Seconds until session expiry. May be 0 even if isOpen — close ASAP. */
|
|
133
|
+
expiresInSec: number;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The buyer's handle to an open tab. Returned by `openTab`; the buyer drives
|
|
137
|
+
* one or more `stream()` calls against it, then `close()`.
|
|
138
|
+
*
|
|
139
|
+
* Mental model: this is to `tab` what `BatchSettlementChannel` is to
|
|
140
|
+
* `batch-settlement` — a per-session live object that owns the buyer's
|
|
141
|
+
* accounting and exposes a streaming I/O primitive.
|
|
142
|
+
*/
|
|
143
|
+
interface Tab {
|
|
144
|
+
/** Deterministic channel id derived from buyer/seller/scope/salt. */
|
|
145
|
+
readonly channelId: string;
|
|
146
|
+
/** Which network the underlying vault lives on. */
|
|
147
|
+
readonly network: TabNetworkId;
|
|
148
|
+
/** Live state. Re-reads after every voucher exchange. */
|
|
149
|
+
readonly state: TabState;
|
|
150
|
+
/**
|
|
151
|
+
* Streamed paid request. Returns an async iterable of chunks. Voucher
|
|
152
|
+
* signing is internal: the seller demands a fresh session-signed voucher
|
|
153
|
+
* before delivering each chunk, so the buyer is paid up exactly to what
|
|
154
|
+
* they've received.
|
|
155
|
+
*
|
|
156
|
+
* The async iterable break-on-throw on cap-exceeded, expiry, or signature
|
|
157
|
+
* rejection — the SDK never silently keeps streaming after a failure.
|
|
158
|
+
*/
|
|
159
|
+
stream(input: string | URL | Request, init?: RequestInit): Promise<AsyncIterable<Uint8Array>>;
|
|
160
|
+
/**
|
|
161
|
+
* Close the tab. Posts the cumulative voucher through the facilitator;
|
|
162
|
+
* facilitator calls `settle_voucher(amount, increment: false)` on chain.
|
|
163
|
+
* The session key is discarded after this resolves.
|
|
164
|
+
*
|
|
165
|
+
* After close(), the buyer's vault `request_withdrawal` is unblocked (the
|
|
166
|
+
* on-chain gate sees pending_voucher_count return to 0).
|
|
167
|
+
*/
|
|
168
|
+
close(): Promise<TabCloseResult>;
|
|
169
|
+
}
|
|
170
|
+
/** Result of `Tab.close()`. */
|
|
171
|
+
interface TabCloseResult {
|
|
172
|
+
/** Cumulative human amount settled on chain. */
|
|
173
|
+
settledAmount: HumanAmount;
|
|
174
|
+
/** Facilitator's on-chain settlement signature. */
|
|
175
|
+
settleTx: string;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Options for `openTab` — the buyer's session-opening call.
|
|
179
|
+
*
|
|
180
|
+
* The shape deliberately mirrors `openBatchChannel` so users coming from
|
|
181
|
+
* `batch-settlement` need only learn the new fields (`perUnitCap`,
|
|
182
|
+
* `sessionDuration`).
|
|
183
|
+
*/
|
|
184
|
+
interface OpenTabOptions {
|
|
185
|
+
/** OTS vault adapter — Solana adapter ships first; future EVM adapter slots in here. */
|
|
186
|
+
vault: VaultAdapter;
|
|
187
|
+
/** CAIP-2-style network the vault lives on; cross-checked against vault.network. */
|
|
188
|
+
network: TabNetworkId;
|
|
189
|
+
/** Seller's endpoint host (used for the counterparty binding + voucher routing). */
|
|
190
|
+
seller: string;
|
|
191
|
+
/** Max amount per voucher — caps how aggressive a single charge can be. */
|
|
192
|
+
perUnitCap: HumanAmount;
|
|
193
|
+
/** Max cumulative for the WHOLE tab — the session-key cap. */
|
|
194
|
+
totalCap: HumanAmount;
|
|
195
|
+
/** Session expiry, seconds from now. Default: 3600 (1 hour). */
|
|
196
|
+
sessionDuration?: number;
|
|
197
|
+
/** Facilitator base URL. Default: https://facilitator.dexter.cash, overridable. */
|
|
198
|
+
facilitatorUrl?: string;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Options for `resumeTab` — open a handle to a tab that was opened by a
|
|
202
|
+
* previous process. Recovery surface for crashed buyers.
|
|
203
|
+
*
|
|
204
|
+
* NOTE: a resumed tab requires a fresh session key, because session keys are
|
|
205
|
+
* memory-only by design. The first call after resume prompts the passkey
|
|
206
|
+
* once to authorize a new session bound to the same channelId.
|
|
207
|
+
*/
|
|
208
|
+
interface ResumeTabOptions {
|
|
209
|
+
vault: VaultAdapter;
|
|
210
|
+
network: TabNetworkId;
|
|
211
|
+
seller: string;
|
|
212
|
+
channelId: string;
|
|
213
|
+
perUnitCap: HumanAmount;
|
|
214
|
+
totalCap: HumanAmount;
|
|
215
|
+
sessionDuration?: number;
|
|
216
|
+
facilitatorUrl?: string;
|
|
217
|
+
}
|
|
218
|
+
/** Thrown when the SDK is invoked against a chain it does not yet support. */
|
|
219
|
+
declare class UnsupportedNetworkError extends Error {
|
|
220
|
+
readonly network: string;
|
|
221
|
+
constructor(network: string);
|
|
222
|
+
}
|
|
223
|
+
/** Thrown by a buyer call when the session-key cap or expiry would be exceeded. */
|
|
224
|
+
declare class SessionScopeExceededError extends Error {
|
|
225
|
+
readonly reason: 'cap_exceeded' | 'expired' | 'wrong_counterparty';
|
|
226
|
+
constructor(reason: 'cap_exceeded' | 'expired' | 'wrong_counterparty', detail?: string);
|
|
227
|
+
}
|
|
228
|
+
/** Thrown when the buyer tries to operate against a tab that has been closed. */
|
|
229
|
+
declare class TabClosedError extends Error {
|
|
230
|
+
readonly channelId: string;
|
|
231
|
+
constructor(channelId: string);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export { type AtomicAmount as A, type HumanAmount as H, type OpenTabOptions as O, type ResumeTabOptions as R, type SessionScope as S, type Tab as T, UnsupportedNetworkError as U, type VoucherPayload as V, type TabState as a, type TabCloseResult as b, type TabNetworkId as c, type SessionKey as d, type SignedVoucher as e, type VaultAdapter as f, SessionScopeExceededError as g, TabClosedError as h };
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @dexterai/x402/tab — type contract for the OTS-backed streaming payment module.
|
|
3
|
+
*
|
|
4
|
+
* Peer of `batch-settlement`. Where `batch-settlement` is for N discrete paid
|
|
5
|
+
* requests against one escrow channel, `tab` is for *continuous metered
|
|
6
|
+
* consumption* — tokens, bytes, frames, seconds — settled on close.
|
|
7
|
+
*
|
|
8
|
+
* Full design: see `docs/DESIGN-tab-streaming.md`. This file is the contract
|
|
9
|
+
* lock for Phase 1: the public types and option shapes that downstream phases
|
|
10
|
+
* must implement against without drift.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* CAIP-2-style network identifier. The buyer-side `openTab` accepts a string
|
|
14
|
+
* here so future networks (EVM L2s) require no API change — only a new
|
|
15
|
+
* VaultAdapter implementation.
|
|
16
|
+
*/
|
|
17
|
+
type TabNetworkId = 'solana:mainnet' | (string & {});
|
|
18
|
+
/**
|
|
19
|
+
* Atomic-unit cumulative amount the seller is asking the buyer to authorize
|
|
20
|
+
* for a single voucher. Strings to avoid bigint JSON-serialization headaches
|
|
21
|
+
* across language boundaries.
|
|
22
|
+
*/
|
|
23
|
+
type AtomicAmount = string;
|
|
24
|
+
/**
|
|
25
|
+
* Human-readable amount (e.g. "0.001" USDC). Used at SDK boundaries; converted
|
|
26
|
+
* to atomic units internally per the vault's token decimals.
|
|
27
|
+
*/
|
|
28
|
+
type HumanAmount = string;
|
|
29
|
+
/**
|
|
30
|
+
* Scope of a session key — the limits the passkey embeds into its
|
|
31
|
+
* registration signature. The on-chain program (via Swig) and the seller's
|
|
32
|
+
* middleware (locally) both enforce these.
|
|
33
|
+
*/
|
|
34
|
+
interface SessionScope {
|
|
35
|
+
/** The specific tab this session is bound to. */
|
|
36
|
+
channelId: string;
|
|
37
|
+
/** Cumulative cap, atomic units. The session-key cannot sign beyond this. */
|
|
38
|
+
maxAmountAtomic: AtomicAmount;
|
|
39
|
+
/** Wall-clock expiry (unix seconds). Hard deadline regardless of usage. */
|
|
40
|
+
expiresAtUnix: number;
|
|
41
|
+
/** Counterparty restriction — typically the seller's address. */
|
|
42
|
+
allowedCounterparty: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* In-memory session key. NEVER persisted to disk. A crashed process forfeits
|
|
46
|
+
* the session and re-prompts the passkey on the next attempt — this is the
|
|
47
|
+
* right default because a session key on disk is a real attack surface.
|
|
48
|
+
*/
|
|
49
|
+
interface SessionKey {
|
|
50
|
+
/** Public key the seller verifies signatures against. */
|
|
51
|
+
publicKey: Uint8Array;
|
|
52
|
+
/** Private key — in-memory only. */
|
|
53
|
+
privateKey: Uint8Array;
|
|
54
|
+
/** Limits this session may operate within. */
|
|
55
|
+
scope: SessionScope;
|
|
56
|
+
/** The passkey signature authorizing this session. The seller verifies it
|
|
57
|
+
* against the vault's registered passkey on every voucher. */
|
|
58
|
+
registration: Uint8Array;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* What the buyer signs per stream chunk, and what the seller verifies before
|
|
62
|
+
* delivering. Cumulative-amount semantics: each voucher represents the TOTAL
|
|
63
|
+
* owed so far, not the incremental amount. Replay-resistant because vouchers
|
|
64
|
+
* monotonically increase.
|
|
65
|
+
*/
|
|
66
|
+
interface VoucherPayload {
|
|
67
|
+
channelId: string;
|
|
68
|
+
/** Total owed so far, atomic units. Must strictly exceed the prior voucher. */
|
|
69
|
+
cumulativeAmount: AtomicAmount;
|
|
70
|
+
/** Monotonic sequence number. Replay protection within a tab. */
|
|
71
|
+
sequenceNumber: number;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The full voucher as sent over the wire: payload + session signature +
|
|
75
|
+
* the registration that authorizes the signing session key. The seller's
|
|
76
|
+
* middleware verifies the registration's passkey signature once per session,
|
|
77
|
+
* caches the result, and verifies only the session-key signature per chunk.
|
|
78
|
+
*/
|
|
79
|
+
interface SignedVoucher {
|
|
80
|
+
payload: VoucherPayload;
|
|
81
|
+
sessionPublicKey: Uint8Array;
|
|
82
|
+
sessionRegistration: Uint8Array;
|
|
83
|
+
sessionSignature: Uint8Array;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Adapter for a specific chain's OTS vault implementation. The SDK calls into
|
|
87
|
+
* `authorizeSession()` ONCE per tab and `signWithSession()` many times. The
|
|
88
|
+
* adapter owns the chain-specific wiring (Solana passkey via WebAuthn or
|
|
89
|
+
* noble-curves, EVM passkey via 7212-aware smart account, etc.).
|
|
90
|
+
*
|
|
91
|
+
* IMPORTANT: this interface must remain stable across vault chains. New
|
|
92
|
+
* chains add adapters; the SDK call site does not change.
|
|
93
|
+
*/
|
|
94
|
+
interface VaultAdapter {
|
|
95
|
+
/** Which chain this adapter operates on. */
|
|
96
|
+
network: TabNetworkId;
|
|
97
|
+
/** Wallet holding the buyer's funds. */
|
|
98
|
+
swigAddress: string;
|
|
99
|
+
/** Program/contract account holding the OTS gate state. */
|
|
100
|
+
vaultPda: string;
|
|
101
|
+
/**
|
|
102
|
+
* Use the ROOT signer (passkey) to authorize a fresh session key. This is
|
|
103
|
+
* the only call that prompts the user. Returns a session that can be passed
|
|
104
|
+
* to `signWithSession` freely until the scope's cap or expiry is reached.
|
|
105
|
+
*/
|
|
106
|
+
authorizeSession(scope: SessionScope): Promise<SessionKey>;
|
|
107
|
+
/**
|
|
108
|
+
* Use the session key to sign a voucher. Cheap. Never prompts. The seller
|
|
109
|
+
* verifies against the session's registration; the session's registration
|
|
110
|
+
* was passkey-signed by `authorizeSession`.
|
|
111
|
+
*/
|
|
112
|
+
signWithSession(session: SessionKey, payload: VoucherPayload): Promise<SignedVoucher>;
|
|
113
|
+
/**
|
|
114
|
+
* Authorize tab open on chain. Posted through the facilitator, which calls
|
|
115
|
+
* `settle_voucher(amount: 0, increment: true)` with the recorded authority.
|
|
116
|
+
*/
|
|
117
|
+
signOpenTab(session: SessionKey, channelId: string): Promise<Uint8Array>;
|
|
118
|
+
/**
|
|
119
|
+
* Authorize tab close on chain. Carries the final cumulative amount; the
|
|
120
|
+
* facilitator settles via `settle_voucher(amount, increment: false)`.
|
|
121
|
+
*/
|
|
122
|
+
signCloseTab(session: SessionKey, channelId: string, cumulativeAmount: AtomicAmount): Promise<Uint8Array>;
|
|
123
|
+
}
|
|
124
|
+
/** Live state of a buyer's tab. All amounts human units. */
|
|
125
|
+
interface TabState {
|
|
126
|
+
/** Whether the tab is currently open (on chain) and accepting vouchers. */
|
|
127
|
+
isOpen: boolean;
|
|
128
|
+
/** Cumulative amount spent against this tab so far. */
|
|
129
|
+
spent: HumanAmount;
|
|
130
|
+
/** Remaining headroom under the session's cap. */
|
|
131
|
+
remaining: HumanAmount;
|
|
132
|
+
/** Seconds until session expiry. May be 0 even if isOpen — close ASAP. */
|
|
133
|
+
expiresInSec: number;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The buyer's handle to an open tab. Returned by `openTab`; the buyer drives
|
|
137
|
+
* one or more `stream()` calls against it, then `close()`.
|
|
138
|
+
*
|
|
139
|
+
* Mental model: this is to `tab` what `BatchSettlementChannel` is to
|
|
140
|
+
* `batch-settlement` — a per-session live object that owns the buyer's
|
|
141
|
+
* accounting and exposes a streaming I/O primitive.
|
|
142
|
+
*/
|
|
143
|
+
interface Tab {
|
|
144
|
+
/** Deterministic channel id derived from buyer/seller/scope/salt. */
|
|
145
|
+
readonly channelId: string;
|
|
146
|
+
/** Which network the underlying vault lives on. */
|
|
147
|
+
readonly network: TabNetworkId;
|
|
148
|
+
/** Live state. Re-reads after every voucher exchange. */
|
|
149
|
+
readonly state: TabState;
|
|
150
|
+
/**
|
|
151
|
+
* Streamed paid request. Returns an async iterable of chunks. Voucher
|
|
152
|
+
* signing is internal: the seller demands a fresh session-signed voucher
|
|
153
|
+
* before delivering each chunk, so the buyer is paid up exactly to what
|
|
154
|
+
* they've received.
|
|
155
|
+
*
|
|
156
|
+
* The async iterable break-on-throw on cap-exceeded, expiry, or signature
|
|
157
|
+
* rejection — the SDK never silently keeps streaming after a failure.
|
|
158
|
+
*/
|
|
159
|
+
stream(input: string | URL | Request, init?: RequestInit): Promise<AsyncIterable<Uint8Array>>;
|
|
160
|
+
/**
|
|
161
|
+
* Close the tab. Posts the cumulative voucher through the facilitator;
|
|
162
|
+
* facilitator calls `settle_voucher(amount, increment: false)` on chain.
|
|
163
|
+
* The session key is discarded after this resolves.
|
|
164
|
+
*
|
|
165
|
+
* After close(), the buyer's vault `request_withdrawal` is unblocked (the
|
|
166
|
+
* on-chain gate sees pending_voucher_count return to 0).
|
|
167
|
+
*/
|
|
168
|
+
close(): Promise<TabCloseResult>;
|
|
169
|
+
}
|
|
170
|
+
/** Result of `Tab.close()`. */
|
|
171
|
+
interface TabCloseResult {
|
|
172
|
+
/** Cumulative human amount settled on chain. */
|
|
173
|
+
settledAmount: HumanAmount;
|
|
174
|
+
/** Facilitator's on-chain settlement signature. */
|
|
175
|
+
settleTx: string;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Options for `openTab` — the buyer's session-opening call.
|
|
179
|
+
*
|
|
180
|
+
* The shape deliberately mirrors `openBatchChannel` so users coming from
|
|
181
|
+
* `batch-settlement` need only learn the new fields (`perUnitCap`,
|
|
182
|
+
* `sessionDuration`).
|
|
183
|
+
*/
|
|
184
|
+
interface OpenTabOptions {
|
|
185
|
+
/** OTS vault adapter — Solana adapter ships first; future EVM adapter slots in here. */
|
|
186
|
+
vault: VaultAdapter;
|
|
187
|
+
/** CAIP-2-style network the vault lives on; cross-checked against vault.network. */
|
|
188
|
+
network: TabNetworkId;
|
|
189
|
+
/** Seller's endpoint host (used for the counterparty binding + voucher routing). */
|
|
190
|
+
seller: string;
|
|
191
|
+
/** Max amount per voucher — caps how aggressive a single charge can be. */
|
|
192
|
+
perUnitCap: HumanAmount;
|
|
193
|
+
/** Max cumulative for the WHOLE tab — the session-key cap. */
|
|
194
|
+
totalCap: HumanAmount;
|
|
195
|
+
/** Session expiry, seconds from now. Default: 3600 (1 hour). */
|
|
196
|
+
sessionDuration?: number;
|
|
197
|
+
/** Facilitator base URL. Default: https://facilitator.dexter.cash, overridable. */
|
|
198
|
+
facilitatorUrl?: string;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Options for `resumeTab` — open a handle to a tab that was opened by a
|
|
202
|
+
* previous process. Recovery surface for crashed buyers.
|
|
203
|
+
*
|
|
204
|
+
* NOTE: a resumed tab requires a fresh session key, because session keys are
|
|
205
|
+
* memory-only by design. The first call after resume prompts the passkey
|
|
206
|
+
* once to authorize a new session bound to the same channelId.
|
|
207
|
+
*/
|
|
208
|
+
interface ResumeTabOptions {
|
|
209
|
+
vault: VaultAdapter;
|
|
210
|
+
network: TabNetworkId;
|
|
211
|
+
seller: string;
|
|
212
|
+
channelId: string;
|
|
213
|
+
perUnitCap: HumanAmount;
|
|
214
|
+
totalCap: HumanAmount;
|
|
215
|
+
sessionDuration?: number;
|
|
216
|
+
facilitatorUrl?: string;
|
|
217
|
+
}
|
|
218
|
+
/** Thrown when the SDK is invoked against a chain it does not yet support. */
|
|
219
|
+
declare class UnsupportedNetworkError extends Error {
|
|
220
|
+
readonly network: string;
|
|
221
|
+
constructor(network: string);
|
|
222
|
+
}
|
|
223
|
+
/** Thrown by a buyer call when the session-key cap or expiry would be exceeded. */
|
|
224
|
+
declare class SessionScopeExceededError extends Error {
|
|
225
|
+
readonly reason: 'cap_exceeded' | 'expired' | 'wrong_counterparty';
|
|
226
|
+
constructor(reason: 'cap_exceeded' | 'expired' | 'wrong_counterparty', detail?: string);
|
|
227
|
+
}
|
|
228
|
+
/** Thrown when the buyer tries to operate against a tab that has been closed. */
|
|
229
|
+
declare class TabClosedError extends Error {
|
|
230
|
+
readonly channelId: string;
|
|
231
|
+
constructor(channelId: string);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export { type AtomicAmount as A, type HumanAmount as H, type OpenTabOptions as O, type ResumeTabOptions as R, type SessionScope as S, type Tab as T, UnsupportedNetworkError as U, type VoucherPayload as V, type TabState as a, type TabCloseResult as b, type TabNetworkId as c, type SessionKey as d, type SignedVoucher as e, type VaultAdapter as f, SessionScopeExceededError as g, TabClosedError as h };
|
package/dist/utils/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var T=Object.defineProperty;var W=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var P=Object.prototype.hasOwnProperty;var F=(t,e)=>{for(var s in e)T(t,s,{get:e[s],enumerable:!0})},$=(t,e,s,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of y(e))!P.call(t,r)&&r!==s&&T(t,r,{get:()=>e[r],enumerable:!(n=W(e,r))||n.enumerable});return t};var V=t=>$(T({},"__esModule",{value:!0}),t);var X={};F(X,{EVM_RPC_URLS:()=>B,SOLANA_RPC_URLS:()=>D,fromAtomicUnits:()=>L,getChainDisplayName:()=>M,getChainFamily:()=>_,getChainName:()=>g,getDefaultRpcUrl:()=>K,getExplorerUrl:()=>U,toAtomicUnits:()=>I});module.exports=V(X);var d="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",i="solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",b="solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";var c="eip155:8453",p="eip155:84532",E="eip155:42161",l="eip155:137",A="eip155:10",h="eip155:43114",m="eip155:56",u="eip155:1187947933",f="eip155:324705682",N="eip155:1";var H="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",J="0x55d398326f99059fF775485246999027B3197955",C="0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",Z={[m]:C,[c]:H,[p]:"0x036CbD53842c5426634e7929541eC2318f3dCF7e",[E]:"0xaf88d065e77c8cC2239327C5EDb3A432268e5831",[l]:"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",[A]:"0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",[h]:"0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",[u]:"0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",[f]:"0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",[N]:"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"},j={[J]:{symbol:"USDT",decimals:18},[C]:{symbol:"USDC",decimals:18}};var Q={[m]:56,[c]:8453,[p]:84532,[E]:42161,[l]:137,[A]:10,[h]:43114,[u]:1187947933,[f]:324705682,[N]:1},D={[d]:"https://api.dexter.cash/api/solana/rpc",[i]:"https://api.devnet.solana.com",[b]:"https://api.testnet.solana.com"},B={[m]:"https://api.dexter.cash/api/evm/bsc/rpc",[c]:"https://api.dexter.cash/api/base/rpc",[p]:"https://sepolia.base.org",[E]:"https://api.dexter.cash/api/evm/arbitrum/rpc",[l]:"https://api.dexter.cash/api/evm/polygon/rpc",[A]:"https://api.dexter.cash/api/evm/optimism/rpc",[h]:"https://api.dexter.cash/api/evm/avalanche/rpc",[u]:"https://skale-base.skalenodes.com/v1/base",[f]:"https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",[N]:"https://eth.llamarpc.com"};function I(t,e){if(!Number.isFinite(t))throw new Error(`toAtomicUnits: amount must be finite, got ${t}`);if(t<0)throw new Error(`toAtomicUnits: amount must be non-negative, got ${t}`);if(!Number.isInteger(e)||e<0)throw new Error(`toAtomicUnits: decimals must be a non-negative integer, got ${e}`);let s=Y(Math.abs(t)),[n,r=""]=s.split("."),x=r.slice(0,e).padEnd(e,"0");return BigInt(n+x).toString()}function Y(t){let e=t.toString();if(!/[eE]/.test(e))return e;let[s,n]=e.split(/[eE]/),r=parseInt(n,10),x=s.startsWith("-"),R=x?s.slice(1):s,[O,v=""]=R.split("."),a=O+v,o=O.length+r,S;return o<=0?S="0."+"0".repeat(-o)+a:o>=a.length?S=a+"0".repeat(o-a.length):S=a.slice(0,o)+"."+a.slice(o),(x?"-":"")+S}function L(t,e){let s=Math.pow(10,e);return Number(t)/s}function G(t){return t.startsWith("solana:")||t==="solana"}function q(t){return t.startsWith("eip155:")||["base","ethereum","arbitrum"].includes(t)}function _(t){return G(t)?"solana":q(t)?"evm":"unknown"}function K(t){let e=_(t);if(e==="solana")return t.includes("devnet")||t===i?"https://api.devnet.solana.com":t.includes("testnet")||t===b?"https://api.testnet.solana.com":"https://api.dexter.cash/api/solana/rpc";if(e==="evm"){if(t.startsWith("eip155:"))switch(t.split(":")[1]){case"8453":return"https://api.dexter.cash/api/base/rpc";case"84532":return"https://sepolia.base.org";case"1":return"https://eth.llamarpc.com";case"42161":return"https://arb1.arbitrum.io/rpc";default:return"https://api.dexter.cash/api/base/rpc"}return t==="base"?"https://api.dexter.cash/api/base/rpc":t==="ethereum"?"https://eth.llamarpc.com":t==="arbitrum"?"https://arb1.arbitrum.io/rpc":"https://api.dexter.cash/api/base/rpc"}return"https://api.dexter.cash/api/solana/rpc"}function g(t){return{[d]:"Solana",[i]:"Solana Devnet",[b]:"Solana Testnet",solana:"Solana","solana-devnet":"Solana Devnet","solana-testnet":"Solana Testnet",[c]:"Base",[p]:"Base Sepolia",[N]:"Ethereum",[E]:"Arbitrum",[l]:"Polygon",[A]:"Optimism",[h]:"Avalanche",[m]:"BSC",[u]:"SKALE Base",[f]:"SKALE Base Sepolia",base:"Base","base-sepolia":"Base Sepolia",ethereum:"Ethereum",arbitrum:"Arbitrum",polygon:"Polygon",optimism:"Optimism",avalanche:"Avalanche",bsc:"BSC","skale-base":"SKALE Base","skale-base-sepolia":"SKALE Base Sepolia"}[t]||t}function M(t,e){let s=g(t);return s===t?e:s}function U(t,e){let s=_(e);if(s==="solana")return e.includes("devnet")||e===i?`https://solscan.io/tx/${t}?cluster=devnet`:`https://www.orbmarkets.io/tx/${t}`;if(s==="evm"){let n="8453";switch(e.startsWith("eip155:")?n=e.split(":")[1]:e==="ethereum"?n="1":e==="arbitrum"?n="42161":e==="polygon"?n="137":e==="optimism"?n="10":e==="avalanche"?n="43114":e==="bsc"?n="56":e==="skale-base"?n="1187947933":e==="skale-base-sepolia"&&(n="324705682"),n){case"8453":return`https://basescan.org/tx/${t}`;case"84532":return`https://sepolia.basescan.org/tx/${t}`;case"1":return`https://etherscan.io/tx/${t}`;case"42161":return`https://arbiscan.io/tx/${t}`;case"137":return`https://polygonscan.com/tx/${t}`;case"10":return`https://optimistic.etherscan.io/tx/${t}`;case"43114":return`https://snowtrace.io/tx/${t}`;case"56":return`https://bscscan.com/tx/${t}`;case"1187947933":return`https://elated-tan-skat.explorer.mainnet.skalenodes.com/tx/${t}`;case"324705682":return`https://base-sepolia-testnet.explorer.skalenodes.com/tx/${t}`;default:return`https://basescan.org/tx/${t}`}}return`https://solscan.io/tx/${t}`}0&&(module.exports={EVM_RPC_URLS,SOLANA_RPC_URLS,fromAtomicUnits,getChainDisplayName,getChainFamily,getChainName,getDefaultRpcUrl,getExplorerUrl,toAtomicUnits});
|
package/dist/utils/index.d.cts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { q as EVM_RPC_URLS, p as SOLANA_RPC_URLS } from '../constants-D41hDAG6.cjs';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Utility Functions
|
|
3
5
|
*
|
|
@@ -48,6 +50,13 @@ type ChainFamily = 'solana' | 'evm' | 'unknown';
|
|
|
48
50
|
* ```
|
|
49
51
|
*/
|
|
50
52
|
declare function getChainFamily(network: string): ChainFamily;
|
|
53
|
+
/**
|
|
54
|
+
* Get default RPC URL for a network
|
|
55
|
+
*
|
|
56
|
+
* @param network - CAIP-2 network identifier
|
|
57
|
+
* @returns Default RPC URL
|
|
58
|
+
*/
|
|
59
|
+
declare function getDefaultRpcUrl(network: string): string;
|
|
51
60
|
/**
|
|
52
61
|
* Get human-readable chain name
|
|
53
62
|
*
|
|
@@ -78,4 +87,4 @@ declare function getChainDisplayName(network: string, family: string): string;
|
|
|
78
87
|
*/
|
|
79
88
|
declare function getExplorerUrl(txSignature: string, network: string): string;
|
|
80
89
|
|
|
81
|
-
export { type ChainFamily, fromAtomicUnits, getChainDisplayName, getChainFamily, getChainName, getExplorerUrl, toAtomicUnits };
|
|
90
|
+
export { type ChainFamily, fromAtomicUnits, getChainDisplayName, getChainFamily, getChainName, getDefaultRpcUrl, getExplorerUrl, toAtomicUnits };
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { q as EVM_RPC_URLS, p as SOLANA_RPC_URLS } from '../constants-D41hDAG6.js';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Utility Functions
|
|
3
5
|
*
|
|
@@ -48,6 +50,13 @@ type ChainFamily = 'solana' | 'evm' | 'unknown';
|
|
|
48
50
|
* ```
|
|
49
51
|
*/
|
|
50
52
|
declare function getChainFamily(network: string): ChainFamily;
|
|
53
|
+
/**
|
|
54
|
+
* Get default RPC URL for a network
|
|
55
|
+
*
|
|
56
|
+
* @param network - CAIP-2 network identifier
|
|
57
|
+
* @returns Default RPC URL
|
|
58
|
+
*/
|
|
59
|
+
declare function getDefaultRpcUrl(network: string): string;
|
|
51
60
|
/**
|
|
52
61
|
* Get human-readable chain name
|
|
53
62
|
*
|
|
@@ -78,4 +87,4 @@ declare function getChainDisplayName(network: string, family: string): string;
|
|
|
78
87
|
*/
|
|
79
88
|
declare function getExplorerUrl(txSignature: string, network: string): string;
|
|
80
89
|
|
|
81
|
-
export { type ChainFamily, fromAtomicUnits, getChainDisplayName, getChainFamily, getChainName, getExplorerUrl, toAtomicUnits };
|
|
90
|
+
export { type ChainFamily, fromAtomicUnits, getChainDisplayName, getChainFamily, getChainName, getDefaultRpcUrl, getExplorerUrl, toAtomicUnits };
|
package/dist/utils/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var _="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",o="solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",S="solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";var i="eip155:8453",c="eip155:84532",p="eip155:42161",E="eip155:137",l="eip155:10",A="eip155:43114",h="eip155:56",m="eip155:1187947933",u="eip155:324705682",f="eip155:1";var D="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",B="0x55d398326f99059fF775485246999027B3197955",R="0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",$={[h]:R,[i]:D,[c]:"0x036CbD53842c5426634e7929541eC2318f3dCF7e",[p]:"0xaf88d065e77c8cC2239327C5EDb3A432268e5831",[E]:"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",[l]:"0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",[A]:"0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",[m]:"0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",[u]:"0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",[f]:"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"},V={[B]:{symbol:"USDT",decimals:18},[R]:{symbol:"USDC",decimals:18}};var H={[h]:56,[i]:8453,[c]:84532,[p]:42161,[E]:137,[l]:10,[A]:43114,[m]:1187947933,[u]:324705682,[f]:1},I={[_]:"https://api.dexter.cash/api/solana/rpc",[o]:"https://api.devnet.solana.com",[S]:"https://api.testnet.solana.com"},L={[h]:"https://api.dexter.cash/api/evm/bsc/rpc",[i]:"https://api.dexter.cash/api/base/rpc",[c]:"https://sepolia.base.org",[p]:"https://api.dexter.cash/api/evm/arbitrum/rpc",[E]:"https://api.dexter.cash/api/evm/polygon/rpc",[l]:"https://api.dexter.cash/api/evm/optimism/rpc",[A]:"https://api.dexter.cash/api/evm/avalanche/rpc",[m]:"https://skale-base.skalenodes.com/v1/base",[u]:"https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",[f]:"https://eth.llamarpc.com"};function K(t,e){if(!Number.isFinite(t))throw new Error(`toAtomicUnits: amount must be finite, got ${t}`);if(t<0)throw new Error(`toAtomicUnits: amount must be non-negative, got ${t}`);if(!Number.isInteger(e)||e<0)throw new Error(`toAtomicUnits: decimals must be a non-negative integer, got ${e}`);let n=M(Math.abs(t)),[s,b=""]=n.split("."),N=b.slice(0,e).padEnd(e,"0");return BigInt(s+N).toString()}function M(t){let e=t.toString();if(!/[eE]/.test(e))return e;let[n,s]=e.split(/[eE]/),b=parseInt(s,10),N=n.startsWith("-"),d=N?n.slice(1):n,[g,C=""]=d.split("."),r=g+C,a=g.length+b,x;return a<=0?x="0."+"0".repeat(-a)+r:a>=r.length?x=r+"0".repeat(a-r.length):x=r.slice(0,a)+"."+r.slice(a),(N?"-":"")+x}function U(t,e){let n=Math.pow(10,e);return Number(t)/n}function v(t){return t.startsWith("solana:")||t==="solana"}function W(t){return t.startsWith("eip155:")||["base","ethereum","arbitrum"].includes(t)}function T(t){return v(t)?"solana":W(t)?"evm":"unknown"}function y(t){let e=T(t);if(e==="solana")return t.includes("devnet")||t===o?"https://api.devnet.solana.com":t.includes("testnet")||t===S?"https://api.testnet.solana.com":"https://api.dexter.cash/api/solana/rpc";if(e==="evm"){if(t.startsWith("eip155:"))switch(t.split(":")[1]){case"8453":return"https://api.dexter.cash/api/base/rpc";case"84532":return"https://sepolia.base.org";case"1":return"https://eth.llamarpc.com";case"42161":return"https://arb1.arbitrum.io/rpc";default:return"https://api.dexter.cash/api/base/rpc"}return t==="base"?"https://api.dexter.cash/api/base/rpc":t==="ethereum"?"https://eth.llamarpc.com":t==="arbitrum"?"https://arb1.arbitrum.io/rpc":"https://api.dexter.cash/api/base/rpc"}return"https://api.dexter.cash/api/solana/rpc"}function O(t){return{[_]:"Solana",[o]:"Solana Devnet",[S]:"Solana Testnet",solana:"Solana","solana-devnet":"Solana Devnet","solana-testnet":"Solana Testnet",[i]:"Base",[c]:"Base Sepolia",[f]:"Ethereum",[p]:"Arbitrum",[E]:"Polygon",[l]:"Optimism",[A]:"Avalanche",[h]:"BSC",[m]:"SKALE Base",[u]:"SKALE Base Sepolia",base:"Base","base-sepolia":"Base Sepolia",ethereum:"Ethereum",arbitrum:"Arbitrum",polygon:"Polygon",optimism:"Optimism",avalanche:"Avalanche",bsc:"BSC","skale-base":"SKALE Base","skale-base-sepolia":"SKALE Base Sepolia"}[t]||t}function P(t,e){let n=O(t);return n===t?e:n}function F(t,e){let n=T(e);if(n==="solana")return e.includes("devnet")||e===o?`https://solscan.io/tx/${t}?cluster=devnet`:`https://www.orbmarkets.io/tx/${t}`;if(n==="evm"){let s="8453";switch(e.startsWith("eip155:")?s=e.split(":")[1]:e==="ethereum"?s="1":e==="arbitrum"?s="42161":e==="polygon"?s="137":e==="optimism"?s="10":e==="avalanche"?s="43114":e==="bsc"?s="56":e==="skale-base"?s="1187947933":e==="skale-base-sepolia"&&(s="324705682"),s){case"8453":return`https://basescan.org/tx/${t}`;case"84532":return`https://sepolia.basescan.org/tx/${t}`;case"1":return`https://etherscan.io/tx/${t}`;case"42161":return`https://arbiscan.io/tx/${t}`;case"137":return`https://polygonscan.com/tx/${t}`;case"10":return`https://optimistic.etherscan.io/tx/${t}`;case"43114":return`https://snowtrace.io/tx/${t}`;case"56":return`https://bscscan.com/tx/${t}`;case"1187947933":return`https://elated-tan-skat.explorer.mainnet.skalenodes.com/tx/${t}`;case"324705682":return`https://base-sepolia-testnet.explorer.skalenodes.com/tx/${t}`;default:return`https://basescan.org/tx/${t}`}}return`https://solscan.io/tx/${t}`}export{L as EVM_RPC_URLS,I as SOLANA_RPC_URLS,U as fromAtomicUnits,P as getChainDisplayName,T as getChainFamily,O as getChainName,y as getDefaultRpcUrl,F as getExplorerUrl,K as toAtomicUnits};
|