@dexterai/x402 3.3.0 → 3.4.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 +66 -8
- package/dist/adapters/index.d.cts +2 -3
- package/dist/adapters/index.d.ts +2 -3
- package/dist/batch-settlement/index.cjs +1 -1
- package/dist/batch-settlement/index.d.cts +5 -81
- package/dist/batch-settlement/index.d.ts +5 -81
- package/dist/batch-settlement/index.js +1 -1
- package/dist/batch-settlement/seller/index.cjs +1 -0
- package/dist/batch-settlement/seller/index.d.cts +17 -0
- package/dist/batch-settlement/seller/index.d.ts +17 -0
- package/dist/batch-settlement/seller/index.js +1 -0
- package/dist/client/index.cjs +1 -1
- package/dist/client/index.d.cts +3 -5
- package/dist/client/index.d.ts +3 -5
- package/dist/client/index.js +1 -1
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.d.cts +4 -5
- package/dist/react/index.d.ts +4 -5
- package/dist/react/index.js +1 -1
- package/dist/server/index.cjs +16 -16
- package/dist/server/index.d.cts +20 -30
- package/dist/server/index.d.ts +20 -30
- package/dist/server/index.js +16 -16
- package/dist/{sponsored-access-BEufXQ6c.d.cts → sponsored-access-DC2x5LQ-.d.cts} +12 -2
- package/dist/{sponsored-access-4wVjCYrH.d.ts → sponsored-access-DSgmtjhF.d.ts} +12 -2
- package/dist/types-BBhXpBwI.d.cts +60 -0
- package/dist/types-BIINnfB4.d.ts +142 -0
- package/dist/types-Bbt_SDZE.d.cts +142 -0
- package/dist/types-CwK4mPWV.d.ts +60 -0
- package/dist/{types-HFS_C6RX.d.ts → types-IqnDBsjL.d.cts} +226 -2
- package/dist/{types-B3kS1y_t.d.cts → types-IqnDBsjL.d.ts} +226 -2
- package/package.json +8 -2
- package/dist/types-Bcsi5jQb.d.cts +0 -227
- package/dist/types-Bcsi5jQb.d.ts +0 -227
package/README.md
CHANGED
|
@@ -207,9 +207,11 @@ const b = await channel.fetch('https://api.example.com/v1/data');
|
|
|
207
207
|
|
|
208
208
|
console.log(channel.state); // { deposited: '0.3', spent: '0.16', remaining: '0.14' }
|
|
209
209
|
|
|
210
|
-
//
|
|
211
|
-
const
|
|
212
|
-
|
|
210
|
+
// Done buying — signal you're finished with the channel.
|
|
211
|
+
const { closed } = await channel.close();
|
|
212
|
+
// closed === true. This is an intent signal, not a settlement: it does not
|
|
213
|
+
// move funds. The seller's settlement (below) claims what you spent and
|
|
214
|
+
// refunds the rest of your escrow automatically on the normal path.
|
|
213
215
|
```
|
|
214
216
|
|
|
215
217
|
Channel state auto-persists (localStorage in the browser, a file under
|
|
@@ -219,20 +221,73 @@ transparently resumes the open channel — the channel's state is recovered from
|
|
|
219
221
|
storage, or from on-chain state if storage was lost. Pass a custom `store` (any
|
|
220
222
|
`ChannelStore`) to persist elsewhere.
|
|
221
223
|
|
|
224
|
+
#### Escape hatch — `forceWithdraw()` / `finalizeWithdraw()`
|
|
225
|
+
|
|
226
|
+
If the seller never settles, the buyer can reclaim unspent escrow directly via
|
|
227
|
+
the channel contract's timed withdrawal:
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
// 1. Start the on-chain timed withdrawal.
|
|
231
|
+
await channel.forceWithdraw();
|
|
232
|
+
|
|
233
|
+
// 2. After the channel's withdraw delay elapses, finalize it.
|
|
234
|
+
await channel.finalizeWithdraw();
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
This is a last-resort safety net — **normal operation never needs it**, since
|
|
238
|
+
the seller's settlement returns unspent escrow on the standard path. Unlike
|
|
239
|
+
every other batch-settlement step, the escape hatch **costs the buyer gas**: it
|
|
240
|
+
submits transactions itself, so the buyer's wallet must be transaction-capable
|
|
241
|
+
(it must expose a `sendTransaction` method). A signature-only wallet cannot use
|
|
242
|
+
the escape hatch.
|
|
243
|
+
|
|
222
244
|
### Seller
|
|
223
245
|
|
|
224
|
-
|
|
225
|
-
|
|
246
|
+
`createBatchSettlementSeller(config)` returns a callable object that **is** an
|
|
247
|
+
Express request handler — mount it directly. It accepts batch-settlement
|
|
248
|
+
payments (each incoming voucher is verified and persisted to channel storage)
|
|
249
|
+
and collects them (claim → settle → refund). Dexter operates the delegate
|
|
250
|
+
authorizer, so the seller manages no signing key:
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
import { createBatchSettlementSeller } from '@dexterai/x402/batch-settlement/seller';
|
|
254
|
+
|
|
255
|
+
const seller = createBatchSettlementSeller({
|
|
256
|
+
payTo: '0xYourReceivingAddress',
|
|
257
|
+
network: 'eip155:8453', // Base
|
|
258
|
+
price: '0.08', // USDC per call
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// The seller object IS the Express handler — mount it directly.
|
|
262
|
+
app.use('/api/data', seller);
|
|
263
|
+
|
|
264
|
+
// Auto-settlement runs in the background by default. On shutdown, stop the
|
|
265
|
+
// seller — this flushes a final settle so no collected vouchers are lost.
|
|
266
|
+
process.on('SIGTERM', async () => {
|
|
267
|
+
await seller.stop();
|
|
268
|
+
});
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Settlement happens automatically via a background loop (on by default). To
|
|
272
|
+
settle on demand, call `seller.closeChannel(channelId)` for one channel or
|
|
273
|
+
`seller.closeAll()` for every open channel.
|
|
274
|
+
|
|
275
|
+
Mounting via `x402Middleware` also works — with `scheme: 'batch-settlement'` it
|
|
276
|
+
returns the same callable seller object, so you still get a `.stop()` /
|
|
277
|
+
`.closeAll()` / `.closeChannel()` handle:
|
|
226
278
|
|
|
227
279
|
```ts
|
|
228
280
|
import { x402Middleware } from '@dexterai/x402/server';
|
|
229
281
|
|
|
230
|
-
|
|
282
|
+
const seller = x402Middleware({
|
|
231
283
|
payTo: '0xYourReceivingAddress',
|
|
232
284
|
amount: '0.08',
|
|
233
285
|
network: 'eip155:8453',
|
|
234
286
|
scheme: 'batch-settlement',
|
|
235
|
-
})
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
app.use('/api/data', seller);
|
|
290
|
+
// seller.stop() / seller.closeAll() are available here too.
|
|
236
291
|
```
|
|
237
292
|
|
|
238
293
|
---
|
|
@@ -312,9 +367,12 @@ import { createX402Client } from '@dexterai/x402/client';
|
|
|
312
367
|
// Client - Node.js (private key wallet)
|
|
313
368
|
import { wrapFetch, createKeypairWallet } from '@dexterai/x402/client';
|
|
314
369
|
|
|
315
|
-
// Batch settlement - EVM escrow channel (gas amortization)
|
|
370
|
+
// Batch settlement - EVM escrow channel buyer (gas amortization)
|
|
316
371
|
import { openBatchChannel } from '@dexterai/x402/batch-settlement';
|
|
317
372
|
|
|
373
|
+
// Batch settlement - EVM escrow channel seller runtime
|
|
374
|
+
import { createBatchSettlementSeller } from '@dexterai/x402/batch-settlement/seller';
|
|
375
|
+
|
|
318
376
|
// React hook
|
|
319
377
|
import { useX402Payment } from '@dexterai/x402/react';
|
|
320
378
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { k as SolanaAdapter, l as EvmAdapter, C as ChainAdapter } from '../types-IqnDBsjL.cjs';
|
|
2
|
+
export { m as AdapterConfig, B as BalanceInfo, E as EvmWallet, G as GenericWallet, n as SignedTransaction, S as SolanaWallet, W as WalletSet, a as createEvmAdapter, c as createSolanaAdapter, p as isEvmWallet, o as isSolanaWallet } from '../types-IqnDBsjL.cjs';
|
|
3
3
|
export { A as ARBITRUM_ONE, l as AVALANCHE, B as BASE_MAINNET, j as BASE_SEPOLIA, f as BSC_MAINNET, i as BSC_STABLECOIN_ADDRESSES, h as BSC_USDC, g as BSC_USDT, E as ETHEREUM_MAINNET, O as OPTIMISM, P as PERMIT2_ADDRESS, k as POLYGON, m as SKALE_BASE, n as SKALE_BASE_SEPOLIA, d as SOLANA_DEVNET, S as SOLANA_MAINNET, e as SOLANA_TESTNET, o as USDC_ADDRESSES, X as X402_EXACT_PERMIT2_PROXY } from '../constants-qU-4U3L-.cjs';
|
|
4
|
-
import '../types-Bcsi5jQb.cjs';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Check if an asset address is a known USDC contract (any chain).
|
package/dist/adapters/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { k as SolanaAdapter, l as EvmAdapter, C as ChainAdapter } from '../types-IqnDBsjL.js';
|
|
2
|
+
export { m as AdapterConfig, B as BalanceInfo, E as EvmWallet, G as GenericWallet, n as SignedTransaction, S as SolanaWallet, W as WalletSet, a as createEvmAdapter, c as createSolanaAdapter, p as isEvmWallet, o as isSolanaWallet } from '../types-IqnDBsjL.js';
|
|
3
3
|
export { A as ARBITRUM_ONE, l as AVALANCHE, B as BASE_MAINNET, j as BASE_SEPOLIA, f as BSC_MAINNET, i as BSC_STABLECOIN_ADDRESSES, h as BSC_USDC, g as BSC_USDT, E as ETHEREUM_MAINNET, O as OPTIMISM, P as PERMIT2_ADDRESS, k as POLYGON, m as SKALE_BASE, n as SKALE_BASE_SEPOLIA, d as SOLANA_DEVNET, S as SOLANA_MAINNET, e as SOLANA_TESTNET, o as USDC_ADDRESSES, X as X402_EXACT_PERMIT2_PROXY } from '../constants-qU-4U3L-.js';
|
|
4
|
-
import '../types-Bcsi5jQb.js';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Check if an asset address is a known USDC contract (any chain).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var T=Object.defineProperty;var et=Object.getOwnPropertyDescriptor;var nt=Object.getOwnPropertyNames;var at=Object.prototype.hasOwnProperty;var rt=(t,e)=>{for(var n in e)T(t,n,{get:e[n],enumerable:!0})},it=(t,e,n,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of nt(e))!at.call(t,r)&&r!==n&&T(t,r,{get:()=>e[r],enumerable:!(a=et(e,r))||a.enumerable});return t};var ot=t=>it(T({},"__esModule",{value:!0}),t);var ut={};rt(ut,{InsufficientBalanceError:()=>k,UnsupportedNetworkError:()=>f,WithdrawNotReadyError:()=>C,createFileChannelStore:()=>P,createLocalStorageChannelStore:()=>B,getDefaultChannelStore:()=>W,openBatchChannel:()=>Q,resumeBatchChannel:()=>V});module.exports=ot(ut);var l=require("viem"),y=require("viem/chains"),X=require("@x402/evm"),v=require("@x402/evm/batch-settlement/client"),I=require("@x402/core/client");var $=require("os"),O=require("path"),N=require("@x402/evm/batch-settlement/client");function P(t){return new N.FileClientChannelStorage({directory:t})}var E="dexter-x402-channel:";function B(t){return{async get(e){let n=t.getItem(E+e);return n?JSON.parse(n):void 0},async set(e,n){t.setItem(E+e,JSON.stringify(n))},async delete(e){t.removeItem(E+e)}}}function W(){let t=globalThis.localStorage;return t?B(t):P((0,O.join)((0,$.homedir)(),".dexter-x402","channels"))}var k=class extends Error{constructor(e){super(e),this.name="InsufficientBalanceError"}},f=class extends Error{constructor(e){super(e),this.name="UnsupportedNetworkError"}};var L=require("viem"),z=require("@x402/evm/batch-settlement/client"),g=require("@x402/evm"),C=class extends Error{constructor(e){super(e),this.name="WithdrawNotReadyError"}};function M(t,e){return t===0?0:t+e}var st=6,j=[{name:"payer",type:"address"},{name:"payerAuthorizer",type:"address"},{name:"receiver",type:"address"},{name:"receiverAuthorizer",type:"address"},{name:"token",type:"address"},{name:"withdrawDelay",type:"uint40"},{name:"salt",type:"bytes32"}],R=[{type:"function",name:"initiateWithdraw",inputs:[{name:"config",type:"tuple",components:j},{name:"amount",type:"uint128"}],outputs:[],stateMutability:"nonpayable"},{type:"function",name:"finalizeWithdraw",inputs:[{name:"config",type:"tuple",components:j}],outputs:[],stateMutability:"nonpayable"},{type:"function",name:"pendingWithdrawals",inputs:[{name:"channelId",type:"bytes32"}],outputs:[{name:"amount",type:"uint128"},{name:"initiatedAt",type:"uint40"}],stateMutability:"view"},{type:"function",name:"channels",inputs:[{name:"channelId",type:"bytes32"}],outputs:[{name:"balance",type:"uint128"},{name:"totalClaimed",type:"uint128"}],stateMutability:"view"}];function lt(t){if(Array.isArray(t))return{balance:BigInt(t[0]),totalClaimed:BigInt(t[1])};let e=t;return{balance:BigInt(e.balance),totalClaimed:BigInt(e.totalClaimed)}}function q(t){if(Array.isArray(t))return{amount:BigInt(t[0]),initiatedAt:Number(t[1])};let e=t;return{amount:BigInt(e.amount),initiatedAt:Number(e.initiatedAt)}}async function H(t){let{config:e,network:n,client:a,withdrawDelaySecs:r}=t,i=(0,z.computeChannelId)(e,n),s=t.amountAtomic;s===void 0&&(s=lt(await a.readContract({address:g.BATCH_SETTLEMENT_ADDRESS,abi:R,functionName:"channels",args:[i]})).balance);let c=await a.writeContract({address:g.BATCH_SETTLEMENT_ADDRESS,abi:R,functionName:"initiateWithdraw",args:[e,s]});await a.waitForTransactionReceipt({hash:c});let d=q(await a.readContract({address:g.BATCH_SETTLEMENT_ADDRESS,abi:R,functionName:"pendingWithdrawals",args:[i]}));return{initiateTx:c,finalizableAt:M(d.initiatedAt,r)}}async function _(t){let{config:e,network:n,client:a,withdrawDelaySecs:r}=t,i=(0,z.computeChannelId)(e,n),s=q(await a.readContract({address:g.BATCH_SETTLEMENT_ADDRESS,abi:R,functionName:"pendingWithdrawals",args:[i]}));if(s.initiatedAt===0)throw new C(`no withdrawal is pending for channel ${i} \u2014 call forceWithdraw first`);let c=M(s.initiatedAt,r),d=Math.floor(Date.now()/1e3);if(d<c)throw new C(`withdrawal for channel ${i} is not finalizable until ${c} (unix seconds) \u2014 ${c-d}s remaining`);let o=await a.writeContract({address:g.BATCH_SETTLEMENT_ADDRESS,abi:R,functionName:"finalizeWithdraw",args:[e]});return await a.waitForTransactionReceipt({hash:o}),{finalizeTx:o,withdrawnAmount:(0,L.formatUnits)(s.amount,st)}}var J={"eip155:8453":{chain:y.base,defaultRpc:"https://mainnet.base.org"},"eip155:42161":{chain:y.arbitrum,defaultRpc:"https://arb1.arbitrum.io/rpc"},"eip155:137":{chain:y.polygon,defaultRpc:"https://polygon-rpc.com"}};function G(t){let e=J[t.network];if(!e)throw new f(`batch-settlement is not available on network "${t.network}" \u2014 supported: ${Object.keys(J).join(", ")}`);let n=t.rpcUrl??e.defaultRpc,a=t.wallet.signTypedData;if(typeof a!="function")throw new Error("batch-settlement requires an EvmWallet that supports signTypedData (EIP-712)");let r=(0,l.createWalletClient)({account:{address:t.wallet.address,type:"json-rpc"},chain:e.chain,transport:(0,l.http)(n)}).extend(l.publicActions),i=t.wallet.sendTransaction,s=typeof i=="function",c=async u=>{let b=u.to??void 0;if(!b)throw new Error("batch-settlement escape hatch: transaction is missing a `to` address");let p=u.data??"0x";if(typeof i=="function")return await i.call(t.wallet,{to:b,data:p,value:u.value});throw new Error("batch-settlement: wallet has no sendTransaction")},d=Object.assign(r,{address:t.wallet.address,signTypedData:u=>a.call(t.wallet,u),sendTransaction:c}),o=(0,X.toClientEvmSigner)(d),m=new v.BatchSettlementEvmScheme(o,{storage:t.store,depositPolicy:{depositMultiplier:4},depositStrategy:()=>t.depositAtomic}),h=new I.x402Client;h.register(t.network,m);let w=new I.x402HTTPClient(h);return{scheme:m,x402Cli:h,httpClient:w,rpcUrl:n,withdrawClient:d,canSubmitTransactions:s}}var A=6;function ct(t,e){let n=e>t?0n:t-e;return{deposited:(0,l.formatUnits)(t,A),spent:(0,l.formatUnits)(e,A),remaining:(0,l.formatUnits)(n,A)}}function dt(t){let e=t.payload;if(!e||typeof e!="object")return"";let n=e.voucher;if(!n||typeof n!="object")return"";let a=n.channelId;return typeof a=="string"?a:""}function ht(t){let e=t.payload;if(!e||typeof e!="object")return;let n=e.channelConfig;if(!(!n||typeof n!="object"))return n}function K(t){let{stack:e,store:n,network:a}=t,r="",i,s=t.depositedAtomic,c=0n;async function d(){if(!r)return;let o=await(0,v.getChannel)(n,r);o&&(o.chargedCumulativeAmount!==void 0&&(c=BigInt(o.chargedCumulativeAmount)),s===0n&&o.balance!==void 0&&(s=BigInt(o.balance)))}return{get channelId(){return r},get network(){return a},get state(){return ct(s,c)},async fetch(o,m){let{httpClient:h}=e,w=await fetch(o,m);if(w.status!==402)return w;let F=h.getPaymentRequiredResponse(p=>w.headers.get(p),await w.clone().json().catch(()=>{})),u=2,b;for(let p=1;p<=u;p+=1){let S=await h.createPaymentPayload(F),D=dt(S);D&&(r=D);let U=ht(S);U&&(i=U);let Y=h.encodePaymentSignatureHeader(S),x=await fetch(o,{...m,headers:{...m?.headers??{},...Y}});b=x;let{recovered:Z}=await h.processPaymentResult(S,tt=>x.headers.get(tt),x.status);if(await d(),!(x.status===402&&Z&&p<u))return x}return b},async close(){return r&&await n.delete(r.toLowerCase()),{closed:!0}},async forceWithdraw(){if(!e.canSubmitTransactions)throw new Error("batch-settlement forceWithdraw requires a wallet with a sendTransaction method (the withdrawal escape hatch submits an on-chain transaction and the buyer pays gas; a signature-only wallet cannot use it).");if(!i)throw new Error("forceWithdraw is unavailable until the channel has resolved on-chain \u2014 make at least one fetch() against the channel first");return H({config:i,network:a,client:e.withdrawClient,withdrawDelaySecs:i.withdrawDelay})},async finalizeWithdraw(){if(!e.canSubmitTransactions)throw new Error("batch-settlement finalizeWithdraw requires a wallet with a sendTransaction method (the withdrawal escape hatch submits an on-chain transaction and the buyer pays gas; a signature-only wallet cannot use it).");if(!i)throw new Error("finalizeWithdraw is unavailable until the channel has resolved on-chain \u2014 make at least one fetch() against the channel first");return _({config:i,network:a,client:e.withdrawClient,withdrawDelaySecs:i.withdrawDelay})}}}async function Q(t){let e=t.store??W(),n;try{n=(0,l.parseUnits)(t.deposit,A)}catch{throw new Error(`deposit must be a valid USDC amount in decimal units (e.g. "0.30"), got "${t.deposit}"`)}if(n<=0n)throw new Error(`deposit must be a positive amount, got "${t.deposit}"`);let a=G({wallet:t.wallet,network:t.network,rpcUrl:t.rpcUrl,store:e,depositAtomic:n.toString()});return K({stack:a,store:e,network:t.network,depositedAtomic:n})}async function V(t){let e=t.store??W(),n=G({wallet:t.wallet,network:t.network,rpcUrl:t.rpcUrl,store:e,depositAtomic:"0"});return K({stack:n,store:e,network:t.network,depositedAtomic:0n})}0&&(module.exports={InsufficientBalanceError,UnsupportedNetworkError,WithdrawNotReadyError,createFileChannelStore,createLocalStorageChannelStore,getDefaultChannelStore,openBatchChannel,resumeBatchChannel});
|
|
@@ -1,83 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import '
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Channel persistence. This is the upstream `ClientChannelStorage` interface
|
|
7
|
-
* (`get` / `set` / `delete`, keyed by lowercased channelId). The SDK ships
|
|
8
|
-
* file-backed and localStorage-backed implementations; a consumer may pass any
|
|
9
|
-
* `ClientChannelStorage` (e.g. one backed by their own database).
|
|
10
|
-
*/
|
|
11
|
-
type ChannelStore = ClientChannelStorage;
|
|
12
|
-
/** Channel accounting, all amounts USDC human units (e.g. "0.30"). */
|
|
13
|
-
interface ChannelState {
|
|
14
|
-
/** Total escrowed into the channel. */
|
|
15
|
-
deposited: string;
|
|
16
|
-
/** Cumulative amount spent via vouchers. */
|
|
17
|
-
spent: string;
|
|
18
|
-
/** deposited - spent. */
|
|
19
|
-
remaining: string;
|
|
20
|
-
}
|
|
21
|
-
/** Options for opening a fresh (or auto-resumed) channel. */
|
|
22
|
-
interface OpenBatchChannelOptions {
|
|
23
|
-
/** EVM wallet — any { address, signTypedData }. The same EvmWallet the exact scheme uses. */
|
|
24
|
-
wallet: EvmWallet;
|
|
25
|
-
/** CAIP-2 network: eip155:8453 (Base), eip155:42161 (Arbitrum), eip155:137 (Polygon). */
|
|
26
|
-
network: string;
|
|
27
|
-
/** Total escrow for the channel, USDC human units, e.g. "0.30". */
|
|
28
|
-
deposit: string;
|
|
29
|
-
/** Facilitator base URL. Default: https://x402.dexter.cash */
|
|
30
|
-
facilitatorUrl?: string;
|
|
31
|
-
/** RPC URL override. Default: per-network. */
|
|
32
|
-
rpcUrl?: string;
|
|
33
|
-
/** Channel persistence. Default: localStorage (browser) / file (Node). */
|
|
34
|
-
store?: ChannelStore;
|
|
35
|
-
}
|
|
36
|
-
/** Options for explicitly resuming an existing channel. */
|
|
37
|
-
interface ResumeBatchChannelOptions {
|
|
38
|
-
wallet: EvmWallet;
|
|
39
|
-
network: string;
|
|
40
|
-
facilitatorUrl?: string;
|
|
41
|
-
rpcUrl?: string;
|
|
42
|
-
store?: ChannelStore;
|
|
43
|
-
}
|
|
44
|
-
/** Result of channel.close() — the three settlement tx hashes and final amounts. */
|
|
45
|
-
interface CloseReceipt {
|
|
46
|
-
/** claimWithSignature tx hash. */
|
|
47
|
-
claimTx: string;
|
|
48
|
-
/** settle tx hash. */
|
|
49
|
-
settleTx: string;
|
|
50
|
-
/** refundWithSignature tx hash. */
|
|
51
|
-
refundTx: string;
|
|
52
|
-
/** Amount paid to the seller, USDC human units. */
|
|
53
|
-
settledAmount: string;
|
|
54
|
-
/** Unspent amount returned to the buyer, USDC human units. */
|
|
55
|
-
refundedAmount: string;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* A live escrow channel. Returned by openBatchChannel / resumeBatchChannel.
|
|
59
|
-
* Hold this handle for the lifetime of a batching session.
|
|
60
|
-
*/
|
|
61
|
-
interface BatchSettlementChannel {
|
|
62
|
-
/** On-chain channel id (bytes32 hex). Empty until the first fetch resolves it. */
|
|
63
|
-
readonly channelId: string;
|
|
64
|
-
/** CAIP-2 network. */
|
|
65
|
-
readonly network: string;
|
|
66
|
-
/** Live channel accounting; updated after each fetch. */
|
|
67
|
-
readonly state: ChannelState;
|
|
68
|
-
/** Drop-in fetch. On a batch-settlement 402, signs a voucher and retries. */
|
|
69
|
-
fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
|
|
70
|
-
/** Facilitator-driven claim -> settle -> refund. Resumable if interrupted. */
|
|
71
|
-
close(): Promise<CloseReceipt>;
|
|
72
|
-
}
|
|
73
|
-
/** Thrown by openBatchChannel when the buyer wallet lacks USDC for the deposit. */
|
|
74
|
-
declare class InsufficientBalanceError extends Error {
|
|
75
|
-
constructor(message: string);
|
|
76
|
-
}
|
|
77
|
-
/** Thrown when a network has no deployed x402BatchSettlement contract. */
|
|
78
|
-
declare class UnsupportedNetworkError extends Error {
|
|
79
|
-
constructor(message: string);
|
|
80
|
-
}
|
|
1
|
+
import { O as OpenBatchChannelOptions, B as BatchSettlementChannel, R as ResumeBatchChannelOptions, C as ChannelStore } from '../types-Bbt_SDZE.cjs';
|
|
2
|
+
export { a as ChannelState, b as CloseReceipt, c as CloseResult, d as FinalizeWithdrawResult, F as ForceWithdrawResult, I as InsufficientBalanceError, U as UnsupportedNetworkError, W as WithdrawNotReadyError } from '../types-Bbt_SDZE.cjs';
|
|
3
|
+
import '@x402/evm/batch-settlement/client';
|
|
4
|
+
import '../types-IqnDBsjL.cjs';
|
|
81
5
|
|
|
82
6
|
/**
|
|
83
7
|
* Opens a fresh batch-settlement escrow channel. No network call happens here:
|
|
@@ -123,4 +47,4 @@ declare function createLocalStorageChannelStore(storage: Storage): ChannelStore;
|
|
|
123
47
|
*/
|
|
124
48
|
declare function getDefaultChannelStore(): ChannelStore;
|
|
125
49
|
|
|
126
|
-
export {
|
|
50
|
+
export { BatchSettlementChannel, ChannelStore, OpenBatchChannelOptions, ResumeBatchChannelOptions, createFileChannelStore, createLocalStorageChannelStore, getDefaultChannelStore, openBatchChannel, resumeBatchChannel };
|
|
@@ -1,83 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import '
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Channel persistence. This is the upstream `ClientChannelStorage` interface
|
|
7
|
-
* (`get` / `set` / `delete`, keyed by lowercased channelId). The SDK ships
|
|
8
|
-
* file-backed and localStorage-backed implementations; a consumer may pass any
|
|
9
|
-
* `ClientChannelStorage` (e.g. one backed by their own database).
|
|
10
|
-
*/
|
|
11
|
-
type ChannelStore = ClientChannelStorage;
|
|
12
|
-
/** Channel accounting, all amounts USDC human units (e.g. "0.30"). */
|
|
13
|
-
interface ChannelState {
|
|
14
|
-
/** Total escrowed into the channel. */
|
|
15
|
-
deposited: string;
|
|
16
|
-
/** Cumulative amount spent via vouchers. */
|
|
17
|
-
spent: string;
|
|
18
|
-
/** deposited - spent. */
|
|
19
|
-
remaining: string;
|
|
20
|
-
}
|
|
21
|
-
/** Options for opening a fresh (or auto-resumed) channel. */
|
|
22
|
-
interface OpenBatchChannelOptions {
|
|
23
|
-
/** EVM wallet — any { address, signTypedData }. The same EvmWallet the exact scheme uses. */
|
|
24
|
-
wallet: EvmWallet;
|
|
25
|
-
/** CAIP-2 network: eip155:8453 (Base), eip155:42161 (Arbitrum), eip155:137 (Polygon). */
|
|
26
|
-
network: string;
|
|
27
|
-
/** Total escrow for the channel, USDC human units, e.g. "0.30". */
|
|
28
|
-
deposit: string;
|
|
29
|
-
/** Facilitator base URL. Default: https://x402.dexter.cash */
|
|
30
|
-
facilitatorUrl?: string;
|
|
31
|
-
/** RPC URL override. Default: per-network. */
|
|
32
|
-
rpcUrl?: string;
|
|
33
|
-
/** Channel persistence. Default: localStorage (browser) / file (Node). */
|
|
34
|
-
store?: ChannelStore;
|
|
35
|
-
}
|
|
36
|
-
/** Options for explicitly resuming an existing channel. */
|
|
37
|
-
interface ResumeBatchChannelOptions {
|
|
38
|
-
wallet: EvmWallet;
|
|
39
|
-
network: string;
|
|
40
|
-
facilitatorUrl?: string;
|
|
41
|
-
rpcUrl?: string;
|
|
42
|
-
store?: ChannelStore;
|
|
43
|
-
}
|
|
44
|
-
/** Result of channel.close() — the three settlement tx hashes and final amounts. */
|
|
45
|
-
interface CloseReceipt {
|
|
46
|
-
/** claimWithSignature tx hash. */
|
|
47
|
-
claimTx: string;
|
|
48
|
-
/** settle tx hash. */
|
|
49
|
-
settleTx: string;
|
|
50
|
-
/** refundWithSignature tx hash. */
|
|
51
|
-
refundTx: string;
|
|
52
|
-
/** Amount paid to the seller, USDC human units. */
|
|
53
|
-
settledAmount: string;
|
|
54
|
-
/** Unspent amount returned to the buyer, USDC human units. */
|
|
55
|
-
refundedAmount: string;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* A live escrow channel. Returned by openBatchChannel / resumeBatchChannel.
|
|
59
|
-
* Hold this handle for the lifetime of a batching session.
|
|
60
|
-
*/
|
|
61
|
-
interface BatchSettlementChannel {
|
|
62
|
-
/** On-chain channel id (bytes32 hex). Empty until the first fetch resolves it. */
|
|
63
|
-
readonly channelId: string;
|
|
64
|
-
/** CAIP-2 network. */
|
|
65
|
-
readonly network: string;
|
|
66
|
-
/** Live channel accounting; updated after each fetch. */
|
|
67
|
-
readonly state: ChannelState;
|
|
68
|
-
/** Drop-in fetch. On a batch-settlement 402, signs a voucher and retries. */
|
|
69
|
-
fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
|
|
70
|
-
/** Facilitator-driven claim -> settle -> refund. Resumable if interrupted. */
|
|
71
|
-
close(): Promise<CloseReceipt>;
|
|
72
|
-
}
|
|
73
|
-
/** Thrown by openBatchChannel when the buyer wallet lacks USDC for the deposit. */
|
|
74
|
-
declare class InsufficientBalanceError extends Error {
|
|
75
|
-
constructor(message: string);
|
|
76
|
-
}
|
|
77
|
-
/** Thrown when a network has no deployed x402BatchSettlement contract. */
|
|
78
|
-
declare class UnsupportedNetworkError extends Error {
|
|
79
|
-
constructor(message: string);
|
|
80
|
-
}
|
|
1
|
+
import { O as OpenBatchChannelOptions, B as BatchSettlementChannel, R as ResumeBatchChannelOptions, C as ChannelStore } from '../types-BIINnfB4.js';
|
|
2
|
+
export { a as ChannelState, b as CloseReceipt, c as CloseResult, d as FinalizeWithdrawResult, F as ForceWithdrawResult, I as InsufficientBalanceError, U as UnsupportedNetworkError, W as WithdrawNotReadyError } from '../types-BIINnfB4.js';
|
|
3
|
+
import '@x402/evm/batch-settlement/client';
|
|
4
|
+
import '../types-IqnDBsjL.js';
|
|
81
5
|
|
|
82
6
|
/**
|
|
83
7
|
* Opens a fresh batch-settlement escrow channel. No network call happens here:
|
|
@@ -123,4 +47,4 @@ declare function createLocalStorageChannelStore(storage: Storage): ChannelStore;
|
|
|
123
47
|
*/
|
|
124
48
|
declare function getDefaultChannelStore(): ChannelStore;
|
|
125
49
|
|
|
126
|
-
export {
|
|
50
|
+
export { BatchSettlementChannel, ChannelStore, OpenBatchChannelOptions, ResumeBatchChannelOptions, createFileChannelStore, createLocalStorageChannelStore, getDefaultChannelStore, openBatchChannel, resumeBatchChannel };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createWalletClient as
|
|
1
|
+
import{createWalletClient as Q,http as V,publicActions as Y,parseUnits as Z,formatUnits as A}from"viem";import{base as tt,arbitrum as et,polygon as nt}from"viem/chains";import{toClientEvmSigner as at}from"@x402/evm";import{BatchSettlementEvmScheme as rt,getChannel as it}from"@x402/evm/batch-settlement/client";import{x402Client as ot,x402HTTPClient as st}from"@x402/core/client";import{homedir as H}from"os";import{join as _}from"path";import{FileClientChannelStorage as J}from"@x402/evm/batch-settlement/client";function E(t){return new J({directory:t})}var R="dexter-x402-channel:";function P(t){return{async get(e){let n=t.getItem(R+e);return n?JSON.parse(n):void 0},async set(e,n){t.setItem(R+e,JSON.stringify(n))},async delete(e){t.removeItem(R+e)}}}function x(){let t=globalThis.localStorage;return t?P(t):E(_(H(),".dexter-x402","channels"))}var k=class extends Error{constructor(e){super(e),this.name="InsufficientBalanceError"}},C=class extends Error{constructor(e){super(e),this.name="UnsupportedNetworkError"}};import{formatUnits as X}from"viem";import{computeChannelId as z}from"@x402/evm/batch-settlement/client";import{BATCH_SETTLEMENT_ADDRESS as y}from"@x402/evm";var S=class extends Error{constructor(e){super(e),this.name="WithdrawNotReadyError"}};function F(t,e){return t===0?0:t+e}var G=6,B=[{name:"payer",type:"address"},{name:"payerAuthorizer",type:"address"},{name:"receiver",type:"address"},{name:"receiverAuthorizer",type:"address"},{name:"token",type:"address"},{name:"withdrawDelay",type:"uint40"},{name:"salt",type:"bytes32"}],b=[{type:"function",name:"initiateWithdraw",inputs:[{name:"config",type:"tuple",components:B},{name:"amount",type:"uint128"}],outputs:[],stateMutability:"nonpayable"},{type:"function",name:"finalizeWithdraw",inputs:[{name:"config",type:"tuple",components:B}],outputs:[],stateMutability:"nonpayable"},{type:"function",name:"pendingWithdrawals",inputs:[{name:"channelId",type:"bytes32"}],outputs:[{name:"amount",type:"uint128"},{name:"initiatedAt",type:"uint40"}],stateMutability:"view"},{type:"function",name:"channels",inputs:[{name:"channelId",type:"bytes32"}],outputs:[{name:"balance",type:"uint128"},{name:"totalClaimed",type:"uint128"}],stateMutability:"view"}];function K(t){if(Array.isArray(t))return{balance:BigInt(t[0]),totalClaimed:BigInt(t[1])};let e=t;return{balance:BigInt(e.balance),totalClaimed:BigInt(e.totalClaimed)}}function D(t){if(Array.isArray(t))return{amount:BigInt(t[0]),initiatedAt:Number(t[1])};let e=t;return{amount:BigInt(e.amount),initiatedAt:Number(e.initiatedAt)}}async function U(t){let{config:e,network:n,client:a,withdrawDelaySecs:s}=t,r=z(e,n),o=t.amountAtomic;o===void 0&&(o=K(await a.readContract({address:y,abi:b,functionName:"channels",args:[r]})).balance);let l=await a.writeContract({address:y,abi:b,functionName:"initiateWithdraw",args:[e,o]});await a.waitForTransactionReceipt({hash:l});let c=D(await a.readContract({address:y,abi:b,functionName:"pendingWithdrawals",args:[r]}));return{initiateTx:l,finalizableAt:F(c.initiatedAt,s)}}async function $(t){let{config:e,network:n,client:a,withdrawDelaySecs:s}=t,r=z(e,n),o=D(await a.readContract({address:y,abi:b,functionName:"pendingWithdrawals",args:[r]}));if(o.initiatedAt===0)throw new S(`no withdrawal is pending for channel ${r} \u2014 call forceWithdraw first`);let l=F(o.initiatedAt,s),c=Math.floor(Date.now()/1e3);if(c<l)throw new S(`withdrawal for channel ${r} is not finalizable until ${l} (unix seconds) \u2014 ${l-c}s remaining`);let i=await a.writeContract({address:y,abi:b,functionName:"finalizeWithdraw",args:[e]});return await a.waitForTransactionReceipt({hash:i}),{finalizeTx:i,withdrawnAmount:X(o.amount,G)}}var O={"eip155:8453":{chain:tt,defaultRpc:"https://mainnet.base.org"},"eip155:42161":{chain:et,defaultRpc:"https://arb1.arbitrum.io/rpc"},"eip155:137":{chain:nt,defaultRpc:"https://polygon-rpc.com"}};function N(t){let e=O[t.network];if(!e)throw new C(`batch-settlement is not available on network "${t.network}" \u2014 supported: ${Object.keys(O).join(", ")}`);let n=t.rpcUrl??e.defaultRpc,a=t.wallet.signTypedData;if(typeof a!="function")throw new Error("batch-settlement requires an EvmWallet that supports signTypedData (EIP-712)");let s=Q({account:{address:t.wallet.address,type:"json-rpc"},chain:e.chain,transport:V(n)}).extend(Y),r=t.wallet.sendTransaction,o=typeof r=="function",l=async h=>{let w=h.to??void 0;if(!w)throw new Error("batch-settlement escape hatch: transaction is missing a `to` address");let u=h.data??"0x";if(typeof r=="function")return await r.call(t.wallet,{to:w,data:u,value:h.value});throw new Error("batch-settlement: wallet has no sendTransaction")},c=Object.assign(s,{address:t.wallet.address,signTypedData:h=>a.call(t.wallet,h),sendTransaction:l}),i=at(c),p=new rt(i,{storage:t.store,depositPolicy:{depositMultiplier:4},depositStrategy:()=>t.depositAtomic}),d=new ot;d.register(t.network,p);let m=new st(d);return{scheme:p,x402Cli:d,httpClient:m,rpcUrl:n,withdrawClient:c,canSubmitTransactions:o}}var W=6;function lt(t,e){let n=e>t?0n:t-e;return{deposited:A(t,W),spent:A(e,W),remaining:A(n,W)}}function ct(t){let e=t.payload;if(!e||typeof e!="object")return"";let n=e.voucher;if(!n||typeof n!="object")return"";let a=n.channelId;return typeof a=="string"?a:""}function dt(t){let e=t.payload;if(!e||typeof e!="object")return;let n=e.channelConfig;if(!(!n||typeof n!="object"))return n}function j(t){let{stack:e,store:n,network:a}=t,s="",r,o=t.depositedAtomic,l=0n;async function c(){if(!s)return;let i=await it(n,s);i&&(i.chargedCumulativeAmount!==void 0&&(l=BigInt(i.chargedCumulativeAmount)),o===0n&&i.balance!==void 0&&(o=BigInt(i.balance)))}return{get channelId(){return s},get network(){return a},get state(){return lt(o,l)},async fetch(i,p){let{httpClient:d}=e,m=await fetch(i,p);if(m.status!==402)return m;let v=d.getPaymentRequiredResponse(u=>m.headers.get(u),await m.clone().json().catch(()=>{})),h=2,w;for(let u=1;u<=h;u+=1){let f=await d.createPaymentPayload(v),I=ct(f);I&&(s=I);let T=dt(f);T&&(r=T);let L=d.encodePaymentSignatureHeader(f),g=await fetch(i,{...p,headers:{...p?.headers??{},...L}});w=g;let{recovered:M}=await d.processPaymentResult(f,q=>g.headers.get(q),g.status);if(await c(),!(g.status===402&&M&&u<h))return g}return w},async close(){return s&&await n.delete(s.toLowerCase()),{closed:!0}},async forceWithdraw(){if(!e.canSubmitTransactions)throw new Error("batch-settlement forceWithdraw requires a wallet with a sendTransaction method (the withdrawal escape hatch submits an on-chain transaction and the buyer pays gas; a signature-only wallet cannot use it).");if(!r)throw new Error("forceWithdraw is unavailable until the channel has resolved on-chain \u2014 make at least one fetch() against the channel first");return U({config:r,network:a,client:e.withdrawClient,withdrawDelaySecs:r.withdrawDelay})},async finalizeWithdraw(){if(!e.canSubmitTransactions)throw new Error("batch-settlement finalizeWithdraw requires a wallet with a sendTransaction method (the withdrawal escape hatch submits an on-chain transaction and the buyer pays gas; a signature-only wallet cannot use it).");if(!r)throw new Error("finalizeWithdraw is unavailable until the channel has resolved on-chain \u2014 make at least one fetch() against the channel first");return $({config:r,network:a,client:e.withdrawClient,withdrawDelaySecs:r.withdrawDelay})}}}async function ht(t){let e=t.store??x(),n;try{n=Z(t.deposit,W)}catch{throw new Error(`deposit must be a valid USDC amount in decimal units (e.g. "0.30"), got "${t.deposit}"`)}if(n<=0n)throw new Error(`deposit must be a positive amount, got "${t.deposit}"`);let a=N({wallet:t.wallet,network:t.network,rpcUrl:t.rpcUrl,store:e,depositAtomic:n.toString()});return j({stack:a,store:e,network:t.network,depositedAtomic:n})}async function ut(t){let e=t.store??x(),n=N({wallet:t.wallet,network:t.network,rpcUrl:t.rpcUrl,store:e,depositAtomic:"0"});return j({stack:n,store:e,network:t.network,depositedAtomic:0n})}export{k as InsufficientBalanceError,C as UnsupportedNetworkError,S as WithdrawNotReadyError,E as createFileChannelStore,P as createLocalStorageChannelStore,x as getDefaultChannelStore,ht as openBatchChannel,ut as resumeBatchChannel};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var R=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var O=Object.getOwnPropertyNames;var _=Object.prototype.hasOwnProperty;var D=(e,r)=>{for(var s in r)R(e,s,{get:r[s],enumerable:!0})},z=(e,r,s,o)=>{if(r&&typeof r=="object"||typeof r=="function")for(let n of O(r))!_.call(e,n)&&n!==s&&R(e,n,{get:()=>r[n],enumerable:!(o=N(r,n))||o.enumerable});return e};var Q=e=>z(R({},"__esModule",{value:!0}),e);var W={};D(W,{createBatchSettlementSeller:()=>E});module.exports=Q(W);var B=require("os"),U=require("path"),$=require("@x402/evm/batch-settlement/server");var C=require("@x402/core/server"),x=require("@x402/core/http"),A=require("@x402/evm/batch-settlement/server");function b(e){let r=e.verbose?console.log.bind(console,"[batch-settlement:seller]"):()=>{},s=new C.HTTPFacilitatorClient({url:e.facilitatorUrl}),o=new A.BatchSettlementEvmScheme(e.payTo,{storage:e.channelStore}),n=new C.x402ResourceServer(s).register(e.network,o),l=new x.x402HTTPResourceServer(n,{[e.route]:{accepts:{scheme:"batch-settlement",payTo:e.payTo,price:e.price,network:e.network},description:"batch-settlement protected route",mimeType:"application/json"}}),i=null;function u(){if(i)return i;let t=l.initialize();return t.catch(a=>{i===t&&(i=null),e.verbose?r("resource server initialize() failed:",a):console.error("[batch-settlement:seller] resource server initialize() failed:",a)}),i=t,t}let h=u();function d(t,a){if(t.headersSent)return;for(let[g,v]of Object.entries(a.headers))t.setHeader(g,v);t.status(a.status);let{body:m}=a;m==null?t.end():typeof m=="string"?t.send(m):t.json(m)}return{scheme:o,facilitator:s,handler:async(t,a,m)=>{try{await u();let g=t.get("host")??"",v=`${t.baseUrl??""}${t.path}`||"/",M={getHeader:y=>t.headers[y.toLowerCase()],getMethod:()=>t.method,getPath:()=>v,getUrl:()=>`${t.protocol}://${g}${t.originalUrl}`,getAcceptHeader:()=>t.headers.accept??"",getUserAgent:()=>t.headers["user-agent"]??"",getBody:()=>t.body??{},getQueryParams:()=>t.query,getQueryParam:y=>{let f=t.query[y];if(typeof f=="string"||Array.isArray(f))return f}},F=t.headers["payment-signature"]??t.headers["x-payment"],w={adapter:M,path:v,method:t.method,paymentHeader:F},p=await l.processHTTPRequest(w);if(r("processHTTPRequest ->",p.type),p.type==="no-payment-required"){m();return}if(p.type==="payment-error"){d(a,p.response);return}let j={request:w,responseBody:Buffer.alloc(0)},S=await l.processSettlement(p.paymentPayload,p.paymentRequirements,p.declaredExtensions,j);if(r("processSettlement ->",S.success?"success":`failure:${S.errorReason}`),!S.success){d(a,S.response);return}for(let[y,f]of Object.entries(S.headers))a.headersSent||a.setHeader(y,f);m()}catch(g){r("handler error:",g),a.headersSent||a.status(500).json({error:"Payment processing error"})}},ready:h}}var P=require("viem"),k=6;async function T(e){let{manager:r,store:s,channelId:o}=e,n=await s.get(o),l=BigInt(n?.chargedCumulativeAmount??"0"),i=BigInt(n?.balance??"0"),u=i>l?i-l:0n,{claims:h,settle:d}=await r.claimAndSettle(),c=await r.refund([o]),t=c.find(a=>a.channel===o)??c[0];return{claimTx:h[0]?.transaction??"",settleTx:d?.transaction??"",refundTx:t?.transaction??"",settledAmount:(0,P.formatUnits)(l,k),refundedAmount:(0,P.formatUnits)(u,k)}}async function I(e){let r=await e.store.list(),s=[];for(let o of r)try{let n=await T({manager:e.manager,store:e.store,channelId:o.channelId});s.push({channelId:o.channelId,...n})}catch(n){s.push({channelId:o.channelId,error:n instanceof Error?n.message:String(n)})}return s}function L(e){let r=!1,s=async()=>{try{await e.claimAndSettle()}catch(n){e.onError?.(n)}},o=setInterval(()=>{r||s()},e.claimIntervalMs);return typeof o.unref=="function"&&o.unref(),{async stop(){r||(r=!0,clearInterval(o),await s())}}}var q="https://x402.dexter.cash",G="GET /",H=new Set(["eip155:8453","eip155:42161","eip155:137"]);function K(e){return e===!1?null:e===void 0||e===!0?3e5:(e.claimIntervalSecs??300)*1e3}function E(e){if(!H.has(e.network))throw new Error(`batch-settlement is not supported on network "${e.network}" \u2014 supported: ${[...H].join(", ")}`);let r=e.facilitatorUrl??q,s=e.channelStore??new $.FileChannelStorage({directory:(0,U.join)((0,B.homedir)(),".dexter-x402","seller-channels")}),o=b({payTo:e.payTo,network:e.network,price:e.price,route:e.route??G,facilitatorUrl:r,channelStore:s,verbose:e.verbose}),n=o.scheme.createChannelManager(o.facilitator,e.network),l=async()=>{await n.claimAndSettle()},i=K(e.autoSettle),u=null;i!==null&&(u=L({claimAndSettle:l,claimIntervalMs:i,onError:t=>console.error("[batch-settlement:seller] auto-loop claim pass failed",t)}));let h=s,d=(t,a,m)=>{o.handler(t,a,m)},c=d;return c.middleware=()=>d,c.closeChannel=t=>T({manager:n,store:h,channelId:t}),c.closeAll=()=>I({manager:n,store:h}),c.stop=async()=>{u&&await u.stop()},c}0&&(module.exports={createBatchSettlementSeller});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { a as BatchSettlementSellerConfig, B as BatchSettlementSeller } from '../../types-BBhXpBwI.cjs';
|
|
2
|
+
export { S as SellerCloseResult } from '../../types-BBhXpBwI.cjs';
|
|
3
|
+
import 'express';
|
|
4
|
+
import '@x402/evm/batch-settlement/server';
|
|
5
|
+
import '../../types-Bbt_SDZE.cjs';
|
|
6
|
+
import '@x402/evm/batch-settlement/client';
|
|
7
|
+
import '../../types-IqnDBsjL.cjs';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates a batch-settlement seller runtime. The returned object is callable
|
|
11
|
+
* (usable directly as an Express RequestHandler) and exposes lifecycle +
|
|
12
|
+
* settlement methods. The auto-settlement loop starts immediately unless
|
|
13
|
+
* disabled.
|
|
14
|
+
*/
|
|
15
|
+
declare function createBatchSettlementSeller(config: BatchSettlementSellerConfig): BatchSettlementSeller;
|
|
16
|
+
|
|
17
|
+
export { BatchSettlementSeller, BatchSettlementSellerConfig, createBatchSettlementSeller };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { a as BatchSettlementSellerConfig, B as BatchSettlementSeller } from '../../types-CwK4mPWV.js';
|
|
2
|
+
export { S as SellerCloseResult } from '../../types-CwK4mPWV.js';
|
|
3
|
+
import 'express';
|
|
4
|
+
import '@x402/evm/batch-settlement/server';
|
|
5
|
+
import '../../types-BIINnfB4.js';
|
|
6
|
+
import '@x402/evm/batch-settlement/client';
|
|
7
|
+
import '../../types-IqnDBsjL.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates a batch-settlement seller runtime. The returned object is callable
|
|
11
|
+
* (usable directly as an Express RequestHandler) and exposes lifecycle +
|
|
12
|
+
* settlement methods. The auto-settlement loop starts immediately unless
|
|
13
|
+
* disabled.
|
|
14
|
+
*/
|
|
15
|
+
declare function createBatchSettlementSeller(config: BatchSettlementSellerConfig): BatchSettlementSeller;
|
|
16
|
+
|
|
17
|
+
export { BatchSettlementSeller, BatchSettlementSellerConfig, createBatchSettlementSeller };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{homedir as E}from"os";import{join as M}from"path";import{FileChannelStorage as F}from"@x402/evm/batch-settlement/server";import{HTTPFacilitatorClient as H,x402ResourceServer as B}from"@x402/core/server";import{x402HTTPResourceServer as U}from"@x402/core/http";import{BatchSettlementEvmScheme as $}from"@x402/evm/batch-settlement/server";function P(e){let s=e.verbose?console.log.bind(console,"[batch-settlement:seller]"):()=>{},a=new H({url:e.facilitatorUrl}),r=new $(e.payTo,{storage:e.channelStore}),o=new B(a).register(e.network,r),l=new U(o,{[e.route]:{accepts:{scheme:"batch-settlement",payTo:e.payTo,price:e.price,network:e.network},description:"batch-settlement protected route",mimeType:"application/json"}}),i=null;function u(){if(i)return i;let t=l.initialize();return t.catch(n=>{i===t&&(i=null),e.verbose?s("resource server initialize() failed:",n):console.error("[batch-settlement:seller] resource server initialize() failed:",n)}),i=t,t}let h=u();function d(t,n){if(t.headersSent)return;for(let[g,v]of Object.entries(n.headers))t.setHeader(g,v);t.status(n.status);let{body:m}=n;m==null?t.end():typeof m=="string"?t.send(m):t.json(m)}return{scheme:r,facilitator:a,handler:async(t,n,m)=>{try{await u();let g=t.get("host")??"",v=`${t.baseUrl??""}${t.path}`||"/",k={getHeader:y=>t.headers[y.toLowerCase()],getMethod:()=>t.method,getPath:()=>v,getUrl:()=>`${t.protocol}://${g}${t.originalUrl}`,getAcceptHeader:()=>t.headers.accept??"",getUserAgent:()=>t.headers["user-agent"]??"",getBody:()=>t.body??{},getQueryParams:()=>t.query,getQueryParam:y=>{let f=t.query[y];if(typeof f=="string"||Array.isArray(f))return f}},I=t.headers["payment-signature"]??t.headers["x-payment"],R={adapter:k,path:v,method:t.method,paymentHeader:I},p=await l.processHTTPRequest(R);if(s("processHTTPRequest ->",p.type),p.type==="no-payment-required"){m();return}if(p.type==="payment-error"){d(n,p.response);return}let L={request:R,responseBody:Buffer.alloc(0)},S=await l.processSettlement(p.paymentPayload,p.paymentRequirements,p.declaredExtensions,L);if(s("processSettlement ->",S.success?"success":`failure:${S.errorReason}`),!S.success){d(n,S.response);return}for(let[y,f]of Object.entries(S.headers))n.headersSent||n.setHeader(y,f);m()}catch(g){s("handler error:",g),n.headersSent||n.status(500).json({error:"Payment processing error"})}},ready:h}}import{formatUnits as T}from"viem";var w=6;async function C(e){let{manager:s,store:a,channelId:r}=e,o=await a.get(r),l=BigInt(o?.chargedCumulativeAmount??"0"),i=BigInt(o?.balance??"0"),u=i>l?i-l:0n,{claims:h,settle:d}=await s.claimAndSettle(),c=await s.refund([r]),t=c.find(n=>n.channel===r)??c[0];return{claimTx:h[0]?.transaction??"",settleTx:d?.transaction??"",refundTx:t?.transaction??"",settledAmount:T(l,w),refundedAmount:T(u,w)}}async function x(e){let s=await e.store.list(),a=[];for(let r of s)try{let o=await C({manager:e.manager,store:e.store,channelId:r.channelId});a.push({channelId:r.channelId,...o})}catch(o){a.push({channelId:r.channelId,error:o instanceof Error?o.message:String(o)})}return a}function A(e){let s=!1,a=async()=>{try{await e.claimAndSettle()}catch(o){e.onError?.(o)}},r=setInterval(()=>{s||a()},e.claimIntervalMs);return typeof r.unref=="function"&&r.unref(),{async stop(){s||(s=!0,clearInterval(r),await a())}}}var j="https://x402.dexter.cash",N="GET /",b=new Set(["eip155:8453","eip155:42161","eip155:137"]);function O(e){return e===!1?null:e===void 0||e===!0?3e5:(e.claimIntervalSecs??300)*1e3}function _(e){if(!b.has(e.network))throw new Error(`batch-settlement is not supported on network "${e.network}" \u2014 supported: ${[...b].join(", ")}`);let s=e.facilitatorUrl??j,a=e.channelStore??new F({directory:M(E(),".dexter-x402","seller-channels")}),r=P({payTo:e.payTo,network:e.network,price:e.price,route:e.route??N,facilitatorUrl:s,channelStore:a,verbose:e.verbose}),o=r.scheme.createChannelManager(r.facilitator,e.network),l=async()=>{await o.claimAndSettle()},i=O(e.autoSettle),u=null;i!==null&&(u=A({claimAndSettle:l,claimIntervalMs:i,onError:t=>console.error("[batch-settlement:seller] auto-loop claim pass failed",t)}));let h=a,d=(t,n,m)=>{r.handler(t,n,m)},c=d;return c.middleware=()=>d,c.closeChannel=t=>C({manager:o,store:h,channelId:t}),c.closeAll=()=>x({manager:o,store:h}),c.stop=async()=>{u&&await u.stop()},c}export{_ as createBatchSettlementSeller};
|