@secondlayer/sdk 6.19.0 → 6.21.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 +61 -4
- package/dist/index.d.ts +281 -164
- package/dist/index.js +294 -169
- package/dist/index.js.map +10 -10
- package/dist/streams/index.d.ts +46 -1
- package/dist/streams/index.js +48 -1
- package/dist/streams/index.js.map +5 -5
- package/dist/subgraphs/index.d.ts +124 -158
- package/dist/subgraphs/index.js +70 -167
- package/dist/subgraphs/index.js.map +8 -9
- package/dist/x402.d.ts +159 -0
- package/dist/x402.js +230 -0
- package/dist/x402.js.map +10 -0
- package/package.json +8 -4
package/dist/x402.d.ts
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { X402TokenSymbol } from "@secondlayer/shared/x402";
|
|
2
|
+
import { LocalAccount } from "@secondlayer/stacks/accounts";
|
|
3
|
+
import { StacksChain } from "@secondlayer/stacks/chains";
|
|
4
|
+
/**
|
|
5
|
+
* Client for the x402 pay-per-request rail. Turns a 402 challenge into a signed
|
|
6
|
+
* `PAYMENT-SIGNATURE` and retries — gasless (the agent signs origin-only; the
|
|
7
|
+
* facilitator sponsors the STX fee) and accountless (no key/Stripe/session).
|
|
8
|
+
*
|
|
9
|
+
* Three layers:
|
|
10
|
+
* - `withX402(fetch, opts)` — drop-in fetch that auto-pays on 402.
|
|
11
|
+
* - `createX402Client(opts)` — `.get/.post` returning `{ data, payment }`.
|
|
12
|
+
* - `buildSignedX402Payment` / `readX402Challenge` — primitives for custom transports.
|
|
13
|
+
*/
|
|
14
|
+
type X402Accept = {
|
|
15
|
+
scheme: "exact"
|
|
16
|
+
network: string
|
|
17
|
+
asset: string
|
|
18
|
+
/** Atomic units. */
|
|
19
|
+
amount: string
|
|
20
|
+
payTo: string
|
|
21
|
+
maxTimeoutSeconds: number
|
|
22
|
+
extra: {
|
|
23
|
+
nonce: string
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
type X402Challenge = {
|
|
27
|
+
x402Version: number
|
|
28
|
+
accepts: X402Accept[]
|
|
29
|
+
error?: string
|
|
30
|
+
};
|
|
31
|
+
/** Decoded `PAYMENT-RESPONSE` settlement receipt. */
|
|
32
|
+
type X402Receipt = {
|
|
33
|
+
success: boolean
|
|
34
|
+
/** Settlement tier: `optimistic` (served on broadcast-accept, reconciled
|
|
35
|
+
* async) or `confirmed` (canonical). Absent on older deployments. */
|
|
36
|
+
state?: "optimistic" | "confirmed"
|
|
37
|
+
txid: string
|
|
38
|
+
payer: string
|
|
39
|
+
network: string
|
|
40
|
+
};
|
|
41
|
+
/** Bitcoin-native first — sBTC is the compelling micropay asset; USDCx the
|
|
42
|
+
* dollar peg; STX the fallback. Override via `preferAssets`. */
|
|
43
|
+
declare const DEFAULT_PREFER_ASSETS: X402TokenSymbol[];
|
|
44
|
+
/** Default node for auto-resolving the payer's account nonce (`/v2/accounts`). */
|
|
45
|
+
declare const DEFAULT_NONCE_NODE_URL = "https://api.hiro.so";
|
|
46
|
+
/** Thrown when no offered asset is within the caller's spend guard / preferences. */
|
|
47
|
+
declare class X402SpendGuardError extends Error {
|
|
48
|
+
constructor(message: string);
|
|
49
|
+
}
|
|
50
|
+
/** Read the x402 challenge from a 402 response — prefer the wire header, fall
|
|
51
|
+
* back to the JSON body. */
|
|
52
|
+
declare function readX402Challenge(res: Response): Promise<X402Challenge | null>;
|
|
53
|
+
/** Read the settlement receipt from a paid 200 response. */
|
|
54
|
+
declare function readX402Receipt(res: Response): X402Receipt | null;
|
|
55
|
+
type SelectOfferOptions = {
|
|
56
|
+
preferAssets?: X402TokenSymbol[]
|
|
57
|
+
maxAmountPerCall?: Partial<Record<X402TokenSymbol, bigint>>
|
|
58
|
+
};
|
|
59
|
+
/** Choose an `accepts[]` entry by preference order, skipping any that exceed the
|
|
60
|
+
* per-asset spend cap. Throws {@link X402SpendGuardError} if none qualify. */
|
|
61
|
+
declare function selectOffer(challenge: X402Challenge, opts?: SelectOfferOptions): {
|
|
62
|
+
accept: X402Accept
|
|
63
|
+
symbol: X402TokenSymbol
|
|
64
|
+
};
|
|
65
|
+
/** Fetch the payer account's next nonce from a Stacks node (`/v2/accounts`). */
|
|
66
|
+
declare function resolveAccountNonce(address: string, nodeUrl?: string): Promise<number>;
|
|
67
|
+
type BuildSignedX402PaymentOptions = {
|
|
68
|
+
challenge: X402Challenge
|
|
69
|
+
account: LocalAccount
|
|
70
|
+
/** The payer account's next nonce. */
|
|
71
|
+
accountNonce: bigint | number | string
|
|
72
|
+
/** Preferred asset string (e.g. an sBTC/USDCx id). Defaults to the first offer. */
|
|
73
|
+
asset?: string
|
|
74
|
+
chain?: StacksChain
|
|
75
|
+
};
|
|
76
|
+
/** Build a signed, base64 `PAYMENT-SIGNATURE` header for one `accepts[]` entry. */
|
|
77
|
+
declare function buildSignedX402Payment(opts: BuildSignedX402PaymentOptions): Promise<{
|
|
78
|
+
header: string
|
|
79
|
+
accept: X402Accept
|
|
80
|
+
}>;
|
|
81
|
+
type WithX402Options = SelectOfferOptions & {
|
|
82
|
+
account: LocalAccount
|
|
83
|
+
/** Prepaid-credit token (PAYMENT-BALANCE) from a prior deposit — calls
|
|
84
|
+
* debit the tab server-side instead of settling on-chain per call. */
|
|
85
|
+
balanceToken?: string
|
|
86
|
+
/** Autonomous treasury policy: when the tab's remaining balance (read from
|
|
87
|
+
* X-BALANCE-REMAINING-USD) drops below `whenBelow`, deposit `usd` more in
|
|
88
|
+
* the background (one on-chain payment) and adopt the fresh token. */
|
|
89
|
+
topUp?: {
|
|
90
|
+
usd: number
|
|
91
|
+
whenBelow: number
|
|
92
|
+
}
|
|
93
|
+
/** Override the payer nonce; auto-resolved from `nodeUrl` when omitted. */
|
|
94
|
+
accountNonce?: bigint | number | string
|
|
95
|
+
/** Node for auto-nonce lookup. Defaults to {@link DEFAULT_NONCE_NODE_URL}. */
|
|
96
|
+
nodeUrl?: string
|
|
97
|
+
chain?: StacksChain
|
|
98
|
+
/** Fired just before the paid retry (the call then blocks on confirmed-tier
|
|
99
|
+
* settle, or returns near-instantly on an optimistic surface). */
|
|
100
|
+
onSettling?: (info: {
|
|
101
|
+
asset: string
|
|
102
|
+
amount: string
|
|
103
|
+
}) => void
|
|
104
|
+
/** Abort the paid retry after this long. */
|
|
105
|
+
timeoutMs?: number
|
|
106
|
+
};
|
|
107
|
+
type X402Fetch = (input: string | URL, init?: RequestInit) => Promise<Response>;
|
|
108
|
+
/**
|
|
109
|
+
* Wrap a `fetch` so requests transparently pay on 402: select an offer (by
|
|
110
|
+
* `preferAssets` + `maxAmountPerCall`), resolve the nonce, sign origin-only, and
|
|
111
|
+
* retry once with `PAYMENT-SIGNATURE`. Returns the final `Response` (read the
|
|
112
|
+
* receipt with {@link readX402Receipt}).
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* const x402fetch = withX402(fetch, { account });
|
|
116
|
+
* const res = await x402fetch("https://api.secondlayer.tools/v1/index/events?event_type=ft_transfer");
|
|
117
|
+
*/
|
|
118
|
+
declare function withX402(baseFetch: typeof fetch, opts: WithX402Options): X402Fetch;
|
|
119
|
+
type X402ClientOptions = WithX402Options & {
|
|
120
|
+
baseUrl: string
|
|
121
|
+
/** Override the underlying fetch (tests). */
|
|
122
|
+
fetch?: typeof fetch
|
|
123
|
+
};
|
|
124
|
+
type X402Result<T = unknown> = {
|
|
125
|
+
data: T
|
|
126
|
+
/** Settlement receipt, or null if the response carried none. */
|
|
127
|
+
payment: X402Receipt | null
|
|
128
|
+
response: Response
|
|
129
|
+
};
|
|
130
|
+
type X402Client = {
|
|
131
|
+
get<T = unknown>(path: string, o?: {
|
|
132
|
+
query?: Record<string, string>
|
|
133
|
+
}): Promise<X402Result<T>>
|
|
134
|
+
post<T = unknown>(path: string, o?: {
|
|
135
|
+
body?: unknown
|
|
136
|
+
}): Promise<X402Result<T>>
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* A small client over {@link withX402}: `.get/.post` against `baseUrl`, returning
|
|
140
|
+
* parsed JSON plus the settlement receipt.
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* const sl = createX402Client({ account, baseUrl: "https://api.secondlayer.tools" });
|
|
144
|
+
* const { data, payment } = await sl.get("/v1/index/events", { query: { event_type: "ft_transfer" } });
|
|
145
|
+
*/
|
|
146
|
+
declare function createX402Client(opts: X402ClientOptions): X402Client;
|
|
147
|
+
/** Caller-supplied fetch that re-runs the request with the given extra headers. */
|
|
148
|
+
type X402FetchFn = (extraHeaders: Record<string, string>) => Promise<Response>;
|
|
149
|
+
type PayAndRetryOptions = Omit<WithX402Options, never> & {
|
|
150
|
+
/** Required here (use `withX402` for auto-nonce). */
|
|
151
|
+
accountNonce: bigint | number | string
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Low-level: run a request via a caller-controlled fetch; if it 402s, pay and
|
|
155
|
+
* retry once. Prefer {@link withX402} for the common case (it auto-resolves the
|
|
156
|
+
* nonce + selects the asset). Kept for custom transports.
|
|
157
|
+
*/
|
|
158
|
+
declare function payAndRetry(doFetch: X402FetchFn, opts: PayAndRetryOptions): Promise<Response>;
|
|
159
|
+
export { withX402, selectOffer, resolveAccountNonce, readX402Receipt, readX402Challenge, payAndRetry, createX402Client, buildSignedX402Payment, X402SpendGuardError, X402Result, X402Receipt, X402FetchFn, X402Fetch, X402ClientOptions, X402Client, X402Challenge, X402Accept, WithX402Options, SelectOfferOptions, PayAndRetryOptions, DEFAULT_PREFER_ASSETS, DEFAULT_NONCE_NODE_URL, BuildSignedX402PaymentOptions };
|
package/dist/x402.js
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
// src/x402.ts
|
|
2
|
+
import {
|
|
3
|
+
X402_TOKENS,
|
|
4
|
+
findX402TokenByAsset
|
|
5
|
+
} from "@secondlayer/shared/x402";
|
|
6
|
+
import {
|
|
7
|
+
serializeTransactionHex,
|
|
8
|
+
signTransactionWithAccount
|
|
9
|
+
} from "@secondlayer/stacks/transactions";
|
|
10
|
+
import { buildExactTransfer } from "@secondlayer/stacks/x402";
|
|
11
|
+
var DEFAULT_PREFER_ASSETS = [
|
|
12
|
+
"sBTC",
|
|
13
|
+
"USDCx",
|
|
14
|
+
"STX"
|
|
15
|
+
];
|
|
16
|
+
var DEFAULT_NONCE_NODE_URL = "https://api.hiro.so";
|
|
17
|
+
|
|
18
|
+
class X402SpendGuardError extends Error {
|
|
19
|
+
constructor(message) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = "X402SpendGuardError";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function b64encode(value) {
|
|
25
|
+
return Buffer.from(JSON.stringify(value), "utf8").toString("base64");
|
|
26
|
+
}
|
|
27
|
+
function b64decodeJson(value) {
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(Buffer.from(value, "base64").toString("utf8"));
|
|
30
|
+
} catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async function readX402Challenge(res) {
|
|
35
|
+
const header = res.headers.get("PAYMENT-REQUIRED");
|
|
36
|
+
if (header) {
|
|
37
|
+
const decoded = b64decodeJson(header);
|
|
38
|
+
if (decoded)
|
|
39
|
+
return decoded;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
return await res.clone().json();
|
|
43
|
+
} catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function readX402Receipt(res) {
|
|
48
|
+
const header = res.headers.get("PAYMENT-RESPONSE");
|
|
49
|
+
return header ? b64decodeJson(header) : null;
|
|
50
|
+
}
|
|
51
|
+
function selectOffer(challenge, opts = {}) {
|
|
52
|
+
const prefer = opts.preferAssets ?? DEFAULT_PREFER_ASSETS;
|
|
53
|
+
for (const symbol of prefer) {
|
|
54
|
+
const token = X402_TOKENS[symbol];
|
|
55
|
+
const accept = challenge.accepts.find((a) => a.asset === token.asset);
|
|
56
|
+
if (!accept)
|
|
57
|
+
continue;
|
|
58
|
+
const cap = opts.maxAmountPerCall?.[symbol];
|
|
59
|
+
if (cap !== undefined && BigInt(accept.amount) > cap)
|
|
60
|
+
continue;
|
|
61
|
+
return { accept, symbol };
|
|
62
|
+
}
|
|
63
|
+
throw new X402SpendGuardError("no x402 offer matched preferAssets within maxAmountPerCall");
|
|
64
|
+
}
|
|
65
|
+
async function resolveAccountNonce(address, nodeUrl = DEFAULT_NONCE_NODE_URL) {
|
|
66
|
+
const res = await fetch(`${nodeUrl.replace(/\/$/, "")}/v2/accounts/${address}?proof=0`);
|
|
67
|
+
if (!res.ok)
|
|
68
|
+
throw new Error(`x402 nonce lookup failed: ${res.status}`);
|
|
69
|
+
const json = await res.json();
|
|
70
|
+
return json.nonce;
|
|
71
|
+
}
|
|
72
|
+
async function buildSignedX402Payment(opts) {
|
|
73
|
+
const accept = opts.asset ? opts.challenge.accepts.find((a) => a.asset === opts.asset) : opts.challenge.accepts[0];
|
|
74
|
+
if (!accept) {
|
|
75
|
+
throw new Error(`No x402 offer${opts.asset ? ` for asset ${opts.asset}` : ""}`);
|
|
76
|
+
}
|
|
77
|
+
const token = findX402TokenByAsset(accept.asset);
|
|
78
|
+
if (!token)
|
|
79
|
+
throw new Error(`Unknown x402 asset: ${accept.asset}`);
|
|
80
|
+
const asset = token.contractId && token.assetName ? {
|
|
81
|
+
kind: "sip010",
|
|
82
|
+
contractId: token.contractId,
|
|
83
|
+
assetName: token.assetName
|
|
84
|
+
} : { kind: "stx" };
|
|
85
|
+
const tx = buildExactTransfer({
|
|
86
|
+
asset,
|
|
87
|
+
amount: BigInt(accept.amount),
|
|
88
|
+
payTo: accept.payTo,
|
|
89
|
+
payer: opts.account.address,
|
|
90
|
+
payerPublicKey: opts.account.publicKey,
|
|
91
|
+
accountNonce: opts.accountNonce,
|
|
92
|
+
nonce: accept.extra.nonce,
|
|
93
|
+
chain: opts.chain
|
|
94
|
+
});
|
|
95
|
+
const signed = await signTransactionWithAccount(tx, opts.account);
|
|
96
|
+
const header = b64encode({
|
|
97
|
+
x402Version: opts.challenge.x402Version ?? 2,
|
|
98
|
+
scheme: "exact",
|
|
99
|
+
network: accept.network,
|
|
100
|
+
asset: accept.asset,
|
|
101
|
+
payload: { transaction: serializeTransactionHex(signed) },
|
|
102
|
+
extra: { nonce: accept.extra.nonce }
|
|
103
|
+
});
|
|
104
|
+
return { header, accept };
|
|
105
|
+
}
|
|
106
|
+
function withX402(baseFetch, opts) {
|
|
107
|
+
const sessions = new Map;
|
|
108
|
+
let balanceToken = opts.balanceToken ?? null;
|
|
109
|
+
let toppingUp = false;
|
|
110
|
+
const originOf = (input) => {
|
|
111
|
+
try {
|
|
112
|
+
return new URL(String(input)).origin;
|
|
113
|
+
} catch {
|
|
114
|
+
return "";
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
const wrapped = async (input, init) => {
|
|
118
|
+
const origin = originOf(input);
|
|
119
|
+
const run = (extra, signal2) => baseFetch(input, {
|
|
120
|
+
...init,
|
|
121
|
+
headers: { ...init?.headers, ...extra },
|
|
122
|
+
...signal2 ? { signal: signal2 } : {}
|
|
123
|
+
});
|
|
124
|
+
const maybeTopUp = (res) => {
|
|
125
|
+
const policy = opts.topUp;
|
|
126
|
+
if (!policy || toppingUp || !origin)
|
|
127
|
+
return;
|
|
128
|
+
const remaining = res.headers.get("X-BALANCE-REMAINING-USD");
|
|
129
|
+
if (remaining === null || Number(remaining) >= policy.whenBelow)
|
|
130
|
+
return;
|
|
131
|
+
toppingUp = true;
|
|
132
|
+
(async () => {
|
|
133
|
+
try {
|
|
134
|
+
const dep = await wrapped(`${origin}/v1/x402/deposit?usd=${policy.usd}`, { method: "POST" });
|
|
135
|
+
if (dep.ok) {
|
|
136
|
+
const body = await dep.json();
|
|
137
|
+
if (body.balance_token)
|
|
138
|
+
balanceToken = body.balance_token;
|
|
139
|
+
}
|
|
140
|
+
} catch {} finally {
|
|
141
|
+
toppingUp = false;
|
|
142
|
+
}
|
|
143
|
+
})();
|
|
144
|
+
};
|
|
145
|
+
const remember = (res) => {
|
|
146
|
+
const voucher = res.headers.get("PAYMENT-SESSION");
|
|
147
|
+
if (voucher && origin)
|
|
148
|
+
sessions.set(origin, voucher);
|
|
149
|
+
maybeTopUp(res);
|
|
150
|
+
return res;
|
|
151
|
+
};
|
|
152
|
+
const cached = origin ? sessions.get(origin) : undefined;
|
|
153
|
+
const first = await run({
|
|
154
|
+
...cached ? { "PAYMENT-SESSION": cached } : {},
|
|
155
|
+
...balanceToken ? { "PAYMENT-BALANCE": balanceToken } : {}
|
|
156
|
+
});
|
|
157
|
+
if (first.status !== 402)
|
|
158
|
+
return remember(first);
|
|
159
|
+
if (cached && origin)
|
|
160
|
+
sessions.delete(origin);
|
|
161
|
+
const challenge = await readX402Challenge(first);
|
|
162
|
+
if (!challenge)
|
|
163
|
+
return first;
|
|
164
|
+
const { accept } = selectOffer(challenge, opts);
|
|
165
|
+
const accountNonce = opts.accountNonce ?? await resolveAccountNonce(opts.account.address, opts.nodeUrl);
|
|
166
|
+
const { header } = await buildSignedX402Payment({
|
|
167
|
+
challenge,
|
|
168
|
+
account: opts.account,
|
|
169
|
+
accountNonce,
|
|
170
|
+
asset: accept.asset,
|
|
171
|
+
chain: opts.chain
|
|
172
|
+
});
|
|
173
|
+
opts.onSettling?.({ asset: accept.asset, amount: accept.amount });
|
|
174
|
+
const signal = opts.timeoutMs ? AbortSignal.timeout(opts.timeoutMs) : undefined;
|
|
175
|
+
return remember(await run({ "PAYMENT-SIGNATURE": header }, signal));
|
|
176
|
+
};
|
|
177
|
+
return wrapped;
|
|
178
|
+
}
|
|
179
|
+
function createX402Client(opts) {
|
|
180
|
+
const f = withX402(opts.fetch ?? fetch, opts);
|
|
181
|
+
const base = opts.baseUrl.replace(/\/$/, "");
|
|
182
|
+
async function request(method, path, o = {}) {
|
|
183
|
+
const qs = o.query ? `?${new URLSearchParams(o.query).toString()}` : "";
|
|
184
|
+
const init = { method };
|
|
185
|
+
if (o.body !== undefined) {
|
|
186
|
+
init.body = JSON.stringify(o.body);
|
|
187
|
+
init.headers = { "content-type": "application/json" };
|
|
188
|
+
}
|
|
189
|
+
const response = await f(`${base}${path}${qs}`, init);
|
|
190
|
+
const data = await response.json().catch(() => null);
|
|
191
|
+
return { data, payment: readX402Receipt(response), response };
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
get: (path, o) => request("GET", path, o),
|
|
195
|
+
post: (path, o) => request("POST", path, o)
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
async function payAndRetry(doFetch, opts) {
|
|
199
|
+
const first = await doFetch({});
|
|
200
|
+
if (first.status !== 402)
|
|
201
|
+
return first;
|
|
202
|
+
const challenge = await readX402Challenge(first);
|
|
203
|
+
if (!challenge)
|
|
204
|
+
return first;
|
|
205
|
+
const { accept } = selectOffer(challenge, opts);
|
|
206
|
+
const { header } = await buildSignedX402Payment({
|
|
207
|
+
challenge,
|
|
208
|
+
account: opts.account,
|
|
209
|
+
accountNonce: opts.accountNonce,
|
|
210
|
+
asset: accept.asset,
|
|
211
|
+
chain: opts.chain
|
|
212
|
+
});
|
|
213
|
+
return doFetch({ "PAYMENT-SIGNATURE": header });
|
|
214
|
+
}
|
|
215
|
+
export {
|
|
216
|
+
withX402,
|
|
217
|
+
selectOffer,
|
|
218
|
+
resolveAccountNonce,
|
|
219
|
+
readX402Receipt,
|
|
220
|
+
readX402Challenge,
|
|
221
|
+
payAndRetry,
|
|
222
|
+
createX402Client,
|
|
223
|
+
buildSignedX402Payment,
|
|
224
|
+
X402SpendGuardError,
|
|
225
|
+
DEFAULT_PREFER_ASSETS,
|
|
226
|
+
DEFAULT_NONCE_NODE_URL
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
//# debugId=264371DAFD103C7564756E2164756E21
|
|
230
|
+
//# sourceMappingURL=x402.js.map
|
package/dist/x402.js.map
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/x402.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import {\n\ttype X402TokenSymbol,\n\tX402_TOKENS,\n\tfindX402TokenByAsset,\n} from \"@secondlayer/shared/x402\";\nimport type { LocalAccount } from \"@secondlayer/stacks/accounts\";\nimport type { StacksChain } from \"@secondlayer/stacks/chains\";\nimport {\n\tserializeTransactionHex,\n\tsignTransactionWithAccount,\n} from \"@secondlayer/stacks/transactions\";\nimport { buildExactTransfer } from \"@secondlayer/stacks/x402\";\n\n/**\n * Client for the x402 pay-per-request rail. Turns a 402 challenge into a signed\n * `PAYMENT-SIGNATURE` and retries — gasless (the agent signs origin-only; the\n * facilitator sponsors the STX fee) and accountless (no key/Stripe/session).\n *\n * Three layers:\n * - `withX402(fetch, opts)` — drop-in fetch that auto-pays on 402.\n * - `createX402Client(opts)` — `.get/.post` returning `{ data, payment }`.\n * - `buildSignedX402Payment` / `readX402Challenge` — primitives for custom transports.\n */\n\nexport type X402Accept = {\n\tscheme: \"exact\";\n\tnetwork: string;\n\tasset: string;\n\t/** Atomic units. */\n\tamount: string;\n\tpayTo: string;\n\tmaxTimeoutSeconds: number;\n\textra: { nonce: string };\n};\n\nexport type X402Challenge = {\n\tx402Version: number;\n\taccepts: X402Accept[];\n\terror?: string;\n};\n\n/** Decoded `PAYMENT-RESPONSE` settlement receipt. */\nexport type X402Receipt = {\n\tsuccess: boolean;\n\t/** Settlement tier: `optimistic` (served on broadcast-accept, reconciled\n\t * async) or `confirmed` (canonical). Absent on older deployments. */\n\tstate?: \"optimistic\" | \"confirmed\";\n\ttxid: string;\n\tpayer: string;\n\tnetwork: string;\n};\n\n/** Bitcoin-native first — sBTC is the compelling micropay asset; USDCx the\n * dollar peg; STX the fallback. Override via `preferAssets`. */\nexport const DEFAULT_PREFER_ASSETS: X402TokenSymbol[] = [\n\t\"sBTC\",\n\t\"USDCx\",\n\t\"STX\",\n];\n\n/** Default node for auto-resolving the payer's account nonce (`/v2/accounts`). */\nexport const DEFAULT_NONCE_NODE_URL = \"https://api.hiro.so\";\n\n/** Thrown when no offered asset is within the caller's spend guard / preferences. */\nexport class X402SpendGuardError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"X402SpendGuardError\";\n\t}\n}\n\nfunction b64encode(value: unknown): string {\n\treturn Buffer.from(JSON.stringify(value), \"utf8\").toString(\"base64\");\n}\n\nfunction b64decodeJson<T>(value: string): T | null {\n\ttry {\n\t\treturn JSON.parse(Buffer.from(value, \"base64\").toString(\"utf8\")) as T;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/** Read the x402 challenge from a 402 response — prefer the wire header, fall\n * back to the JSON body. */\nexport async function readX402Challenge(\n\tres: Response,\n): Promise<X402Challenge | null> {\n\tconst header = res.headers.get(\"PAYMENT-REQUIRED\");\n\tif (header) {\n\t\tconst decoded = b64decodeJson<X402Challenge>(header);\n\t\tif (decoded) return decoded;\n\t}\n\ttry {\n\t\treturn (await res.clone().json()) as X402Challenge;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/** Read the settlement receipt from a paid 200 response. */\nexport function readX402Receipt(res: Response): X402Receipt | null {\n\tconst header = res.headers.get(\"PAYMENT-RESPONSE\");\n\treturn header ? b64decodeJson<X402Receipt>(header) : null;\n}\n\nexport type SelectOfferOptions = {\n\tpreferAssets?: X402TokenSymbol[];\n\tmaxAmountPerCall?: Partial<Record<X402TokenSymbol, bigint>>;\n};\n\n/** Choose an `accepts[]` entry by preference order, skipping any that exceed the\n * per-asset spend cap. Throws {@link X402SpendGuardError} if none qualify. */\nexport function selectOffer(\n\tchallenge: X402Challenge,\n\topts: SelectOfferOptions = {},\n): { accept: X402Accept; symbol: X402TokenSymbol } {\n\tconst prefer = opts.preferAssets ?? DEFAULT_PREFER_ASSETS;\n\tfor (const symbol of prefer) {\n\t\tconst token = X402_TOKENS[symbol];\n\t\tconst accept = challenge.accepts.find((a) => a.asset === token.asset);\n\t\tif (!accept) continue;\n\t\tconst cap = opts.maxAmountPerCall?.[symbol];\n\t\tif (cap !== undefined && BigInt(accept.amount) > cap) continue;\n\t\treturn { accept, symbol };\n\t}\n\tthrow new X402SpendGuardError(\n\t\t\"no x402 offer matched preferAssets within maxAmountPerCall\",\n\t);\n}\n\n/** Fetch the payer account's next nonce from a Stacks node (`/v2/accounts`). */\nexport async function resolveAccountNonce(\n\taddress: string,\n\tnodeUrl: string = DEFAULT_NONCE_NODE_URL,\n): Promise<number> {\n\tconst res = await fetch(\n\t\t`${nodeUrl.replace(/\\/$/, \"\")}/v2/accounts/${address}?proof=0`,\n\t);\n\tif (!res.ok) throw new Error(`x402 nonce lookup failed: ${res.status}`);\n\tconst json = (await res.json()) as { nonce: number };\n\treturn json.nonce;\n}\n\nexport type BuildSignedX402PaymentOptions = {\n\tchallenge: X402Challenge;\n\taccount: LocalAccount;\n\t/** The payer account's next nonce. */\n\taccountNonce: bigint | number | string;\n\t/** Preferred asset string (e.g. an sBTC/USDCx id). Defaults to the first offer. */\n\tasset?: string;\n\tchain?: StacksChain;\n};\n\n/** Build a signed, base64 `PAYMENT-SIGNATURE` header for one `accepts[]` entry. */\nexport async function buildSignedX402Payment(\n\topts: BuildSignedX402PaymentOptions,\n): Promise<{ header: string; accept: X402Accept }> {\n\tconst accept = opts.asset\n\t\t? opts.challenge.accepts.find((a) => a.asset === opts.asset)\n\t\t: opts.challenge.accepts[0];\n\tif (!accept) {\n\t\tthrow new Error(\n\t\t\t`No x402 offer${opts.asset ? ` for asset ${opts.asset}` : \"\"}`,\n\t\t);\n\t}\n\tconst token = findX402TokenByAsset(accept.asset);\n\tif (!token) throw new Error(`Unknown x402 asset: ${accept.asset}`);\n\n\tconst asset =\n\t\ttoken.contractId && token.assetName\n\t\t\t? {\n\t\t\t\t\tkind: \"sip010\" as const,\n\t\t\t\t\tcontractId: token.contractId,\n\t\t\t\t\tassetName: token.assetName,\n\t\t\t\t}\n\t\t\t: { kind: \"stx\" as const };\n\n\tconst tx = buildExactTransfer({\n\t\tasset,\n\t\tamount: BigInt(accept.amount),\n\t\tpayTo: accept.payTo,\n\t\tpayer: opts.account.address,\n\t\tpayerPublicKey: opts.account.publicKey,\n\t\taccountNonce: opts.accountNonce,\n\t\tnonce: accept.extra.nonce,\n\t\tchain: opts.chain,\n\t});\n\tconst signed = await signTransactionWithAccount(tx, opts.account);\n\n\tconst header = b64encode({\n\t\tx402Version: opts.challenge.x402Version ?? 2,\n\t\tscheme: \"exact\",\n\t\tnetwork: accept.network,\n\t\tasset: accept.asset,\n\t\tpayload: { transaction: serializeTransactionHex(signed) },\n\t\textra: { nonce: accept.extra.nonce },\n\t});\n\treturn { header, accept };\n}\n\nexport type WithX402Options = SelectOfferOptions & {\n\taccount: LocalAccount;\n\t/** Prepaid-credit token (PAYMENT-BALANCE) from a prior deposit — calls\n\t * debit the tab server-side instead of settling on-chain per call. */\n\tbalanceToken?: string;\n\t/** Autonomous treasury policy: when the tab's remaining balance (read from\n\t * X-BALANCE-REMAINING-USD) drops below `whenBelow`, deposit `usd` more in\n\t * the background (one on-chain payment) and adopt the fresh token. */\n\ttopUp?: { usd: number; whenBelow: number };\n\t/** Override the payer nonce; auto-resolved from `nodeUrl` when omitted. */\n\taccountNonce?: bigint | number | string;\n\t/** Node for auto-nonce lookup. Defaults to {@link DEFAULT_NONCE_NODE_URL}. */\n\tnodeUrl?: string;\n\tchain?: StacksChain;\n\t/** Fired just before the paid retry (the call then blocks on confirmed-tier\n\t * settle, or returns near-instantly on an optimistic surface). */\n\tonSettling?: (info: { asset: string; amount: string }) => void;\n\t/** Abort the paid retry after this long. */\n\ttimeoutMs?: number;\n};\n\nexport type X402Fetch = (\n\tinput: string | URL,\n\tinit?: RequestInit,\n) => Promise<Response>;\n\n/**\n * Wrap a `fetch` so requests transparently pay on 402: select an offer (by\n * `preferAssets` + `maxAmountPerCall`), resolve the nonce, sign origin-only, and\n * retry once with `PAYMENT-SIGNATURE`. Returns the final `Response` (read the\n * receipt with {@link readX402Receipt}).\n *\n * @example\n * const x402fetch = withX402(fetch, { account });\n * const res = await x402fetch(\"https://api.secondlayer.tools/v1/index/events?event_type=ft_transfer\");\n */\nexport function withX402(\n\tbaseFetch: typeof fetch,\n\topts: WithX402Options,\n): X402Fetch {\n\t// Session vouchers (PAYMENT-SESSION): surfaces with session pricing hand\n\t// back a voucher on settle — replaying it lets subsequent calls ride the\n\t// paid session instead of re-paying per request. Cached per origin; the\n\t// server is authoritative (a 402 despite a voucher just restarts the\n\t// payment cycle and refreshes the cache).\n\tconst sessions = new Map<string, string>();\n\tlet balanceToken = opts.balanceToken ?? null;\n\tlet toppingUp = false;\n\tconst originOf = (input: Parameters<X402Fetch>[0]) => {\n\t\ttry {\n\t\t\treturn new URL(String(input)).origin;\n\t\t} catch {\n\t\t\treturn \"\";\n\t\t}\n\t};\n\n\tconst wrapped: X402Fetch = async (input, init) => {\n\t\tconst origin = originOf(input);\n\t\tconst run = (extra: Record<string, string>, signal?: AbortSignal) =>\n\t\t\tbaseFetch(input, {\n\t\t\t\t...init,\n\t\t\t\theaders: { ...(init?.headers as Record<string, string>), ...extra },\n\t\t\t\t...(signal ? { signal } : {}),\n\t\t\t});\n\n\t\t// Treasury policy: refill the tab in the background before it empties.\n\t\t// The deposit goes through this same wrapper (402 → pay → credited);\n\t\t// its response carries the fresh PAYMENT-BALANCE token.\n\t\tconst maybeTopUp = (res: Response) => {\n\t\t\tconst policy = opts.topUp;\n\t\t\tif (!policy || toppingUp || !origin) return;\n\t\t\tconst remaining = res.headers.get(\"X-BALANCE-REMAINING-USD\");\n\t\t\tif (remaining === null || Number(remaining) >= policy.whenBelow) return;\n\t\t\ttoppingUp = true;\n\t\t\tvoid (async () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst dep = await wrapped(\n\t\t\t\t\t\t`${origin}/v1/x402/deposit?usd=${policy.usd}`,\n\t\t\t\t\t\t{ method: \"POST\" },\n\t\t\t\t\t);\n\t\t\t\t\tif (dep.ok) {\n\t\t\t\t\t\tconst body = (await dep.json()) as { balance_token?: string };\n\t\t\t\t\t\tif (body.balance_token) balanceToken = body.balance_token;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// next sub-threshold response retries the top-up\n\t\t\t\t} finally {\n\t\t\t\t\ttoppingUp = false;\n\t\t\t\t}\n\t\t\t})();\n\t\t};\n\n\t\tconst remember = (res: Response) => {\n\t\t\tconst voucher = res.headers.get(\"PAYMENT-SESSION\");\n\t\t\tif (voucher && origin) sessions.set(origin, voucher);\n\t\t\tmaybeTopUp(res);\n\t\t\treturn res;\n\t\t};\n\n\t\tconst cached = origin ? sessions.get(origin) : undefined;\n\t\tconst first = await run({\n\t\t\t...(cached ? { \"PAYMENT-SESSION\": cached } : {}),\n\t\t\t...(balanceToken ? { \"PAYMENT-BALANCE\": balanceToken } : {}),\n\t\t});\n\t\tif (first.status !== 402) return remember(first);\n\t\tif (cached && origin) sessions.delete(origin);\n\n\t\tconst challenge = await readX402Challenge(first);\n\t\tif (!challenge) return first;\n\n\t\tconst { accept } = selectOffer(challenge, opts);\n\t\tconst accountNonce =\n\t\t\topts.accountNonce ??\n\t\t\t(await resolveAccountNonce(opts.account.address, opts.nodeUrl));\n\t\tconst { header } = await buildSignedX402Payment({\n\t\t\tchallenge,\n\t\t\taccount: opts.account,\n\t\t\taccountNonce,\n\t\t\tasset: accept.asset,\n\t\t\tchain: opts.chain,\n\t\t});\n\n\t\topts.onSettling?.({ asset: accept.asset, amount: accept.amount });\n\t\tconst signal = opts.timeoutMs\n\t\t\t? AbortSignal.timeout(opts.timeoutMs)\n\t\t\t: undefined;\n\t\treturn remember(await run({ \"PAYMENT-SIGNATURE\": header }, signal));\n\t};\n\treturn wrapped;\n}\n\nexport type X402ClientOptions = WithX402Options & {\n\tbaseUrl: string;\n\t/** Override the underlying fetch (tests). */\n\tfetch?: typeof fetch;\n};\n\nexport type X402Result<T = unknown> = {\n\tdata: T;\n\t/** Settlement receipt, or null if the response carried none. */\n\tpayment: X402Receipt | null;\n\tresponse: Response;\n};\n\nexport type X402Client = {\n\tget<T = unknown>(\n\t\tpath: string,\n\t\to?: { query?: Record<string, string> },\n\t): Promise<X402Result<T>>;\n\tpost<T = unknown>(\n\t\tpath: string,\n\t\to?: { body?: unknown },\n\t): Promise<X402Result<T>>;\n};\n\n/**\n * A small client over {@link withX402}: `.get/.post` against `baseUrl`, returning\n * parsed JSON plus the settlement receipt.\n *\n * @example\n * const sl = createX402Client({ account, baseUrl: \"https://api.secondlayer.tools\" });\n * const { data, payment } = await sl.get(\"/v1/index/events\", { query: { event_type: \"ft_transfer\" } });\n */\nexport function createX402Client(opts: X402ClientOptions): X402Client {\n\tconst f = withX402(opts.fetch ?? fetch, opts);\n\tconst base = opts.baseUrl.replace(/\\/$/, \"\");\n\n\tasync function request<T>(\n\t\tmethod: \"GET\" | \"POST\",\n\t\tpath: string,\n\t\to: { query?: Record<string, string>; body?: unknown } = {},\n\t): Promise<X402Result<T>> {\n\t\tconst qs = o.query ? `?${new URLSearchParams(o.query).toString()}` : \"\";\n\t\tconst init: RequestInit = { method };\n\t\tif (o.body !== undefined) {\n\t\t\tinit.body = JSON.stringify(o.body);\n\t\t\tinit.headers = { \"content-type\": \"application/json\" };\n\t\t}\n\t\tconst response = await f(`${base}${path}${qs}`, init);\n\t\tconst data = (await response.json().catch(() => null)) as T;\n\t\treturn { data, payment: readX402Receipt(response), response };\n\t}\n\n\treturn {\n\t\tget: <T = unknown>(path: string, o?: { query?: Record<string, string> }) =>\n\t\t\trequest<T>(\"GET\", path, o),\n\t\tpost: <T = unknown>(path: string, o?: { body?: unknown }) =>\n\t\t\trequest<T>(\"POST\", path, o),\n\t};\n}\n\n/** Caller-supplied fetch that re-runs the request with the given extra headers. */\nexport type X402FetchFn = (\n\textraHeaders: Record<string, string>,\n) => Promise<Response>;\n\nexport type PayAndRetryOptions = Omit<WithX402Options, never> & {\n\t/** Required here (use `withX402` for auto-nonce). */\n\taccountNonce: bigint | number | string;\n};\n\n/**\n * Low-level: run a request via a caller-controlled fetch; if it 402s, pay and\n * retry once. Prefer {@link withX402} for the common case (it auto-resolves the\n * nonce + selects the asset). Kept for custom transports.\n */\nexport async function payAndRetry(\n\tdoFetch: X402FetchFn,\n\topts: PayAndRetryOptions,\n): Promise<Response> {\n\tconst first = await doFetch({});\n\tif (first.status !== 402) return first;\n\tconst challenge = await readX402Challenge(first);\n\tif (!challenge) return first;\n\tconst { accept } = selectOffer(challenge, opts);\n\tconst { header } = await buildSignedX402Payment({\n\t\tchallenge,\n\t\taccount: opts.account,\n\t\taccountNonce: opts.accountNonce,\n\t\tasset: accept.asset,\n\t\tchain: opts.chain,\n\t});\n\treturn doFetch({ \"PAYMENT-SIGNATURE\": header });\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "264371DAFD103C7564756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@secondlayer/sdk",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.21.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -23,6 +23,10 @@
|
|
|
23
23
|
"./subgraphs": {
|
|
24
24
|
"types": "./dist/subgraphs/index.d.ts",
|
|
25
25
|
"import": "./dist/subgraphs/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./x402": {
|
|
28
|
+
"types": "./dist/x402.d.ts",
|
|
29
|
+
"import": "./dist/x402.js"
|
|
26
30
|
}
|
|
27
31
|
},
|
|
28
32
|
"files": [
|
|
@@ -36,9 +40,9 @@
|
|
|
36
40
|
"prepublishOnly": "bun run build"
|
|
37
41
|
},
|
|
38
42
|
"dependencies": {
|
|
39
|
-
"@secondlayer/shared": "^6.
|
|
40
|
-
"@secondlayer/stacks": "^2.
|
|
41
|
-
"@secondlayer/subgraphs": "^3.
|
|
43
|
+
"@secondlayer/shared": "^6.30.0",
|
|
44
|
+
"@secondlayer/stacks": "^2.5.0",
|
|
45
|
+
"@secondlayer/subgraphs": "^3.11.0"
|
|
42
46
|
},
|
|
43
47
|
"devDependencies": {
|
|
44
48
|
"@types/bun": "latest",
|