@bankofai/x402-evm 1.0.0-beta.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 +172 -0
- package/dist/cjs/auth-capture/client/index.d.ts +44 -0
- package/dist/cjs/auth-capture/client/index.js +298 -0
- package/dist/cjs/auth-capture/client/index.js.map +1 -0
- package/dist/cjs/batch-settlement/client/file-storage.d.ts +47 -0
- package/dist/cjs/batch-settlement/client/file-storage.js +116 -0
- package/dist/cjs/batch-settlement/client/file-storage.js.map +1 -0
- package/dist/cjs/batch-settlement/client/index.d.ts +111 -0
- package/dist/cjs/batch-settlement/client/index.js +1565 -0
- package/dist/cjs/batch-settlement/client/index.js.map +1 -0
- package/dist/cjs/batch-settlement/facilitator/index.d.ts +72 -0
- package/dist/cjs/batch-settlement/facilitator/index.js +2102 -0
- package/dist/cjs/batch-settlement/facilitator/index.js.map +1 -0
- package/dist/cjs/batch-settlement/server/file-storage.d.ts +53 -0
- package/dist/cjs/batch-settlement/server/file-storage.js +181 -0
- package/dist/cjs/batch-settlement/server/file-storage.js.map +1 -0
- package/dist/cjs/batch-settlement/server/index.d.ts +491 -0
- package/dist/cjs/batch-settlement/server/index.js +1978 -0
- package/dist/cjs/batch-settlement/server/index.js.map +1 -0
- package/dist/cjs/batch-settlement/server/redis-storage.d.ts +87 -0
- package/dist/cjs/batch-settlement/server/redis-storage.js +181 -0
- package/dist/cjs/batch-settlement/server/redis-storage.js.map +1 -0
- package/dist/cjs/client/agent-wallet.d.ts +69 -0
- package/dist/cjs/client/agent-wallet.js +84 -0
- package/dist/cjs/client/agent-wallet.js.map +1 -0
- package/dist/cjs/exact/client/index.d.ts +63 -0
- package/dist/cjs/exact/client/index.js +739 -0
- package/dist/cjs/exact/client/index.js.map +1 -0
- package/dist/cjs/exact/facilitator/index.d.ts +141 -0
- package/dist/cjs/exact/facilitator/index.js +1989 -0
- package/dist/cjs/exact/facilitator/index.js.map +1 -0
- package/dist/cjs/exact/server/index.d.ts +118 -0
- package/dist/cjs/exact/server/index.js +326 -0
- package/dist/cjs/exact/server/index.js.map +1 -0
- package/dist/cjs/exact/v1/client/index.d.ts +38 -0
- package/dist/cjs/exact/v1/client/index.js +193 -0
- package/dist/cjs/exact/v1/client/index.js.map +1 -0
- package/dist/cjs/exact/v1/facilitator/index.d.ts +84 -0
- package/dist/cjs/exact/v1/facilitator/index.js +739 -0
- package/dist/cjs/exact/v1/facilitator/index.js.map +1 -0
- package/dist/cjs/facilitator/agent-wallet.d.ts +109 -0
- package/dist/cjs/facilitator/agent-wallet.js +105 -0
- package/dist/cjs/facilitator/agent-wallet.js.map +1 -0
- package/dist/cjs/index.d.ts +338 -0
- package/dist/cjs/index.js +2860 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/permit2-DK5A8alk.d.ts +729 -0
- package/dist/cjs/permit2-DhJRUcgY.d.ts +729 -0
- package/dist/cjs/rpc-DULZzRne.d.ts +13 -0
- package/dist/cjs/scheme-7ehldYoO.d.ts +307 -0
- package/dist/cjs/scheme-BjBJzHF7.d.ts +307 -0
- package/dist/cjs/scheme-DWgpkDgz.d.ts +47 -0
- package/dist/cjs/signer-BFelv8DL.d.ts +170 -0
- package/dist/cjs/storage-6W5MO46W.d.ts +50 -0
- package/dist/cjs/storage-CHNote8s.d.ts +81 -0
- package/dist/cjs/storage-DjCv5IPh.d.ts +81 -0
- package/dist/cjs/types-CKd3Xoi1.d.ts +180 -0
- package/dist/cjs/types-DIt9uAUy.d.ts +180 -0
- package/dist/cjs/upto/client/index.d.ts +34 -0
- package/dist/cjs/upto/client/index.js +509 -0
- package/dist/cjs/upto/client/index.js.map +1 -0
- package/dist/cjs/upto/facilitator/index.d.ts +54 -0
- package/dist/cjs/upto/facilitator/index.js +1313 -0
- package/dist/cjs/upto/facilitator/index.js.map +1 -0
- package/dist/cjs/upto/server/index.d.ts +69 -0
- package/dist/cjs/upto/server/index.js +296 -0
- package/dist/cjs/upto/server/index.js.map +1 -0
- package/dist/cjs/v1/index.d.ts +40 -0
- package/dist/cjs/v1/index.js +199 -0
- package/dist/cjs/v1/index.js.map +1 -0
- package/dist/esm/auth-capture/client/index.d.mts +44 -0
- package/dist/esm/auth-capture/client/index.mjs +8 -0
- package/dist/esm/auth-capture/client/index.mjs.map +1 -0
- package/dist/esm/batch-settlement/client/file-storage.d.mts +47 -0
- package/dist/esm/batch-settlement/client/file-storage.mjs +63 -0
- package/dist/esm/batch-settlement/client/file-storage.mjs.map +1 -0
- package/dist/esm/batch-settlement/client/index.d.mts +111 -0
- package/dist/esm/batch-settlement/client/index.mjs +58 -0
- package/dist/esm/batch-settlement/client/index.mjs.map +1 -0
- package/dist/esm/batch-settlement/facilitator/index.d.mts +72 -0
- package/dist/esm/batch-settlement/facilitator/index.mjs +1252 -0
- package/dist/esm/batch-settlement/facilitator/index.mjs.map +1 -0
- package/dist/esm/batch-settlement/server/file-storage.d.mts +53 -0
- package/dist/esm/batch-settlement/server/file-storage.mjs +128 -0
- package/dist/esm/batch-settlement/server/file-storage.mjs.map +1 -0
- package/dist/esm/batch-settlement/server/index.d.mts +491 -0
- package/dist/esm/batch-settlement/server/index.mjs +1640 -0
- package/dist/esm/batch-settlement/server/index.mjs.map +1 -0
- package/dist/esm/batch-settlement/server/redis-storage.d.mts +87 -0
- package/dist/esm/batch-settlement/server/redis-storage.mjs +156 -0
- package/dist/esm/batch-settlement/server/redis-storage.mjs.map +1 -0
- package/dist/esm/chunk-2EUQTNJO.mjs +38 -0
- package/dist/esm/chunk-2EUQTNJO.mjs.map +1 -0
- package/dist/esm/chunk-3WZF6722.mjs +36 -0
- package/dist/esm/chunk-3WZF6722.mjs.map +1 -0
- package/dist/esm/chunk-E4Z7PNXC.mjs +275 -0
- package/dist/esm/chunk-E4Z7PNXC.mjs.map +1 -0
- package/dist/esm/chunk-GQVMVP4N.mjs +911 -0
- package/dist/esm/chunk-GQVMVP4N.mjs.map +1 -0
- package/dist/esm/chunk-H2EYJIZL.mjs +489 -0
- package/dist/esm/chunk-H2EYJIZL.mjs.map +1 -0
- package/dist/esm/chunk-H3KPLYGI.mjs +152 -0
- package/dist/esm/chunk-H3KPLYGI.mjs.map +1 -0
- package/dist/esm/chunk-HYABYUBD.mjs +432 -0
- package/dist/esm/chunk-HYABYUBD.mjs.map +1 -0
- package/dist/esm/chunk-I2DVUHM5.mjs +123 -0
- package/dist/esm/chunk-I2DVUHM5.mjs.map +1 -0
- package/dist/esm/chunk-JK7SLLF7.mjs +34 -0
- package/dist/esm/chunk-JK7SLLF7.mjs.map +1 -0
- package/dist/esm/chunk-JNT7C46S.mjs +352 -0
- package/dist/esm/chunk-JNT7C46S.mjs.map +1 -0
- package/dist/esm/chunk-MACPBXCT.mjs +415 -0
- package/dist/esm/chunk-MACPBXCT.mjs.map +1 -0
- package/dist/esm/chunk-P3QOX3QZ.mjs +113 -0
- package/dist/esm/chunk-P3QOX3QZ.mjs.map +1 -0
- package/dist/esm/chunk-QVATVA3J.mjs +47 -0
- package/dist/esm/chunk-QVATVA3J.mjs.map +1 -0
- package/dist/esm/chunk-SHJFA25H.mjs +159 -0
- package/dist/esm/chunk-SHJFA25H.mjs.map +1 -0
- package/dist/esm/chunk-TW7Z65AO.mjs +34 -0
- package/dist/esm/chunk-TW7Z65AO.mjs.map +1 -0
- package/dist/esm/chunk-U4HCGTLU.mjs +35 -0
- package/dist/esm/chunk-U4HCGTLU.mjs.map +1 -0
- package/dist/esm/chunk-VS3RYAYE.mjs +80 -0
- package/dist/esm/chunk-VS3RYAYE.mjs.map +1 -0
- package/dist/esm/chunk-W6ON4LG2.mjs +39 -0
- package/dist/esm/chunk-W6ON4LG2.mjs.map +1 -0
- package/dist/esm/chunk-XG2JLZVJ.mjs +627 -0
- package/dist/esm/chunk-XG2JLZVJ.mjs.map +1 -0
- package/dist/esm/chunk-ZCJRY5LQ.mjs +162 -0
- package/dist/esm/chunk-ZCJRY5LQ.mjs.map +1 -0
- package/dist/esm/client/agent-wallet.d.mts +69 -0
- package/dist/esm/client/agent-wallet.mjs +36 -0
- package/dist/esm/client/agent-wallet.mjs.map +1 -0
- package/dist/esm/exact/client/index.d.mts +63 -0
- package/dist/esm/exact/client/index.mjs +25 -0
- package/dist/esm/exact/client/index.mjs.map +1 -0
- package/dist/esm/exact/facilitator/index.d.mts +141 -0
- package/dist/esm/exact/facilitator/index.mjs +694 -0
- package/dist/esm/exact/facilitator/index.mjs.map +1 -0
- package/dist/esm/exact/server/index.d.mts +118 -0
- package/dist/esm/exact/server/index.mjs +153 -0
- package/dist/esm/exact/server/index.mjs.map +1 -0
- package/dist/esm/exact/v1/client/index.d.mts +38 -0
- package/dist/esm/exact/v1/client/index.mjs +12 -0
- package/dist/esm/exact/v1/client/index.mjs.map +1 -0
- package/dist/esm/exact/v1/facilitator/index.d.mts +84 -0
- package/dist/esm/exact/v1/facilitator/index.mjs +12 -0
- package/dist/esm/exact/v1/facilitator/index.mjs.map +1 -0
- package/dist/esm/facilitator/agent-wallet.d.mts +109 -0
- package/dist/esm/facilitator/agent-wallet.mjs +74 -0
- package/dist/esm/facilitator/agent-wallet.mjs.map +1 -0
- package/dist/esm/index.d.mts +338 -0
- package/dist/esm/index.mjs +144 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/permit2-DhJRUcgY.d.mts +729 -0
- package/dist/esm/rpc-DULZzRne.d.mts +13 -0
- package/dist/esm/scheme-CkNhpXrG.d.mts +307 -0
- package/dist/esm/scheme-D8ZbykGV.d.mts +47 -0
- package/dist/esm/signer-BFelv8DL.d.mts +170 -0
- package/dist/esm/storage-6W5MO46W.d.mts +50 -0
- package/dist/esm/storage-BEzTEiUr.d.mts +81 -0
- package/dist/esm/types-DIt9uAUy.d.mts +180 -0
- package/dist/esm/upto/client/index.d.mts +34 -0
- package/dist/esm/upto/client/index.mjs +22 -0
- package/dist/esm/upto/client/index.mjs.map +1 -0
- package/dist/esm/upto/facilitator/index.d.mts +54 -0
- package/dist/esm/upto/facilitator/index.mjs +507 -0
- package/dist/esm/upto/facilitator/index.mjs.map +1 -0
- package/dist/esm/upto/server/index.d.mts +69 -0
- package/dist/esm/upto/server/index.mjs +124 -0
- package/dist/esm/upto/server/index.mjs.map +1 -0
- package/dist/esm/v1/index.d.mts +40 -0
- package/dist/esm/v1/index.mjs +18 -0
- package/dist/esm/v1/index.mjs.map +1 -0
- package/package.json +250 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/batch-settlement/server/redisStorage.ts
|
|
21
|
+
var redisStorage_exports = {};
|
|
22
|
+
__export(redisStorage_exports, {
|
|
23
|
+
RedisChannelStorage: () => RedisChannelStorage
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(redisStorage_exports);
|
|
26
|
+
var DEFAULT_KEY_PREFIX = "x402:batch-settlement";
|
|
27
|
+
var DEFAULT_LOCK_RETRY_INTERVAL_MS = 10;
|
|
28
|
+
var DEFAULT_SCAN_COUNT = 100;
|
|
29
|
+
var UPDATE_CHANNEL_SCRIPT = `
|
|
30
|
+
local current = redis.call("GET", KEYS[1])
|
|
31
|
+
local expectedExists = ARGV[1]
|
|
32
|
+
local expected = ARGV[2]
|
|
33
|
+
local operation = ARGV[3]
|
|
34
|
+
local nextValue = ARGV[4]
|
|
35
|
+
|
|
36
|
+
if expectedExists == "0" then
|
|
37
|
+
if current ~= false then
|
|
38
|
+
return {0, current}
|
|
39
|
+
end
|
|
40
|
+
elseif current ~= expected then
|
|
41
|
+
return {0, current or false}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
if operation == "delete" then
|
|
45
|
+
redis.call("DEL", KEYS[1])
|
|
46
|
+
return {1, false}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
if operation == "set" then
|
|
50
|
+
redis.call("SET", KEYS[1], nextValue)
|
|
51
|
+
return {1, nextValue}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
return {1, current or false}
|
|
55
|
+
`;
|
|
56
|
+
var RedisChannelStorage = class {
|
|
57
|
+
/**
|
|
58
|
+
* Creates Redis-backed server channel storage.
|
|
59
|
+
*
|
|
60
|
+
* @param options - Redis client and optional key/retry configuration.
|
|
61
|
+
*/
|
|
62
|
+
constructor(options) {
|
|
63
|
+
this.client = options.client;
|
|
64
|
+
this.keyPrefix = options.keyPrefix ?? DEFAULT_KEY_PREFIX;
|
|
65
|
+
this.channelKeyPrefix = `${this.keyPrefix}:server:channel`;
|
|
66
|
+
this.lockRetryIntervalMs = options.lockRetryIntervalMs ?? DEFAULT_LOCK_RETRY_INTERVAL_MS;
|
|
67
|
+
this.scanCount = options.scanCount ?? DEFAULT_SCAN_COUNT;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Loads a persisted channel record, if present.
|
|
71
|
+
*
|
|
72
|
+
* @param channelId - The channel identifier.
|
|
73
|
+
* @returns Parsed channel record or `undefined` when the key is missing.
|
|
74
|
+
*/
|
|
75
|
+
async get(channelId) {
|
|
76
|
+
const raw = await this.client.get(this.channelKey(channelId));
|
|
77
|
+
if (!raw) return void 0;
|
|
78
|
+
return JSON.parse(raw);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Lists all stored channel records by scanning Redis keys.
|
|
82
|
+
*
|
|
83
|
+
* @returns Channel records sorted by channelId.
|
|
84
|
+
*/
|
|
85
|
+
async list() {
|
|
86
|
+
const channels = [];
|
|
87
|
+
for await (const keyOrKeys of this.client.scanIterator({
|
|
88
|
+
MATCH: `${this.channelKeyPrefix}:*`,
|
|
89
|
+
COUNT: this.scanCount
|
|
90
|
+
})) {
|
|
91
|
+
const keys = Array.isArray(keyOrKeys) ? keyOrKeys : [keyOrKeys];
|
|
92
|
+
for (const key of keys) {
|
|
93
|
+
if (key.endsWith(":lock")) continue;
|
|
94
|
+
const raw = await this.client.get(key);
|
|
95
|
+
if (!raw) continue;
|
|
96
|
+
channels.push(JSON.parse(raw));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return channels.sort((a, b) => a.channelId.localeCompare(b.channelId));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Atomically inspects and mutates a channel record with Redis compare-and-write retries.
|
|
103
|
+
*
|
|
104
|
+
* @param channelId - The channel identifier.
|
|
105
|
+
* @param update - Mutation callback. Return `undefined` to delete, or `current` to leave unchanged.
|
|
106
|
+
* @returns The final stored channel and whether storage updated, stayed unchanged, or deleted.
|
|
107
|
+
*/
|
|
108
|
+
async updateChannel(channelId, update) {
|
|
109
|
+
const key = this.channelKey(channelId);
|
|
110
|
+
while (true) {
|
|
111
|
+
const currentRaw = await this.client.get(key);
|
|
112
|
+
const current = currentRaw ? JSON.parse(currentRaw) : void 0;
|
|
113
|
+
const next = update(current);
|
|
114
|
+
if (next === current) {
|
|
115
|
+
const result2 = await this.commitUpdate(key, currentRaw, "keep");
|
|
116
|
+
if (result2.applied) return { channel: current, status: "unchanged" };
|
|
117
|
+
await sleep(this.lockRetryIntervalMs);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (!next) {
|
|
121
|
+
const result2 = await this.commitUpdate(key, currentRaw, "delete");
|
|
122
|
+
if (result2.applied) {
|
|
123
|
+
return { channel: void 0, status: current ? "deleted" : "unchanged" };
|
|
124
|
+
}
|
|
125
|
+
await sleep(this.lockRetryIntervalMs);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const nextRaw = JSON.stringify(next);
|
|
129
|
+
const result = await this.commitUpdate(key, currentRaw, "set", nextRaw);
|
|
130
|
+
if (result.applied) return { channel: next, status: "updated" };
|
|
131
|
+
await sleep(this.lockRetryIntervalMs);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Applies a channel mutation only if the key still contains the value that was inspected.
|
|
136
|
+
*
|
|
137
|
+
* @param key - Redis channel key to mutate.
|
|
138
|
+
* @param expectedRaw - Raw JSON value observed before running the update callback.
|
|
139
|
+
* @param operation - Mutation to apply when the observed value is still current.
|
|
140
|
+
* @param nextRaw - Raw JSON value to write for set operations.
|
|
141
|
+
* @returns Whether the mutation was applied.
|
|
142
|
+
*/
|
|
143
|
+
async commitUpdate(key, expectedRaw, operation, nextRaw = "") {
|
|
144
|
+
return parseRedisUpdateResult(
|
|
145
|
+
await this.client.eval(UPDATE_CHANNEL_SCRIPT, {
|
|
146
|
+
keys: [key],
|
|
147
|
+
arguments: [expectedRaw === null ? "0" : "1", expectedRaw ?? "", operation, nextRaw]
|
|
148
|
+
})
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Builds the Redis key for a stored channel record.
|
|
153
|
+
*
|
|
154
|
+
* @param channelId - The channel identifier.
|
|
155
|
+
* @returns Redis key for the channel JSON.
|
|
156
|
+
*/
|
|
157
|
+
channelKey(channelId) {
|
|
158
|
+
return `${this.channelKeyPrefix}:${channelId.toLowerCase()}`;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
function parseRedisUpdateResult(value) {
|
|
162
|
+
if (!Array.isArray(value) || value.length < 1) {
|
|
163
|
+
throw new Error("Unexpected Redis update response");
|
|
164
|
+
}
|
|
165
|
+
const [applied, raw] = value;
|
|
166
|
+
if (applied !== 0 && applied !== 1) {
|
|
167
|
+
throw new Error("Unexpected Redis update status");
|
|
168
|
+
}
|
|
169
|
+
if (raw !== false && raw !== null && raw !== void 0 && typeof raw !== "string") {
|
|
170
|
+
throw new Error("Unexpected Redis update value");
|
|
171
|
+
}
|
|
172
|
+
return { applied: applied === 1 };
|
|
173
|
+
}
|
|
174
|
+
function sleep(ms) {
|
|
175
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
176
|
+
}
|
|
177
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
178
|
+
0 && (module.exports = {
|
|
179
|
+
RedisChannelStorage
|
|
180
|
+
});
|
|
181
|
+
//# sourceMappingURL=redis-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/batch-settlement/server/redisStorage.ts"],"sourcesContent":["import type { Channel, ChannelStorage, ChannelUpdateResult } from \"./storage\";\n\nconst DEFAULT_KEY_PREFIX = \"x402:batch-settlement\";\nconst DEFAULT_LOCK_RETRY_INTERVAL_MS = 10;\nconst DEFAULT_SCAN_COUNT = 100;\n\nconst UPDATE_CHANNEL_SCRIPT = `\nlocal current = redis.call(\"GET\", KEYS[1])\nlocal expectedExists = ARGV[1]\nlocal expected = ARGV[2]\nlocal operation = ARGV[3]\nlocal nextValue = ARGV[4]\n\nif expectedExists == \"0\" then\n if current ~= false then\n return {0, current}\n end\nelseif current ~= expected then\n return {0, current or false}\nend\n\nif operation == \"delete\" then\n redis.call(\"DEL\", KEYS[1])\n return {1, false}\nend\n\nif operation == \"set\" then\n redis.call(\"SET\", KEYS[1], nextValue)\n return {1, nextValue}\nend\n\nreturn {1, current or false}\n`;\n\nexport type RedisEvalOptions = {\n keys: string[];\n arguments: string[];\n};\n\nexport type RedisSetOptions = {\n NX?: true;\n PX?: number;\n};\n\nexport type RedisScanOptions = {\n MATCH?: string;\n COUNT?: number;\n};\n\nexport type RedisChannelStorageClient = {\n get(key: string): Promise<string | null>;\n set(key: string, value: string, options?: RedisSetOptions): Promise<string | null>;\n del(key: string): Promise<number>;\n eval(script: string, options: RedisEvalOptions): Promise<unknown>;\n scanIterator(options: RedisScanOptions): AsyncIterable<string | string[]>;\n};\n\nexport type RedisChannelStorageOptions = {\n client: RedisChannelStorageClient;\n keyPrefix?: string;\n lockTtlMs?: number;\n lockRetryIntervalMs?: number;\n lockRenewalIntervalMs?: number;\n scanCount?: number;\n};\n\ntype RedisUpdateOperation = \"delete\" | \"keep\" | \"set\";\n\ntype ParsedRedisUpdateResult = {\n applied: boolean;\n};\n\n/**\n * Redis-backed {@link ChannelStorage} with optimistic atomic updates.\n */\nexport class RedisChannelStorage implements ChannelStorage {\n private readonly client: RedisChannelStorageClient;\n private readonly keyPrefix: string;\n private readonly channelKeyPrefix: string;\n private readonly lockRetryIntervalMs: number;\n private readonly scanCount: number;\n\n /**\n * Creates Redis-backed server channel storage.\n *\n * @param options - Redis client and optional key/retry configuration.\n */\n constructor(options: RedisChannelStorageOptions) {\n this.client = options.client;\n this.keyPrefix = options.keyPrefix ?? DEFAULT_KEY_PREFIX;\n this.channelKeyPrefix = `${this.keyPrefix}:server:channel`;\n this.lockRetryIntervalMs = options.lockRetryIntervalMs ?? DEFAULT_LOCK_RETRY_INTERVAL_MS;\n this.scanCount = options.scanCount ?? DEFAULT_SCAN_COUNT;\n }\n\n /**\n * Loads a persisted channel record, if present.\n *\n * @param channelId - The channel identifier.\n * @returns Parsed channel record or `undefined` when the key is missing.\n */\n async get(channelId: string): Promise<Channel | undefined> {\n const raw = await this.client.get(this.channelKey(channelId));\n if (!raw) return undefined;\n return JSON.parse(raw) as Channel;\n }\n\n /**\n * Lists all stored channel records by scanning Redis keys.\n *\n * @returns Channel records sorted by channelId.\n */\n async list(): Promise<Channel[]> {\n const channels: Channel[] = [];\n for await (const keyOrKeys of this.client.scanIterator({\n MATCH: `${this.channelKeyPrefix}:*`,\n COUNT: this.scanCount,\n })) {\n const keys = Array.isArray(keyOrKeys) ? keyOrKeys : [keyOrKeys];\n for (const key of keys) {\n if (key.endsWith(\":lock\")) continue;\n const raw = await this.client.get(key);\n if (!raw) continue;\n channels.push(JSON.parse(raw) as Channel);\n }\n }\n return channels.sort((a, b) => a.channelId.localeCompare(b.channelId));\n }\n\n /**\n * Atomically inspects and mutates a channel record with Redis compare-and-write retries.\n *\n * @param channelId - The channel identifier.\n * @param update - Mutation callback. Return `undefined` to delete, or `current` to leave unchanged.\n * @returns The final stored channel and whether storage updated, stayed unchanged, or deleted.\n */\n async updateChannel(\n channelId: string,\n update: (current: Channel | undefined) => Channel | undefined,\n ): Promise<ChannelUpdateResult> {\n const key = this.channelKey(channelId);\n while (true) {\n const currentRaw = await this.client.get(key);\n const current = currentRaw ? (JSON.parse(currentRaw) as Channel) : undefined;\n const next = update(current);\n\n if (next === current) {\n const result = await this.commitUpdate(key, currentRaw, \"keep\");\n if (result.applied) return { channel: current, status: \"unchanged\" };\n await sleep(this.lockRetryIntervalMs);\n continue;\n }\n\n if (!next) {\n const result = await this.commitUpdate(key, currentRaw, \"delete\");\n if (result.applied) {\n return { channel: undefined, status: current ? \"deleted\" : \"unchanged\" };\n }\n await sleep(this.lockRetryIntervalMs);\n continue;\n }\n\n const nextRaw = JSON.stringify(next);\n const result = await this.commitUpdate(key, currentRaw, \"set\", nextRaw);\n if (result.applied) return { channel: next, status: \"updated\" };\n await sleep(this.lockRetryIntervalMs);\n }\n }\n\n /**\n * Applies a channel mutation only if the key still contains the value that was inspected.\n *\n * @param key - Redis channel key to mutate.\n * @param expectedRaw - Raw JSON value observed before running the update callback.\n * @param operation - Mutation to apply when the observed value is still current.\n * @param nextRaw - Raw JSON value to write for set operations.\n * @returns Whether the mutation was applied.\n */\n private async commitUpdate(\n key: string,\n expectedRaw: string | null,\n operation: RedisUpdateOperation,\n nextRaw = \"\",\n ): Promise<ParsedRedisUpdateResult> {\n return parseRedisUpdateResult(\n await this.client.eval(UPDATE_CHANNEL_SCRIPT, {\n keys: [key],\n arguments: [expectedRaw === null ? \"0\" : \"1\", expectedRaw ?? \"\", operation, nextRaw],\n }),\n );\n }\n\n /**\n * Builds the Redis key for a stored channel record.\n *\n * @param channelId - The channel identifier.\n * @returns Redis key for the channel JSON.\n */\n private channelKey(channelId: string) {\n return `${this.channelKeyPrefix}:${channelId.toLowerCase()}`;\n }\n}\n\n/**\n * Parses the Redis script response.\n *\n * @param value - Raw response from the Redis client.\n * @returns Whether the compare-and-write applied.\n */\nfunction parseRedisUpdateResult(value: unknown): ParsedRedisUpdateResult {\n if (!Array.isArray(value) || value.length < 1) {\n throw new Error(\"Unexpected Redis update response\");\n }\n\n const [applied, raw] = value;\n if (applied !== 0 && applied !== 1) {\n throw new Error(\"Unexpected Redis update status\");\n }\n\n if (raw !== false && raw !== null && raw !== undefined && typeof raw !== \"string\") {\n throw new Error(\"Unexpected Redis update value\");\n }\n\n return { applied: applied === 1 };\n}\n\n/**\n * Resolves after the requested delay.\n *\n * @param ms - Delay in milliseconds.\n * @returns Promise resolved after the delay.\n */\nfunction sleep(ms: number) {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n"],"mappings":"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","names":["result"]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { C as ClientEvmSigner } from '../signer-BFelv8DL.js';
|
|
2
|
+
import 'viem';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* BankofAI overlay — NOT from upstream @x402/evm.
|
|
6
|
+
*
|
|
7
|
+
* Client-side wallet-bridge factory, symmetric to TRON's
|
|
8
|
+
* `createClientTronSigner` and to this package's `createFacilitatorEvmSigner`.
|
|
9
|
+
* Upstream ships only `toClientEvmSigner`, a composition helper that expects an
|
|
10
|
+
* already-resolved `{ address, signTypedData }`; it does not adapt an
|
|
11
|
+
* `@bankofai/agent-wallet` wallet (async `getAddress`, and a `signTypedData`
|
|
12
|
+
* that strips the `0x` prefix). This factory closes that gap so client examples
|
|
13
|
+
* stay a one-liner and never touch a raw key.
|
|
14
|
+
*
|
|
15
|
+
* Upgrade safety: consumes only upstream's public surface (`toClientEvmSigner` +
|
|
16
|
+
* the `ClientEvmSigner` type); never edits `signer.ts` / `index.ts`.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A wallet that signs EIP-712 typed data without exposing its key — structurally
|
|
21
|
+
* compatible with `@bankofai/agent-wallet`'s `EvmSigner`. `signTypedData` may
|
|
22
|
+
* return the signature with or without the `0x` prefix (agent-wallet strips it);
|
|
23
|
+
* the factory normalizes it.
|
|
24
|
+
*/
|
|
25
|
+
interface ClientEvmWallet {
|
|
26
|
+
getAddress(): Promise<string>;
|
|
27
|
+
signTypedData(data: {
|
|
28
|
+
domain: Record<string, unknown>;
|
|
29
|
+
types: Record<string, unknown>;
|
|
30
|
+
primaryType: string;
|
|
31
|
+
message: Record<string, unknown>;
|
|
32
|
+
}): Promise<string>;
|
|
33
|
+
/**
|
|
34
|
+
* Optionally sign a fully-specified EIP-1559 transaction (e.g. the one-time
|
|
35
|
+
* `approve(Permit2)` for the ERC-20 approval gas-sponsoring extension).
|
|
36
|
+
* agent-wallet's `EvmSigner` satisfies this; the returned hex may omit the
|
|
37
|
+
* `0x` prefix (agent-wallet strips it). When absent, the signer can't produce
|
|
38
|
+
* the gas-sponsored approval and that flow is simply skipped.
|
|
39
|
+
*/
|
|
40
|
+
signTransaction?(tx: Record<string, unknown>): Promise<string>;
|
|
41
|
+
}
|
|
42
|
+
/** Minimal read surface for permit2 allowance enrichment (a viem client satisfies it). */
|
|
43
|
+
interface ClientEvmReadClient {
|
|
44
|
+
readContract(args: {
|
|
45
|
+
address: `0x${string}`;
|
|
46
|
+
abi: readonly unknown[];
|
|
47
|
+
functionName: string;
|
|
48
|
+
args?: readonly unknown[];
|
|
49
|
+
}): Promise<unknown>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Creates a {@link ClientEvmSigner} from an agent-wallet — the EVM counterpart
|
|
53
|
+
* of `createClientTronSigner`. The key never enters the SDK; the wallet signs.
|
|
54
|
+
*
|
|
55
|
+
* @param wallet - The wallet that signs payment authorizations.
|
|
56
|
+
* @param publicClient - Optional viem client; enables EIP-2612/permit2
|
|
57
|
+
* enrichment via `readContract`. Omit for ERC-3009-only flows.
|
|
58
|
+
* @returns A {@link ClientEvmSigner} backed by the wallet.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* const wallet = await resolveWallet({ network: "evm" }); // @bankofai/agent-wallet
|
|
63
|
+
* const signer = await createClientEvmSigner(wallet, publicClient);
|
|
64
|
+
* new ExactEvmScheme(signer);
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
declare function createClientEvmSigner(wallet: ClientEvmWallet, publicClient?: ClientEvmReadClient): Promise<ClientEvmSigner>;
|
|
68
|
+
|
|
69
|
+
export { type ClientEvmReadClient, type ClientEvmWallet, createClientEvmSigner };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/client/agent-wallet.ts
|
|
21
|
+
var agent_wallet_exports = {};
|
|
22
|
+
__export(agent_wallet_exports, {
|
|
23
|
+
createClientEvmSigner: () => createClientEvmSigner
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(agent_wallet_exports);
|
|
26
|
+
|
|
27
|
+
// src/signer.ts
|
|
28
|
+
function toClientEvmSigner(signer, publicClient) {
|
|
29
|
+
const readContract = signer.readContract ?? publicClient?.readContract.bind(publicClient);
|
|
30
|
+
const result = {
|
|
31
|
+
address: signer.address,
|
|
32
|
+
signTypedData: (msg) => signer.signTypedData(msg)
|
|
33
|
+
};
|
|
34
|
+
if (readContract) {
|
|
35
|
+
result.readContract = readContract;
|
|
36
|
+
}
|
|
37
|
+
const signTransaction = signer.signTransaction;
|
|
38
|
+
if (signTransaction) {
|
|
39
|
+
result.signTransaction = (args) => signTransaction(args);
|
|
40
|
+
}
|
|
41
|
+
const getTransactionCount = signer.getTransactionCount ?? publicClient?.getTransactionCount?.bind(publicClient);
|
|
42
|
+
if (getTransactionCount) {
|
|
43
|
+
result.getTransactionCount = (args) => getTransactionCount(args);
|
|
44
|
+
}
|
|
45
|
+
const estimateFeesPerGas = signer.estimateFeesPerGas ?? publicClient?.estimateFeesPerGas?.bind(publicClient);
|
|
46
|
+
if (estimateFeesPerGas) {
|
|
47
|
+
result.estimateFeesPerGas = () => estimateFeesPerGas();
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/client/agent-wallet.ts
|
|
53
|
+
async function createClientEvmSigner(wallet, publicClient) {
|
|
54
|
+
const address = await wallet.getAddress();
|
|
55
|
+
const signTransaction = wallet.signTransaction?.bind(wallet);
|
|
56
|
+
return toClientEvmSigner(
|
|
57
|
+
{
|
|
58
|
+
address,
|
|
59
|
+
// agent-wallet strips the `0x` (signature analog of SDK issue #2);
|
|
60
|
+
// re-add it so the returned signature matches the ClientEvmSigner contract.
|
|
61
|
+
signTypedData: async (msg) => {
|
|
62
|
+
const sig = await wallet.signTypedData(msg);
|
|
63
|
+
return `0x${sig.replace(/^0x/, "")}`;
|
|
64
|
+
},
|
|
65
|
+
// Enables the ERC-20 approval gas-sponsoring extension: the client signs
|
|
66
|
+
// the `approve(Permit2, MaxUint256)` tx offline (facilitator broadcasts it).
|
|
67
|
+
// agent-wallet's EvmSigner.signTransaction takes the viem EIP-1559 fields
|
|
68
|
+
// as-is and strips the `0x`; re-add it. getTransactionCount/estimateFeesPerGas
|
|
69
|
+
// come from `publicClient` via toClientEvmSigner.
|
|
70
|
+
...signTransaction ? {
|
|
71
|
+
signTransaction: async (args) => {
|
|
72
|
+
const signed = await signTransaction(args);
|
|
73
|
+
return `0x${signed.replace(/^0x/, "")}`;
|
|
74
|
+
}
|
|
75
|
+
} : {}
|
|
76
|
+
},
|
|
77
|
+
publicClient
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
81
|
+
0 && (module.exports = {
|
|
82
|
+
createClientEvmSigner
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=agent-wallet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/client/agent-wallet.ts","../../../src/signer.ts"],"sourcesContent":["/**\n * BankofAI overlay — NOT from upstream @x402/evm.\n *\n * Client-side wallet-bridge factory, symmetric to TRON's\n * `createClientTronSigner` and to this package's `createFacilitatorEvmSigner`.\n * Upstream ships only `toClientEvmSigner`, a composition helper that expects an\n * already-resolved `{ address, signTypedData }`; it does not adapt an\n * `@bankofai/agent-wallet` wallet (async `getAddress`, and a `signTypedData`\n * that strips the `0x` prefix). This factory closes that gap so client examples\n * stay a one-liner and never touch a raw key.\n *\n * Upgrade safety: consumes only upstream's public surface (`toClientEvmSigner` +\n * the `ClientEvmSigner` type); never edits `signer.ts` / `index.ts`.\n */\nimport { toClientEvmSigner, type ClientEvmSigner } from \"../signer\";\n\n/**\n * A wallet that signs EIP-712 typed data without exposing its key — structurally\n * compatible with `@bankofai/agent-wallet`'s `EvmSigner`. `signTypedData` may\n * return the signature with or without the `0x` prefix (agent-wallet strips it);\n * the factory normalizes it.\n */\nexport interface ClientEvmWallet {\n getAddress(): Promise<string>;\n signTypedData(data: {\n domain: Record<string, unknown>;\n types: Record<string, unknown>;\n primaryType: string;\n message: Record<string, unknown>;\n }): Promise<string>;\n /**\n * Optionally sign a fully-specified EIP-1559 transaction (e.g. the one-time\n * `approve(Permit2)` for the ERC-20 approval gas-sponsoring extension).\n * agent-wallet's `EvmSigner` satisfies this; the returned hex may omit the\n * `0x` prefix (agent-wallet strips it). When absent, the signer can't produce\n * the gas-sponsored approval and that flow is simply skipped.\n */\n signTransaction?(tx: Record<string, unknown>): Promise<string>;\n}\n\n/** Minimal read surface for permit2 allowance enrichment (a viem client satisfies it). */\nexport interface ClientEvmReadClient {\n readContract(args: {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args?: readonly unknown[];\n }): Promise<unknown>;\n}\n\n/**\n * Creates a {@link ClientEvmSigner} from an agent-wallet — the EVM counterpart\n * of `createClientTronSigner`. The key never enters the SDK; the wallet signs.\n *\n * @param wallet - The wallet that signs payment authorizations.\n * @param publicClient - Optional viem client; enables EIP-2612/permit2\n * enrichment via `readContract`. Omit for ERC-3009-only flows.\n * @returns A {@link ClientEvmSigner} backed by the wallet.\n *\n * @example\n * ```typescript\n * const wallet = await resolveWallet({ network: \"evm\" }); // @bankofai/agent-wallet\n * const signer = await createClientEvmSigner(wallet, publicClient);\n * new ExactEvmScheme(signer);\n * ```\n */\nexport async function createClientEvmSigner(\n wallet: ClientEvmWallet,\n publicClient?: ClientEvmReadClient,\n): Promise<ClientEvmSigner> {\n const address = (await wallet.getAddress()) as `0x${string}`;\n\n // Bind to the wallet: agent-wallet's `LocalSigner.signTransaction` reads\n // `this._impl`, so calling a detached reference throws. (`signTypedData` below\n // is invoked as `wallet.signTypedData(...)`, so it stays bound.)\n const signTransaction = wallet.signTransaction?.bind(wallet);\n\n return toClientEvmSigner(\n {\n address,\n // agent-wallet strips the `0x` (signature analog of SDK issue #2);\n // re-add it so the returned signature matches the ClientEvmSigner contract.\n signTypedData: async msg => {\n const sig = await wallet.signTypedData(msg);\n return `0x${sig.replace(/^0x/, \"\")}` as `0x${string}`;\n },\n // Enables the ERC-20 approval gas-sponsoring extension: the client signs\n // the `approve(Permit2, MaxUint256)` tx offline (facilitator broadcasts it).\n // agent-wallet's EvmSigner.signTransaction takes the viem EIP-1559 fields\n // as-is and strips the `0x`; re-add it. getTransactionCount/estimateFeesPerGas\n // come from `publicClient` via toClientEvmSigner.\n ...(signTransaction\n ? {\n signTransaction: async (args: Record<string, unknown>) => {\n const signed = await signTransaction(args);\n return `0x${signed.replace(/^0x/, \"\")}` as `0x${string}`;\n },\n }\n : {}),\n },\n publicClient,\n );\n}\n","import type { Log } from \"viem\";\n\n/**\n * ClientEvmSigner - Used by x402 clients to sign payment authorizations.\n *\n * Typically a viem WalletClient extended with publicActions:\n * ```typescript\n * const client = createWalletClient({\n * account: privateKeyToAccount('0x...'),\n * chain: baseSepolia,\n * transport: http(),\n * }).extend(publicActions);\n * ```\n *\n * Or composed via `toClientEvmSigner(account, publicClient)`.\n */\nexport type ClientEvmSigner = {\n readonly address: `0x${string}`;\n signTypedData(message: {\n domain: Record<string, unknown>;\n types: Record<string, unknown>;\n primaryType: string;\n message: Record<string, unknown>;\n }): Promise<`0x${string}`>;\n /**\n * Optional on-chain reads.\n * Required only for extension enrichment (EIP-2612 / ERC-20 approval).\n */\n readContract?(args: {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args?: readonly unknown[];\n }): Promise<unknown>;\n /**\n * Optional: Signs a raw EIP-1559 transaction without broadcasting.\n * Required for ERC-20 approval gas sponsoring when the token lacks EIP-2612.\n */\n signTransaction?(args: {\n to: `0x${string}`;\n data: `0x${string}`;\n nonce: number;\n gas: bigint;\n maxFeePerGas: bigint;\n maxPriorityFeePerGas: bigint;\n chainId: number;\n }): Promise<`0x${string}`>;\n /**\n * Optional: Gets the current transaction count (nonce) for an address.\n * Required for ERC-20 approval gas sponsoring.\n */\n getTransactionCount?(args: { address: `0x${string}` }): Promise<number>;\n /**\n * Optional: Estimates current gas fees per gas.\n * Required for ERC-20 approval gas sponsoring.\n */\n estimateFeesPerGas?(): Promise<{ maxFeePerGas: bigint; maxPriorityFeePerGas: bigint }>;\n};\n\n/**\n * FacilitatorEvmSigner - Used by x402 facilitators to verify and settle payments\n * This is typically a viem PublicClient + WalletClient combination that can\n * read contract state, verify signatures, write transactions, and wait for receipts\n *\n * Supports multiple addresses for load balancing, key rotation, and high availability\n */\nexport type FacilitatorEvmSigner = {\n /**\n * Get all addresses this facilitator can use for signing\n * Enables dynamic address selection for load balancing and key rotation\n */\n getAddresses(): readonly `0x${string}`[];\n\n readContract(args: {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args?: readonly unknown[];\n }): Promise<unknown>;\n verifyTypedData(args: {\n address: `0x${string}`;\n domain: Record<string, unknown>;\n types: Record<string, unknown>;\n primaryType: string;\n message: Record<string, unknown>;\n signature: `0x${string}`;\n }): Promise<boolean>;\n writeContract(args: {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args: readonly unknown[];\n gas?: bigint;\n dataSuffix?: `0x${string}`;\n }): Promise<`0x${string}`>;\n sendTransaction(args: { to: `0x${string}`; data: `0x${string}` }): Promise<`0x${string}`>;\n waitForTransactionReceipt(args: { hash: `0x${string}` }): Promise<{\n status: string;\n logs?: readonly Log[];\n }>;\n getCode(args: { address: `0x${string}` }): Promise<`0x${string}` | undefined>;\n};\n\n/**\n * Composes a ClientEvmSigner from a local account and a public client.\n *\n * Use this when your signer (e.g., `privateKeyToAccount`) doesn't have\n * `readContract`. The `publicClient` provides the on-chain read capability.\n *\n * Alternatively, use a WalletClient extended with publicActions directly:\n * ```typescript\n * const signer = createWalletClient({\n * account: privateKeyToAccount('0x...'),\n * chain: baseSepolia,\n * transport: http(),\n * }).extend(publicActions);\n * ```\n *\n * @param signer - A signer with `address` and `signTypedData` (and optionally `readContract`)\n * @param publicClient - A client with optional read/nonce/fee helpers\n * @param publicClient.readContract - The readContract method from the public client\n * @param publicClient.getTransactionCount - Optional getTransactionCount for ERC-20 approval\n * @param publicClient.estimateFeesPerGas - Optional estimateFeesPerGas for ERC-20 approval\n * @returns A ClientEvmSigner with any available optional capabilities\n *\n * @example\n * ```typescript\n * const account = privateKeyToAccount(\"0x...\");\n * const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });\n * const signer = toClientEvmSigner(account, publicClient);\n * ```\n */\nexport function toClientEvmSigner(\n signer: Omit<ClientEvmSigner, \"readContract\"> & {\n readContract?: ClientEvmSigner[\"readContract\"];\n },\n publicClient?: {\n readContract(args: {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args?: readonly unknown[];\n }): Promise<unknown>;\n getTransactionCount?(args: { address: `0x${string}` }): Promise<number>;\n estimateFeesPerGas?(): Promise<{ maxFeePerGas: bigint; maxPriorityFeePerGas: bigint }>;\n },\n): ClientEvmSigner {\n const readContract = signer.readContract ?? publicClient?.readContract.bind(publicClient);\n\n const result: ClientEvmSigner = {\n address: signer.address,\n signTypedData: msg => signer.signTypedData(msg),\n };\n\n if (readContract) {\n result.readContract = readContract;\n }\n\n // Forward optional capabilities from signer or publicClient\n const signTransaction = signer.signTransaction;\n if (signTransaction) {\n result.signTransaction = args => signTransaction(args);\n }\n\n const getTransactionCount =\n signer.getTransactionCount ?? publicClient?.getTransactionCount?.bind(publicClient);\n if (getTransactionCount) {\n result.getTransactionCount = args => getTransactionCount(args);\n }\n\n const estimateFeesPerGas =\n signer.estimateFeesPerGas ?? publicClient?.estimateFeesPerGas?.bind(publicClient);\n if (estimateFeesPerGas) {\n result.estimateFeesPerGas = () => estimateFeesPerGas();\n }\n\n return result;\n}\n\n/**\n * Converts a viem client with single address to a FacilitatorEvmSigner\n * Wraps the single address in a getAddresses() function for compatibility\n *\n * @param client - The client to convert (must have 'address' property)\n * @returns FacilitatorEvmSigner with getAddresses() support\n */\nexport function toFacilitatorEvmSigner(\n client: Omit<FacilitatorEvmSigner, \"getAddresses\"> & { address: `0x${string}` },\n): FacilitatorEvmSigner {\n return {\n ...client,\n getAddresses: () => [client.address],\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACoIO,SAAS,kBACd,QAGA,cAUiB;AACjB,QAAM,eAAe,OAAO,gBAAgB,cAAc,aAAa,KAAK,YAAY;AAExF,QAAM,SAA0B;AAAA,IAC9B,SAAS,OAAO;AAAA,IAChB,eAAe,SAAO,OAAO,cAAc,GAAG;AAAA,EAChD;AAEA,MAAI,cAAc;AAChB,WAAO,eAAe;AAAA,EACxB;AAGA,QAAM,kBAAkB,OAAO;AAC/B,MAAI,iBAAiB;AACnB,WAAO,kBAAkB,UAAQ,gBAAgB,IAAI;AAAA,EACvD;AAEA,QAAM,sBACJ,OAAO,uBAAuB,cAAc,qBAAqB,KAAK,YAAY;AACpF,MAAI,qBAAqB;AACvB,WAAO,sBAAsB,UAAQ,oBAAoB,IAAI;AAAA,EAC/D;AAEA,QAAM,qBACJ,OAAO,sBAAsB,cAAc,oBAAoB,KAAK,YAAY;AAClF,MAAI,oBAAoB;AACtB,WAAO,qBAAqB,MAAM,mBAAmB;AAAA,EACvD;AAEA,SAAO;AACT;;;AD/GA,eAAsB,sBACpB,QACA,cAC0B;AAC1B,QAAM,UAAW,MAAM,OAAO,WAAW;AAKzC,QAAM,kBAAkB,OAAO,iBAAiB,KAAK,MAAM;AAE3D,SAAO;AAAA,IACL;AAAA,MACE;AAAA;AAAA;AAAA,MAGA,eAAe,OAAM,QAAO;AAC1B,cAAM,MAAM,MAAM,OAAO,cAAc,GAAG;AAC1C,eAAO,KAAK,IAAI,QAAQ,OAAO,EAAE,CAAC;AAAA,MACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,GAAI,kBACA;AAAA,QACE,iBAAiB,OAAO,SAAkC;AACxD,gBAAM,SAAS,MAAM,gBAAgB,IAAI;AACzC,iBAAO,KAAK,OAAO,QAAQ,OAAO,EAAE,CAAC;AAAA,QACvC;AAAA,MACF,IACA,CAAC;AAAA,IACP;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export { E as ExactEvmScheme } from '../../scheme-DWgpkDgz.js';
|
|
2
|
+
import { x402Client, SelectPaymentRequirements, PaymentPolicy } from '@bankofai/x402-core/client';
|
|
3
|
+
import { Network } from '@bankofai/x402-core/types';
|
|
4
|
+
import { C as ClientEvmSigner } from '../../signer-BFelv8DL.js';
|
|
5
|
+
import { E as ExactEvmSchemeOptions } from '../../rpc-DULZzRne.js';
|
|
6
|
+
export { a as ExactEvmSchemeConfig, b as ExactEvmSchemeConfigByChainId } from '../../rpc-DULZzRne.js';
|
|
7
|
+
export { P as Permit2AllowanceParams, c as createPermit2ApprovalTx, e as erc20AllowanceAbi, g as getPermit2AllowanceReadParams } from '../../permit2-DhJRUcgY.js';
|
|
8
|
+
import 'viem';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Configuration options for registering EVM schemes to an x402Client
|
|
12
|
+
*/
|
|
13
|
+
interface EvmClientConfig {
|
|
14
|
+
/**
|
|
15
|
+
* The EVM signer to use for creating payment payloads
|
|
16
|
+
*/
|
|
17
|
+
signer: ClientEvmSigner;
|
|
18
|
+
/**
|
|
19
|
+
* Optional payment requirements selector function
|
|
20
|
+
* If not provided, uses the default selector (first available option)
|
|
21
|
+
*/
|
|
22
|
+
paymentRequirementsSelector?: SelectPaymentRequirements;
|
|
23
|
+
/**
|
|
24
|
+
* Optional policies to apply to the client
|
|
25
|
+
*/
|
|
26
|
+
policies?: PaymentPolicy[];
|
|
27
|
+
/**
|
|
28
|
+
* Optional Exact EVM client scheme options.
|
|
29
|
+
* Supports either a single config ({ rpcUrl }) or per-chain configs
|
|
30
|
+
* keyed by EVM chain ID ({ 8453: { rpcUrl: "..." } }).
|
|
31
|
+
*/
|
|
32
|
+
schemeOptions?: ExactEvmSchemeOptions;
|
|
33
|
+
/**
|
|
34
|
+
* Optional specific networks to register.
|
|
35
|
+
* If not provided, registers wildcard support (eip155:*).
|
|
36
|
+
*/
|
|
37
|
+
networks?: Network[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Registers EVM exact payment schemes to an x402Client instance.
|
|
41
|
+
*
|
|
42
|
+
* This function registers:
|
|
43
|
+
* - V2: eip155:* wildcard scheme with ExactEvmScheme (or specific networks if provided)
|
|
44
|
+
* - V1: All supported EVM networks with ExactEvmSchemeV1
|
|
45
|
+
*
|
|
46
|
+
* @param client - The x402Client instance to register schemes to
|
|
47
|
+
* @param config - Configuration for EVM client registration
|
|
48
|
+
* @returns The client instance for chaining
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* import { registerExactEvmScheme } from "@bankofai/x402-evm/exact/client/register";
|
|
53
|
+
* import { x402Client } from "@bankofai/x402-core/client";
|
|
54
|
+
* import { privateKeyToAccount } from "viem/accounts";
|
|
55
|
+
*
|
|
56
|
+
* const account = privateKeyToAccount("0x...");
|
|
57
|
+
* const client = new x402Client();
|
|
58
|
+
* registerExactEvmScheme(client, { signer: account });
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
declare function registerExactEvmScheme(client: x402Client, config: EvmClientConfig): x402Client;
|
|
62
|
+
|
|
63
|
+
export { type EvmClientConfig, ExactEvmSchemeOptions, registerExactEvmScheme };
|