@dexterai/x402 3.14.0 → 3.15.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/dist/tab/adapters/solana/index.cjs +1 -1
- package/dist/tab/adapters/solana/index.d.cts +4 -0
- package/dist/tab/adapters/solana/index.d.ts +4 -0
- package/dist/tab/adapters/solana/index.js +1 -1
- package/dist/tab/seller/index.cjs +4 -4
- package/dist/tab/seller/index.d.cts +13 -25
- package/dist/tab/seller/index.d.ts +13 -25
- package/dist/tab/seller/index.js +3 -3
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var Y=Object.create;var h=Object.defineProperty;var z=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var Z=Object.getPrototypeOf,Q=Object.prototype.hasOwnProperty;var ee=(e,t)=>{for(var n in t)h(e,n,{get:t[n],enumerable:!0})},U=(e,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of j(t))!Q.call(e,s)&&s!==n&&h(e,s,{get:()=>t[s],enumerable:!(i=z(t,s))||i.enumerable});return e};var I=(e,t,n)=>(n=e!=null?Y(Z(e)):{},U(t||!e||!e.__esModule?h(n,"default",{value:e,enumerable:!0}):n,e)),te=e=>U(h({},"__esModule",{value:!0}),e);var ge={};ee(ge,{buildAdapterRegisterInstruction:()=>q,createSolanaVaultAdapter:()=>ue,deriveChannelId:()=>F,passkeySignerFromP256Keypair:()=>le});module.exports=te(ge);var p=require("@solana/web3.js"),$=require("@solana/spl-token");var ne="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",ie="solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",se="solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";var P="eip155:8453",b="eip155:84532",E="eip155:42161",K="eip155:137",v="eip155:10",w="eip155:43114",O="eip155:56",R="eip155:1187947933",C="eip155:324705682",T="eip155:1";var k="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";var re="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",oe="0x55d398326f99059fF775485246999027B3197955",B="0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",he={[O]:B,[P]:re,[b]:"0x036CbD53842c5426634e7929541eC2318f3dCF7e",[E]:"0xaf88d065e77c8cC2239327C5EDb3A432268e5831",[K]:"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",[v]:"0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",[w]:"0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",[R]:"0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",[C]:"0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",[T]:"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"},Se={[oe]:{symbol:"USDT",decimals:18},[B]:{symbol:"USDC",decimals:18}};var fe={[O]:56,[P]:8453,[b]:84532,[E]:42161,[K]:137,[v]:10,[w]:43114,[R]:1187947933,[C]:324705682,[T]:1},xe={[ne]:"https://api.dexter.cash/api/solana/rpc",[ie]:"https://api.devnet.solana.com",[se]:"https://api.testnet.solana.com"},Pe={[O]:"https://api.dexter.cash/api/evm/bsc/rpc",[P]:"https://api.dexter.cash/api/base/rpc",[b]:"https://sepolia.base.org",[E]:"https://api.dexter.cash/api/evm/arbitrum/rpc",[K]:"https://api.dexter.cash/api/evm/polygon/rpc",[v]:"https://api.dexter.cash/api/evm/optimism/rpc",[w]:"https://api.dexter.cash/api/evm/avalanche/rpc",[R]:"https://skale-base.skalenodes.com/v1/base",[C]:"https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",[T]:"https://eth.llamarpc.com"};var c=require("@dexterai/vault/instructions"),S=require("@dexterai/vault/precompile"),m=require("@dexterai/vault/constants");var o=require("@dexterai/vault/messages");var _=I(require("tweetnacl"),1);var W=require("@noble/hashes/sha256");function M(){let e=_.default.sign.keyPair();return{publicKey:e.publicKey,privateKey:e.secretKey}}function V(e,t,n){return{publicKey:e.publicKey,privateKey:e.privateKey,scope:t,registration:n}}function L(e,t,n){if(n.length!==32)throw new Error(`channelIdBytes must be 32 bytes, got ${n.length}`);let i=BigInt(t.cumulativeAmount),s=BigInt(e.scope.maxAmountAtomic);if(i>s)throw new Error(`voucher cumulative ${i} exceeds session cap ${s}`);let r=Math.floor(Date.now()/1e3);if(r>=e.scope.expiresAtUnix)throw new Error(`session expired at ${e.scope.expiresAtUnix}, now ${r}`);let l=(0,o.voucherPayloadMessage)({channelId:n,cumulativeAmount:i,sequenceNumber:t.sequenceNumber}),a=_.default.sign.detached(l,e.privateKey);return{payload:t,sessionPublicKey:e.publicKey,sessionRegistration:e.registration,sessionSignature:a}}function f(e){if(!/^\d+$/.test(e))throw new Error(`atomic amount must be a non-negative integer string, got "${e}"`);return BigInt(e)}function F(e){let t=new Uint8Array(8);new DataView(t.buffer).setBigUint64(0,e.nonce,!0);let n=new TextEncoder().encode(e.sellerUrl),i=W.sha256.create();return i.update(e.vaultPda.toBytes()),i.update(n),i.update(t),i.digest()}var d=require("@dexterai/vault/session");var J=require("@noble/curves/p256"),g=require("@noble/hashes/sha256"),H="dexter.cash";function ae(e){return Buffer.from(e).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function ce(e,t=`https://${H}`){let i={type:"webauthn.get",challenge:ae(e),origin:t,crossOrigin:!1};return new TextEncoder().encode(JSON.stringify(i))}function pe(e=1){let t=(0,g.sha256)(new TextEncoder().encode(H)),n=new Uint8Array(37);return n.set(t,0),n[32]=5,new DataView(n.buffer).setUint32(33,e,!1),n}function G(e,t){let n=(0,g.sha256)(t),i=ce(n),s=pe(1),r=new Uint8Array(s.length+32);r.set(s,0),r.set((0,g.sha256)(i),s.length);let l=(0,g.sha256)(r),u=J.p256.sign(l,e.privateKey,{lowS:!0}).toCompactRawBytes();return{clientDataJSON:i,authenticatorData:s,precompileMessage:r,signature:u}}function le(e){return{publicKey:e.publicKey,signOperation:async t=>G(e,t)}}function q(e){let t=(0,c.deriveSwigWalletAddress)(e.swigAddress),n=(0,$.getAssociatedTokenAddressSync)(new p.PublicKey(k),t,!0);return(0,c.buildRegisterSessionKeyInstruction)({vaultPda:e.vaultPda,sessionPubkey:e.sessionPubkey,maxAmount:e.maxAmount,maxRevolvingCapacity:e.maxRevolvingCapacity,expiresAt:e.expiresAt,allowedCounterparty:e.allowedCounterparty,nonce:e.nonce,swigAddress:e.swigAddress,vaultUsdcAta:n,clientDataJSON:e.clientDataJSON,authenticatorData:e.authenticatorData,payer:e.payer,siblingSessionPdas:e.siblingSessionPdas})}var N=class{network="solana:mainnet";swigAddress;vaultPda;connection;vaultPdaKey;passkey;feePayer;confirmOptions;constructor(t){this.connection=t.connection,this.swigAddress=typeof t.swigAddress=="string"?t.swigAddress:t.swigAddress.toBase58(),this.vaultPdaKey=typeof t.vaultPda=="string"?new p.PublicKey(t.vaultPda):t.vaultPda,this.vaultPda=this.vaultPdaKey.toBase58(),this.passkey=t.passkeySigner,this.feePayer=t.feePayer,this.confirmOptions=t.confirmOptions??{commitment:"confirmed"}}async authorizeSession(t){let n=new p.PublicKey(t.allowedCounterparty),i=f(t.revolvingCapacityAtomic??t.maxAmountAtomic),s=M(),r=ye(),l=(0,o.sessionRegisterMessage)({programId:m.DEXTER_VAULT_PROGRAM_ID,vaultPda:this.vaultPdaKey,sessionPubkey:s.publicKey,maxAmount:f(t.maxAmountAtomic),maxRevolvingCapacity:i,expiresAt:BigInt(t.expiresAtUnix),allowedCounterparty:n,nonce:r}),a=await this.passkey.signOperation(l),u=(0,S.buildSecp256r1VerifyInstruction)(this.passkey.publicKey,a.signature,a.precompileMessage),A=(0,d.sessionPdasOf)(await(0,d.fetchVaultSessionAccounts)(this.connection,this.vaultPdaKey)),x=q({vaultPda:this.vaultPdaKey,swigAddress:new p.PublicKey(this.swigAddress),sessionPubkey:s.publicKey,maxAmount:f(t.maxAmountAtomic),maxRevolvingCapacity:i,expiresAt:BigInt(t.expiresAtUnix),allowedCounterparty:n,nonce:r,clientDataJSON:a.clientDataJSON,authenticatorData:a.authenticatorData,payer:this.feePayer.publicKey,siblingSessionPdas:A}),y=new p.Transaction().add(u,x);y.feePayer=this.feePayer.publicKey;let{blockhash:D}=await this.connection.getLatestBlockhash(this.confirmOptions.commitment);y.recentBlockhash=D,y.sign(this.feePayer);let X=await this.connection.sendRawTransaction(y.serialize(),{skipPreflight:!1,preflightCommitment:this.confirmOptions.preflightCommitment??this.confirmOptions.commitment});return await this.connection.confirmTransaction({signature:X,blockhash:D,lastValidBlockHeight:(await this.connection.getLatestBlockhash(this.confirmOptions.commitment)).lastValidBlockHeight},this.confirmOptions.commitment),await(0,d.waitForSession)(this.connection,this.vaultPdaKey,n,{expectedSessionPubkey:s.publicKey,timeoutMs:2e4}),V(s,t,l)}async signWithSession(t,n){let i=await me(n.channelId);return L(t,n,i)}async signOpenTab(t,n){return t.registration}async signCloseTab(t,n,i){let s=(0,o.sessionRevokeMessage)({programId:m.DEXTER_VAULT_PROGRAM_ID,vaultPda:this.vaultPdaKey,sessionPubkey:t.publicKey}),r=await this.passkey.signOperation(s),l=(0,S.buildSecp256r1VerifyInstruction)(this.passkey.publicKey,r.signature,r.precompileMessage),a=(0,c.buildRevokeSessionKeyInstruction)({vaultPda:this.vaultPdaKey,allowedCounterparty:new p.PublicKey(t.scope.allowedCounterparty),clientDataJSON:r.clientDataJSON,authenticatorData:r.authenticatorData}),u=new p.Transaction().add(l,a);u.feePayer=this.feePayer.publicKey;let{blockhash:A,lastValidBlockHeight:x}=await this.connection.getLatestBlockhash(this.confirmOptions.commitment);u.recentBlockhash=A,u.sign(this.feePayer);let y=await this.connection.sendRawTransaction(u.serialize(),{skipPreflight:!1,preflightCommitment:this.confirmOptions.preflightCommitment??this.confirmOptions.commitment});return await this.connection.confirmTransaction({signature:y,blockhash:A,lastValidBlockHeight:x},this.confirmOptions.commitment),s}};function ue(e){return new N(e)}function ye(){return Math.floor(Math.random()*4294967295)>>>0}async function me(e){if(/^[0-9a-f]{64}$/i.test(e))return de(e);let{sha256:t}=await import("@noble/hashes/sha256");return t(new TextEncoder().encode(e))}function de(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}0&&(module.exports={buildAdapterRegisterInstruction,createSolanaVaultAdapter,deriveChannelId,passkeySignerFromP256Keypair});
|
|
@@ -112,6 +112,10 @@ interface AdapterRegisterIxParams {
|
|
|
112
112
|
nonce: number;
|
|
113
113
|
clientDataJSON: Uint8Array;
|
|
114
114
|
authenticatorData: Uint8Array;
|
|
115
|
+
/** V6: rent payer for the init_if_needed session PDA (the buyer's fee payer). */
|
|
116
|
+
payer: PublicKey;
|
|
117
|
+
/** V6: existing session PDAs for this vault — the overcommit aggregate gate. */
|
|
118
|
+
siblingSessionPdas: PublicKey[];
|
|
115
119
|
}
|
|
116
120
|
declare function buildAdapterRegisterInstruction(p: AdapterRegisterIxParams): _solana_web3_js.TransactionInstruction;
|
|
117
121
|
/** Factory entry point. */
|
|
@@ -112,6 +112,10 @@ interface AdapterRegisterIxParams {
|
|
|
112
112
|
nonce: number;
|
|
113
113
|
clientDataJSON: Uint8Array;
|
|
114
114
|
authenticatorData: Uint8Array;
|
|
115
|
+
/** V6: rent payer for the init_if_needed session PDA (the buyer's fee payer). */
|
|
116
|
+
payer: PublicKey;
|
|
117
|
+
/** V6: existing session PDAs for this vault — the overcommit aggregate gate. */
|
|
118
|
+
siblingSessionPdas: PublicKey[];
|
|
115
119
|
}
|
|
116
120
|
declare function buildAdapterRegisterInstruction(p: AdapterRegisterIxParams): _solana_web3_js.TransactionInstruction;
|
|
117
121
|
/** Factory entry point. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{PublicKey as
|
|
1
|
+
import{PublicKey as l,Transaction as J}from"@solana/web3.js";import{getAssociatedTokenAddressSync as ne}from"@solana/spl-token";var G="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",$="solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",q="solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";var g="eip155:8453",A="eip155:84532",h="eip155:42161",S="eip155:137",f="eip155:10",x="eip155:43114",P="eip155:56",b="eip155:1187947933",E="eip155:324705682",K="eip155:1";var C="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";var X="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",Y="0x55d398326f99059fF775485246999027B3197955",T="0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",le={[P]:T,[g]:X,[A]:"0x036CbD53842c5426634e7929541eC2318f3dCF7e",[h]:"0xaf88d065e77c8cC2239327C5EDb3A432268e5831",[S]:"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",[f]:"0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",[x]:"0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",[b]:"0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",[E]:"0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",[K]:"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"},ue={[Y]:{symbol:"USDT",decimals:18},[T]:{symbol:"USDC",decimals:18}};var ye={[P]:56,[g]:8453,[A]:84532,[h]:42161,[S]:137,[f]:10,[x]:43114,[b]:1187947933,[E]:324705682,[K]:1},me={[G]:"https://api.dexter.cash/api/solana/rpc",[$]:"https://api.devnet.solana.com",[q]:"https://api.testnet.solana.com"},de={[P]:"https://api.dexter.cash/api/evm/bsc/rpc",[g]:"https://api.dexter.cash/api/base/rpc",[A]:"https://sepolia.base.org",[h]:"https://api.dexter.cash/api/evm/arbitrum/rpc",[S]:"https://api.dexter.cash/api/evm/polygon/rpc",[f]:"https://api.dexter.cash/api/evm/optimism/rpc",[x]:"https://api.dexter.cash/api/evm/avalanche/rpc",[b]:"https://skale-base.skalenodes.com/v1/base",[E]:"https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",[K]:"https://eth.llamarpc.com"};import{buildRegisterSessionKeyInstruction as _,buildRevokeSessionKeyInstruction as N,deriveSwigWalletAddress as D}from"@dexterai/vault/instructions";import{buildSecp256r1VerifyInstruction as v}from"@dexterai/vault/precompile";import{DEXTER_VAULT_PROGRAM_ID as w,SECP256R1_PROGRAM_ID as xe,INSTRUCTIONS_SYSVAR_ID as Pe}from"@dexterai/vault/constants";import{sessionRegisterMessage as U,sessionRevokeMessage as I,voucherPayloadMessage as k,buildVoucherMessage as Ke}from"@dexterai/vault/messages";import B from"tweetnacl";import{sha256 as z}from"@noble/hashes/sha256";function M(){let e=B.sign.keyPair();return{publicKey:e.publicKey,privateKey:e.secretKey}}function V(e,t,n){return{publicKey:e.publicKey,privateKey:e.privateKey,scope:t,registration:n}}function L(e,t,n){if(n.length!==32)throw new Error(`channelIdBytes must be 32 bytes, got ${n.length}`);let i=BigInt(t.cumulativeAmount),s=BigInt(e.scope.maxAmountAtomic);if(i>s)throw new Error(`voucher cumulative ${i} exceeds session cap ${s}`);let r=Math.floor(Date.now()/1e3);if(r>=e.scope.expiresAtUnix)throw new Error(`session expired at ${e.scope.expiresAtUnix}, now ${r}`);let a=k({channelId:n,cumulativeAmount:i,sequenceNumber:t.sequenceNumber}),o=B.sign.detached(a,e.privateKey);return{payload:t,sessionPublicKey:e.publicKey,sessionRegistration:e.registration,sessionSignature:o}}function y(e){if(!/^\d+$/.test(e))throw new Error(`atomic amount must be a non-negative integer string, got "${e}"`);return BigInt(e)}function j(e){let t=new Uint8Array(8);new DataView(t.buffer).setBigUint64(0,e.nonce,!0);let n=new TextEncoder().encode(e.sellerUrl),i=z.create();return i.update(e.vaultPda.toBytes()),i.update(n),i.update(t),i.digest()}import{fetchVaultSessionAccounts as ie,sessionPdasOf as se,waitForSession as re}from"@dexterai/vault/session";import{p256 as Z}from"@noble/curves/p256";import{sha256 as m}from"@noble/hashes/sha256";var W="dexter.cash";function Q(e){return Buffer.from(e).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function ee(e,t=`https://${W}`){let i={type:"webauthn.get",challenge:Q(e),origin:t,crossOrigin:!1};return new TextEncoder().encode(JSON.stringify(i))}function te(e=1){let t=m(new TextEncoder().encode(W)),n=new Uint8Array(37);return n.set(t,0),n[32]=5,new DataView(n.buffer).setUint32(33,e,!1),n}function F(e,t){let n=m(t),i=ee(n),s=te(1),r=new Uint8Array(s.length+32);r.set(s,0),r.set(m(i),s.length);let a=m(r),c=Z.sign(a,e.privateKey,{lowS:!0}).toCompactRawBytes();return{clientDataJSON:i,authenticatorData:s,precompileMessage:r,signature:c}}function We(e){return{publicKey:e.publicKey,signOperation:async t=>F(e,t)}}function oe(e){let t=D(e.swigAddress),n=ne(new l(C),t,!0);return _({vaultPda:e.vaultPda,sessionPubkey:e.sessionPubkey,maxAmount:e.maxAmount,maxRevolvingCapacity:e.maxRevolvingCapacity,expiresAt:e.expiresAt,allowedCounterparty:e.allowedCounterparty,nonce:e.nonce,swigAddress:e.swigAddress,vaultUsdcAta:n,clientDataJSON:e.clientDataJSON,authenticatorData:e.authenticatorData,payer:e.payer,siblingSessionPdas:e.siblingSessionPdas})}var O=class{network="solana:mainnet";swigAddress;vaultPda;connection;vaultPdaKey;passkey;feePayer;confirmOptions;constructor(t){this.connection=t.connection,this.swigAddress=typeof t.swigAddress=="string"?t.swigAddress:t.swigAddress.toBase58(),this.vaultPdaKey=typeof t.vaultPda=="string"?new l(t.vaultPda):t.vaultPda,this.vaultPda=this.vaultPdaKey.toBase58(),this.passkey=t.passkeySigner,this.feePayer=t.feePayer,this.confirmOptions=t.confirmOptions??{commitment:"confirmed"}}async authorizeSession(t){let n=new l(t.allowedCounterparty),i=y(t.revolvingCapacityAtomic??t.maxAmountAtomic),s=M(),r=ae(),a=U({programId:w,vaultPda:this.vaultPdaKey,sessionPubkey:s.publicKey,maxAmount:y(t.maxAmountAtomic),maxRevolvingCapacity:i,expiresAt:BigInt(t.expiresAtUnix),allowedCounterparty:n,nonce:r}),o=await this.passkey.signOperation(a),c=v(this.passkey.publicKey,o.signature,o.precompileMessage),u=se(await ie(this.connection,this.vaultPdaKey)),d=oe({vaultPda:this.vaultPdaKey,swigAddress:new l(this.swigAddress),sessionPubkey:s.publicKey,maxAmount:y(t.maxAmountAtomic),maxRevolvingCapacity:i,expiresAt:BigInt(t.expiresAtUnix),allowedCounterparty:n,nonce:r,clientDataJSON:o.clientDataJSON,authenticatorData:o.authenticatorData,payer:this.feePayer.publicKey,siblingSessionPdas:u}),p=new J().add(c,d);p.feePayer=this.feePayer.publicKey;let{blockhash:R}=await this.connection.getLatestBlockhash(this.confirmOptions.commitment);p.recentBlockhash=R,p.sign(this.feePayer);let H=await this.connection.sendRawTransaction(p.serialize(),{skipPreflight:!1,preflightCommitment:this.confirmOptions.preflightCommitment??this.confirmOptions.commitment});return await this.connection.confirmTransaction({signature:H,blockhash:R,lastValidBlockHeight:(await this.connection.getLatestBlockhash(this.confirmOptions.commitment)).lastValidBlockHeight},this.confirmOptions.commitment),await re(this.connection,this.vaultPdaKey,n,{expectedSessionPubkey:s.publicKey,timeoutMs:2e4}),V(s,t,a)}async signWithSession(t,n){let i=await ce(n.channelId);return L(t,n,i)}async signOpenTab(t,n){return t.registration}async signCloseTab(t,n,i){let s=I({programId:w,vaultPda:this.vaultPdaKey,sessionPubkey:t.publicKey}),r=await this.passkey.signOperation(s),a=v(this.passkey.publicKey,r.signature,r.precompileMessage),o=N({vaultPda:this.vaultPdaKey,allowedCounterparty:new l(t.scope.allowedCounterparty),clientDataJSON:r.clientDataJSON,authenticatorData:r.authenticatorData}),c=new J().add(a,o);c.feePayer=this.feePayer.publicKey;let{blockhash:u,lastValidBlockHeight:d}=await this.connection.getLatestBlockhash(this.confirmOptions.commitment);c.recentBlockhash=u,c.sign(this.feePayer);let p=await this.connection.sendRawTransaction(c.serialize(),{skipPreflight:!1,preflightCommitment:this.confirmOptions.preflightCommitment??this.confirmOptions.commitment});return await this.connection.confirmTransaction({signature:p,blockhash:u,lastValidBlockHeight:d},this.confirmOptions.commitment),s}};function Fe(e){return new O(e)}function ae(){return Math.floor(Math.random()*4294967295)>>>0}async function ce(e){if(/^[0-9a-f]{64}$/i.test(e))return pe(e);let{sha256:t}=await import("@noble/hashes/sha256");return t(new TextEncoder().encode(e))}function pe(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}export{oe as buildAdapterRegisterInstruction,Fe as createSolanaVaultAdapter,j as deriveChannelId,We as passkeySignerFromP256Keypair};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"use strict";var te=Object.create;var P=Object.defineProperty;var ne=Object.getOwnPropertyDescriptor;var re=Object.getOwnPropertyNames;var oe=Object.getPrototypeOf,ie=Object.prototype.hasOwnProperty;var se=(e,t)=>{for(var n in t)P(e,n,{get:t[n],enumerable:!0})},L=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of re(t))!ie.call(e,o)&&o!==n&&P(e,o,{get:()=>t[o],enumerable:!(r=ne(t,o))||r.enumerable});return e};var j=(e,t,n)=>(n=e!=null?te(oe(e)):{},L(t||!e||!e.__esModule?P(n,"default",{value:e,enumerable:!0}):n,e)),ae=e=>L(P({},"__esModule",{value:!0}),e);var Se={};se(Se,{FileVoucherStore:()=>C,InMemoryVoucherStore:()=>A,InvalidRegistrationError:()=>d,InvalidVoucherError:()=>m,InvalidVoucherSignatureError:()=>h,OnChainVerificationError:()=>y,ScopeViolationError:()=>c,TAB_VOUCHER_HEADER:()=>R,enforceScope:()=>_,openSse:()=>Q,parseRegistration:()=>I,readVaultState:()=>N,requireTab:()=>Z,tabMiddleware:()=>Y,verifyRegistrationOnChain:()=>V,verifyVoucherSignature:()=>k});module.exports=ae(Se);var m=class extends Error{constructor(n,r){super(`Invalid voucher: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidVoucherError"}};var X=require("@solana/web3.js");var G=j(require("tweetnacl"),1),ce=require("@noble/hashes/sha256"),le=require("@noble/curves/p256"),T=require("@solana/web3.js");var w=require("@dexterai/vault/messages");var K=require("@dexterai/vault/instructions"),ue=require("@dexterai/vault/precompile"),b=require("@dexterai/vault/constants");var O="OTS_SESSION_REGISTER_V2",d=class extends Error{constructor(n,r){super(`Invalid registration: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidRegistrationError"}};function I(e){if(e.length!==188)throw new d("wrong_length",`expected 188, got ${e.length}`);let t=new TextDecoder().decode(e.slice(0,O.length));if(t!==O)throw new d("wrong_domain",`got "${t}"`);for(let a=O.length;a<32;a++)if(e[a]!==0)throw new d("wrong_domain",`non-NUL padding at byte ${a}`);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)),l=e.slice(96,128),p=n.getBigUint64(128,!0),f=n.getBigInt64(136,!0),i=new T.PublicKey(e.slice(144,176)),u=n.getUint32(176,!0),g=n.getBigUint64(180,!0);if(!r.equals(b.DEXTER_VAULT_PROGRAM_ID))throw new d("wrong_program",`${r.toBase58()} is not ${b.DEXTER_VAULT_PROGRAM_ID.toBase58()}`);if(p===0n)throw new d("cap_zero");let s=BigInt(Math.floor(Date.now()/1e3));if(f<=s)throw new d("expiry_in_past",`expires_at=${f}, now=${s}`);return{programId:r,vaultPda:o,sessionPubkey:new Uint8Array(l),maxAmount:p,expiresAt:f,allowedCounterparty:i,nonce:u,maxRevolvingCapacity:g}}var F=10,y=class extends Error{constructor(n,r){super(`On-chain verification failed: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="OnChainVerificationError"}};async function N(e,t){let n=await e.getAccountInfo(t,"finalized");if(!n)throw new y("vault_not_found",t.toBase58());if(!n.owner.equals(b.DEXTER_VAULT_PROGRAM_ID))throw new y("wrong_program",`owner ${n.owner.toBase58()} is not the vault program`);let r=n.data,o=new Uint8Array(r.slice(F,F+33)),u=84+(r[83]===1?48:0)+32+32;if(r[u]!==1)return{passkeyPubkey:o,activeSessionPubkey:null};let s=u+1,a=new Uint8Array(r.slice(s,s+32));return{passkeyPubkey:o,activeSessionPubkey:a}}async function V(e,t){let n=await N(e,t.vaultPda);if(n.activeSessionPubkey===null)throw new y("session_not_active","vault has no active_session \u2014 was it revoked?");if(!me(n.activeSessionPubkey,t.sessionPubkey))throw new y("session_pubkey_mismatch",`on-chain ${J(n.activeSessionPubkey)} != registration ${J(t.sessionPubkey)}`);return{passkeyPubkey:n.passkeyPubkey}}var h=class extends Error{constructor(t){super(`Invalid voucher signature${t?`: ${t}`:""}`),this.name="InvalidVoucherSignatureError"}};function k(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=(0,w.voucherPayloadMessage)({channelId:t,cumulativeAmount:BigInt(e.payload.cumulativeAmount),sequenceNumber:e.payload.sequenceNumber});if(!G.default.sign.detached.verify(n,e.sessionSignature,e.sessionPublicKey))throw new h("ed25519 verify rejected")}var c=class extends Error{constructor(n,r){super(`Scope violation: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="ScopeViolationError"}};function _(e){let t=BigInt(e.voucher.payload.cumulativeAmount);if(t>e.registration.maxAmount)throw new c("cumulative_exceeds_cap",`${t} > ${e.registration.maxAmount}`);let n=BigInt(Math.floor(Date.now()/1e3));if(n>=e.registration.expiresAt)throw new c("session_expired",`now=${n} >= expiresAt=${e.registration.expiresAt}`);if(!e.registration.allowedCounterparty.equals(e.expectedCounterparty))throw new c("wrong_counterparty",`${e.registration.allowedCounterparty.toBase58()} != ${e.expectedCounterparty.toBase58()}`);if(e.previousCumulativeAtomic!==void 0){let r=BigInt(e.previousCumulativeAtomic);if(t<=r)throw new c("non_monotonic",`cumulative=${t} not > previous=${r}`)}}function me(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 J(e){let t="";for(let n of e)t+=n.toString(16).padStart(2,"0");return t}var S=require("fs"),U=require("path");function de(e){return{payload:e.payload,sessionPublicKey:H(e.sessionPublicKey),sessionRegistration:H(e.sessionRegistration),sessionSignature:H(e.sessionSignature)}}function pe(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 A=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)}},C=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 S.promises.readFile(this.pathFor(t),"utf8");return pe(JSON.parse(n))}catch(n){if(n?.code==="ENOENT")return null;throw n}}async set(t,n){let r=this.pathFor(t);await S.promises.mkdir((0,U.dirname)(r),{recursive:!0});let o=`${r}.tmp`;await S.promises.writeFile(o,JSON.stringify(de(n))),await S.promises.rename(o,r)}async delete(t){try{await S.promises.unlink(this.pathFor(t))}catch(n){if(n?.code!=="ENOENT")throw n}}};var ye=require("@solana/web3.js"),fe=require("@noble/hashes/utils");var ge=j(require("tweetnacl"),1);var he=require("@noble/hashes/sha256");var W=6;function v(e,t=W){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"),l=`${n}${o}`.replace(/^0+(?=\d)/,"");return l===""?"0":l}function x(e,t=W){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 R="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 we(e){if(typeof e!="string"||e.length===0)throw new m("signature_invalid",`missing ${R} header`);let t;try{t=Buffer.from(e,"base64").toString("utf8")}catch{throw new m("signature_invalid","malformed base64")}let n;try{n=JSON.parse(t)}catch{throw new m("signature_invalid","malformed JSON")}if(!n||typeof n!="object"||!n.payload||!n.sessionPublicKey)throw new m("signature_invalid","missing required fields");return{payload:n.payload,sessionPublicKey:$(n.sessionPublicKey),sessionRegistration:$(n.sessionRegistration),sessionSignature:$(n.sessionSignature)}}function $(e){if(typeof e!="string"||e.length%2!==0)throw new m("signature_invalid",`bad hex: ${typeof e}`);let t=new Uint8Array(e.length/2);for(let n=0;n<t.length;n++)t[n]=parseInt(e.substr(n*2,2),16);return t}function be(e){if(!/^[0-9a-f]{64}$/i.test(e))throw new m("signature_invalid",`channelId must be 64-char hex, got "${e}"`);return $(e)}function Y(e){let t=e.store??new A,n=new M,r=typeof e.sellerPubkey=="string"?new X.PublicKey(e.sellerPubkey):e.sellerPubkey,o=e.maxPerVoucherAtomic?BigInt(e.maxPerVoucherAtomic):BigInt(v(e.perUnit))*100n;return async(l,p,f)=>{try{let i=we(l.headers[R]),u=i.payload.channelId,g=be(u),s=n.get(u);if(!s){let E=I(i.sessionRegistration);await V(e.connection,E),s={registration:E,lastCumulativeAtomic:"0"},n.set(u,s)}k(i,g),_({registration:s.registration,voucher:i,expectedCounterparty:r,previousCumulativeAtomic:s.lastCumulativeAtomic});let a=BigInt(i.payload.cumulativeAmount),ee=BigInt(s.lastCumulativeAtomic),D=a-ee;if(D>o)throw new c("cumulative_exceeds_cap",`single voucher increment ${D} exceeds maxPerVoucherAtomic ${o}`);await t.set(u,i),n.update(u,i.payload.cumulativeAmount);let z=new q(u,e.network,a,async E=>{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.")});z.setSessionPublicKey(i.sessionPublicKey),l.tab=z,f()}catch(i){if(i instanceof m||i instanceof d||i instanceof y||i instanceof h||i instanceof c){p.status(402).json({error:"invalid_voucher",reason:i.reason??"unknown",detail:i.message});return}f(i)}}}function Z(e){if(!e.tab)throw new Error("req.tab is missing \u2014 did tabMiddleware run on this route?");return e.tab}function Q(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,l=0n,p=!1;function f(g=1){if(p)return Promise.reject(new Error("meter ended"));if(o===null)return Promise.reject(new Error("charge() needs options.perUnit"));let s=o*BigInt(g),a=l+s;return a>r?Promise.reject(new c("cumulative_exceeds_cap",`chunk would push request total to ${x(a.toString())} beyond voucher-authorized budget ${x(r.toString())}`)):(l=a,Promise.resolve())}function i(g){if(p)throw new Error("meter ended");let a=(typeof g=="string"?g:Buffer.from(g).toString("utf8")).replace(/\n/g,"\\n");e.write(`data: ${a}
|
|
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}
|
|
2
2
|
|
|
3
|
-
`)}function
|
|
4
|
-
data: {"chargedAtomic":"${
|
|
3
|
+
`)}function d(){g||(g=!0,e.write(`event: end
|
|
4
|
+
data: {"chargedAtomic":"${m}"}
|
|
5
5
|
|
|
6
|
-
`),e.end())}return{charge:f,send:i,end:
|
|
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});
|
|
@@ -231,38 +231,26 @@ declare class InvalidRegistrationError extends Error {
|
|
|
231
231
|
* passkey signature check is a separate on-chain step.
|
|
232
232
|
*/
|
|
233
233
|
declare function parseRegistration(registration: Uint8Array): ParsedRegistration;
|
|
234
|
-
interface OnChainVaultState {
|
|
235
|
-
passkeyPubkey: Uint8Array;
|
|
236
|
-
activeSessionPubkey: Uint8Array | null;
|
|
237
|
-
}
|
|
238
234
|
declare class OnChainVerificationError extends Error {
|
|
239
235
|
readonly reason: 'vault_not_found' | 'session_not_active' | 'session_pubkey_mismatch' | 'wrong_program';
|
|
240
236
|
constructor(reason: 'vault_not_found' | 'session_not_active' | 'session_pubkey_mismatch' | 'wrong_program', detail?: string);
|
|
241
237
|
}
|
|
242
238
|
/**
|
|
243
|
-
*
|
|
239
|
+
* Verify a registration against on-chain state. Throws on any mismatch.
|
|
244
240
|
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Verify a registration against on-chain state. Returns the vault's
|
|
254
|
-
* passkey pubkey (caller can cache it). Throws on any mismatch.
|
|
241
|
+
* V6: a session is its own PDA ([b"session", vault, allowed_counterparty]),
|
|
242
|
+
* NOT an inline field on the vault. We read that SessionAccount and confirm it
|
|
243
|
+
* is live (version 1 + unexpired) AND carries the same session pubkey the
|
|
244
|
+
* registration claims. If the program accepted the register_session_key tx
|
|
245
|
+
* (which is what wrote the PDA), the passkey signature was already verified by
|
|
246
|
+
* the secp256r1 precompile inside that tx — the seller just confirms the
|
|
247
|
+
* on-chain witness still holds.
|
|
255
248
|
*
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
* in the first place), then the passkey signature was verified by the
|
|
260
|
-
* secp256r1 precompile inside that tx. The seller doesn't need to redo
|
|
261
|
-
* that work; they just need to confirm the on-chain witness still holds.
|
|
249
|
+
* fetchSessionAccount reads at the connection's commitment; pass a connection
|
|
250
|
+
* configured at the commitment the buyer's registration was confirmed to (the
|
|
251
|
+
* adapter waits for visibility before openTab returns).
|
|
262
252
|
*/
|
|
263
|
-
declare function verifyRegistrationOnChain(connection: Connection, registration: ParsedRegistration): Promise<
|
|
264
|
-
passkeyPubkey: Uint8Array;
|
|
265
|
-
}>;
|
|
253
|
+
declare function verifyRegistrationOnChain(connection: Connection, registration: ParsedRegistration): Promise<void>;
|
|
266
254
|
declare class InvalidVoucherSignatureError extends Error {
|
|
267
255
|
constructor(detail?: string);
|
|
268
256
|
}
|
|
@@ -289,4 +277,4 @@ declare function enforceScope(args: {
|
|
|
289
277
|
previousCumulativeAtomic?: AtomicAmount;
|
|
290
278
|
}): void;
|
|
291
279
|
|
|
292
|
-
export { FileVoucherStore, InMemoryVoucherStore, InvalidRegistrationError, InvalidVoucherError, InvalidVoucherSignatureError,
|
|
280
|
+
export { FileVoucherStore, InMemoryVoucherStore, InvalidRegistrationError, InvalidVoucherError, InvalidVoucherSignatureError, OnChainVerificationError, type OpenSseOptions, type ParsedRegistration, ScopeViolationError, type SellerTab, type SseMeter, TAB_VOUCHER_HEADER, type TabMiddlewareConfig, type TabMiddlewareOptions, type VoucherStore, enforceScope, openSse, parseRegistration, requireTab, tabMiddleware, verifyRegistrationOnChain, verifyVoucherSignature };
|
|
@@ -231,38 +231,26 @@ declare class InvalidRegistrationError extends Error {
|
|
|
231
231
|
* passkey signature check is a separate on-chain step.
|
|
232
232
|
*/
|
|
233
233
|
declare function parseRegistration(registration: Uint8Array): ParsedRegistration;
|
|
234
|
-
interface OnChainVaultState {
|
|
235
|
-
passkeyPubkey: Uint8Array;
|
|
236
|
-
activeSessionPubkey: Uint8Array | null;
|
|
237
|
-
}
|
|
238
234
|
declare class OnChainVerificationError extends Error {
|
|
239
235
|
readonly reason: 'vault_not_found' | 'session_not_active' | 'session_pubkey_mismatch' | 'wrong_program';
|
|
240
236
|
constructor(reason: 'vault_not_found' | 'session_not_active' | 'session_pubkey_mismatch' | 'wrong_program', detail?: string);
|
|
241
237
|
}
|
|
242
238
|
/**
|
|
243
|
-
*
|
|
239
|
+
* Verify a registration against on-chain state. Throws on any mismatch.
|
|
244
240
|
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Verify a registration against on-chain state. Returns the vault's
|
|
254
|
-
* passkey pubkey (caller can cache it). Throws on any mismatch.
|
|
241
|
+
* V6: a session is its own PDA ([b"session", vault, allowed_counterparty]),
|
|
242
|
+
* NOT an inline field on the vault. We read that SessionAccount and confirm it
|
|
243
|
+
* is live (version 1 + unexpired) AND carries the same session pubkey the
|
|
244
|
+
* registration claims. If the program accepted the register_session_key tx
|
|
245
|
+
* (which is what wrote the PDA), the passkey signature was already verified by
|
|
246
|
+
* the secp256r1 precompile inside that tx — the seller just confirms the
|
|
247
|
+
* on-chain witness still holds.
|
|
255
248
|
*
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
* in the first place), then the passkey signature was verified by the
|
|
260
|
-
* secp256r1 precompile inside that tx. The seller doesn't need to redo
|
|
261
|
-
* that work; they just need to confirm the on-chain witness still holds.
|
|
249
|
+
* fetchSessionAccount reads at the connection's commitment; pass a connection
|
|
250
|
+
* configured at the commitment the buyer's registration was confirmed to (the
|
|
251
|
+
* adapter waits for visibility before openTab returns).
|
|
262
252
|
*/
|
|
263
|
-
declare function verifyRegistrationOnChain(connection: Connection, registration: ParsedRegistration): Promise<
|
|
264
|
-
passkeyPubkey: Uint8Array;
|
|
265
|
-
}>;
|
|
253
|
+
declare function verifyRegistrationOnChain(connection: Connection, registration: ParsedRegistration): Promise<void>;
|
|
266
254
|
declare class InvalidVoucherSignatureError extends Error {
|
|
267
255
|
constructor(detail?: string);
|
|
268
256
|
}
|
|
@@ -289,4 +277,4 @@ declare function enforceScope(args: {
|
|
|
289
277
|
previousCumulativeAtomic?: AtomicAmount;
|
|
290
278
|
}): void;
|
|
291
279
|
|
|
292
|
-
export { FileVoucherStore, InMemoryVoucherStore, InvalidRegistrationError, InvalidVoucherError, InvalidVoucherSignatureError,
|
|
280
|
+
export { FileVoucherStore, InMemoryVoucherStore, InvalidRegistrationError, InvalidVoucherError, InvalidVoucherSignatureError, OnChainVerificationError, type OpenSseOptions, type ParsedRegistration, ScopeViolationError, type SellerTab, type SseMeter, TAB_VOUCHER_HEADER, type TabMiddlewareConfig, type TabMiddlewareOptions, type VoucherStore, enforceScope, openSse, parseRegistration, requireTab, tabMiddleware, verifyRegistrationOnChain, verifyVoucherSignature };
|
package/dist/tab/seller/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
var m=class extends Error{constructor(n,r){super(`Invalid voucher: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidVoucherError"}};import{PublicKey as Y}from"@solana/web3.js";import j from"tweetnacl";import{sha256 as Ae}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 T,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 v,SECP256R1_PROGRAM_ID as fe,INSTRUCTIONS_SYSVAR_ID as we}from"@dexterai/vault/constants";var V="OTS_SESSION_REGISTER_V2",d=class extends Error{constructor(n,r){super(`Invalid registration: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="InvalidRegistrationError"}};function k(e){if(e.length!==188)throw new d("wrong_length",`expected 188, got ${e.length}`);let t=new TextDecoder().decode(e.slice(0,V.length));if(t!==V)throw new d("wrong_domain",`got "${t}"`);for(let a=V.length;a<32;a++)if(e[a]!==0)throw new d("wrong_domain",`non-NUL padding at byte ${a}`);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),h=n.getBigInt64(136,!0),o=new I(e.slice(144,176)),u=n.getUint32(176,!0),g=n.getBigUint64(180,!0);if(!r.equals(v))throw new d("wrong_program",`${r.toBase58()} is not ${v.toBase58()}`);if(p===0n)throw new d("cap_zero");let s=BigInt(Math.floor(Date.now()/1e3));if(h<=s)throw new d("expiry_in_past",`expires_at=${h}, now=${s}`);return{programId:r,vaultPda:i,sessionPubkey:new Uint8Array(c),maxAmount:p,expiresAt:h,allowedCounterparty:o,nonce:u,maxRevolvingCapacity:g}}var M=10,f=class extends Error{constructor(n,r){super(`On-chain verification failed: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="OnChainVerificationError"}};async function D(e,t){let n=await e.getAccountInfo(t,"finalized");if(!n)throw new f("vault_not_found",t.toBase58());if(!n.owner.equals(v))throw new f("wrong_program",`owner ${n.owner.toBase58()} is not the vault program`);let r=n.data,i=new Uint8Array(r.slice(M,M+33)),u=84+(r[83]===1?48:0)+32+32;if(r[u]!==1)return{passkeyPubkey:i,activeSessionPubkey:null};let s=u+1,a=new Uint8Array(r.slice(s,s+32));return{passkeyPubkey:i,activeSessionPubkey:a}}async function _(e,t){let n=await D(e,t.vaultPda);if(n.activeSessionPubkey===null)throw new f("session_not_active","vault has no active_session \u2014 was it revoked?");if(!F(n.activeSessionPubkey,t.sessionPubkey))throw new f("session_pubkey_mismatch",`on-chain ${q(n.activeSessionPubkey)} != registration ${q(t.sessionPubkey)}`);return{passkeyPubkey:n.passkeyPubkey}}var y=class extends Error{constructor(t){super(`Invalid voucher signature${t?`: ${t}`:""}`),this.name="InvalidVoucherSignatureError"}};function C(e,t){if(t.length!==32)throw new y(`channelIdBytes must be 32 bytes, got ${t.length}`);if(e.sessionPublicKey.length!==32)throw new y(`sessionPublicKey must be 32 bytes, got ${e.sessionPublicKey.length}`);if(e.sessionSignature.length!==64)throw new y(`sessionSignature must be 64 bytes, got ${e.sessionSignature.length}`);let n=T({channelId:t,cumulativeAmount:BigInt(e.payload.cumulativeAmount),sequenceNumber:e.payload.sequenceNumber});if(!j.sign.detached.verify(n,e.sessionSignature,e.sessionPublicKey))throw new y("ed25519 verify rejected")}var l=class extends Error{constructor(n,r){super(`Scope violation: ${n}${r?` (${r})`:""}`);this.reason=n;this.name="ScopeViolationError"}};function U(e){let t=BigInt(e.voucher.payload.cumulativeAmount);if(t>e.registration.maxAmount)throw new l("cumulative_exceeds_cap",`${t} > ${e.registration.maxAmount}`);let n=BigInt(Math.floor(Date.now()/1e3));if(n>=e.registration.expiresAt)throw new l("session_expired",`now=${n} >= expiresAt=${e.registration.expiresAt}`);if(!e.registration.allowedCounterparty.equals(e.expectedCounterparty))throw new l("wrong_counterparty",`${e.registration.allowedCounterparty.toBase58()} != ${e.expectedCounterparty.toBase58()}`);if(e.previousCumulativeAtomic!==void 0){let r=BigInt(e.previousCumulativeAtomic);if(t<=r)throw new l("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 q(e){let t="";for(let n of e)t+=n.toString(16).padStart(2,"0");return t}import{promises as w}from"fs";import{join as J,dirname as G}from"path";function W(e){return{payload:e.payload,sessionPublicKey:$(e.sessionPublicKey),sessionRegistration:$(e.sessionRegistration),sessionSignature:$(e.sessionSignature)}}function X(e){return{payload:e.payload,sessionPublicKey:R(e.sessionPublicKey),sessionRegistration:R(e.sessionRegistration),sessionSignature:R(e.sessionSignature)}}function $(e){let t="";for(let n of e)t+=n.toString(16).padStart(2,"0");return t}function R(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 Le}from"@solana/web3.js";import{bytesToHex as Fe}from"@noble/hashes/utils";import Ee from"tweetnacl";import{sha256 as Ne}from"@noble/hashes/sha256";var z=6;function S(e,t=z){if(!/^\d+(\.\d+)?$/.test(e))throw new Error(`amount must be a non-negative decimal string, got "${e}"`);let[n,r=""]=e.split(".");if(r.length>t)throw new Error(`amount "${e}" has more than ${t} decimals`);let i=r.padEnd(t,"0"),c=`${n}${i}`.replace(/^0+(?=\d)/,"");return c===""?"0":c}function A(e,t=z){if(!/^\d+$/.test(e))throw new Error(`atomic must be a non-negative integer string, got "${e}"`);let n=e.padStart(t+1,"0"),r=n.slice(0,-t).replace(/^0+(?=\d)/,"")||"0",i=n.slice(-t).replace(/0+$/,"");return i?`${r}.${i}`:r}var N="x-tab-voucher",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)}},O=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 A(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 m("signature_invalid",`missing ${N} header`);let t;try{t=Buffer.from(e,"base64").toString("utf8")}catch{throw new m("signature_invalid","malformed base64")}let n;try{n=JSON.parse(t)}catch{throw new m("signature_invalid","malformed JSON")}if(!n||typeof n!="object"||!n.payload||!n.sessionPublicKey)throw new m("signature_invalid","missing required fields");return{payload:n.payload,sessionPublicKey:x(n.sessionPublicKey),sessionRegistration:x(n.sessionRegistration),sessionSignature:x(n.sessionSignature)}}function x(e){if(typeof e!="string"||e.length%2!==0)throw new m("signature_invalid",`bad hex: ${typeof e}`);let t=new Uint8Array(e.length/2);for(let n=0;n<t.length;n++)t[n]=parseInt(e.substr(n*2,2),16);return t}function Q(e){if(!/^[0-9a-f]{64}$/i.test(e))throw new m("signature_invalid",`channelId must be 64-char hex, got "${e}"`);return x(e)}function 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(S(e.perUnit))*100n;return async(c,p,h)=>{try{let o=Z(c.headers[N]),u=o.payload.channelId,g=Q(u),s=n.get(u);if(!s){let P=k(o.sessionRegistration);await _(e.connection,P),s={registration:P,lastCumulativeAtomic:"0"},n.set(u,s)}C(o,g),U({registration:s.registration,voucher:o,expectedCounterparty:r,previousCumulativeAtomic:s.lastCumulativeAtomic});let a=BigInt(o.payload.cumulativeAmount),L=BigInt(s.lastCumulativeAtomic),H=a-L;if(H>i)throw new l("cumulative_exceeds_cap",`single voucher increment ${H} exceeds maxPerVoucherAtomic ${i}`);await t.set(u,o),n.update(u,o.payload.cumulativeAmount);let B=new O(u,e.network,a,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.")});B.setSessionPublicKey(o.sessionPublicKey),c.tab=B,h()}catch(o){if(o instanceof m||o instanceof d||o instanceof f||o instanceof y||o instanceof l){p.status(402).json({error:"invalid_voucher",reason:o.reason??"unknown",detail:o.message});return}h(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(S(n.cumulative())),i=t.perUnit?BigInt(S(t.perUnit)):null,c=0n,p=!1;function h(g=1){if(p)return Promise.reject(new Error("meter ended"));if(i===null)return Promise.reject(new Error("charge() needs options.perUnit"));let s=i*BigInt(g),a=c+s;return a>r?Promise.reject(new l("cumulative_exceeds_cap",`chunk would push request total to ${A(a.toString())} beyond voucher-authorized budget ${A(r.toString())}`)):(c=a,Promise.resolve())}function o(g){if(p)throw new Error("meter ended");let a=(typeof g=="string"?g:Buffer.from(g).toString("utf8")).replace(/\n/g,"\\n");e.write(`data: ${a}
|
|
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}
|
|
2
2
|
|
|
3
|
-
`)}function
|
|
3
|
+
`)}function d(){p||(p=!0,e.write(`event: end
|
|
4
4
|
data: {"chargedAtomic":"${c}"}
|
|
5
5
|
|
|
6
|
-
`),e.end())}return{charge:
|
|
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};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dexterai/x402",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.15.0",
|
|
4
4
|
"description": "Full-stack x402 SDK - add paid API monetization to any endpoint. Express middleware, React hooks, Access Pass, dynamic pricing. Solana, Base, Polygon, Arbitrum, Optimism, Avalanche, SKALE.",
|
|
5
5
|
"author": "Dexter",
|
|
6
6
|
"license": "MIT",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"release:major": "npm version major && npm publish --access public"
|
|
77
77
|
},
|
|
78
78
|
"dependencies": {
|
|
79
|
-
"@dexterai/vault": "^0.
|
|
79
|
+
"@dexterai/vault": "^0.9.0",
|
|
80
80
|
"@dexterai/x402-ads-types": "^0.2.0",
|
|
81
81
|
"@dexterai/x402-core": "^1.4.0",
|
|
82
82
|
"@noble/curves": "^1.9.7",
|