@dexterai/x402 3.15.0 → 3.17.0
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 +77 -1
- package/dist/client/index.cjs +1 -1
- package/dist/client/index.d.cts +3 -152
- package/dist/client/index.d.ts +3 -152
- package/dist/client/index.js +1 -1
- package/dist/tab/index.cjs +5 -5
- package/dist/tab/index.d.cts +137 -3
- package/dist/tab/index.d.ts +137 -3
- package/dist/tab/index.js +5 -5
- package/dist/tab/seller/index.cjs +4 -4
- package/dist/tab/seller/index.d.cts +65 -1
- package/dist/tab/seller/index.d.ts +65 -1
- package/dist/tab/seller/index.js +4 -4
- package/dist/types-B1wGPP7B.d.cts +154 -0
- package/dist/types-ZjcxOAbW.d.ts +154 -0
- package/package.json +1 -1
package/dist/tab/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
var
|
|
1
|
+
var pe=class extends Error{constructor(t){super(`Network ${t} is not yet supported by @dexterai/x402/tab`);this.network=t;this.name="UnsupportedNetworkError"}},me=class extends Error{constructor(t,r){super(`Session scope exceeded: ${t}${r?` (${r})`:""}`);this.reason=t;this.name="SessionScopeExceededError"}},Q=class extends Error{constructor(t){super(`Tab ${t} is already closed`);this.channelId=t;this.name="TabClosedError"}};import{PublicKey as ht}from"@solana/web3.js";import{bytesToHex as ee}from"@noble/hashes/utils";import In from"tweetnacl";import{sessionRegisterMessage as Ot,sessionRevokeMessage as Ut,voucherPayloadMessage as gt,buildVoucherMessage as Bt}from"@dexterai/vault/messages";import{sha256 as Dt}from"@noble/hashes/sha256";function yt(n){let e=new Uint8Array(8);new DataView(e.buffer).setBigUint64(0,n.nonce,!0);let t=new TextEncoder().encode(n.sellerUrl),r=Dt.create();return r.update(n.vaultPda.toBytes()),r.update(t),r.update(e),r.digest()}var Mt=3600,st="https://x402.dexter.cash",St=6;function Z(n,e=St){if(!/^\d+(\.\d+)?$/.test(n))throw new Error(`amount must be a non-negative decimal string, got "${n}"`);let[t,r=""]=n.split(".");if(r.length>e)throw new Error(`amount "${n}" has more than ${e} decimals`);let s=r.padEnd(e,"0"),a=`${t}${s}`.replace(/^0+(?=\d)/,"");return a===""?"0":a}function de(n,e=St){if(!/^\d+$/.test(n))throw new Error(`atomic must be a non-negative integer string, got "${n}"`);let t=n.padStart(e+1,"0"),r=t.slice(0,-e).replace(/^0+(?=\d)/,"")||"0",s=t.slice(-e).replace(/0+$/,"");return s?`${r}.${s}`:r}var at=class{channelId;network;counterparty;internals;cumulativeAtomic=0n;sequenceNumber=0;closed=!1;lastSignedVoucher=null;previousSignedVoucher=null;constructor(e){this.internals=e,this.channelId=e.channelIdHex,this.network=e.network,this.counterparty=e.counterparty}get state(){let e=this.internals.totalCapAtomic-this.cumulativeAtomic,t=Math.floor(Date.now()/1e3);return{isOpen:!this.closed,spent:de(this.cumulativeAtomic.toString()),remaining:de(e.toString()),expiresInSec:Math.max(0,this.internals.expiresAtUnix-t)}}async signNextVoucher(e){if(this.closed)throw new Q(this.channelId);let t=BigInt(e);if(t<=0n)throw new Error(`voucher increment must be > 0, got ${e}`);if(t>this.internals.perUnitCapAtomic)throw new me("cap_exceeded",`single voucher increment ${t} exceeds perUnitCap ${this.internals.perUnitCapAtomic}`);let r=this.cumulativeAtomic+t;if(r>this.internals.totalCapAtomic)throw new me("cap_exceeded",`cumulative ${r} would exceed totalCap ${this.internals.totalCapAtomic}`);let s=this.sequenceNumber+1,a={channelId:this.channelId,cumulativeAmount:r.toString(),sequenceNumber:s},o=await this.internals.vault.signWithSession(this.internals.session,a);return this.previousSignedVoucher=this.lastSignedVoucher,this.lastSignedVoucher=o,this.sequenceNumber=s,this.cumulativeAtomic=r,o}rollbackVoucher(e){let t=this.lastSignedVoucher;if(!t||t.payload.sequenceNumber!==e.payload.sequenceNumber||t.payload.cumulativeAmount!==e.payload.cumulativeAmount)return!1;let r=this.previousSignedVoucher;if(r)this.sequenceNumber=r.payload.sequenceNumber,this.cumulativeAtomic=BigInt(r.payload.cumulativeAmount),this.lastSignedVoucher=r;else if(t.payload.sequenceNumber===1)this.sequenceNumber=0,this.cumulativeAtomic=0n,this.lastSignedVoucher=null;else return!1;return this.previousSignedVoucher=null,!0}async stream(e,t){if(this.closed)throw new Q(this.channelId);let r=await this.signNextVoucher(this.internals.perUnitCapAtomic.toString()),s=new Headers(t?.headers);s.set("X-Tab-Voucher",qe(r)),s.set("Accept","text/event-stream");let a=await fetch(e,{...t,headers:s});if(!a.ok){let o=await a.text().catch(()=>"");throw new Error(`tab.stream HTTP ${a.status}: ${o.slice(0,500)}`)}if(!a.body)throw new Error("tab.stream response has no body");return Wt(a.body)}async close(){if(this.closed)throw new Q(this.channelId);let e={settleTx:""};return this.lastSignedVoucher&&this.cumulativeAtomic>0n&&(e=await $t(this.internals.facilitatorUrl,this.lastSignedVoucher,this.internals.network)),await this.internals.vault.signCloseTab(this.internals.session,this.channelId,this.cumulativeAtomic.toString()),this.closed=!0,this.internals.session.privateKey.fill(0),{settledAmount:de(this.cumulativeAtomic.toString()),...e}}};function qe(n){return Buffer.from(JSON.stringify({payload:n.payload,sessionPublicKey:ee(n.sessionPublicKey),sessionRegistration:ee(n.sessionRegistration),sessionSignature:ee(n.sessionSignature)}),"utf8").toString("base64")}async function $t(n,e,t){let r=`${n.replace(/\/$/,"")}/tab/settle`,s={channelId:e.payload.channelId,cumulativeAmount:e.payload.cumulativeAmount,sequenceNumber:e.payload.sequenceNumber,sessionPublicKey:ee(e.sessionPublicKey),sessionSignature:ee(e.sessionSignature),sessionRegistration:ee(e.sessionRegistration),network:t},a=await fetch(r,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(s)}),o=await a.text();if(!a.ok)throw new Error(`tab settle ${a.status}: ${o.slice(0,500)}`);let i;try{i=JSON.parse(o)}catch{throw new Error(`tab settle returned non-JSON: ${o.slice(0,200)}`)}if(!i.settleTx)throw new Error(`tab settle returned no settleTx: ${o.slice(0,200)}`);let c={settleTx:i.settleTx};return typeof i.grossAmount=="string"&&(c.grossAmount=i.grossAmount),typeof i.feeAmount=="string"&&(c.feeAmount=i.feeAmount),typeof i.netAmount=="string"&&(c.netAmount=i.netAmount),c}async function Lt(n,e,t,r,s){let a=`${n.replace(/\/$/,"")}/tab/open`,o=await fetch(a,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({buyer_swig_address:e,seller:s,max_amount_atomic:t.toString(),network:r})}),i=await o.json().catch(()=>({}));if(!o.ok||!i.success||!i.armed)throw new Error(`tab_open_unprotected: ${i.error??`http_${o.status}`}`);return{armed:!0,signature:i.signature??""}}async function ot(n){if(n.network!==n.vault.network)throw new pe(`options.network (${n.network}) doesn't match vault.network (${n.vault.network})`);if(n.network!=="solana:mainnet")throw new pe(n.network);let e=BigInt(Math.floor(Math.random()*4294967295)),t=new ht(n.vault.vaultPda),r=yt({vaultPda:t,sellerUrl:n.seller,nonce:BigInt(e)}),s=ee(r),a=BigInt(Z(n.perUnitCap)),o=BigInt(Z(n.totalCap));if(a<=0n)throw new Error("perUnitCap must be > 0");if(o<a)throw new Error("totalCap must be >= perUnitCap");if(n.revolvingCapacity!==void 0&&BigInt(Z(n.revolvingCapacity))<=0n)throw new Error("revolvingCapacity must be > 0");let i=n.sessionDuration??Mt,c=Math.floor(Date.now()/1e3)+i,l=Kt(n.seller),m={channelId:s,maxAmountAtomic:o.toString(),revolvingCapacityAtomic:n.revolvingCapacity?Z(n.revolvingCapacity):o.toString(),expiresAtUnix:c,allowedCounterparty:l},f=await n.vault.authorizeSession(m);return await Lt(n.facilitatorUrl??st,n.vault.swigAddress,o,n.network,l),new at({vault:n.vault,network:n.network,seller:n.seller,counterparty:l,session:f,channelIdHex:s,channelIdBytes:r,perUnitCapAtomic:a,totalCapAtomic:o,expiresAtUnix:c,facilitatorUrl:n.facilitatorUrl??st})}async function Vt(n){throw new Error("resumeTab is Phase 3 work. Session keys are memory-only by design; recovery requires reading active_session on chain and re-authorizing. Tracked in dexter-vault roadmap.")}function Kt(n){if(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(n))try{return new ht(n),n}catch{}throw new Error(`seller must be a base58 Solana pubkey for Phase 2 (got "${n}"). URL-based counterparty resolution lands in Phase 3 (seller middleware).`)}async function*Wt(n){let e=n.getReader(),t=new TextDecoder,r="";try{for(;;){let{done:s,value:a}=await e.read();if(s)break;r+=t.decode(a,{stream:!0});let o;for(;(o=r.indexOf(`
|
|
2
2
|
|
|
3
|
-
`))!==-1;){let
|
|
4
|
-
`);yield new TextEncoder().encode(
|
|
5
|
-
`))
|
|
6
|
-
`):null}}import{buildRegisterSessionKeyInstruction as O,buildRevokeSessionKeyInstruction as H,deriveSwigWalletAddress as se}from"@dexterai/vault/instructions";import{buildSecp256r1VerifyInstruction as M}from"@dexterai/vault/precompile";import{DEXTER_VAULT_PROGRAM_ID as B,SECP256R1_PROGRAM_ID as D,INSTRUCTIONS_SYSVAR_ID as q}from"@dexterai/vault/constants";export{y as DEFAULT_FACILITATOR_URL,B as DEXTER_VAULT_PROGRAM_ID,q as INSTRUCTIONS_SYSVAR_ID,D as SECP256R1_PROGRAM_ID,d as SessionScopeExceededError,c as TabClosedError,m as UnsupportedNetworkError,h as atomicToHuman,O as buildRegisterSessionKeyInstruction,H as buildRevokeSessionKeyInstruction,M as buildSecp256r1VerifyInstruction,k as buildVoucherMessage,g as humanToAtomic,E as openTab,K as resumeTab,I as sessionRegisterMessage,R as sessionRevokeMessage,b as voucherPayloadMessage,v as voucherToHeader};
|
|
3
|
+
`))!==-1;){let i=r.slice(0,o);r=r.slice(o+2);let c=qt(i);if(c.eventName==="end")return;if(c.data!==null){let l=c.data.replace(/\\n/g,`
|
|
4
|
+
`);yield new TextEncoder().encode(l)}}}}finally{e.releaseLock()}}function qt(n){let e=null,t=[];for(let r of n.split(`
|
|
5
|
+
`))r.startsWith("event:")?e=r.slice(6).trim():r.startsWith("data:")&&t.push(r.slice(5).trimStart());return{eventName:e,data:t.length?t.join(`
|
|
6
|
+
`):null}}import{PublicKey as Jt}from"@solana/web3.js";var At=[{caip2:"eip155:8453",bare:"base",family:"evm"},{caip2:"eip155:1",bare:"ethereum",family:"evm"},{caip2:"eip155:137",bare:"polygon",family:"evm"},{caip2:"eip155:42161",bare:"arbitrum",family:"evm"},{caip2:"eip155:10",bare:"optimism",family:"evm"},{caip2:"eip155:43114",bare:"avalanche",family:"evm"},{caip2:"eip155:56",bare:"bsc",family:"evm"},{caip2:"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",bare:"solana",family:"svm"}],Ht=new Map(At.map(n=>[n.caip2.toLowerCase(),n])),Ft=new Map(At.map(n=>[n.bare.toLowerCase(),n]));function Re(n){if(!n)return null;let e=n.toLowerCase(),t=Ht.get(e)||Ft.get(e);return t?{caip2:t.caip2,bare:t.bare,family:t.family}:null}function it(n){let e=n.replace(/-/g,"+").replace(/_/g,"/"),t=e+"=".repeat((4-(e.length%4||4))%4);return JSON.parse(Buffer.from(t,"base64").toString("utf8"))}function jt(n){let e=[];for(let t of n){if(!t||typeof t!="object")continue;let r=t,s=Re(String(r.network??""));s&&e.push({scheme:String(r.scheme??"exact"),network:s,amount:String(r.amount??r.maxAmountRequired??"0"),asset:String(r.asset??""),payTo:String(r.payTo??""),maxTimeoutSeconds:typeof r.maxTimeoutSeconds=="number"?r.maxTimeoutSeconds:void 0,extra:r.extra&&typeof r.extra=="object"?r.extra:void 0})}return e}async function He(n){let e=n.headers.get("payment-required");if(!e)return null;let t;try{t=it(e)}catch{return null}let r=Array.isArray(t.accepts)?t.accepts:[];return r.length===0?null:{x402Version:2,options:jt(r),resourceUrl:t.resource&&typeof t.resource=="object"?String(t.resource.url??""):void 0}}async function Pe(n,e={},t=fetch){let r={method:e.method??"GET",headers:e.headers};typeof e.body=="string"&&(r.body=e.body);let s;try{s=await t(n,r)}catch(i){return{kind:"error",detail:`probe failed: ${i?.message??String(i)}`}}if(s.status!==402)return s.ok?{kind:"free",response:s}:{kind:"error",detail:`probe returned HTTP ${s.status}`};let a=await He(s);if(!a)return{kind:"error",detail:"the 402 carries no x402 v2 PAYMENT-REQUIRED challenge"};let o=a.options.find(i=>i.scheme==="tab"&&i.network.family==="svm");if(!o)return{kind:"no_tab",schemesOffered:a.options.map(i=>i.scheme)};try{new Jt(o.payTo)}catch{return{kind:"error",detail:`tab option payTo is not a valid Solana pubkey: "${o.payTo}"`}}return{kind:"offer",offer:{payTo:o.payTo,amountAtomic:o.amount,asset:o.asset,networkCaip2:o.network.caip2,resourceUrl:a.resourceUrl}}}var ve="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",Fe="solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",je="solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z",te=ve,_e=Fe,Ce=je,ne="eip155:8453",fe="eip155:84532",ge="eip155:42161",ye="eip155:137",he="eip155:10",Se="eip155:43114",Ae="eip155:56",be="eip155:1187947933",we="eip155:324705682",Te="eip155:1",re=ne,Je=fe,ke=ge,Ie=ye,Ne=he,Oe=Se,Ue=Ae,Be=be,De=we,Me=Te,$e="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",bt="4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",wt="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",ct="0x55d398326f99059fF775485246999027B3197955",Xe="0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",Ye={[Ae]:Xe,[ne]:wt,[fe]:"0x036CbD53842c5426634e7929541eC2318f3dCF7e",[ge]:"0xaf88d065e77c8cC2239327C5EDb3A432268e5831",[ye]:"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",[he]:"0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",[Se]:"0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",[be]:"0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",[we]:"0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",[Te]:"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"},ze={[ct]:{symbol:"USDT",decimals:18},[Xe]:{symbol:"USDC",decimals:18}};var J="0x000000000022D473030F116dDEE9F6B43aC78BA3",Le="0x402085c248EeA27D92E8b30b2C58ed07f9E20001",Ve={[Ae]:56,[ne]:8453,[fe]:84532,[ge]:42161,[ye]:137,[he]:10,[Se]:43114,[be]:1187947933,[we]:324705682,[Te]:1},se={[ve]:"https://api.dexter.cash/api/solana/rpc",[Fe]:"https://api.devnet.solana.com",[je]:"https://api.testnet.solana.com"},O={[Ae]:"https://api.dexter.cash/api/evm/bsc/rpc",[ne]:"https://api.dexter.cash/api/base/rpc",[fe]:"https://sepolia.base.org",[ge]:"https://api.dexter.cash/api/evm/arbitrum/rpc",[ye]:"https://api.dexter.cash/api/evm/polygon/rpc",[he]:"https://api.dexter.cash/api/evm/optimism/rpc",[Se]:"https://api.dexter.cash/api/evm/avalanche/rpc",[be]:"https://skale-base.skalenodes.com/v1/base",[we]:"https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",[Te]:"https://eth.llamarpc.com"};var k=class n extends Error{code;details;constructor(e,t,r){super(t),this.name="X402Error",this.code=e,this.details=r,Object.setPrototypeOf(this,n.prototype)}};import{PublicKey as ae,Connection as lt,TransactionMessage as Xt,VersionedTransaction as Yt,ComputeBudgetProgram as Tt}from"@solana/web3.js";import{getAssociatedTokenAddress as ut,getAccount as zt,createTransferCheckedInstruction as Gt,getMint as Qt,TOKEN_PROGRAM_ID as xt,TOKEN_2022_PROGRAM_ID as Ge}from"@solana/spl-token";var Zt=12e3,en=1;function oe(n){if(!n||typeof n!="object")return!1;let e=n;return"publicKey"in e&&"signTransaction"in e&&typeof e.signTransaction=="function"}var Qe=class{name="Solana";networks=[te,_e,Ce];config;log;constructor(e={}){this.config=e,this.log=e.verbose?console.log.bind(console,"[x402:solana]"):()=>{}}canHandle(e){return!!(this.networks.includes(e)||e==="solana"||e==="solana-devnet"||e==="solana-testnet"||e.startsWith("solana:"))}getDefaultRpcUrl(e){return this.config.rpcUrls?.[e]?this.config.rpcUrls[e]:se[e]?se[e]:e==="solana"?se[te]:e==="solana-devnet"?se[_e]:e==="solana-testnet"?se[Ce]:se[te]}getAddress(e){return oe(e)?e.publicKey?.toBase58()??null:null}isConnected(e){return oe(e)?e.publicKey!==null:!1}async getBalance(e,t,r){if(!oe(t)||!t.publicKey)return 0;let s=r||this.getDefaultRpcUrl(e.network),a=new lt(s,"confirmed"),o=new ae(t.publicKey.toBase58()),i=new ae(e.asset);try{let l=(await a.getAccountInfo(i,"confirmed"))?.owner.toBase58()===Ge.toBase58()?Ge:xt,m=await ut(i,o,!1,l),f=await zt(a,m,void 0,l),d=e.extra?.decimals??6;return Number(f.amount)/Math.pow(10,d)}catch(c){if(c&&typeof c=="object"&&"name"in c&&(c.name==="TokenAccountNotFoundError"||c.name==="TokenInvalidAccountOwnerError"))return 0;throw c}}async buildTransaction(e,t,r){if(!oe(t))throw new Error("Invalid Solana wallet");if(!t.publicKey)throw new Error("Wallet not connected");let s=r||this.getDefaultRpcUrl(e.network),a=new lt(s,"confirmed"),o=new ae(t.publicKey.toBase58()),{payTo:i,asset:c,extra:l}=e,m=e.amount??e.maxAmountRequired;if(!m)throw new Error("Missing amount in payment requirements");if(!l?.feePayer)throw new Error("Missing feePayer in payment requirements");let f=new ae(l.feePayer),d=new ae(c),E=new ae(i);this.log("Building transaction:",{from:o.toBase58(),to:i,amount:m,asset:c,feePayer:l.feePayer});let p=[];p.push(Tt.setComputeUnitLimit({units:Zt})),p.push(Tt.setComputeUnitPrice({microLamports:en}));let _=await a.getAccountInfo(d,"confirmed");if(!_)throw new Error(`Token mint ${c} not found`);let R=_.owner.toBase58()===Ge.toBase58()?Ge:xt,h=await Qt(a,d,void 0,R);typeof l?.decimals=="number"&&h.decimals!==l.decimals&&this.log(`Decimals mismatch: requirements say ${l.decimals}, mint says ${h.decimals}`);let y=await ut(d,o,!1,R),x=await ut(d,E,!0,R);if(!await a.getAccountInfo(y,"confirmed"))throw new Error(`No token account found for ${c}. Please ensure you have USDC in your wallet.`);if(!await a.getAccountInfo(x,"confirmed"))throw new Error(`Seller token account not found. The seller (${i}) must have a USDC account.`);let W=BigInt(m);p.push(Gt(y,d,x,o,W,h.decimals,[],R));let{blockhash:L}=await a.getLatestBlockhash("confirmed"),Y=new Xt({payerKey:f,recentBlockhash:L,instructions:p}).compileToV0Message(),D=new Yt(Y),g=await t.signTransaction(D);return this.log("Transaction signed successfully"),{serialized:Buffer.from(g.serialize()).toString("base64"),settlementProbe:{kind:"solana",sourceAta:y.toBase58(),destinationAta:x.toBase58(),asset:c,amount:m,blockhash:L}}}async confirmSettlement(e,t){if(e.kind!=="solana")throw new Error(`SolanaAdapter.confirmSettlement cannot handle probe kind "${e.kind}"`);let r=new lt(t,"confirmed"),s=new ae(e.destinationAta),a=await r.getSignaturesForAddress(s,{limit:25});if(a.length===0)return{settled:!1};let o=BigInt(e.amount);for(let i of a){if(i.err)continue;let c=await r.getTransaction(i.signature,{commitment:"confirmed",maxSupportedTransactionVersion:0});if(!c?.meta)continue;let l=c.transaction.message.getAccountKeys().keySegments().flat(),m=c.meta.preTokenBalances??[],f=c.meta.postTokenBalances??[];for(let d of f){if(d.mint!==e.asset)continue;let E=l[d.accountIndex];if(!E||!E.equals(s))continue;let p=m.find(h=>h.accountIndex===d.accountIndex),_=BigInt(p?.uiTokenAmount.amount??"0");if(BigInt(d.uiTokenAmount.amount??"0")-_===o)return{settled:!0,txSignature:i.signature}}}return{settled:!1}}};function X(n){return new Qe(n)}var tn={PermitWitnessTransferFrom:[{name:"permitted",type:"TokenPermissions"},{name:"spender",type:"address"},{name:"nonce",type:"uint256"},{name:"deadline",type:"uint256"},{name:"witness",type:"Witness"}],TokenPermissions:[{name:"token",type:"address"},{name:"amount",type:"uint256"}],Witness:[{name:"to",type:"address"},{name:"validAfter",type:"uint256"}]},Et=BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");function ie(n){if(!n||typeof n!="object")return!1;let e=n;return"address"in e&&typeof e.address=="string"&&e.address.startsWith("0x")}var Ze=class{name="EVM";networks=[Ue,re,Je,Me,ke,Ie,Ne,Oe,Be,De];config;log;constructor(e={}){this.config=e,this.log=e.verbose?console.log.bind(console,"[x402:evm]"):()=>{}}canHandle(e){return!!(this.networks.includes(e)||e==="base"||e==="bsc"||e==="ethereum"||e==="arbitrum"||e==="polygon"||e==="optimism"||e==="avalanche"||e==="skale-base"||e==="skale-base-sepolia"||e.startsWith("eip155:"))}getDefaultRpcUrl(e){return this.config.rpcUrls?.[e]?this.config.rpcUrls[e]:O[e]?O[e]:e==="base"?O[re]:e==="bsc"?O[Ue]:e==="ethereum"?O[Me]:e==="arbitrum"?O[ke]:e==="polygon"?O[Ie]:e==="optimism"?O[Ne]:e==="avalanche"?O[Oe]:e==="skale-base"?O[Be]:e==="skale-base-sepolia"?O[De]:O[re]}getAddress(e){return ie(e)?e.address:null}isConnected(e){return ie(e)?!!e.address:!1}getChainId(e){if(Ve[e])return Ve[e];if(e.startsWith("eip155:")){let t=e.split(":")[1];return parseInt(t,10)}return e==="base"?8453:e==="bsc"?56:e==="ethereum"?1:e==="arbitrum"?42161:8453}async getBalance(e,t,r){if(!ie(t)||!t.address)return 0;let s=r||this.getDefaultRpcUrl(e.network);try{let a=this.encodeBalanceOf(t.address),o=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"eth_call",params:[{to:e.asset,data:a},"latest"]})});if(!o.ok)throw new Error(`RPC request failed: ${o.status}`);let i=await o.json();if(i.error)throw new Error(`RPC error: ${JSON.stringify(i.error)}`);if(!i.result||i.result==="0x")return 0;let c=BigInt(i.result),l=e.extra?.decimals??6;return Number(c)/Math.pow(10,l)}catch(a){throw a}}encodeBalanceOf(e){let t="0x70a08231",r=e.slice(2).toLowerCase().padStart(64,"0");return t+r}async confirmSettlement(e,t){if(e.kind==="eip3009"){let r="0xe94a0102",s=e.from.slice(2).toLowerCase().padStart(64,"0"),a=e.nonce.slice(2).toLowerCase().padStart(64,"0"),o=r+s+a,i=await this.ethCall(t,e.asset,o);return{settled:BigInt(i)!==0n}}if(e.kind==="permit2"){let r="0x4fe02b44",s=BigInt(e.nonce),a=s>>8n,o=s&0xffn,i=e.from.slice(2).toLowerCase().padStart(64,"0"),c=a.toString(16).padStart(64,"0"),l=r+i+c,m=await this.ethCall(t,J,l);return{settled:(BigInt(m)>>o&1n)===1n}}throw new Error(`EvmAdapter.confirmSettlement cannot handle probe kind "${e.kind}"`)}async ethCall(e,t,r){let s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"eth_call",params:[{to:t,data:r},"latest"]})});if(!s.ok)throw new Error(`RPC request failed: ${s.status}`);let a=await s.json();if(a.error)throw new Error(`RPC error: ${JSON.stringify(a.error)}`);if(!a.result||a.result==="0x")throw new Error("RPC returned an empty result");return a.result}async buildTransaction(e,t,r){if(!ie(t))throw new Error("Invalid EVM wallet");if(!t.address)throw new Error("Wallet not connected");if(e.scheme==="exact-approval")return this.buildApprovalTransaction(e,t,r);if(e.extra?.assetTransferMethod==="permit2")return this.buildPermit2Transaction(e,t,r);let{payTo:s,asset:a,extra:o}=e,i=e.amount??e.maxAmountRequired;if(!i)throw new Error("Missing amount in payment requirements");this.log("Building EVM transaction:",{from:t.address,to:s,amount:i,asset:a,network:e.network});let c=this.getChainId(e.network),l={name:o?.name??"USD Coin",version:o?.version??"2",chainId:BigInt(c),verifyingContract:a},m={TransferWithAuthorization:[{name:"from",type:"address"},{name:"to",type:"address"},{name:"value",type:"uint256"},{name:"validAfter",type:"uint256"},{name:"validBefore",type:"uint256"},{name:"nonce",type:"bytes32"}]},f=new Uint8Array(32);(globalThis.crypto??(await import("crypto")).webcrypto).getRandomValues(f);let d="0x"+[...f].map(y=>y.toString(16).padStart(2,"0")).join(""),E=Math.floor(Date.now()/1e3),p={from:t.address,to:s,value:i,validAfter:String(E-600),validBefore:String(E+(e.maxTimeoutSeconds||60)),nonce:d},_={from:t.address,to:s,value:BigInt(i),validAfter:BigInt(E-600),validBefore:BigInt(E+(e.maxTimeoutSeconds||60)),nonce:d};if(!t.signTypedData)throw new Error("Wallet does not support signTypedData (EIP-712)");let R=await t.signTypedData({domain:l,types:m,primaryType:"TransferWithAuthorization",message:_});return this.log("EIP-712 signature obtained"),{serialized:JSON.stringify({authorization:p,signature:R}),signature:R,settlementProbe:{kind:"eip3009",from:t.address,nonce:d,asset:a,chainId:c}}}async buildApprovalTransaction(e,t,r){let{payTo:s,asset:a,extra:o}=e,i=e.amount??e.maxAmountRequired;if(!i)throw new Error("Missing amount in payment requirements");let c=o?.facilitatorContract;if(!c)throw new Error("exact-approval scheme requires extra.facilitatorContract from the facilitator. The /supported endpoint should provide this.");if(!t.signTypedData)throw new Error("Wallet does not support signTypedData (EIP-712)");this.log("Building approval-based transaction:",{from:t.address,to:s,amount:i,asset:a,network:e.network,facilitatorContract:c});let l=r||this.getDefaultRpcUrl(e.network),m=o?.fee??"0",f=BigInt(i)+BigInt(m),d=await this.readAllowance(l,a,t.address,c);if(d<f){if(!t.sendTransaction)throw new Error("BSC payments require a wallet that supports sendTransaction for the one-time token approval. Use createEvmKeypairWallet() or a browser wallet with transaction support.");let D=this.calculateApprovalAmount(i,m,o?.approvalStrategy);this.log(`Approving ${D} for ${c} (current allowance: ${d})`);let g=await t.sendTransaction({to:a,data:this.encodeApprove(c,D),value:0n});this.log(`Approval tx sent: ${g}`),await this.waitForReceipt(l,g),this.log("Approval confirmed")}else this.log("Sufficient allowance, skipping approval");let E=new Uint8Array(16);(globalThis.crypto??(await import("crypto")).webcrypto).getRandomValues(E);let p=[...E].reduce((D,g)=>D*256n+BigInt(g),0n).toString(),_=new Uint8Array(32);(globalThis.crypto??(await import("crypto")).webcrypto).getRandomValues(_);let R="0x"+[..._].map(D=>D.toString(16).padStart(2,"0")).join(""),y=Math.floor(Date.now()/1e3)+(e.maxTimeoutSeconds||300),x=o?.eip712Domain,N=x?{name:x.name,version:x.version,chainId:BigInt(x.chainId),verifyingContract:x.verifyingContract}:{name:"DexterBSCFacilitator",version:"1",chainId:BigInt(this.getChainId(e.network)),verifyingContract:c},U=o?.eip712Types??{Payment:[{name:"from",type:"address"},{name:"to",type:"address"},{name:"token",type:"address"},{name:"amount",type:"uint256"},{name:"fee",type:"uint256"},{name:"nonce",type:"uint256"},{name:"deadline",type:"uint256"},{name:"paymentId",type:"bytes32"}]},W={from:t.address,to:s,token:a,amount:BigInt(i),fee:BigInt(m),nonce:BigInt(p),deadline:BigInt(y),paymentId:R},L=await t.signTypedData({domain:N,types:U,primaryType:"Payment",message:W});this.log("EIP-712 Payment signature obtained");let Y={from:t.address,to:s,token:a,amount:i,fee:m,nonce:p,deadline:y,paymentId:R,signature:L};return{serialized:JSON.stringify(Y),signature:L}}async buildPermit2Transaction(e,t,r){let{payTo:s,asset:a}=e,o=e.amount??e.maxAmountRequired;if(!o)throw new Error("Missing amount in payment requirements");if(!t.signTypedData)throw new Error("Wallet does not support signTypedData (EIP-712)");this.log("Building Permit2 transaction:",{from:t.address,to:s,amount:o,asset:a,network:e.network});let i=r||this.getDefaultRpcUrl(e.network),c=await this.readAllowance(i,a,t.address,J),l;if(c<BigInt(o)){let N=this.encodeApprove(J,Et);if(t.signTransaction){this.log(`Signing Permit2 approval for relay (current allowance: ${c})`);let U=this.getChainId(e.network),W=await this.readGasPrice(i),L=await this.readNonce(i,t.address),Y=await t.signTransaction({to:a,data:N,chainId:U,gas:50000n,gasPrice:W,nonce:L});l={erc20ApprovalGasSponsoring:{info:{from:t.address,asset:a,spender:J,amount:Et.toString(),signedTransaction:Y,version:"1"}}},this.log("Permit2 approval signed for facilitator relay")}else if(t.sendTransaction){this.log(`Approving Permit2 directly (current allowance: ${c})`);let U=await t.sendTransaction({to:a,data:N,value:0n});this.log(`Permit2 approval tx sent: ${U}`),await this.waitForReceipt(i,U),this.log("Permit2 approval confirmed")}else throw new Error("Permit2 payments require a wallet that supports signTransaction or sendTransaction for the one-time Permit2 approval. Use createEvmKeypairWallet() or a browser wallet with transaction support.")}else this.log("Sufficient Permit2 allowance, skipping approval");let m=new Uint8Array(32);(globalThis.crypto??(await import("crypto")).webcrypto).getRandomValues(m);let f=[...m].reduce((N,U)=>N*256n+BigInt(U),0n),d=Math.floor(Date.now()/1e3),E=d-600,p=d+(e.maxTimeoutSeconds||300),_=this.getChainId(e.network),R={name:"Permit2",chainId:BigInt(_),verifyingContract:J},h={permitted:{token:a,amount:BigInt(o)},spender:Le,nonce:f,deadline:BigInt(p),witness:{to:s,validAfter:BigInt(E)}},y=await t.signTypedData({domain:R,types:tn,primaryType:"PermitWitnessTransferFrom",message:h});this.log("Permit2 PermitWitnessTransferFrom signature obtained");let x={signature:y,permit2Authorization:{from:t.address,permitted:{token:a,amount:o},spender:Le,nonce:f.toString(),deadline:String(p),witness:{to:s,validAfter:String(E)}}};return{serialized:JSON.stringify(x),signature:y,extensions:l,settlementProbe:{kind:"permit2",from:t.address,nonce:f.toString(),chainId:_}}}async readAllowance(e,t,r,s){let a="0xdd62ed3e",o=r.slice(2).toLowerCase().padStart(64,"0"),i=s.slice(2).toLowerCase().padStart(64,"0"),c=a+o+i;try{let m=await(await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"eth_call",params:[{to:t,data:c},"latest"]})})).json();return m.error||!m.result||m.result==="0x"?0n:BigInt(m.result)}catch{return 0n}}encodeApprove(e,t){let r="0x095ea7b3",s=e.slice(2).toLowerCase().padStart(64,"0"),a=t.toString(16).padStart(64,"0");return r+s+a}async waitForReceipt(e,t,r=3e4){let s=Date.now();for(;Date.now()-s<r;){try{let o=await(await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"eth_getTransactionReceipt",params:[t]})})).json();if(o.result){if(o.result.status==="0x0")throw new Error(`Approval transaction reverted: ${t}`);return}}catch(a){if(a instanceof Error&&a.message.includes("reverted"))throw a}await new Promise(a=>setTimeout(a,2e3))}throw new Error(`Approval transaction receipt timeout after ${r}ms: ${t}`)}async readGasPrice(e){try{let r=await(await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"eth_gasPrice",params:[]})})).json();return r.result?BigInt(r.result):50000000n}catch{return 50000000n}}async readNonce(e,t){try{let s=await(await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"eth_getTransactionCount",params:[t,"latest"]})})).json();return s.result?parseInt(s.result,16):0}catch{return 0}}calculateApprovalAmount(e,t,r){let s=BigInt(e)+BigInt(t);if(!r||r.mode==="exact")return s;let a=BigInt(r.defaultMultiple??10),o=s*a;if(r.maxCapUsd){let i=this.inferDecimals(e),c=BigInt(Math.floor(r.maxCapUsd*Math.pow(10,i)));if(o>c)return c}if(r.exactAboveUsd){let i=this.inferDecimals(e),c=BigInt(Math.floor(r.exactAboveUsd*Math.pow(10,i)));if(BigInt(e)>c)return s}return o}inferDecimals(e){return e.length>12?18:6}};function xe(n){return new Ze(n)}function pt(n){if(n===$e||n===bt)return!0;let e=n.toLowerCase();for(let t of Object.values(Ye))if(t.toLowerCase()===e)return!0;for(let t of Object.keys(ze))if(t.toLowerCase()===e)return!0;return!1}function nn(n){return{[ve]:"Solana",[Fe]:"Solana Devnet",[je]:"Solana Testnet",solana:"Solana","solana-devnet":"Solana Devnet","solana-testnet":"Solana Testnet",[ne]:"Base",[fe]:"Base Sepolia",[Te]:"Ethereum",[ge]:"Arbitrum",[ye]:"Polygon",[he]:"Optimism",[Se]:"Avalanche",[Ae]:"BSC",[be]:"SKALE Base",[we]:"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"}[n]||n}function Rt(n,e){let t=nn(n);return t===n?e:t}async function rn(n,e){if(typeof n=="string")return[n,e];if(n instanceof URL)return[n.href,e];let t=n,r=new Headers(t.headers);e?.headers&&new Headers(e.headers).forEach((o,i)=>r.set(i,o));let s={method:e?.method??t.method,headers:r,signal:e?.signal??t.signal,redirect:e?.redirect??t.redirect,credentials:e?.credentials??t.credentials},a=(s.method??"GET").toUpperCase();return e&&"body"in e?s.body=e.body:a!=="GET"&&a!=="HEAD"&&t.body&&(s.body=await t.arrayBuffer()),[t.url,s]}var sn=new WeakMap;function Pt(n){let{adapters:e=[X({verbose:n.verbose}),xe({verbose:n.verbose})],wallets:t,wallet:r,preferredNetwork:s,rpcUrls:a={},maxAmountAtomic:o,fetch:i=globalThis.fetch,verbose:c=!1,accessPass:l,onPaymentRequired:m,onPaymentDispatched:f,maxRetries:d=0,retryDelayMs:E=500}=n,p=c?console.log.bind(console,"[x402]"):()=>{};async function _(g,b){let w;for(let S=0;S<=d;S++)try{let T=await i(g,b);if(T.status>=502&&T.status<=504&&S<d){p(`Retry ${S+1}/${d}: server returned ${T.status}`),await new Promise(P=>setTimeout(P,E*Math.pow(2,S)));continue}return T}catch(T){w=T,S<d&&(p(`Retry ${S+1}/${d}: ${T instanceof Error?T.message:"network error"}`),await new Promise(P=>setTimeout(P,E*Math.pow(2,S))))}throw w}let R=new Map;function h(g){try{let b=new URL(g).host,w=R.get(b);if(w&&w.expiresAt>Date.now()/1e3+10)return w.jwt;w&&R.delete(b)}catch{}return null}function y(g,b){try{let w=new URL(g).host,S=b.split(".");if(S.length===3){let T=JSON.parse(atob(S[1].replace(/-/g,"+").replace(/_/g,"/"))),P=Math.floor(Date.now()/1e3),v=P+86400,M=Math.min(typeof T.exp=="number"?T.exp:P,v);R.set(w,{jwt:b,expiresAt:M}),p("Access pass cached for",w,"| expires:",new Date(M*1e3).toISOString())}}catch{p("Failed to cache access pass")}}let x=t||{};r&&!x.solana&&oe(r)&&(x.solana=r),r&&!x.evm&&ie(r)&&(x.evm=r);function N(g){let b=[];for(let w of g){let S=w.scheme??"exact";if(S!=="exact"&&S!=="exact-approval")continue;let T=e.find(v=>v.canHandle(w.network));if(!T)continue;let P;T.name==="Solana"?P=x.solana:T.name==="EVM"&&(P=x.evm),P&&T.isConnected(P)&&b.push({accept:w,adapter:T,wallet:P})}if(b.length===0)return null;if(s){let w=b.find(S=>S.accept.network===s);if(w)return w}return b[0]}function U(g,b){return Rt(g,b)}function W(g,b){return a[g]||b.getDefaultRpcUrl(g)}async function L(g,b,w,S,T){let P="";if(l?.preferTier&&S.tiers){let u=S.tiers.find(A=>A.id===l.preferTier);if(u){if(l.maxSpend&&parseFloat(u.price)>parseFloat(l.maxSpend))throw new k("access_pass_exceeds_max_spend",`Access pass tier "${u.id}" costs $${u.price}, exceeds max spend $${l.maxSpend}`);P=`tier=${u.id}`}}else if(l?.preferDuration&&S.ratePerHour)P=`duration=${l.preferDuration}`;else if(S.tiers&&S.tiers.length>0){let u=S.tiers[0];if(l?.maxSpend&&parseFloat(u.price)>parseFloat(l.maxSpend))throw new k("access_pass_exceeds_max_spend",`Cheapest access pass costs $${u.price}, exceeds max spend $${l?.maxSpend}`);P=`tier=${u.id}`}let v=P?T.includes("?")?`${T}&${P}`:`${T}?${P}`:T;p("Purchasing access pass:",P||"default tier");let M=w.headers.get("PAYMENT-REQUIRED");if(!M)return null;let B;try{B=JSON.parse(atob(M))}catch{return null}let I=N(B.accepts);if(!I)return null;let{accept:C,adapter:V,wallet:ce}=I;if(V.name==="Solana"&&!C.extra?.feePayer)return null;let q=C.extra?.decimals??(pt(C.asset)?6:void 0);if(typeof q!="number")return null;let Ee=C.amount??C.maxAmountRequired;if(!Ee)return null;let H=W(C.network,V);try{let u=await V.getBalance(C,ce,H),A=Number(Ee)/Math.pow(10,q);if(u<A){let rt=U(C.network,V.name);throw new k("insufficient_balance",`Insufficient balance for access pass on ${rt}. Have $${u.toFixed(4)}, need $${A.toFixed(4)}`)}}catch(u){if(u instanceof k)throw u}let F=await V.buildTransaction(C,ce,H),le;V.name==="EVM"?le=JSON.parse(F.serialized):le={transaction:F.serialized};let z=typeof g=="string"?g:g instanceof URL?g.href:g.url,ue=B.resource;if(typeof B.resource=="string")try{let u=new URL(B.resource,z);["http:","https:"].includes(u.protocol)&&(ue=u.toString())}catch{}else if(B.resource&&typeof B.resource=="object"&&"url"in B.resource){let u=B.resource;try{let A=new URL(u.url,z);["http:","https:"].includes(A.protocol)&&(ue={...u,url:A.toString()})}catch{}}let We={x402Version:C.x402Version??2,resource:ue,accepted:C,payload:le};F.extensions&&(We.extensions=F.extensions);let j=btoa(JSON.stringify(We)),G=await i(v,{...b,method:"POST",headers:{...b?.headers||{},"Content-Type":"application/json","PAYMENT-SIGNATURE":j}});if(!G.ok)return p("Pass purchase failed:",G.status),null;let $=G.headers.get("ACCESS-PASS");return $&&(y(T,$),p("Access pass purchased and cached")),G}async function Y(g,b){let w=g;if(p("Making request:",w),l){let u=h(w);if(u){p("Using cached access pass");let A=await i(g,{...b,headers:{...b?.headers||{},Authorization:`Bearer ${u}`}});if(A.status!==401&&A.status!==402)return A;p("Cached pass rejected (status",A.status,"), purchasing new pass");try{R.delete(new URL(w).host)}catch{}}}let S=await _(g,b);if(S.status!==402)return S;p("Received 402 Payment Required");let T=S.headers.get("X-ACCESS-PASS-TIERS");if(l&&T){p("Server offers access passes, purchasing...");try{let u=JSON.parse(atob(T)),A=await L(g,b,S,u,w);if(A)return A}catch(u){p("Access pass purchase failed, falling back to per-request payment:",u)}}let P=S.headers.get("PAYMENT-REQUIRED");if(!P)throw new k("missing_payment_required_header","Server returned 402 but no PAYMENT-REQUIRED header");let v;try{let u=atob(P);v=JSON.parse(u)}catch{throw new k("invalid_payment_required","Failed to decode PAYMENT-REQUIRED header")}p("Payment requirements:",v);let M=S.headers.get("X-Quote-Hash");M&&p("Quote hash received:",M);let B=N(v.accepts);if(!B){let u=v.accepts.map(A=>A.network).join(", ");throw new k("no_matching_payment_option",`No connected wallet for any available network: ${u}`)}let{accept:I,adapter:C,wallet:V}=B;if(p(`Using ${C.name} for ${I.network}`),C.name==="Solana"&&!I.extra?.feePayer)throw new k("missing_fee_payer","Solana payment option missing feePayer in extra");let ce=I.extra?.decimals??(pt(I.asset)?6:void 0);if(typeof ce!="number")throw new k("missing_decimals","Payment option missing decimals - provide in extra or use a known stablecoin");let q=I.amount??I.maxAmountRequired;if(!q)throw new k("missing_amount","Payment option missing amount");if(o&&BigInt(q)>BigInt(o))throw new k("amount_exceeds_max",`Payment amount ${q} exceeds maximum ${o}`);let Ee=W(I.network,C);p("Checking balance...");try{let u=await C.getBalance(I,V,Ee),A=Number(q)/Math.pow(10,ce);if(u<A){let rt=U(I.network,C.name);throw new k("insufficient_balance",`Insufficient balance on ${rt}. Have $${u.toFixed(4)}, need $${A.toFixed(4)}`)}p(`Balance OK: $${u.toFixed(4)} >= $${A.toFixed(4)}`)}catch(u){if(u instanceof k)throw u;p("Balance check failed (RPC error), proceeding with transaction attempt")}if(m&&!await m(I))throw new k("payment_rejected","Payment rejected by onPaymentRequired callback");p("Building transaction...");let H=await C.buildTransaction(I,V,Ee);p("Transaction signed");let F;C.name==="EVM"?F=JSON.parse(H.serialized):F={transaction:H.serialized};let le=g,z=v.resource;if(typeof v.resource=="string")try{let u=new URL(v.resource,le).toString();u!==v.resource&&p("Resolved relative resource URL:",v.resource,"\u2192",u),z=u}catch{z=v.resource}else if(v.resource&&typeof v.resource=="object"&&"url"in v.resource){let u=v.resource;try{let A=new URL(u.url,le).toString();A!==u.url&&(p("Resolved relative resource URL:",u.url,"\u2192",A),z={...u,url:A})}catch{}}let ue={x402Version:I.x402Version??2,resource:z,accepted:I,payload:F};H.extensions&&(ue.extensions=H.extensions);let We=btoa(JSON.stringify(ue));if(f)try{f(I,H.settlementProbe)}catch{}p("Retrying request with payment...");let j=await _(g,{...b,headers:{...b?.headers||{},"PAYMENT-SIGNATURE":We,...M?{"X-Quote-Hash":M}:{}}});if(p("Retry response status:",j.status),j.status===402){let u="unknown";try{let A=await j.clone().json();u=String(A.error||A.message||JSON.stringify(A)),p("Rejection reason:",u)}catch{}throw new k("payment_rejected",`Payment was rejected by the server: ${u}`)}let G=j.headers.get("PAYMENT-RESPONSE"),$;if(G)try{$=JSON.parse(atob(G))}catch{}return $??={},$.amountAtomic=q,$.assetDecimals=ce,sn.set(j,$),$.extensions&&p("Settlement extensions:",Object.keys($.extensions).join(", ")),j}async function D(g,b){let[w,S]=await rn(g,b);return Y(w,S)}return{fetch:D}}function K(n){if(n instanceof Error){if(n.message&&n.message.length>0)return n.message;if(n.name&&n.name.length>0)return n.name}let e=String(n);return e.length>0?e:"unknown error"}async function Ke(n){let e="";try{e=(await n.clone().text()).slice(0,600)}catch{}let t=e.toLowerCase(),r=t.includes("settle")||t.includes("facilitator"),s=e;try{let a=JSON.parse(e),o=[a.error,a.detail,a.message].filter(i=>typeof i=="string"&&i.length>0);o.length>0&&(s=o.join(" \u2014 "))}catch{}return s||(s=`HTTP ${n.status}`),{reason:r?"settlement_failed":"merchant_rejected",detail:`merchant HTTP ${n.status}: ${s}`}}var et="Payment authorization was sent, but the merchant did not respond within the timeout. ",tt=" Do not retry without checking \u2014 inspect the funding wallet for a transfer to the merchant before attempting payment again.";async function nt(n,e,t){if(!n)return{confirmed:!1,detail:et+"This payment scheme has no on-chain confirmation check, so the SDK cannot verify whether it settled."+tt};try{if(n.kind==="solana"){let o=X(),i=t??o.getDefaultRpcUrl(e.caip2);if(!o.confirmSettlement)return _t();let c=await o.confirmSettlement(n,i);return c.settled?{confirmed:!0,txSignature:c.txSignature}:vt()}let r=xe(),s=r.getDefaultRpcUrl(e.caip2);if(!r.confirmSettlement)return _t();let a=await r.confirmSettlement(n,s);return a.settled?{confirmed:!0,txSignature:a.txSignature}:vt()}catch(r){return{confirmed:!1,detail:et+`On-chain confirmation could not be completed (${K(r)}).`+tt}}}function vt(){return{confirmed:!1,detail:et+"On-chain confirmation found no matching settlement yet \u2014 the payment may still be pending, or may not have settled."+tt}}function _t(){return{confirmed:!1,detail:et+"The chain adapter does not support on-chain confirmation."+tt}}var an=new Set(["exact","exact-approval"]);async function on(n,e,t,r){let s;try{s=await r.signNextVoucher(t.amount)}catch{return null}let a=new Headers(e.headers??void 0);a.set("X-Tab-Voucher",qe(s));let o={method:e.method??"GET",headers:a};e.signal&&(o.signal=e.signal),typeof e.body=="string"&&(o.body=e.body);let i;try{i=await fetch(n,o)}catch(c){return{ok:!1,reason:"error",detail:c?.message??String(c)}}return i.status===402?(r.rollbackVoucher?.call(r,s),null):i.ok?{ok:!0,paid:!0,response:i,amountPaid:t.amount,network:t.network}:{ok:!1,...await Ke(i)}}var Ct={version:2,async parseChallenge(n){return He(n)},async pay(n,e,t,r,s){if(s.tab){let h=t.options.find(y=>y.scheme==="tab"&&y.network.family==="svm"&&y.payTo===s.tab.counterparty);if(h){let y=await on(n,e,h,s.tab);if(y)return y}}let a=t.options.filter(h=>an.has(h.scheme));if(a.length===0)return{ok:!1,reason:"no_payment_options",detail:`no generically payable scheme offered (got: ${t.options.map(h=>h.scheme).join(", ")})`};let o=a.find(h=>h.network.family==="evm"?!!r.evm:h.network.family==="svm"?!!r.solana:!1);if(!o)return{ok:!1,reason:"unsupported_network"};let i=s.timeoutMs??15e3,c=s.responseTimeoutMs??12e4,l=new AbortController,m=setTimeout(()=>l.abort(),i),f=!1,d,E=(h,y)=>{f=!0,d=y,clearTimeout(m),m=setTimeout(()=>l.abort(),c)},p=Pt({wallets:r,preferredNetwork:o.network.caip2,maxAmountAtomic:s.maxAmountAtomic,fetch:globalThis.fetch,onPaymentDispatched:E}),_=e.signal?AbortSignal.any([e.signal,l.signal]):l.signal,R={method:e.method??"GET",headers:e.headers,signal:_};typeof e.body=="string"&&(R.body=e.body);try{let h=await p.fetch(n,R);if(clearTimeout(m),!h.ok)return{ok:!1,...await Ke(h)};let y,x=h.headers.get("PAYMENT-RESPONSE");if(x)try{let N=it(x);N&&typeof N.transaction=="string"&&(y=N.transaction)}catch{}return{ok:!0,paid:!0,response:h,amountPaid:o.amount,network:o.network,txSignature:y}}catch(h){clearTimeout(m);let y=h;if(y?.name==="AbortError"){if(!f)return{ok:!1,reason:"timeout"};let x=await nt(d,o.network,s.solanaRpcUrl);return x.confirmed?{ok:!0,paid:!0,response:void 0,amountPaid:o.amount,network:o.network,txSignature:x.txSignature}:{ok:!1,reason:"payment_unconfirmed",detail:x.detail}}return{ok:!1,reason:"error",detail:y?.message??String(h)}}}};import{getAddress as cn}from"viem";var ln={TransferWithAuthorization:[{name:"from",type:"address"},{name:"to",type:"address"},{name:"value",type:"uint256"},{name:"validAfter",type:"uint256"},{name:"validBefore",type:"uint256"},{name:"nonce",type:"bytes32"}]};async function un(){let n=globalThis.crypto??(await import("crypto")).webcrypto,e=new Uint8Array(32);return n.getRandomValues(e),"0x"+Array.from(e,t=>t.toString(16).padStart(2,"0")).join("")}async function pn(n,e,t){if(typeof n.signTypedData!="function")throw new Error("EVM wallet does not support signTypedData");let r=Math.floor(Date.now()/1e3),s=String(r-600),a=String(r+(e.maxTimeoutSeconds??60)),o={from:n.address,to:e.payTo,value:e.amount,validAfter:s,validBefore:a,nonce:await un()},i=Ve[e.network.caip2];if(i===void 0)throw new Error(`unknown chain id for network ${e.network.caip2}`);let c=e.extra,l=await n.signTypedData({domain:{name:c.name,version:c.version,chainId:i,verifyingContract:cn(e.asset)},types:ln,primaryType:"TransferWithAuthorization",message:o});return{payment:{x402Version:1,scheme:e.scheme,network:t,payload:{signature:l,authorization:o}},settlementProbe:{kind:"eip3009",from:o.from,nonce:o.nonce,asset:e.asset,chainId:i}}}async function mt(n,e,t){try{let r;for(let s of n.options){let a=s.network.family==="evm"&&!!e.evm||s.network.family==="svm"&&!!e.solana;if(s.scheme!=="exact"){a&&(r=s.scheme);continue}if(s.network.family==="evm"&&e.evm){let o=await e.evm;return await mn(s,o,t)}if(s.network.family==="svm"&&e.solana){let o=await e.solana;return await dn(s,o,t)}}return r!==void 0?{ok:!1,reason:"merchant_rejected",detail:`v1 supports only the 'exact' scheme, got '${r}'`}:{ok:!1,reason:"unsupported_network"}}catch(r){return{ok:!1,reason:"error",detail:K(r)}}}async function mn(n,e,t){if(t.maxAmountAtomic!==void 0&&BigInt(n.amount)>BigInt(t.maxAmountAtomic))return{ok:!1,reason:"budget_exceeded"};let r=n.extra??{},s=r.name,a=r.version;if(typeof s!="string"||s.length===0||typeof a!="string"||a.length===0)return{ok:!1,reason:"merchant_rejected",detail:"v1 challenge missing exact-scheme EIP-712 domain (extra.name / extra.version)"};let o=n.network.bare,{payment:i,settlementProbe:c}=await pn(e,n,o);return{ok:!0,headerValue:Buffer.from(JSON.stringify(i),"utf8").toString("base64"),option:n,settlementProbe:c}}async function dn(n,e,t){if(t.maxAmountAtomic!==void 0&&BigInt(n.amount)>BigInt(t.maxAmountAtomic))return{ok:!1,reason:"budget_exceeded"};if(n.scheme!=="exact")return{ok:!1,reason:"merchant_rejected",detail:`v1 SVM supports only the 'exact' scheme, got '${n.scheme}'`};let r=n.extra??{};if(typeof r.feePayer!="string"||r.feePayer.length===0)return{ok:!1,reason:"merchant_rejected",detail:"v1 SVM challenge missing extra.feePayer (required as the transaction fee payer)"};let s=n.network.bare,a={x402Version:1,scheme:n.scheme,network:s,asset:n.asset,payTo:n.payTo,amount:n.amount,maxAmountRequired:n.amount,maxTimeoutSeconds:n.maxTimeoutSeconds??60,extra:r},i=await X().buildTransaction(a,e,t.solanaRpcUrl),c={x402Version:1,scheme:n.scheme,network:s,payload:{transaction:i.serialized}};return{ok:!0,headerValue:Buffer.from(JSON.stringify(c),"utf8").toString("base64"),option:n,settlementProbe:i.settlementProbe}}function fn(n){let e=[];for(let t of n){if(!t||typeof t!="object")continue;let r=t,s=Re(String(r.network??""));s&&e.push({scheme:String(r.scheme??"exact"),network:s,amount:String(r.maxAmountRequired??r.amount??"0"),asset:String(r.asset??""),payTo:String(r.payTo??""),maxTimeoutSeconds:typeof r.maxTimeoutSeconds=="number"?r.maxTimeoutSeconds:void 0,extra:r.extra&&typeof r.extra=="object"?r.extra:void 0})}return e}var kt={version:1,async parseChallenge(n){if(n.headers.get("payment-required"))return null;let e;try{e=await n.clone().json()}catch{return null}let t=Array.isArray(e.accepts)?e.accepts:[];if(t.length===0)return null;let r=fn(t);return r.length===0?null:{x402Version:1,options:r}},async pay(n,e,t,r,s){let a,o=new AbortController,i=!1,c,l;try{let m=s.timeoutMs??15e3;a=setTimeout(()=>o.abort(),m);let f=await mt(t,r,s);if(!f.ok)return{ok:!1,reason:f.reason,detail:f.detail};let d=f.headerValue,E=f.option;l=E,c=f.settlementProbe;let p=new Headers(e.headers??void 0);p.set("X-PAYMENT",d);let _=e.signal!=null?AbortSignal.any([e.signal,o.signal]):o.signal,R={method:e.method,headers:p,signal:_};typeof e.body=="string"&&(R.body=e.body),i=!0,clearTimeout(a);let h=s.responseTimeoutMs??12e4;a=setTimeout(()=>o.abort(),h);let y=await fetch(n,R);return y.ok?{ok:!0,paid:!0,response:y,amountPaid:E.amount,network:E.network,txSignature:gn(y)}:{ok:!1,...await Ke(y)}}catch(m){if(m instanceof Error&&m.name==="AbortError"){if(!i)return{ok:!1,reason:"timeout"};let f=await nt(c,l.network,s.solanaRpcUrl);return f.confirmed?{ok:!0,paid:!0,response:void 0,amountPaid:l.amount,network:l.network,txSignature:f.txSignature}:{ok:!1,reason:"payment_unconfirmed",detail:f.detail}}return{ok:!1,reason:"error",detail:K(m)}}finally{a!==void 0&&clearTimeout(a)}}};function gn(n){let e=n.headers.get("x-payment-response")??n.headers.get("X-PAYMENT-RESPONSE");if(e)try{let t=JSON.parse(Buffer.from(e,"base64").toString("utf8")),r=t.transaction??t.txHash??t.transactionHash;return typeof r=="string"?r:void 0}catch{return}}import*as Nt from"tweetnacl";import{Keypair as $r,VersionedTransaction as Lr,Transaction as Vr}from"@solana/web3.js";var It=Symbol.for("x402:keypair");function dt(n){let e=n.evm;if(e&&typeof e.signMessage=="function"&&typeof e.address=="string")return{address:e.address,signMessage:e.signMessage};let t=n.solana;if(t){let r=t[It];if(r&&r.secretKey&&r.publicKey)return{publicKey:r.publicKey,signMessage:async s=>Nt.sign.detached(s,r.secretKey)}}return null}var yn=[Ct,kt];async function hn(n){let e=dt(n);if(!e)return fetch;try{return(await import("@x402/extensions/sign-in-with-x")).wrapFetchWithSIWx(fetch,e)}catch(t){return console.warn(`[x402] SIW-X unavailable \u2014 @x402/extensions failed to load; SIW-X merchants will not authenticate. ${K(t)}`),fetch}}async function ft(n,e,t,r){if(e.body!==void 0&&e.body!==null&&typeof e.body!="string")return{ok:!1,reason:"error",detail:"payAndFetch requires a string body; non-string bodies (Buffer, FormData, URLSearchParams, ReadableStream) cannot be safely re-sent on the paid retry"};let s;try{s=await(await hn(t))(n,{...e})}catch(a){return{ok:!1,reason:"error",detail:K(a)}}if(s.status!==402)return{ok:!0,paid:!1,response:s};for(let a of yn){let o=await a.parseChallenge(s.clone());if(o)return a.pay(n,e,o,t,r)}return{ok:!1,reason:"no_payment_options"}}async function Sn(n,e={},t){let r=await Pe(n,e);if(r.kind==="free")return{result:{ok:!0,paid:!1,response:r.response},tab:null};if(r.kind==="no_tab")return{result:{ok:!1,reason:"no_payment_options",detail:`no tab option offered (schemes: ${r.schemesOffered.join(", ")})`},tab:null};if(r.kind==="error")return{result:{ok:!1,reason:"error",detail:r.detail},tab:null};let{offer:s}=r,a=BigInt(Z(t.perUnitCap));if(BigInt(s.amountAtomic)>a)return{result:{ok:!1,reason:"budget_exceeded",detail:`seller quotes ${s.amountAtomic} atomic; perUnitCap allows ${a}`},tab:null};let o=t.tabs?.get(s.payTo);return(!o||!o.state.isOpen)&&(o=await ot({vault:t.vault,network:"solana:mainnet",seller:s.payTo,perUnitCap:t.perUnitCap,totalCap:t.totalCap,sessionDuration:t.sessionDuration,facilitatorUrl:t.facilitatorUrl}),t.tabs?.set(s.payTo,o)),{result:await ft(n,e,{},{tab:o}),tab:o}}import{buildRegisterSessionKeyInstruction as An,buildRevokeSessionKeyInstruction as bn,deriveSwigWalletAddress as is}from"@dexterai/vault/instructions";import{buildSecp256r1VerifyInstruction as wn}from"@dexterai/vault/precompile";import{DEXTER_VAULT_PROGRAM_ID as Tn,SECP256R1_PROGRAM_ID as xn,INSTRUCTIONS_SYSVAR_ID as En}from"@dexterai/vault/constants";function Rn(n){return{counterparty:n.payTo,perRequest:{atomic:n.amountAtomic,human:de(n.amountAtomic)},asset:n.asset,network:{caip2:n.networkCaip2},scheme:"tab",settlement:{custody:"non-custodial",protection:"freeze",settleOn:"close"},credit:null,...n.resourceUrl!==void 0?{resourceUrl:n.resourceUrl}:{}}}async function Pn(n,e={},t={}){let r=t.cache?.get(n);if(r)return{kind:"terms",terms:r};let s=await Pe(n,e,t.fetchImpl??fetch);if(s.kind!=="offer")return s;if(s.offer.asset!==$e)return{kind:"error",detail:`tab offer asset is not USDC ("${s.offer.asset}"); refusing to render a human price`};let a=Rn(s.offer);return t.cache?.set(n,a),{kind:"terms",terms:a}}export{st as DEFAULT_FACILITATOR_URL,Tn as DEXTER_VAULT_PROGRAM_ID,En as INSTRUCTIONS_SYSVAR_ID,xn as SECP256R1_PROGRAM_ID,me as SessionScopeExceededError,Q as TabClosedError,pe as UnsupportedNetworkError,de as atomicToHuman,An as buildRegisterSessionKeyInstruction,bn as buildRevokeSessionKeyInstruction,wn as buildSecp256r1VerifyInstruction,Bt as buildVoucherMessage,Z as humanToAtomic,ot as openTab,Sn as payUrlWithTab,Pe as resolveTabOffer,Pn as resolveTabTerms,Vt as resumeTab,Ot as sessionRegisterMessage,Ut as sessionRevokeMessage,gt as voucherPayloadMessage,qe as voucherToHeader};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"use strict";var ee=Object.create;var P=Object.defineProperty;var te=Object.getOwnPropertyDescriptor;var ne=Object.getOwnPropertyNames;var re=Object.getPrototypeOf,oe=Object.prototype.hasOwnProperty;var ie=(e,t)=>{for(var n in t)P(e,n,{get:t[n],enumerable:!0})},j=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ne(t))!oe.call(e,o)&&o!==n&&P(e,o,{get:()=>t[o],enumerable:!(r=te(t,o))||r.enumerable});return e};var z=(e,t,n)=>(n=e!=null?ee(re(e)):{},j(t||!e||!e.__esModule?P(n,"default",{value:e,enumerable:!0}):n,e)),se=e=>j(P({},"__esModule",{value:!0}),e);var be={};ie(be,{FileVoucherStore:()=>R,InMemoryVoucherStore:()=>S,InvalidRegistrationError:()=>l,InvalidVoucherError:()=>c,InvalidVoucherSignatureError:()=>p,OnChainVerificationError:()=>y,ScopeViolationError:()=>a,TAB_VOUCHER_HEADER:()=>E,enforceScope:()=>C,openSse:()=>Z,parseRegistration:()=>V,requireTab:()=>Y,tabMiddleware:()=>X,verifyRegistrationOnChain:()=>_,verifyVoucherSignature:()=>$});module.exports=se(be);var c=class extends Error{constructor(n,r){super(`Invalid voucher: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidVoucherError"}};var W=require("@solana/web3.js");var J=z(require("tweetnacl"),1),ue=require("@noble/hashes/sha256"),ce=require("@noble/curves/p256"),T=require("@solana/web3.js");var w=require("@dexterai/vault/messages");var N=require("@dexterai/vault/instructions"),ae=require("@dexterai/vault/precompile"),b=require("@dexterai/vault/constants");var I=require("@dexterai/vault/session"),O="OTS_SESSION_REGISTER_V2",l=class extends Error{constructor(n,r){super(`Invalid registration: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidRegistrationError"}};function V(e){if(e.length!==188)throw new l("wrong_length",`expected 188, got ${e.length}`);let t=new TextDecoder().decode(e.slice(0,O.length));if(t!==O)throw new l("wrong_domain",`got "${t}"`);for(let s=O.length;s<32;s++)if(e[s]!==0)throw new l("wrong_domain",`non-NUL padding at byte ${s}`);let n=new DataView(e.buffer,e.byteOffset,e.byteLength),r=new T.PublicKey(e.slice(32,64)),o=new T.PublicKey(e.slice(64,96)),m=e.slice(96,128),g=n.getBigUint64(128,!0),f=n.getBigInt64(136,!0),i=new T.PublicKey(e.slice(144,176)),d=n.getUint32(176,!0),h=n.getBigUint64(180,!0);if(!r.equals(b.DEXTER_VAULT_PROGRAM_ID))throw new l("wrong_program",`${r.toBase58()} is not ${b.DEXTER_VAULT_PROGRAM_ID.toBase58()}`);if(g===0n)throw new l("cap_zero");let u=BigInt(Math.floor(Date.now()/1e3));if(f<=u)throw new l("expiry_in_past",`expires_at=${f}, now=${u}`);return{programId:r,vaultPda:o,sessionPubkey:new Uint8Array(m),maxAmount:g,expiresAt:f,allowedCounterparty:i,nonce:d,maxRevolvingCapacity:h}}var y=class extends Error{constructor(n,r){super(`On-chain verification failed: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="OnChainVerificationError"}};async function _(e,t){let n=await(0,I.fetchSessionAccount)(e,t.vaultPda,t.allowedCounterparty);if(!n||n.version===0)throw new y("session_not_active","no live SessionAccount PDA for this (vault, counterparty) \u2014 revoked, expiry-swept, or never registered");if(!(0,I.isSessionLive)(n))throw new y("session_not_active","SessionAccount PDA is present but expired");if(!le(n.session.sessionPubkey,t.sessionPubkey))throw new y("session_pubkey_mismatch",`on-chain ${F(n.session.sessionPubkey)} != registration ${F(t.sessionPubkey)}`)}var p=class extends Error{constructor(t){super(`Invalid voucher signature${t?`: ${t}`:""}`),this.name="InvalidVoucherSignatureError"}};function $(e,t){if(t.length!==32)throw new p(`channelIdBytes must be 32 bytes, got ${t.length}`);if(e.sessionPublicKey.length!==32)throw new p(`sessionPublicKey must be 32 bytes, got ${e.sessionPublicKey.length}`);if(e.sessionSignature.length!==64)throw new p(`sessionSignature must be 64 bytes, got ${e.sessionSignature.length}`);let n=(0,w.voucherPayloadMessage)({channelId:t,cumulativeAmount:BigInt(e.payload.cumulativeAmount),sequenceNumber:e.payload.sequenceNumber});if(!J.default.sign.detached.verify(n,e.sessionSignature,e.sessionPublicKey))throw new p("ed25519 verify rejected")}var a=class extends Error{constructor(n,r){super(`Scope violation: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="ScopeViolationError"}};function C(e){let t=BigInt(e.voucher.payload.cumulativeAmount);if(t>e.registration.maxAmount)throw new a("cumulative_exceeds_cap",`${t} > ${e.registration.maxAmount}`);let n=BigInt(Math.floor(Date.now()/1e3));if(n>=e.registration.expiresAt)throw new a("session_expired",`now=${n} >= expiresAt=${e.registration.expiresAt}`);if(!e.registration.allowedCounterparty.equals(e.expectedCounterparty))throw new a("wrong_counterparty",`${e.registration.allowedCounterparty.toBase58()} != ${e.expectedCounterparty.toBase58()}`);if(e.previousCumulativeAtomic!==void 0){let r=BigInt(e.previousCumulativeAtomic);if(t<=r)throw new a("non_monotonic",`cumulative=${t} not > previous=${r}`)}}function le(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 F(e){let t="";for(let n of e)t+=n.toString(16).padStart(2,"0");return t}var A=require("fs"),U=require("path");function me(e){return{payload:e.payload,sessionPublicKey:H(e.sessionPublicKey),sessionRegistration:H(e.sessionRegistration),sessionSignature:H(e.sessionSignature)}}function de(e){return{payload:e.payload,sessionPublicKey:B(e.sessionPublicKey),sessionRegistration:B(e.sessionRegistration),sessionSignature:B(e.sessionSignature)}}function H(e){let t="";for(let n of e)t+=n.toString(16).padStart(2,"0");return t}function B(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 S=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)}},R=class{constructor(t){this.dir=t}pathFor(t){if(!/^[a-z0-9_-]+$/i.test(t))throw new Error(`unsafe channelId for filesystem: ${t}`);return(0,U.join)(this.dir,`${t}.json`)}async get(t){try{let n=await A.promises.readFile(this.pathFor(t),"utf8");return de(JSON.parse(n))}catch(n){if(n?.code==="ENOENT")return null;throw n}}async set(t,n){let r=this.pathFor(t);await A.promises.mkdir((0,U.dirname)(r),{recursive:!0});let o=`${r}.tmp`;await A.promises.writeFile(o,JSON.stringify(me(n))),await A.promises.rename(o,r)}async delete(t){try{await A.promises.unlink(this.pathFor(t))}catch(n){if(n?.code!=="ENOENT")throw n}}};var he=require("@solana/web3.js"),ye=require("@noble/hashes/utils");var pe=z(require("tweetnacl"),1);var ge=require("@noble/hashes/sha256");var G=6;function v(e,t=G){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 o=r.padEnd(t,"0"),m=`${n}${o}`.replace(/^0+(?=\d)/,"");return m===""?"0":m}function x(e,t=G){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",o=n.slice(-t).replace(/0+$/,"");return o?`${r}.${o}`:r}var E="x-tab-voucher",M=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)}},q=class{constructor(t,n,r,o){this.chargeImpl=o;this.channelId=t,this.network=n,this.cumulativeAtomic=r}channelId;network;sessionPublicKey=null;cumulativeAtomic;cumulative(){return x(this.cumulativeAtomic.toString())}bumpCumulative(t){this.cumulativeAtomic=t}setSessionPublicKey(t){this.sessionPublicKey=t}async charge(t){return this.chargeImpl(t)}};function fe(e){if(typeof e!="string"||e.length===0)throw new c("signature_invalid",`missing ${E} header`);let t;try{t=Buffer.from(e,"base64").toString("utf8")}catch{throw new c("signature_invalid","malformed base64")}let n;try{n=JSON.parse(t)}catch{throw new c("signature_invalid","malformed JSON")}if(!n||typeof n!="object"||!n.payload||!n.sessionPublicKey)throw new c("signature_invalid","missing required fields");return{payload:n.payload,sessionPublicKey:k(n.sessionPublicKey),sessionRegistration:k(n.sessionRegistration),sessionSignature:k(n.sessionSignature)}}function k(e){if(typeof e!="string"||e.length%2!==0)throw new c("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 we(e){if(!/^[0-9a-f]{64}$/i.test(e))throw new c("signature_invalid",`channelId must be 64-char hex, got "${e}"`);return k(e)}function X(e){let t=e.store??new S,n=new M,r=typeof e.sellerPubkey=="string"?new W.PublicKey(e.sellerPubkey):e.sellerPubkey,o=e.maxPerVoucherAtomic?BigInt(e.maxPerVoucherAtomic):BigInt(v(e.perUnit))*100n;return async(m,g,f)=>{try{let i=fe(m.headers[E]),d=i.payload.channelId,h=we(d),u=n.get(d);if(!u){let K=V(i.sessionRegistration);await _(e.connection,K),u={registration:K,lastCumulativeAtomic:"0"},n.set(d,u)}$(i,h),C({registration:u.registration,voucher:i,expectedCounterparty:r,previousCumulativeAtomic:u.lastCumulativeAtomic});let s=BigInt(i.payload.cumulativeAmount),Q=BigInt(u.lastCumulativeAtomic),D=s-Q;if(D>o)throw new a("cumulative_exceeds_cap",`single voucher increment ${D} exceeds maxPerVoucherAtomic ${o}`);await t.set(d,i),n.update(d,i.payload.cumulativeAmount);let L=new q(d,e.network,s,async K=>{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.")});L.setSessionPublicKey(i.sessionPublicKey),m.tab=L,f()}catch(i){if(i instanceof c||i instanceof l||i instanceof y||i instanceof p||i instanceof a){g.status(402).json({error:"invalid_voucher",reason:i.reason??"unknown",detail:i.message});return}f(i)}}}function Y(e){if(!e.tab)throw new Error("req.tab is missing \u2014 did tabMiddleware run on this route?");return e.tab}function Z(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(v(n.cumulative())),o=t.perUnit?BigInt(v(t.perUnit)):null,m=0n,g=!1;function f(h=1){if(g)return Promise.reject(new Error("meter ended"));if(o===null)return Promise.reject(new Error("charge() needs options.perUnit"));let u=o*BigInt(h),s=m+u;return s>r?Promise.reject(new a("cumulative_exceeds_cap",`chunk would push request total to ${x(s.toString())} beyond voucher-authorized budget ${x(r.toString())}`)):(m=s,Promise.resolve())}function i(h){if(g)throw new Error("meter ended");let s=(typeof h=="string"?h:Buffer.from(h).toString("utf8")).replace(/\n/g,"\\n");e.write(`data: ${s}
|
|
1
|
+
"use strict";var qe=Object.create;var H=Object.defineProperty;var Le=Object.getOwnPropertyDescriptor;var We=Object.getOwnPropertyNames;var Fe=Object.getPrototypeOf,je=Object.prototype.hasOwnProperty;var Xe=(e,t)=>{for(var r in t)H(e,r,{get:t[r],enumerable:!0})},Ae=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of We(t))!je.call(e,s)&&s!==r&&H(e,s,{get:()=>t[s],enumerable:!(n=Le(t,s))||n.enumerable});return e};var Se=(e,t,r)=>(r=e!=null?qe(Fe(e)):{},Ae(t||!e||!e.__esModule?H(r,"default",{value:e,enumerable:!0}):r,e)),Je=e=>Ae(H({},"__esModule",{value:!0}),e);var gt={};Xe(gt,{FileVoucherStore:()=>J,InMemoryVoucherStore:()=>I,InvalidRegistrationError:()=>S,InvalidVoucherError:()=>A,InvalidVoucherSignatureError:()=>w,OnChainVerificationError:()=>x,ScopeViolationError:()=>b,TAB_VOUCHER_HEADER:()=>P,enforceScope:()=>X,openSse:()=>Pe,parseRegistration:()=>W,requireTab:()=>Te,tabChallengeMiddleware:()=>Ve,tabMiddleware:()=>G,tabOrExactMiddleware:()=>Ke,verifyRegistrationOnChain:()=>F,verifyVoucherSignature:()=>j});module.exports=Je(gt);var A=class extends Error{constructor(r,n){super(`Invalid voucher: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="InvalidVoucherError"}};var Ee=require("@solana/web3.js");var xe=Se(require("tweetnacl"),1),Ye=require("@noble/hashes/sha256"),Ge=require("@noble/curves/p256"),q=require("@solana/web3.js");var R=require("@dexterai/vault/messages");var pe=require("@dexterai/vault/instructions"),ze=require("@dexterai/vault/precompile"),C=require("@dexterai/vault/constants");var L=require("@dexterai/vault/session"),me="OTS_SESSION_REGISTER_V2",S=class extends Error{constructor(r,n){super(`Invalid registration: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="InvalidRegistrationError"}};function W(e){if(e.length!==188)throw new S("wrong_length",`expected 188, got ${e.length}`);let t=new TextDecoder().decode(e.slice(0,me.length));if(t!==me)throw new S("wrong_domain",`got "${t}"`);for(let u=me.length;u<32;u++)if(e[u]!==0)throw new S("wrong_domain",`non-NUL padding at byte ${u}`);let r=new DataView(e.buffer,e.byteOffset,e.byteLength),n=new q.PublicKey(e.slice(32,64)),s=new q.PublicKey(e.slice(64,96)),i=e.slice(96,128),m=r.getBigUint64(128,!0),c=r.getBigInt64(136,!0),o=new q.PublicKey(e.slice(144,176)),l=r.getUint32(176,!0),g=r.getBigUint64(180,!0);if(!n.equals(C.DEXTER_VAULT_PROGRAM_ID))throw new S("wrong_program",`${n.toBase58()} is not ${C.DEXTER_VAULT_PROGRAM_ID.toBase58()}`);if(m===0n)throw new S("cap_zero");let d=BigInt(Math.floor(Date.now()/1e3));if(c<=d)throw new S("expiry_in_past",`expires_at=${c}, now=${d}`);return{programId:n,vaultPda:s,sessionPubkey:new Uint8Array(i),maxAmount:m,expiresAt:c,allowedCounterparty:o,nonce:l,maxRevolvingCapacity:g}}var x=class extends Error{constructor(r,n){super(`On-chain verification failed: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="OnChainVerificationError"}};async function F(e,t){let r=await(0,L.fetchSessionAccount)(e,t.vaultPda,t.allowedCounterparty);if(!r||r.version===0)throw new x("session_not_active","no live SessionAccount PDA for this (vault, counterparty) \u2014 revoked, expiry-swept, or never registered");if(!(0,L.isSessionLive)(r))throw new x("session_not_active","SessionAccount PDA is present but expired");if(!Ze(r.session.sessionPubkey,t.sessionPubkey))throw new x("session_pubkey_mismatch",`on-chain ${we(r.session.sessionPubkey)} != registration ${we(t.sessionPubkey)}`)}var w=class extends Error{constructor(t){super(`Invalid voucher signature${t?`: ${t}`:""}`),this.name="InvalidVoucherSignatureError"}};function j(e,t){if(t.length!==32)throw new w(`channelIdBytes must be 32 bytes, got ${t.length}`);if(e.sessionPublicKey.length!==32)throw new w(`sessionPublicKey must be 32 bytes, got ${e.sessionPublicKey.length}`);if(e.sessionSignature.length!==64)throw new w(`sessionSignature must be 64 bytes, got ${e.sessionSignature.length}`);let r=(0,R.voucherPayloadMessage)({channelId:t,cumulativeAmount:BigInt(e.payload.cumulativeAmount),sequenceNumber:e.payload.sequenceNumber});if(!xe.default.sign.detached.verify(r,e.sessionSignature,e.sessionPublicKey))throw new w("ed25519 verify rejected")}var b=class extends Error{constructor(r,n){super(`Scope violation: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="ScopeViolationError"}};function X(e){let t=BigInt(e.voucher.payload.cumulativeAmount);if(t>e.registration.maxAmount)throw new b("cumulative_exceeds_cap",`${t} > ${e.registration.maxAmount}`);let r=BigInt(Math.floor(Date.now()/1e3));if(r>=e.registration.expiresAt)throw new b("session_expired",`now=${r} >= expiresAt=${e.registration.expiresAt}`);if(!e.registration.allowedCounterparty.equals(e.expectedCounterparty))throw new b("wrong_counterparty",`${e.registration.allowedCounterparty.toBase58()} != ${e.expectedCounterparty.toBase58()}`);if(e.previousCumulativeAtomic!==void 0){let n=BigInt(e.previousCumulativeAtomic);if(t<=n)throw new b("non_monotonic",`cumulative=${t} not > previous=${n}`)}}function Ze(e,t){if(e.length!==t.length)return!1;for(let r=0;r<e.length;r++)if(e[r]!==t[r])return!1;return!0}function we(e){let t="";for(let r of e)t+=r.toString(16).padStart(2,"0");return t}var N=require("fs"),z=require("path");function Qe(e){return{payload:e.payload,sessionPublicKey:de(e.sessionPublicKey),sessionRegistration:de(e.sessionRegistration),sessionSignature:de(e.sessionSignature)}}function et(e){return{payload:e.payload,sessionPublicKey:ge(e.sessionPublicKey),sessionRegistration:ge(e.sessionRegistration),sessionSignature:ge(e.sessionSignature)}}function de(e){let t="";for(let r of e)t+=r.toString(16).padStart(2,"0");return t}function ge(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 r=0;r<t.length;r++)t[r]=parseInt(e.substr(r*2,2),16);return t}var I=class{map=new Map;async get(t){return this.map.get(t)??null}async set(t,r){this.map.set(t,r)}async delete(t){this.map.delete(t)}},J=class{constructor(t){this.dir=t}pathFor(t){if(!/^[a-z0-9_-]+$/i.test(t))throw new Error(`unsafe channelId for filesystem: ${t}`);return(0,z.join)(this.dir,`${t}.json`)}async get(t){try{let r=await N.promises.readFile(this.pathFor(t),"utf8");return et(JSON.parse(r))}catch(r){if(r?.code==="ENOENT")return null;throw r}}async set(t,r){let n=this.pathFor(t);await N.promises.mkdir((0,z.dirname)(n),{recursive:!0});let s=`${n}.tmp`;await N.promises.writeFile(s,JSON.stringify(Qe(r))),await N.promises.rename(s,n)}async delete(t){try{await N.promises.unlink(this.pathFor(t))}catch(r){if(r?.code!=="ENOENT")throw r}}};var nt=require("@solana/web3.js"),st=require("@noble/hashes/utils");var tt=Se(require("tweetnacl"),1);var rt=require("@noble/hashes/sha256");var ve=6;function v(e,t=ve){if(!/^\d+(\.\d+)?$/.test(e))throw new Error(`amount must be a non-negative decimal string, got "${e}"`);let[r,n=""]=e.split(".");if(n.length>t)throw new Error(`amount "${e}" has more than ${t} decimals`);let s=n.padEnd(t,"0"),i=`${r}${s}`.replace(/^0+(?=\d)/,"");return i===""?"0":i}function k(e,t=ve){if(!/^\d+$/.test(e))throw new Error(`atomic must be a non-negative integer string, got "${e}"`);let r=e.padStart(t+1,"0"),n=r.slice(0,-t).replace(/^0+(?=\d)/,"")||"0",s=r.slice(-t).replace(/0+$/,"");return s?`${n}.${s}`:n}var P="x-tab-voucher",he=class{map=new Map;get(t){return this.map.get(t)}set(t,r){this.map.set(t,r)}update(t,r){let n=this.map.get(t);n&&(n.lastCumulativeAtomic=r)}delete(t){this.map.delete(t)}},fe=class{constructor(t,r,n,s){this.chargeImpl=s;this.channelId=t,this.network=r,this.cumulativeAtomic=n}channelId;network;sessionPublicKey=null;cumulativeAtomic;cumulative(){return k(this.cumulativeAtomic.toString())}bumpCumulative(t){this.cumulativeAtomic=t}setSessionPublicKey(t){this.sessionPublicKey=t}async charge(t){return this.chargeImpl(t)}};function ot(e){if(typeof e!="string"||e.length===0)throw new A("signature_invalid",`missing ${P} header`);let t;try{t=Buffer.from(e,"base64").toString("utf8")}catch{throw new A("signature_invalid","malformed base64")}let r;try{r=JSON.parse(t)}catch{throw new A("signature_invalid","malformed JSON")}if(!r||typeof r!="object"||!r.payload||!r.sessionPublicKey)throw new A("signature_invalid","missing required fields");return{payload:r.payload,sessionPublicKey:Y(r.sessionPublicKey),sessionRegistration:Y(r.sessionRegistration),sessionSignature:Y(r.sessionSignature)}}function Y(e){if(typeof e!="string"||e.length%2!==0)throw new A("signature_invalid",`bad hex: ${typeof e}`);let t=new Uint8Array(e.length/2);for(let r=0;r<t.length;r++)t[r]=parseInt(e.substr(r*2,2),16);return t}function it(e){if(!/^[0-9a-f]{64}$/i.test(e))throw new A("signature_invalid",`channelId must be 64-char hex, got "${e}"`);return Y(e)}function G(e){let t=e.store??new I,r=new he,n=typeof e.sellerPubkey=="string"?new Ee.PublicKey(e.sellerPubkey):e.sellerPubkey,s=e.maxPerVoucherAtomic?BigInt(e.maxPerVoucherAtomic):BigInt(v(e.perUnit))*100n;return async(i,m,c)=>{try{let o=ot(i.headers[P]),l=o.payload.channelId,g=it(l),d=r.get(l);if(!d){let _=W(o.sessionRegistration);await F(e.connection,_),d={registration:_,lastCumulativeAtomic:"0"},r.set(l,d)}j(o,g),X({registration:d.registration,voucher:o,expectedCounterparty:n,previousCumulativeAtomic:d.lastCumulativeAtomic});let u=BigInt(o.payload.cumulativeAmount),h=BigInt(d.lastCumulativeAtomic),f=u-h;if(f>s)throw new b("cumulative_exceeds_cap",`single voucher increment ${f} exceeds maxPerVoucherAtomic ${s}`);await t.set(l,o),r.update(l,o.payload.cumulativeAmount);let T=new fe(l,e.network,u,async _=>{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.")});T.setSessionPublicKey(o.sessionPublicKey),i.tab=T,c()}catch(o){if(o instanceof A||o instanceof S||o instanceof x||o instanceof w||o instanceof b){m.status(402).json({error:"invalid_voucher",reason:o.reason??"unknown",detail:o.message});return}c(o)}}}function Te(e){if(!e.tab)throw new Error("req.tab is missing \u2014 did tabMiddleware run on this route?");return e.tab}function Pe(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 r=t.tab,n=BigInt(v(r.cumulative())),s=t.perUnit?BigInt(v(t.perUnit)):null,i=0n,m=!1;function c(g=1){if(m)return Promise.reject(new Error("meter ended"));if(s===null)return Promise.reject(new Error("charge() needs options.perUnit"));let d=s*BigInt(g),u=i+d;return u>n?Promise.reject(new b("cumulative_exceeds_cap",`chunk would push request total to ${k(u.toString())} beyond voucher-authorized budget ${k(n.toString())}`)):(i=u,Promise.resolve())}function o(g){if(m)throw new Error("meter ended");let u=(typeof g=="string"?g:Buffer.from(g).toString("utf8")).replace(/\n/g,"\\n");e.write(`data: ${u}
|
|
2
2
|
|
|
3
|
-
`)}function
|
|
4
|
-
data: {"chargedAtomic":"${
|
|
3
|
+
`)}function l(){m||(m=!0,e.write(`event: end
|
|
4
|
+
data: {"chargedAtomic":"${i}"}
|
|
5
5
|
|
|
6
|
-
`),e.end())}return{charge:f,send:i,end:d}}0&&(module.exports={FileVoucherStore,InMemoryVoucherStore,InvalidRegistrationError,InvalidVoucherError,InvalidVoucherSignatureError,OnChainVerificationError,ScopeViolationError,TAB_VOUCHER_HEADER,enforceScope,openSse,parseRegistration,requireTab,tabMiddleware,verifyRegistrationOnChain,verifyVoucherSignature});
|
|
6
|
+
`),e.end())}return{charge:c,send:o,end:l}}var ke=require("@solana/web3.js");var E="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",_e="solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",Re="solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";var V="eip155:8453",Z="eip155:84532",Q="eip155:42161",ee="eip155:137",te="eip155:10",re="eip155:43114",ne="eip155:56",se="eip155:1187947933",oe="eip155:324705682",ie="eip155:1";var ae="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";var Ce="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",at="0x55d398326f99059fF775485246999027B3197955",Ne="0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",Ie={[ne]:Ne,[V]:Ce,[Z]:"0x036CbD53842c5426634e7929541eC2318f3dCF7e",[Q]:"0xaf88d065e77c8cC2239327C5EDb3A432268e5831",[ee]:"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",[te]:"0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",[re]:"0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",[se]:"0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",[oe]:"0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",[ie]:"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"},Ue={[at]:{symbol:"USDT",decimals:18},[Ne]:{symbol:"USDC",decimals:18}};var Lt={[ne]:56,[V]:8453,[Z]:84532,[Q]:42161,[ee]:137,[te]:10,[re]:43114,[se]:1187947933,[oe]:324705682,[ie]:1},Wt={[E]:"https://api.dexter.cash/api/solana/rpc",[_e]:"https://api.devnet.solana.com",[Re]:"https://api.testnet.solana.com"},Ft={[ne]:"https://api.dexter.cash/api/evm/bsc/rpc",[V]:"https://api.dexter.cash/api/base/rpc",[Z]:"https://sepolia.base.org",[Q]:"https://api.dexter.cash/api/evm/arbitrum/rpc",[ee]:"https://api.dexter.cash/api/evm/polygon/rpc",[te]:"https://api.dexter.cash/api/evm/optimism/rpc",[re]:"https://api.dexter.cash/api/evm/avalanche/rpc",[se]:"https://skale-base.skalenodes.com/v1/base",[oe]:"https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",[ie]:"https://eth.llamarpc.com"},$="https://x402.dexter.cash";function ce(e){return e.startsWith("solana:")||e==="solana"}function ct(e){if(typeof Buffer<"u")return Buffer.from(e,"utf-8").toString("base64");let t=new TextEncoder().encode(e),r="";for(let n=0;n<t.length;n++)r+=String.fromCharCode(t[n]);return btoa(r)}function ut(e){if(typeof Buffer<"u")return Buffer.from(e,"base64").toString("utf-8");let t=atob(e),r=new Uint8Array(t.length);for(let n=0;n<t.length;n++)r[n]=t.charCodeAt(n);return new TextDecoder().decode(r)}function ue(e){return ct(JSON.stringify(e))}function K(e){return JSON.parse(ut(e))}function lt(e){if(e instanceof TypeError)return!0;if(e&&typeof e=="object"&&"status"in e){let t=e.status;return t>=500&&t<600}return!1}var B=class extends Error{status;body;constructor(t,r){super(`HTTP ${t}`),this.status=t,this.body=r}},le=class{facilitatorUrl;cachedSupported=null;cacheTime=0;CACHE_TTL_MS=6e4;timeoutMs;maxRetries;retryBaseMs;constructor(t=$,r){this.facilitatorUrl=t.replace(/\/$/,""),this.timeoutMs=r?.timeoutMs??1e4,this.maxRetries=r?.maxRetries??3,this.retryBaseMs=r?.retryBaseMs??500}async fetchWithTimeout(t,r){let n=new AbortController,s=setTimeout(()=>n.abort(),this.timeoutMs);try{return await fetch(t,{...r,signal:n.signal})}finally{clearTimeout(s)}}async fetchWithRetry(t,r){let n;for(let s=0;s<this.maxRetries;s++)try{let i=await this.fetchWithTimeout(t,r);if(!i.ok&&i.status>=500)throw new B(i.status,await i.text());return i}catch(i){if(n=i,s<this.maxRetries-1&<(i)){let m=this.retryBaseMs*Math.pow(2,s);await new Promise(c=>setTimeout(c,m));continue}throw i}throw n}async getSupported(){let t=Date.now();if(this.cachedSupported&&t-this.cacheTime<this.CACHE_TTL_MS)return this.cachedSupported;let r=await this.fetchWithTimeout(`${this.facilitatorUrl}/supported`);if(!r.ok)throw new Error(`Facilitator /supported returned ${r.status}`);return this.cachedSupported=await r.json(),this.cacheTime=t,this.cachedSupported}async getFeePayer(t){let n=(await this.getSupported()).kinds.find(s=>s.x402Version===2&&(s.scheme==="exact"||s.scheme==="exact-approval")&&s.network===t);if(!n)throw new Error(`Facilitator does not support network "${t}" with a recognized scheme`);return n.extra?.feePayer}async getNetworkExtra(t){return(await this.getSupported()).kinds.find(s=>s.x402Version===2&&(s.scheme==="exact"||s.scheme==="exact-approval"||s.scheme==="batch-settlement")&&s.network===t)?.extra}async verifyPayment(t,r){try{let n=K(t),s=await this.fetchWithRetry(`${this.facilitatorUrl}/verify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({x402Version:2,paymentPayload:n,paymentRequirements:r})});return s.ok?await s.json():{isValid:!1,invalidReason:`facilitator_error_${s.status}`}}catch(n){return{isValid:!1,invalidReason:n instanceof B?`facilitator_error_${n.status}`:n instanceof Error&&n.name==="AbortError"?"facilitator_timeout":n instanceof Error?n.message:"unexpected_verify_error"}}}async settlePayment(t,r){try{let n=K(t),s=await this.fetchWithRetry(`${this.facilitatorUrl}/settle`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({x402Version:2,paymentPayload:n,paymentRequirements:r})});return s.ok?{...await s.json(),network:r.network}:{success:!1,network:r.network,errorReason:`facilitator_error_${s.status}`}}catch(n){let s=n instanceof B?`facilitator_error_${n.status}`:n instanceof Error&&n.name==="AbortError"?"facilitator_timeout":n instanceof Error?n.message:"unexpected_settle_error";return{success:!1,network:r.network,errorReason:s}}}};function pt(e){if(ce(e))return{address:ae,decimals:6};let t=Ie[e];if(t){let r=Ue[t]?.decimals??6;return{address:t,decimals:r}}return{address:ae,decimals:6}}function Oe(e){try{let t=K(e);return t?.accepted?.amount??t?.accepted?.maxAmountRequired}catch{return}}function M(e){let{payTo:t,facilitatorUrl:r=$,network:n=E,defaultTimeoutSeconds:s=60}=e,i=e.asset??pt(n),m=e.scheme??"exact";if(m==="tab"&&!ce(n))throw new Error(`scheme 'tab' is SVM-only; got network "${n}"`);let c=new le(r),o=null,l=new Map,g=3e4,d=Date.now();function u(a){let p=(a.maxTimeoutSeconds||s)*1e3;if(l.set(a.payTo,{accept:a,expiresAt:Date.now()+p}),Date.now()-d>g){let y=Date.now();for(let[U,O]of l)O.expiresAt<y&&l.delete(U);d=y}}function h(a){let p=l.get(a);if(p){if(p.expiresAt<Date.now()){l.delete(a);return}return p.accept}}async function f(a){return typeof t=="string"?t:t(a||{})}async function T(){if(o||(o=await c.getNetworkExtra(n)),ce(n)&&!o?.feePayer)throw new Error(`Facilitator does not provide feePayer for network "${n}"`);return{...o?.feePayer?{feePayer:o.feePayer}:{},decimals:o?.decimals??i.decimals,name:o?.name,version:o?.version,...m==="batch-settlement"&&o?.receiverAuthorizer?{receiverAuthorizer:o.receiverAuthorizer}:{},...m==="tab"?{voucherHeader:"x-tab-voucher",registrationEncoding:"base64(188-byte sessionRegisterMessage)"}:{}}}async function _(a,p){let{amountAtomic:y,timeoutSeconds:U=s}=p,O=await T(),D={scheme:m,network:n,amount:y,maxAmountRequired:y,asset:i.address,payTo:a,maxTimeoutSeconds:U,extra:O};return u(D),D}async function ye(a){let p=await f({amountAtomic:a.amountAtomic,resourceUrl:a.resourceUrl});return _(p,a)}async function Be(a){let{resourceUrl:p,description:y,mimeType:U="application/json"}=a,O={url:p,description:y,mimeType:U},D=await ye(a);return{x402Version:2,resource:O,accepts:[D],error:"Payment required"}}function be(a){return ue(a)}function Me(a){return{status:402,headers:{"PAYMENT-REQUIRED":be(a)},body:{}}}async function De(a,p){if(!p){let y=await f({paymentHeader:a});p=h(y),p||(p=await _(y,{amountAtomic:Oe(a)??"0",resourceUrl:""}))}return c.verifyPayment(a,p)}async function He(a,p){if(!p){let y=await f({paymentHeader:a});p=h(y),p||(p=await _(y,{amountAtomic:Oe(a)??"0",resourceUrl:""}))}return c.settlePayment(a,p)}return{buildRequirements:Be,encodeRequirements:be,create402Response:Me,verifyPayment:De,settlePayment:He,getPaymentAccept:ye,network:n,assetDecimals:i.decimals,facilitator:c}}var mt={"solana:mainnet":E};function Ve(e){let t=mt[e.network];if(!t)throw new Error(`tabChallengeMiddleware: unsupported network "${e.network}"`);let r=typeof e.sellerPubkey=="string"?e.sellerPubkey:e.sellerPubkey.toBase58();new ke.PublicKey(r);let n=M({payTo:r,network:t,scheme:"tab",facilitatorUrl:e.facilitatorUrl}),s=v(e.perUnit);return async(i,m,c)=>{if(i.headers[P])return c();try{let o=`${i.protocol}://${i.get("host")}${i.originalUrl}`,l=await n.buildRequirements({amountAtomic:s,resourceUrl:o,description:e.description}),g=n.create402Response(l);m.set(g.headers).status(g.status).json(g.body)}catch(o){let l=o?.message??String(o);m.status(503).set({"Retry-After":"5"}).json({error:"challenge_unavailable",detail:l})}}}var $e=require("@solana/web3.js");var dt={"solana:mainnet":E};function Ke(e){let t=dt[e.network];if(!t)throw new Error(`tabOrExactMiddleware: unsupported network "${e.network}"`);let r=typeof e.sellerPubkey=="string"?e.sellerPubkey:e.sellerPubkey.toBase58();new $e.PublicKey(r);let n=M({payTo:r,network:t,scheme:"tab",facilitatorUrl:e.facilitatorUrl}),s=M({payTo:r,network:t,scheme:"exact",facilitatorUrl:e.facilitatorUrl}),i=v(e.perUnit),m=G({connection:e.connection,sellerPubkey:r,network:e.network,perUnit:e.perUnit,settle:"on-close",facilitatorUrl:e.facilitatorUrl});return async(c,o,l)=>{if(c.headers[P])return m(c,o,l);let g=`${c.protocol}://${c.get("host")}${c.originalUrl}`,d=c.headers["payment-signature"];if(d){let u;try{u=await s.getPaymentAccept({amountAtomic:i,resourceUrl:g,description:e.description})}catch(h){let f=h?.message??String(h);o.status(503).set({"Retry-After":"5"}).json({error:"challenge_unavailable",detail:f});return}try{let h=await s.verifyPayment(d,u);if(!h.isValid){o.status(402).json({error:"Payment verification failed",reason:h.invalidReason});return}let f=await s.settlePayment(d,u);if(!f.success){o.status(402).json({error:"Payment settlement failed",reason:f.errorReason});return}return c.x402={transaction:f.transaction,payer:h.payer??"",network:f.network||t},o.setHeader("PAYMENT-RESPONSE",ue({success:!0,transaction:f.transaction,network:f.network||t,payer:h.payer??""})),l()}catch{o.status(500).json({error:"Payment processing error"});return}}try{let u={amountAtomic:i,resourceUrl:g,description:e.description},[h,f]=await Promise.all([n.buildRequirements(u),s.buildRequirements(u)]),T={...h,accepts:[...h.accepts,...f.accepts]};o.set({"PAYMENT-REQUIRED":n.encodeRequirements(T)}).status(402).json({error:"Payment required",accepts:T.accepts,resource:T.resource})}catch(u){let h=u?.message??String(u);o.status(503).set({"Retry-After":"5"}).json({error:"challenge_unavailable",detail:h})}}}0&&(module.exports={FileVoucherStore,InMemoryVoucherStore,InvalidRegistrationError,InvalidVoucherError,InvalidVoucherSignatureError,OnChainVerificationError,ScopeViolationError,TAB_VOUCHER_HEADER,enforceScope,openSse,parseRegistration,requireTab,tabChallengeMiddleware,tabMiddleware,tabOrExactMiddleware,verifyRegistrationOnChain,verifyVoucherSignature});
|
|
@@ -277,4 +277,68 @@ declare function enforceScope(args: {
|
|
|
277
277
|
previousCumulativeAtomic?: AtomicAmount;
|
|
278
278
|
}): void;
|
|
279
279
|
|
|
280
|
-
|
|
280
|
+
/**
|
|
281
|
+
* The discovery half of a tab seller: answer voucher-LESS requests with a
|
|
282
|
+
* standard x402 v2 402 challenge advertising scheme 'tab', so a stranger's
|
|
283
|
+
* agent can resolve the counterparty off the wire. Compose BEFORE
|
|
284
|
+
* tabMiddleware:
|
|
285
|
+
*
|
|
286
|
+
* app.get('/paid/x',
|
|
287
|
+
* tabChallengeMiddleware({ sellerPubkey, network, perUnit, facilitatorUrl }),
|
|
288
|
+
* tabMiddleware({ ... }),
|
|
289
|
+
* handler);
|
|
290
|
+
*
|
|
291
|
+
* Requests carrying x-tab-voucher fall through to tabMiddleware untouched.
|
|
292
|
+
* The challenge emits the CAIP-2 network form (x402 v2) — the SDK-internal
|
|
293
|
+
* 'solana:mainnet' alias is NOT standard and buyers drop it.
|
|
294
|
+
*/
|
|
295
|
+
|
|
296
|
+
interface TabChallengeConfig {
|
|
297
|
+
/** Seller pubkey — advertised as the tab counterparty (payTo). */
|
|
298
|
+
sellerPubkey: string | PublicKey;
|
|
299
|
+
/** Tab network id ('solana:mainnet'); mapped to CAIP-2 on the wire. */
|
|
300
|
+
network: TabNetworkId;
|
|
301
|
+
/** Per-request price in human units; advertised as maxAmountRequired. */
|
|
302
|
+
perUnit: HumanAmount;
|
|
303
|
+
/** Facilitator base URL (the challenge embeds its feePayer extra). */
|
|
304
|
+
facilitatorUrl?: string;
|
|
305
|
+
description?: string;
|
|
306
|
+
}
|
|
307
|
+
declare function tabChallengeMiddleware(config: TabChallengeConfig): RequestHandler;
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Dual-rail tab seller: ONE middleware advertising BOTH payment rails in a
|
|
311
|
+
* single standard x402 v2 402 challenge —
|
|
312
|
+
*
|
|
313
|
+
* scheme 'tab' — agents open a freeze-protected tab and stream vouchers
|
|
314
|
+
* scheme 'exact' — one-shot buyers (and catalog verifiers, which cannot
|
|
315
|
+
* open tabs) pay per request
|
|
316
|
+
*
|
|
317
|
+
* Compose as the ONLY payment middleware on the route:
|
|
318
|
+
*
|
|
319
|
+
* app.get('/paid/x', tabOrExactMiddleware({ ... }), handler);
|
|
320
|
+
*
|
|
321
|
+
* In the handler: `(req as X402Request).x402` set -> the request was paid
|
|
322
|
+
* via exact (respond normally); otherwise `requireTab(req)` -> tab rail
|
|
323
|
+
* (charge via openSse meter).
|
|
324
|
+
*
|
|
325
|
+
* SECURITY: the exact rail passes requirements EXPLICITLY to verify/settle
|
|
326
|
+
* (built from OUR configured amount). X402Server's no-requirements fallback
|
|
327
|
+
* rebuilds them from the BUYER'S header amount on cache miss — an
|
|
328
|
+
* underpayment hole this middleware must never take (pinned in dual.test.ts).
|
|
329
|
+
*/
|
|
330
|
+
|
|
331
|
+
interface TabOrExactConfig {
|
|
332
|
+
/** For tab voucher verification (V6 session PDA reads). */
|
|
333
|
+
connection: Connection;
|
|
334
|
+
/** Seller pubkey — payTo on BOTH rails. */
|
|
335
|
+
sellerPubkey: string | PublicKey;
|
|
336
|
+
network: TabNetworkId;
|
|
337
|
+
/** Price per request, human units — identical on both rails. */
|
|
338
|
+
perUnit: HumanAmount;
|
|
339
|
+
facilitatorUrl?: string;
|
|
340
|
+
description?: string;
|
|
341
|
+
}
|
|
342
|
+
declare function tabOrExactMiddleware(config: TabOrExactConfig): RequestHandler;
|
|
343
|
+
|
|
344
|
+
export { FileVoucherStore, InMemoryVoucherStore, InvalidRegistrationError, InvalidVoucherError, InvalidVoucherSignatureError, OnChainVerificationError, type OpenSseOptions, type ParsedRegistration, ScopeViolationError, type SellerTab, type SseMeter, TAB_VOUCHER_HEADER, type TabChallengeConfig, type TabMiddlewareConfig, type TabMiddlewareOptions, type TabOrExactConfig, type VoucherStore, enforceScope, openSse, parseRegistration, requireTab, tabChallengeMiddleware, tabMiddleware, tabOrExactMiddleware, verifyRegistrationOnChain, verifyVoucherSignature };
|
|
@@ -277,4 +277,68 @@ declare function enforceScope(args: {
|
|
|
277
277
|
previousCumulativeAtomic?: AtomicAmount;
|
|
278
278
|
}): void;
|
|
279
279
|
|
|
280
|
-
|
|
280
|
+
/**
|
|
281
|
+
* The discovery half of a tab seller: answer voucher-LESS requests with a
|
|
282
|
+
* standard x402 v2 402 challenge advertising scheme 'tab', so a stranger's
|
|
283
|
+
* agent can resolve the counterparty off the wire. Compose BEFORE
|
|
284
|
+
* tabMiddleware:
|
|
285
|
+
*
|
|
286
|
+
* app.get('/paid/x',
|
|
287
|
+
* tabChallengeMiddleware({ sellerPubkey, network, perUnit, facilitatorUrl }),
|
|
288
|
+
* tabMiddleware({ ... }),
|
|
289
|
+
* handler);
|
|
290
|
+
*
|
|
291
|
+
* Requests carrying x-tab-voucher fall through to tabMiddleware untouched.
|
|
292
|
+
* The challenge emits the CAIP-2 network form (x402 v2) — the SDK-internal
|
|
293
|
+
* 'solana:mainnet' alias is NOT standard and buyers drop it.
|
|
294
|
+
*/
|
|
295
|
+
|
|
296
|
+
interface TabChallengeConfig {
|
|
297
|
+
/** Seller pubkey — advertised as the tab counterparty (payTo). */
|
|
298
|
+
sellerPubkey: string | PublicKey;
|
|
299
|
+
/** Tab network id ('solana:mainnet'); mapped to CAIP-2 on the wire. */
|
|
300
|
+
network: TabNetworkId;
|
|
301
|
+
/** Per-request price in human units; advertised as maxAmountRequired. */
|
|
302
|
+
perUnit: HumanAmount;
|
|
303
|
+
/** Facilitator base URL (the challenge embeds its feePayer extra). */
|
|
304
|
+
facilitatorUrl?: string;
|
|
305
|
+
description?: string;
|
|
306
|
+
}
|
|
307
|
+
declare function tabChallengeMiddleware(config: TabChallengeConfig): RequestHandler;
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Dual-rail tab seller: ONE middleware advertising BOTH payment rails in a
|
|
311
|
+
* single standard x402 v2 402 challenge —
|
|
312
|
+
*
|
|
313
|
+
* scheme 'tab' — agents open a freeze-protected tab and stream vouchers
|
|
314
|
+
* scheme 'exact' — one-shot buyers (and catalog verifiers, which cannot
|
|
315
|
+
* open tabs) pay per request
|
|
316
|
+
*
|
|
317
|
+
* Compose as the ONLY payment middleware on the route:
|
|
318
|
+
*
|
|
319
|
+
* app.get('/paid/x', tabOrExactMiddleware({ ... }), handler);
|
|
320
|
+
*
|
|
321
|
+
* In the handler: `(req as X402Request).x402` set -> the request was paid
|
|
322
|
+
* via exact (respond normally); otherwise `requireTab(req)` -> tab rail
|
|
323
|
+
* (charge via openSse meter).
|
|
324
|
+
*
|
|
325
|
+
* SECURITY: the exact rail passes requirements EXPLICITLY to verify/settle
|
|
326
|
+
* (built from OUR configured amount). X402Server's no-requirements fallback
|
|
327
|
+
* rebuilds them from the BUYER'S header amount on cache miss — an
|
|
328
|
+
* underpayment hole this middleware must never take (pinned in dual.test.ts).
|
|
329
|
+
*/
|
|
330
|
+
|
|
331
|
+
interface TabOrExactConfig {
|
|
332
|
+
/** For tab voucher verification (V6 session PDA reads). */
|
|
333
|
+
connection: Connection;
|
|
334
|
+
/** Seller pubkey — payTo on BOTH rails. */
|
|
335
|
+
sellerPubkey: string | PublicKey;
|
|
336
|
+
network: TabNetworkId;
|
|
337
|
+
/** Price per request, human units — identical on both rails. */
|
|
338
|
+
perUnit: HumanAmount;
|
|
339
|
+
facilitatorUrl?: string;
|
|
340
|
+
description?: string;
|
|
341
|
+
}
|
|
342
|
+
declare function tabOrExactMiddleware(config: TabOrExactConfig): RequestHandler;
|
|
343
|
+
|
|
344
|
+
export { FileVoucherStore, InMemoryVoucherStore, InvalidRegistrationError, InvalidVoucherError, InvalidVoucherSignatureError, OnChainVerificationError, type OpenSseOptions, type ParsedRegistration, ScopeViolationError, type SellerTab, type SseMeter, TAB_VOUCHER_HEADER, type TabChallengeConfig, type TabMiddlewareConfig, type TabMiddlewareOptions, type TabOrExactConfig, type VoucherStore, enforceScope, openSse, parseRegistration, requireTab, tabChallengeMiddleware, tabMiddleware, tabOrExactMiddleware, verifyRegistrationOnChain, verifyVoucherSignature };
|
package/dist/tab/seller/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
var l=class extends Error{constructor(n,r){super(`Invalid voucher: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidVoucherError"}};import{PublicKey as Y}from"@solana/web3.js";import L from"tweetnacl";import{sha256 as Se}from"@noble/hashes/sha256";import{p256 as xe}from"@noble/curves/p256";import{PublicKey as I}from"@solana/web3.js";import{sessionRegisterMessage as se,sessionRevokeMessage as ae,voucherPayloadMessage as P,buildVoucherMessage as ue}from"@dexterai/vault/messages";import{buildRegisterSessionKeyInstruction as me,buildRevokeSessionKeyInstruction as de,deriveSwigWalletAddress as pe}from"@dexterai/vault/instructions";import{buildSecp256r1VerifyInstruction as he}from"@dexterai/vault/precompile";import{DEXTER_VAULT_PROGRAM_ID as T,SECP256R1_PROGRAM_ID as fe,INSTRUCTIONS_SYSVAR_ID as we}from"@dexterai/vault/constants";import{fetchSessionAccount as j,isSessionLive as z}from"@dexterai/vault/session";var V="OTS_SESSION_REGISTER_V2",m=class extends Error{constructor(n,r){super(`Invalid registration: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidRegistrationError"}};function _(e){if(e.length!==188)throw new m("wrong_length",`expected 188, got ${e.length}`);let t=new TextDecoder().decode(e.slice(0,V.length));if(t!==V)throw new m("wrong_domain",`got "${t}"`);for(let s=V.length;s<32;s++)if(e[s]!==0)throw new m("wrong_domain",`non-NUL padding at byte ${s}`);let n=new DataView(e.buffer,e.byteOffset,e.byteLength),r=new I(e.slice(32,64)),i=new I(e.slice(64,96)),c=e.slice(96,128),p=n.getBigUint64(128,!0),y=n.getBigInt64(136,!0),o=new I(e.slice(144,176)),d=n.getUint32(176,!0),g=n.getBigUint64(180,!0);if(!r.equals(T))throw new m("wrong_program",`${r.toBase58()} is not ${T.toBase58()}`);if(p===0n)throw new m("cap_zero");let a=BigInt(Math.floor(Date.now()/1e3));if(y<=a)throw new m("expiry_in_past",`expires_at=${y}, now=${a}`);return{programId:r,vaultPda:i,sessionPubkey:new Uint8Array(c),maxAmount:p,expiresAt:y,allowedCounterparty:o,nonce:d,maxRevolvingCapacity:g}}var f=class extends Error{constructor(n,r){super(`On-chain verification failed: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="OnChainVerificationError"}};async function $(e,t){let n=await j(e,t.vaultPda,t.allowedCounterparty);if(!n||n.version===0)throw new f("session_not_active","no live SessionAccount PDA for this (vault, counterparty) \u2014 revoked, expiry-swept, or never registered");if(!z(n))throw new f("session_not_active","SessionAccount PDA is present but expired");if(!F(n.session.sessionPubkey,t.sessionPubkey))throw new f("session_pubkey_mismatch",`on-chain ${M(n.session.sessionPubkey)} != registration ${M(t.sessionPubkey)}`)}var h=class extends Error{constructor(t){super(`Invalid voucher signature${t?`: ${t}`:""}`),this.name="InvalidVoucherSignatureError"}};function C(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=P({channelId:t,cumulativeAmount:BigInt(e.payload.cumulativeAmount),sequenceNumber:e.payload.sequenceNumber});if(!L.sign.detached.verify(n,e.sessionSignature,e.sessionPublicKey))throw new h("ed25519 verify rejected")}var u=class extends Error{constructor(n,r){super(`Scope violation: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="ScopeViolationError"}};function R(e){let t=BigInt(e.voucher.payload.cumulativeAmount);if(t>e.registration.maxAmount)throw new u("cumulative_exceeds_cap",`${t} > ${e.registration.maxAmount}`);let n=BigInt(Math.floor(Date.now()/1e3));if(n>=e.registration.expiresAt)throw new u("session_expired",`now=${n} >= expiresAt=${e.registration.expiresAt}`);if(!e.registration.allowedCounterparty.equals(e.expectedCounterparty))throw new u("wrong_counterparty",`${e.registration.allowedCounterparty.toBase58()} != ${e.expectedCounterparty.toBase58()}`);if(e.previousCumulativeAtomic!==void 0){let r=BigInt(e.previousCumulativeAtomic);if(t<=r)throw new u("non_monotonic",`cumulative=${t} not > previous=${r}`)}}function F(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 M(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 J,dirname as G}from"path";function W(e){return{payload:e.payload,sessionPublicKey:U(e.sessionPublicKey),sessionRegistration:U(e.sessionRegistration),sessionSignature:U(e.sessionSignature)}}function X(e){return{payload:e.payload,sessionPublicKey:k(e.sessionPublicKey),sessionRegistration:k(e.sessionRegistration),sessionSignature:k(e.sessionSignature)}}function U(e){let t="";for(let n of e)t+=n.toString(16).padStart(2,"0");return t}function k(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)}},E=class{constructor(t){this.dir=t}pathFor(t){if(!/^[a-z0-9_-]+$/i.test(t))throw new Error(`unsafe channelId for filesystem: ${t}`);return J(this.dir,`${t}.json`)}async get(t){try{let n=await w.readFile(this.pathFor(t),"utf8");return X(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(G(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 ze}from"@solana/web3.js";import{bytesToHex as Je}from"@noble/hashes/utils";import Ke from"tweetnacl";import{sha256 as He}from"@noble/hashes/sha256";var q=6;function A(e,t=q){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"),c=`${n}${i}`.replace(/^0+(?=\d)/,"");return c===""?"0":c}function S(e,t=q){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 O="x-tab-voucher",K=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)}},N=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 Z(e){if(typeof e!="string"||e.length===0)throw new l("signature_invalid",`missing ${O} header`);let t;try{t=Buffer.from(e,"base64").toString("utf8")}catch{throw new l("signature_invalid","malformed base64")}let n;try{n=JSON.parse(t)}catch{throw new l("signature_invalid","malformed JSON")}if(!n||typeof n!="object"||!n.payload||!n.sessionPublicKey)throw new l("signature_invalid","missing required fields");return{payload:n.payload,sessionPublicKey:v(n.sessionPublicKey),sessionRegistration:v(n.sessionRegistration),sessionSignature:v(n.sessionSignature)}}function v(e){if(typeof e!="string"||e.length%2!==0)throw new l("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 Q(e){if(!/^[0-9a-f]{64}$/i.test(e))throw new l("signature_invalid",`channelId must be 64-char hex, got "${e}"`);return v(e)}function ee(e){let t=e.store??new b,n=new K,r=typeof e.sellerPubkey=="string"?new Y(e.sellerPubkey):e.sellerPubkey,i=e.maxPerVoucherAtomic?BigInt(e.maxPerVoucherAtomic):BigInt(A(e.perUnit))*100n;return async(c,p,y)=>{try{let o=Z(c.headers[O]),d=o.payload.channelId,g=Q(d),a=n.get(d);if(!a){let x=_(o.sessionRegistration);await $(e.connection,x),a={registration:x,lastCumulativeAtomic:"0"},n.set(d,a)}C(o,g),R({registration:a.registration,voucher:o,expectedCounterparty:r,previousCumulativeAtomic:a.lastCumulativeAtomic});let s=BigInt(o.payload.cumulativeAmount),D=BigInt(a.lastCumulativeAtomic),H=s-D;if(H>i)throw new u("cumulative_exceeds_cap",`single voucher increment ${H} exceeds maxPerVoucherAtomic ${i}`);await t.set(d,o),n.update(d,o.payload.cumulativeAmount);let B=new N(d,e.network,s,async x=>{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.")});B.setSessionPublicKey(o.sessionPublicKey),c.tab=B,y()}catch(o){if(o instanceof l||o instanceof m||o instanceof f||o instanceof h||o instanceof u){p.status(402).json({error:"invalid_voucher",reason:o.reason??"unknown",detail:o.message});return}y(o)}}}function te(e){if(!e.tab)throw new Error("req.tab is missing \u2014 did tabMiddleware run on this route?");return e.tab}function ne(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,c=0n,p=!1;function y(g=1){if(p)return Promise.reject(new Error("meter ended"));if(i===null)return Promise.reject(new Error("charge() needs options.perUnit"));let a=i*BigInt(g),s=c+a;return s>r?Promise.reject(new u("cumulative_exceeds_cap",`chunk would push request total to ${S(s.toString())} beyond voucher-authorized budget ${S(r.toString())}`)):(c=s,Promise.resolve())}function o(g){if(p)throw new Error("meter ended");let s=(typeof g=="string"?g:Buffer.from(g).toString("utf8")).replace(/\n/g,"\\n");e.write(`data: ${s}
|
|
1
|
+
var A=class extends Error{constructor(r,n){super(`Invalid voucher: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="InvalidVoucherError"}};import{PublicKey as $e}from"@solana/web3.js";import Re from"tweetnacl";import{sha256 as ft}from"@noble/hashes/sha256";import{p256 as bt}from"@noble/curves/p256";import{PublicKey as te}from"@solana/web3.js";import{sessionRegisterMessage as tt,sessionRevokeMessage as rt,voucherPayloadMessage as Q,buildVoucherMessage as nt}from"@dexterai/vault/messages";import{buildRegisterSessionKeyInstruction as it,buildRevokeSessionKeyInstruction as at,deriveSwigWalletAddress as ct}from"@dexterai/vault/instructions";import{buildSecp256r1VerifyInstruction as lt}from"@dexterai/vault/precompile";import{DEXTER_VAULT_PROGRAM_ID as ee,SECP256R1_PROGRAM_ID as mt,INSTRUCTIONS_SYSVAR_ID as dt}from"@dexterai/vault/constants";import{fetchSessionAccount as Ce,isSessionLive as Ne}from"@dexterai/vault/session";var re="OTS_SESSION_REGISTER_V2",S=class extends Error{constructor(r,n){super(`Invalid registration: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="InvalidRegistrationError"}};function ne(e){if(e.length!==188)throw new S("wrong_length",`expected 188, got ${e.length}`);let t=new TextDecoder().decode(e.slice(0,re.length));if(t!==re)throw new S("wrong_domain",`got "${t}"`);for(let u=re.length;u<32;u++)if(e[u]!==0)throw new S("wrong_domain",`non-NUL padding at byte ${u}`);let r=new DataView(e.buffer,e.byteOffset,e.byteLength),n=new te(e.slice(32,64)),s=new te(e.slice(64,96)),i=e.slice(96,128),m=r.getBigUint64(128,!0),c=r.getBigInt64(136,!0),o=new te(e.slice(144,176)),l=r.getUint32(176,!0),g=r.getBigUint64(180,!0);if(!n.equals(ee))throw new S("wrong_program",`${n.toBase58()} is not ${ee.toBase58()}`);if(m===0n)throw new S("cap_zero");let d=BigInt(Math.floor(Date.now()/1e3));if(c<=d)throw new S("expiry_in_past",`expires_at=${c}, now=${d}`);return{programId:n,vaultPda:s,sessionPubkey:new Uint8Array(i),maxAmount:m,expiresAt:c,allowedCounterparty:o,nonce:l,maxRevolvingCapacity:g}}var T=class extends Error{constructor(r,n){super(`On-chain verification failed: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="OnChainVerificationError"}};async function se(e,t){let r=await Ce(e,t.vaultPda,t.allowedCounterparty);if(!r||r.version===0)throw new T("session_not_active","no live SessionAccount PDA for this (vault, counterparty) \u2014 revoked, expiry-swept, or never registered");if(!Ne(r))throw new T("session_not_active","SessionAccount PDA is present but expired");if(!Ie(r.session.sessionPubkey,t.sessionPubkey))throw new T("session_pubkey_mismatch",`on-chain ${he(r.session.sessionPubkey)} != registration ${he(t.sessionPubkey)}`)}var w=class extends Error{constructor(t){super(`Invalid voucher signature${t?`: ${t}`:""}`),this.name="InvalidVoucherSignatureError"}};function oe(e,t){if(t.length!==32)throw new w(`channelIdBytes must be 32 bytes, got ${t.length}`);if(e.sessionPublicKey.length!==32)throw new w(`sessionPublicKey must be 32 bytes, got ${e.sessionPublicKey.length}`);if(e.sessionSignature.length!==64)throw new w(`sessionSignature must be 64 bytes, got ${e.sessionSignature.length}`);let r=Q({channelId:t,cumulativeAmount:BigInt(e.payload.cumulativeAmount),sequenceNumber:e.payload.sequenceNumber});if(!Re.sign.detached.verify(r,e.sessionSignature,e.sessionPublicKey))throw new w("ed25519 verify rejected")}var b=class extends Error{constructor(r,n){super(`Scope violation: ${r}${n?` (${n})`:""}`);this.reason=r;this.name="ScopeViolationError"}};function ie(e){let t=BigInt(e.voucher.payload.cumulativeAmount);if(t>e.registration.maxAmount)throw new b("cumulative_exceeds_cap",`${t} > ${e.registration.maxAmount}`);let r=BigInt(Math.floor(Date.now()/1e3));if(r>=e.registration.expiresAt)throw new b("session_expired",`now=${r} >= expiresAt=${e.registration.expiresAt}`);if(!e.registration.allowedCounterparty.equals(e.expectedCounterparty))throw new b("wrong_counterparty",`${e.registration.allowedCounterparty.toBase58()} != ${e.expectedCounterparty.toBase58()}`);if(e.previousCumulativeAtomic!==void 0){let n=BigInt(e.previousCumulativeAtomic);if(t<=n)throw new b("non_monotonic",`cumulative=${t} not > previous=${n}`)}}function Ie(e,t){if(e.length!==t.length)return!1;for(let r=0;r<e.length;r++)if(e[r]!==t[r])return!1;return!0}function he(e){let t="";for(let r of e)t+=r.toString(16).padStart(2,"0");return t}import{promises as N}from"fs";import{join as Ue,dirname as Oe}from"path";function ke(e){return{payload:e.payload,sessionPublicKey:ae(e.sessionPublicKey),sessionRegistration:ae(e.sessionRegistration),sessionSignature:ae(e.sessionSignature)}}function Ve(e){return{payload:e.payload,sessionPublicKey:ce(e.sessionPublicKey),sessionRegistration:ce(e.sessionRegistration),sessionSignature:ce(e.sessionSignature)}}function ae(e){let t="";for(let r of e)t+=r.toString(16).padStart(2,"0");return t}function ce(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 r=0;r<t.length;r++)t[r]=parseInt(e.substr(r*2,2),16);return t}var I=class{map=new Map;async get(t){return this.map.get(t)??null}async set(t,r){this.map.set(t,r)}async delete(t){this.map.delete(t)}},ue=class{constructor(t){this.dir=t}pathFor(t){if(!/^[a-z0-9_-]+$/i.test(t))throw new Error(`unsafe channelId for filesystem: ${t}`);return Ue(this.dir,`${t}.json`)}async get(t){try{let r=await N.readFile(this.pathFor(t),"utf8");return Ve(JSON.parse(r))}catch(r){if(r?.code==="ENOENT")return null;throw r}}async set(t,r){let n=this.pathFor(t);await N.mkdir(Oe(n),{recursive:!0});let s=`${n}.tmp`;await N.writeFile(s,JSON.stringify(ke(r))),await N.rename(s,n)}async delete(t){try{await N.unlink(this.pathFor(t))}catch(r){if(r?.code!=="ENOENT")throw r}}};import{PublicKey as Dt}from"@solana/web3.js";import{bytesToHex as qt}from"@noble/hashes/utils";import Nt from"tweetnacl";import{sha256 as Ot}from"@noble/hashes/sha256";var fe=6;function x(e,t=fe){if(!/^\d+(\.\d+)?$/.test(e))throw new Error(`amount must be a non-negative decimal string, got "${e}"`);let[r,n=""]=e.split(".");if(n.length>t)throw new Error(`amount "${e}" has more than ${t} decimals`);let s=n.padEnd(t,"0"),i=`${r}${s}`.replace(/^0+(?=\d)/,"");return i===""?"0":i}function U(e,t=fe){if(!/^\d+$/.test(e))throw new Error(`atomic must be a non-negative integer string, got "${e}"`);let r=e.padStart(t+1,"0"),n=r.slice(0,-t).replace(/^0+(?=\d)/,"")||"0",s=r.slice(-t).replace(/0+$/,"");return s?`${n}.${s}`:n}var _="x-tab-voucher",le=class{map=new Map;get(t){return this.map.get(t)}set(t,r){this.map.set(t,r)}update(t,r){let n=this.map.get(t);n&&(n.lastCumulativeAtomic=r)}delete(t){this.map.delete(t)}},pe=class{constructor(t,r,n,s){this.chargeImpl=s;this.channelId=t,this.network=r,this.cumulativeAtomic=n}channelId;network;sessionPublicKey=null;cumulativeAtomic;cumulative(){return U(this.cumulativeAtomic.toString())}bumpCumulative(t){this.cumulativeAtomic=t}setSessionPublicKey(t){this.sessionPublicKey=t}async charge(t){return this.chargeImpl(t)}};function Ke(e){if(typeof e!="string"||e.length===0)throw new A("signature_invalid",`missing ${_} header`);let t;try{t=Buffer.from(e,"base64").toString("utf8")}catch{throw new A("signature_invalid","malformed base64")}let r;try{r=JSON.parse(t)}catch{throw new A("signature_invalid","malformed JSON")}if(!r||typeof r!="object"||!r.payload||!r.sessionPublicKey)throw new A("signature_invalid","missing required fields");return{payload:r.payload,sessionPublicKey:M(r.sessionPublicKey),sessionRegistration:M(r.sessionRegistration),sessionSignature:M(r.sessionSignature)}}function M(e){if(typeof e!="string"||e.length%2!==0)throw new A("signature_invalid",`bad hex: ${typeof e}`);let t=new Uint8Array(e.length/2);for(let r=0;r<t.length;r++)t[r]=parseInt(e.substr(r*2,2),16);return t}function Be(e){if(!/^[0-9a-f]{64}$/i.test(e))throw new A("signature_invalid",`channelId must be 64-char hex, got "${e}"`);return M(e)}function me(e){let t=e.store??new I,r=new le,n=typeof e.sellerPubkey=="string"?new $e(e.sellerPubkey):e.sellerPubkey,s=e.maxPerVoucherAtomic?BigInt(e.maxPerVoucherAtomic):BigInt(x(e.perUnit))*100n;return async(i,m,c)=>{try{let o=Ke(i.headers[_]),l=o.payload.channelId,g=Be(l),d=r.get(l);if(!d){let P=ne(o.sessionRegistration);await se(e.connection,P),d={registration:P,lastCumulativeAtomic:"0"},r.set(l,d)}oe(o,g),ie({registration:d.registration,voucher:o,expectedCounterparty:n,previousCumulativeAtomic:d.lastCumulativeAtomic});let u=BigInt(o.payload.cumulativeAmount),h=BigInt(d.lastCumulativeAtomic),f=u-h;if(f>s)throw new b("cumulative_exceeds_cap",`single voucher increment ${f} exceeds maxPerVoucherAtomic ${s}`);await t.set(l,o),r.update(l,o.payload.cumulativeAmount);let E=new pe(l,e.network,u,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.")});E.setSessionPublicKey(o.sessionPublicKey),i.tab=E,c()}catch(o){if(o instanceof A||o instanceof S||o instanceof T||o instanceof w||o instanceof b){m.status(402).json({error:"invalid_voucher",reason:o.reason??"unknown",detail:o.message});return}c(o)}}}function Me(e){if(!e.tab)throw new Error("req.tab is missing \u2014 did tabMiddleware run on this route?");return e.tab}function De(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 r=t.tab,n=BigInt(x(r.cumulative())),s=t.perUnit?BigInt(x(t.perUnit)):null,i=0n,m=!1;function c(g=1){if(m)return Promise.reject(new Error("meter ended"));if(s===null)return Promise.reject(new Error("charge() needs options.perUnit"));let d=s*BigInt(g),u=i+d;return u>n?Promise.reject(new b("cumulative_exceeds_cap",`chunk would push request total to ${U(u.toString())} beyond voucher-authorized budget ${U(n.toString())}`)):(i=u,Promise.resolve())}function o(g){if(m)throw new Error("meter ended");let u=(typeof g=="string"?g:Buffer.from(g).toString("utf8")).replace(/\n/g,"\\n");e.write(`data: ${u}
|
|
2
2
|
|
|
3
|
-
`)}function
|
|
4
|
-
data: {"chargedAtomic":"${
|
|
3
|
+
`)}function l(){m||(m=!0,e.write(`event: end
|
|
4
|
+
data: {"chargedAtomic":"${i}"}
|
|
5
5
|
|
|
6
|
-
`),e.end())}return{charge:y,send:o,end:d}}export{E as FileVoucherStore,b as InMemoryVoucherStore,m as InvalidRegistrationError,l as InvalidVoucherError,h as InvalidVoucherSignatureError,f as OnChainVerificationError,u as ScopeViolationError,O as TAB_VOUCHER_HEADER,R as enforceScope,ne as openSse,_ as parseRegistration,te as requireTab,ee as tabMiddleware,$ as verifyRegistrationOnChain,C as verifyVoucherSignature};
|
|
6
|
+
`),e.end())}return{charge:c,send:o,end:l}}import{PublicKey as je}from"@solana/web3.js";var v="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",ye="solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",be="solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";var O="eip155:8453",D="eip155:84532",H="eip155:42161",q="eip155:137",L="eip155:10",W="eip155:43114",F="eip155:56",j="eip155:1187947933",X="eip155:324705682",J="eip155:1";var z="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";var Ae="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",He="0x55d398326f99059fF775485246999027B3197955",Se="0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",we={[F]:Se,[O]:Ae,[D]:"0x036CbD53842c5426634e7929541eC2318f3dCF7e",[H]:"0xaf88d065e77c8cC2239327C5EDb3A432268e5831",[q]:"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",[L]:"0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",[W]:"0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",[j]:"0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",[X]:"0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",[J]:"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"},xe={[He]:{symbol:"USDT",decimals:18},[Se]:{symbol:"USDC",decimals:18}};var rr={[F]:56,[O]:8453,[D]:84532,[H]:42161,[q]:137,[L]:10,[W]:43114,[j]:1187947933,[X]:324705682,[J]:1},nr={[v]:"https://api.dexter.cash/api/solana/rpc",[ye]:"https://api.devnet.solana.com",[be]:"https://api.testnet.solana.com"},sr={[F]:"https://api.dexter.cash/api/evm/bsc/rpc",[O]:"https://api.dexter.cash/api/base/rpc",[D]:"https://sepolia.base.org",[H]:"https://api.dexter.cash/api/evm/arbitrum/rpc",[q]:"https://api.dexter.cash/api/evm/polygon/rpc",[L]:"https://api.dexter.cash/api/evm/optimism/rpc",[W]:"https://api.dexter.cash/api/evm/avalanche/rpc",[j]:"https://skale-base.skalenodes.com/v1/base",[X]:"https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",[J]:"https://eth.llamarpc.com"},k="https://x402.dexter.cash";function Y(e){return e.startsWith("solana:")||e==="solana"}function qe(e){if(typeof Buffer<"u")return Buffer.from(e,"utf-8").toString("base64");let t=new TextEncoder().encode(e),r="";for(let n=0;n<t.length;n++)r+=String.fromCharCode(t[n]);return btoa(r)}function Le(e){if(typeof Buffer<"u")return Buffer.from(e,"base64").toString("utf-8");let t=atob(e),r=new Uint8Array(t.length);for(let n=0;n<t.length;n++)r[n]=t.charCodeAt(n);return new TextDecoder().decode(r)}function G(e){return qe(JSON.stringify(e))}function V(e){return JSON.parse(Le(e))}function We(e){if(e instanceof TypeError)return!0;if(e&&typeof e=="object"&&"status"in e){let t=e.status;return t>=500&&t<600}return!1}var $=class extends Error{status;body;constructor(t,r){super(`HTTP ${t}`),this.status=t,this.body=r}},Z=class{facilitatorUrl;cachedSupported=null;cacheTime=0;CACHE_TTL_MS=6e4;timeoutMs;maxRetries;retryBaseMs;constructor(t=k,r){this.facilitatorUrl=t.replace(/\/$/,""),this.timeoutMs=r?.timeoutMs??1e4,this.maxRetries=r?.maxRetries??3,this.retryBaseMs=r?.retryBaseMs??500}async fetchWithTimeout(t,r){let n=new AbortController,s=setTimeout(()=>n.abort(),this.timeoutMs);try{return await fetch(t,{...r,signal:n.signal})}finally{clearTimeout(s)}}async fetchWithRetry(t,r){let n;for(let s=0;s<this.maxRetries;s++)try{let i=await this.fetchWithTimeout(t,r);if(!i.ok&&i.status>=500)throw new $(i.status,await i.text());return i}catch(i){if(n=i,s<this.maxRetries-1&&We(i)){let m=this.retryBaseMs*Math.pow(2,s);await new Promise(c=>setTimeout(c,m));continue}throw i}throw n}async getSupported(){let t=Date.now();if(this.cachedSupported&&t-this.cacheTime<this.CACHE_TTL_MS)return this.cachedSupported;let r=await this.fetchWithTimeout(`${this.facilitatorUrl}/supported`);if(!r.ok)throw new Error(`Facilitator /supported returned ${r.status}`);return this.cachedSupported=await r.json(),this.cacheTime=t,this.cachedSupported}async getFeePayer(t){let n=(await this.getSupported()).kinds.find(s=>s.x402Version===2&&(s.scheme==="exact"||s.scheme==="exact-approval")&&s.network===t);if(!n)throw new Error(`Facilitator does not support network "${t}" with a recognized scheme`);return n.extra?.feePayer}async getNetworkExtra(t){return(await this.getSupported()).kinds.find(s=>s.x402Version===2&&(s.scheme==="exact"||s.scheme==="exact-approval"||s.scheme==="batch-settlement")&&s.network===t)?.extra}async verifyPayment(t,r){try{let n=V(t),s=await this.fetchWithRetry(`${this.facilitatorUrl}/verify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({x402Version:2,paymentPayload:n,paymentRequirements:r})});return s.ok?await s.json():{isValid:!1,invalidReason:`facilitator_error_${s.status}`}}catch(n){return{isValid:!1,invalidReason:n instanceof $?`facilitator_error_${n.status}`:n instanceof Error&&n.name==="AbortError"?"facilitator_timeout":n instanceof Error?n.message:"unexpected_verify_error"}}}async settlePayment(t,r){try{let n=V(t),s=await this.fetchWithRetry(`${this.facilitatorUrl}/settle`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({x402Version:2,paymentPayload:n,paymentRequirements:r})});return s.ok?{...await s.json(),network:r.network}:{success:!1,network:r.network,errorReason:`facilitator_error_${s.status}`}}catch(n){let s=n instanceof $?`facilitator_error_${n.status}`:n instanceof Error&&n.name==="AbortError"?"facilitator_timeout":n instanceof Error?n.message:"unexpected_settle_error";return{success:!1,network:r.network,errorReason:s}}}};function Fe(e){if(Y(e))return{address:z,decimals:6};let t=we[e];if(t){let r=xe[t]?.decimals??6;return{address:t,decimals:r}}return{address:z,decimals:6}}function ve(e){try{let t=V(e);return t?.accepted?.amount??t?.accepted?.maxAmountRequired}catch{return}}function K(e){let{payTo:t,facilitatorUrl:r=k,network:n=v,defaultTimeoutSeconds:s=60}=e,i=e.asset??Fe(n),m=e.scheme??"exact";if(m==="tab"&&!Y(n))throw new Error(`scheme 'tab' is SVM-only; got network "${n}"`);let c=new Z(r),o=null,l=new Map,g=3e4,d=Date.now();function u(a){let p=(a.maxTimeoutSeconds||s)*1e3;if(l.set(a.payTo,{accept:a,expiresAt:Date.now()+p}),Date.now()-d>g){let y=Date.now();for(let[R,C]of l)C.expiresAt<y&&l.delete(R);d=y}}function h(a){let p=l.get(a);if(p){if(p.expiresAt<Date.now()){l.delete(a);return}return p.accept}}async function f(a){return typeof t=="string"?t:t(a||{})}async function E(){if(o||(o=await c.getNetworkExtra(n)),Y(n)&&!o?.feePayer)throw new Error(`Facilitator does not provide feePayer for network "${n}"`);return{...o?.feePayer?{feePayer:o.feePayer}:{},decimals:o?.decimals??i.decimals,name:o?.name,version:o?.version,...m==="batch-settlement"&&o?.receiverAuthorizer?{receiverAuthorizer:o.receiverAuthorizer}:{},...m==="tab"?{voucherHeader:"x-tab-voucher",registrationEncoding:"base64(188-byte sessionRegisterMessage)"}:{}}}async function P(a,p){let{amountAtomic:y,timeoutSeconds:R=s}=p,C=await E(),B={scheme:m,network:n,amount:y,maxAmountRequired:y,asset:i.address,payTo:a,maxTimeoutSeconds:R,extra:C};return u(B),B}async function de(a){let p=await f({amountAtomic:a.amountAtomic,resourceUrl:a.resourceUrl});return P(p,a)}async function Ee(a){let{resourceUrl:p,description:y,mimeType:R="application/json"}=a,C={url:p,description:y,mimeType:R},B=await de(a);return{x402Version:2,resource:C,accepts:[B],error:"Payment required"}}function ge(a){return G(a)}function Te(a){return{status:402,headers:{"PAYMENT-REQUIRED":ge(a)},body:{}}}async function Pe(a,p){if(!p){let y=await f({paymentHeader:a});p=h(y),p||(p=await P(y,{amountAtomic:ve(a)??"0",resourceUrl:""}))}return c.verifyPayment(a,p)}async function _e(a,p){if(!p){let y=await f({paymentHeader:a});p=h(y),p||(p=await P(y,{amountAtomic:ve(a)??"0",resourceUrl:""}))}return c.settlePayment(a,p)}return{buildRequirements:Ee,encodeRequirements:ge,create402Response:Te,verifyPayment:Pe,settlePayment:_e,getPaymentAccept:de,network:n,assetDecimals:i.decimals,facilitator:c}}var Xe={"solana:mainnet":v};function Je(e){let t=Xe[e.network];if(!t)throw new Error(`tabChallengeMiddleware: unsupported network "${e.network}"`);let r=typeof e.sellerPubkey=="string"?e.sellerPubkey:e.sellerPubkey.toBase58();new je(r);let n=K({payTo:r,network:t,scheme:"tab",facilitatorUrl:e.facilitatorUrl}),s=x(e.perUnit);return async(i,m,c)=>{if(i.headers[_])return c();try{let o=`${i.protocol}://${i.get("host")}${i.originalUrl}`,l=await n.buildRequirements({amountAtomic:s,resourceUrl:o,description:e.description}),g=n.create402Response(l);m.set(g.headers).status(g.status).json(g.body)}catch(o){let l=o?.message??String(o);m.status(503).set({"Retry-After":"5"}).json({error:"challenge_unavailable",detail:l})}}}import{PublicKey as ze}from"@solana/web3.js";var Ye={"solana:mainnet":v};function Ge(e){let t=Ye[e.network];if(!t)throw new Error(`tabOrExactMiddleware: unsupported network "${e.network}"`);let r=typeof e.sellerPubkey=="string"?e.sellerPubkey:e.sellerPubkey.toBase58();new ze(r);let n=K({payTo:r,network:t,scheme:"tab",facilitatorUrl:e.facilitatorUrl}),s=K({payTo:r,network:t,scheme:"exact",facilitatorUrl:e.facilitatorUrl}),i=x(e.perUnit),m=me({connection:e.connection,sellerPubkey:r,network:e.network,perUnit:e.perUnit,settle:"on-close",facilitatorUrl:e.facilitatorUrl});return async(c,o,l)=>{if(c.headers[_])return m(c,o,l);let g=`${c.protocol}://${c.get("host")}${c.originalUrl}`,d=c.headers["payment-signature"];if(d){let u;try{u=await s.getPaymentAccept({amountAtomic:i,resourceUrl:g,description:e.description})}catch(h){let f=h?.message??String(h);o.status(503).set({"Retry-After":"5"}).json({error:"challenge_unavailable",detail:f});return}try{let h=await s.verifyPayment(d,u);if(!h.isValid){o.status(402).json({error:"Payment verification failed",reason:h.invalidReason});return}let f=await s.settlePayment(d,u);if(!f.success){o.status(402).json({error:"Payment settlement failed",reason:f.errorReason});return}return c.x402={transaction:f.transaction,payer:h.payer??"",network:f.network||t},o.setHeader("PAYMENT-RESPONSE",G({success:!0,transaction:f.transaction,network:f.network||t,payer:h.payer??""})),l()}catch{o.status(500).json({error:"Payment processing error"});return}}try{let u={amountAtomic:i,resourceUrl:g,description:e.description},[h,f]=await Promise.all([n.buildRequirements(u),s.buildRequirements(u)]),E={...h,accepts:[...h.accepts,...f.accepts]};o.set({"PAYMENT-REQUIRED":n.encodeRequirements(E)}).status(402).json({error:"Payment required",accepts:E.accepts,resource:E.resource})}catch(u){let h=u?.message??String(u);o.status(503).set({"Retry-After":"5"}).json({error:"challenge_unavailable",detail:h})}}}export{ue as FileVoucherStore,I as InMemoryVoucherStore,S as InvalidRegistrationError,A as InvalidVoucherError,w as InvalidVoucherSignatureError,T as OnChainVerificationError,b as ScopeViolationError,_ as TAB_VOUCHER_HEADER,ie as enforceScope,De as openSse,ne as parseRegistration,Me as requireTab,Je as tabChallengeMiddleware,me as tabMiddleware,Ge as tabOrExactMiddleware,se as verifyRegistrationOnChain,oe as verifyVoucherSignature};
|