@spectratools/tx-shared 0.4.2 → 0.5.1
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 +6 -2
- package/dist/chunk-HFRJBEDT.js +1144 -0
- package/dist/errors.d.ts +1 -1
- package/dist/execute-tx-DO8p_9dP.d.ts +160 -0
- package/dist/execute-tx.d.ts +4 -63
- package/dist/execute-tx.js +1 -1
- package/dist/index.d.ts +54 -47
- package/dist/index.js +25 -381
- package/package.json +1 -1
- package/dist/chunk-4XI6TBKX.js +0 -130
package/dist/index.js
CHANGED
|
@@ -3,8 +3,22 @@ import {
|
|
|
3
3
|
createAbstractClient
|
|
4
4
|
} from "./chunk-P4ACSL6N.js";
|
|
5
5
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
attachPrivyPolicyContext,
|
|
7
|
+
createPrivyAccount,
|
|
8
|
+
createPrivyAuthorizationPayload,
|
|
9
|
+
createPrivyClient,
|
|
10
|
+
createPrivySigner,
|
|
11
|
+
executeTx,
|
|
12
|
+
fetchPrivyPolicyVisibility,
|
|
13
|
+
generatePrivyAuthorizationSignature,
|
|
14
|
+
getPrivyPolicyContext,
|
|
15
|
+
normalizePrivyApiUrl,
|
|
16
|
+
normalizePrivyPolicy,
|
|
17
|
+
parsePrivyAuthorizationKey,
|
|
18
|
+
preflightPrivyTransactionPolicy,
|
|
19
|
+
serializePrivyAuthorizationPayload,
|
|
20
|
+
toPrivyPolicyViolationError
|
|
21
|
+
} from "./chunk-HFRJBEDT.js";
|
|
8
22
|
import {
|
|
9
23
|
TxError,
|
|
10
24
|
toTxError
|
|
@@ -57,384 +71,6 @@ function createKeystoreSigner(options) {
|
|
|
57
71
|
return { account, address: account.address, provider: "keystore" };
|
|
58
72
|
}
|
|
59
73
|
|
|
60
|
-
// src/signers/privy-signature.ts
|
|
61
|
-
import { createPrivateKey, sign as signWithCrypto } from "crypto";
|
|
62
|
-
var PRIVY_AUTHORIZATION_KEY_PREFIX = "wallet-auth:";
|
|
63
|
-
var PRIVY_AUTHORIZATION_KEY_REGEX = /^wallet-auth:[A-Za-z0-9+/]+={0,2}$/;
|
|
64
|
-
var DEFAULT_PRIVY_API_URL = "https://api.privy.io";
|
|
65
|
-
function normalizePrivyApiUrl(apiUrl) {
|
|
66
|
-
const value = (apiUrl ?? DEFAULT_PRIVY_API_URL).trim();
|
|
67
|
-
if (value.length === 0) {
|
|
68
|
-
throw new TxError(
|
|
69
|
-
"PRIVY_AUTH_FAILED",
|
|
70
|
-
"Invalid PRIVY_API_URL format: expected a non-empty http(s) URL"
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
let parsed;
|
|
74
|
-
try {
|
|
75
|
-
parsed = new URL(value);
|
|
76
|
-
} catch (cause) {
|
|
77
|
-
throw new TxError(
|
|
78
|
-
"PRIVY_AUTH_FAILED",
|
|
79
|
-
"Invalid PRIVY_API_URL format: expected a non-empty http(s) URL",
|
|
80
|
-
cause
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
84
|
-
throw new TxError(
|
|
85
|
-
"PRIVY_AUTH_FAILED",
|
|
86
|
-
"Invalid PRIVY_API_URL format: expected a non-empty http(s) URL"
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
return parsed.toString().replace(/\/+$/, "");
|
|
90
|
-
}
|
|
91
|
-
function parsePrivyAuthorizationKey(authorizationKey) {
|
|
92
|
-
const normalizedKey = authorizationKey.trim();
|
|
93
|
-
if (!PRIVY_AUTHORIZATION_KEY_REGEX.test(normalizedKey)) {
|
|
94
|
-
throw new TxError(
|
|
95
|
-
"PRIVY_AUTH_FAILED",
|
|
96
|
-
"Invalid PRIVY_AUTHORIZATION_KEY format: expected wallet-auth:<base64-pkcs8-p256-private-key>"
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
const rawPrivateKey = normalizedKey.slice(PRIVY_AUTHORIZATION_KEY_PREFIX.length);
|
|
100
|
-
let derKey;
|
|
101
|
-
try {
|
|
102
|
-
derKey = Buffer.from(rawPrivateKey, "base64");
|
|
103
|
-
} catch (cause) {
|
|
104
|
-
throw new TxError(
|
|
105
|
-
"PRIVY_AUTH_FAILED",
|
|
106
|
-
"Invalid PRIVY_AUTHORIZATION_KEY format: expected wallet-auth:<base64-pkcs8-p256-private-key>",
|
|
107
|
-
cause
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
let keyObject;
|
|
111
|
-
try {
|
|
112
|
-
keyObject = createPrivateKey({
|
|
113
|
-
key: derKey,
|
|
114
|
-
format: "der",
|
|
115
|
-
type: "pkcs8"
|
|
116
|
-
});
|
|
117
|
-
} catch (cause) {
|
|
118
|
-
throw new TxError(
|
|
119
|
-
"PRIVY_AUTH_FAILED",
|
|
120
|
-
"Invalid PRIVY_AUTHORIZATION_KEY format: expected wallet-auth:<base64-pkcs8-p256-private-key>",
|
|
121
|
-
cause
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
if (keyObject.asymmetricKeyType !== "ec") {
|
|
125
|
-
throw new TxError(
|
|
126
|
-
"PRIVY_AUTH_FAILED",
|
|
127
|
-
"Invalid PRIVY_AUTHORIZATION_KEY format: expected wallet-auth:<base64-pkcs8-p256-private-key>"
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
const details = keyObject.asymmetricKeyDetails;
|
|
131
|
-
const namedCurve = details !== void 0 && "namedCurve" in details ? details.namedCurve : void 0;
|
|
132
|
-
if (namedCurve !== void 0 && namedCurve !== "prime256v1") {
|
|
133
|
-
throw new TxError(
|
|
134
|
-
"PRIVY_AUTH_FAILED",
|
|
135
|
-
"Invalid PRIVY_AUTHORIZATION_KEY format: expected wallet-auth:<base64-pkcs8-p256-private-key>"
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
return keyObject;
|
|
139
|
-
}
|
|
140
|
-
function createPrivyAuthorizationPayload(options) {
|
|
141
|
-
const appId = options.appId.trim();
|
|
142
|
-
if (appId.length === 0) {
|
|
143
|
-
throw new TxError(
|
|
144
|
-
"PRIVY_AUTH_FAILED",
|
|
145
|
-
"Invalid PRIVY_APP_ID format: expected non-empty string"
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
const url = options.url.trim().replace(/\/+$/, "");
|
|
149
|
-
if (url.length === 0) {
|
|
150
|
-
throw new TxError(
|
|
151
|
-
"PRIVY_TRANSPORT_FAILED",
|
|
152
|
-
"Failed to build Privy authorization payload: request URL is empty"
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
return {
|
|
156
|
-
version: 1,
|
|
157
|
-
method: options.method,
|
|
158
|
-
url,
|
|
159
|
-
headers: {
|
|
160
|
-
"privy-app-id": appId,
|
|
161
|
-
...options.idempotencyKey !== void 0 ? { "privy-idempotency-key": options.idempotencyKey } : {}
|
|
162
|
-
},
|
|
163
|
-
body: options.body
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
function serializePrivyAuthorizationPayload(payload) {
|
|
167
|
-
return canonicalizeJson(payload);
|
|
168
|
-
}
|
|
169
|
-
function generatePrivyAuthorizationSignature(payload, authorizationKey) {
|
|
170
|
-
const privateKey = parsePrivyAuthorizationKey(authorizationKey);
|
|
171
|
-
const serializedPayload = serializePrivyAuthorizationPayload(payload);
|
|
172
|
-
const signature = signWithCrypto("sha256", Buffer.from(serializedPayload), privateKey);
|
|
173
|
-
return signature.toString("base64");
|
|
174
|
-
}
|
|
175
|
-
function canonicalizeJson(value) {
|
|
176
|
-
if (value === null) {
|
|
177
|
-
return "null";
|
|
178
|
-
}
|
|
179
|
-
if (typeof value === "string" || typeof value === "boolean") {
|
|
180
|
-
return JSON.stringify(value);
|
|
181
|
-
}
|
|
182
|
-
if (typeof value === "number") {
|
|
183
|
-
if (!Number.isFinite(value)) {
|
|
184
|
-
throw new TxError(
|
|
185
|
-
"PRIVY_TRANSPORT_FAILED",
|
|
186
|
-
"Failed to build Privy authorization payload: JSON payload contains a non-finite number"
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
return JSON.stringify(value);
|
|
190
|
-
}
|
|
191
|
-
if (Array.isArray(value)) {
|
|
192
|
-
return `[${value.map((item) => canonicalizeJson(item)).join(",")}]`;
|
|
193
|
-
}
|
|
194
|
-
if (typeof value === "object") {
|
|
195
|
-
const record = value;
|
|
196
|
-
const keys = Object.keys(record).sort((left, right) => left.localeCompare(right));
|
|
197
|
-
const entries = [];
|
|
198
|
-
for (const key of keys) {
|
|
199
|
-
const entryValue = record[key];
|
|
200
|
-
if (entryValue === void 0) {
|
|
201
|
-
continue;
|
|
202
|
-
}
|
|
203
|
-
entries.push(`${JSON.stringify(key)}:${canonicalizeJson(entryValue)}`);
|
|
204
|
-
}
|
|
205
|
-
return `{${entries.join(",")}}`;
|
|
206
|
-
}
|
|
207
|
-
throw new TxError(
|
|
208
|
-
"PRIVY_TRANSPORT_FAILED",
|
|
209
|
-
"Failed to build Privy authorization payload: JSON payload contains unsupported value type"
|
|
210
|
-
);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// src/signers/privy-client.ts
|
|
214
|
-
function createPrivyClient(options) {
|
|
215
|
-
const appId = options.appId.trim();
|
|
216
|
-
const walletId = options.walletId.trim();
|
|
217
|
-
if (appId.length === 0) {
|
|
218
|
-
throw new TxError(
|
|
219
|
-
"PRIVY_AUTH_FAILED",
|
|
220
|
-
"Invalid PRIVY_APP_ID format: expected non-empty string"
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
if (walletId.length === 0) {
|
|
224
|
-
throw new TxError(
|
|
225
|
-
"PRIVY_AUTH_FAILED",
|
|
226
|
-
"Invalid PRIVY_WALLET_ID format: expected non-empty string"
|
|
227
|
-
);
|
|
228
|
-
}
|
|
229
|
-
const apiUrl = normalizePrivyApiUrl(options.apiUrl);
|
|
230
|
-
const fetchImplementation = options.fetchImplementation ?? fetch;
|
|
231
|
-
return {
|
|
232
|
-
appId,
|
|
233
|
-
walletId,
|
|
234
|
-
apiUrl,
|
|
235
|
-
async createRpcIntent(request, requestOptions) {
|
|
236
|
-
const url = `${apiUrl}/v1/intents/wallets/${walletId}/rpc`;
|
|
237
|
-
const payload = createPrivyAuthorizationPayload({
|
|
238
|
-
appId,
|
|
239
|
-
method: "POST",
|
|
240
|
-
url,
|
|
241
|
-
body: request,
|
|
242
|
-
...requestOptions?.idempotencyKey !== void 0 ? { idempotencyKey: requestOptions.idempotencyKey } : {}
|
|
243
|
-
});
|
|
244
|
-
const signature = generatePrivyAuthorizationSignature(payload, options.authorizationKey);
|
|
245
|
-
return sendPrivyRequest({
|
|
246
|
-
fetchImplementation,
|
|
247
|
-
method: "POST",
|
|
248
|
-
url,
|
|
249
|
-
body: request,
|
|
250
|
-
operation: "create rpc intent",
|
|
251
|
-
headers: {
|
|
252
|
-
"privy-app-id": appId,
|
|
253
|
-
"privy-authorization-signature": signature,
|
|
254
|
-
...requestOptions?.idempotencyKey !== void 0 ? { "privy-idempotency-key": requestOptions.idempotencyKey } : {}
|
|
255
|
-
}
|
|
256
|
-
});
|
|
257
|
-
},
|
|
258
|
-
async getWallet() {
|
|
259
|
-
const url = `${apiUrl}/v1/wallets/${walletId}`;
|
|
260
|
-
return sendPrivyRequest({
|
|
261
|
-
fetchImplementation,
|
|
262
|
-
method: "GET",
|
|
263
|
-
url,
|
|
264
|
-
operation: "get wallet",
|
|
265
|
-
headers: {
|
|
266
|
-
"privy-app-id": appId
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
},
|
|
270
|
-
async getPolicy(policyId) {
|
|
271
|
-
if (policyId.trim().length === 0) {
|
|
272
|
-
throw new TxError(
|
|
273
|
-
"PRIVY_TRANSPORT_FAILED",
|
|
274
|
-
"Failed to build Privy policy lookup request: policy id is empty"
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
|
-
const url = `${apiUrl}/v1/policies/${policyId}`;
|
|
278
|
-
return sendPrivyRequest({
|
|
279
|
-
fetchImplementation,
|
|
280
|
-
method: "GET",
|
|
281
|
-
url,
|
|
282
|
-
operation: "get policy",
|
|
283
|
-
headers: {
|
|
284
|
-
"privy-app-id": appId
|
|
285
|
-
}
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
async function sendPrivyRequest(options) {
|
|
291
|
-
let response;
|
|
292
|
-
try {
|
|
293
|
-
response = await options.fetchImplementation(options.url, {
|
|
294
|
-
method: options.method,
|
|
295
|
-
headers: {
|
|
296
|
-
...options.headers,
|
|
297
|
-
...options.body !== void 0 ? { "content-type": "application/json" } : {}
|
|
298
|
-
},
|
|
299
|
-
...options.body !== void 0 ? { body: JSON.stringify(options.body) } : {}
|
|
300
|
-
});
|
|
301
|
-
} catch (cause) {
|
|
302
|
-
throw new TxError(
|
|
303
|
-
"PRIVY_TRANSPORT_FAILED",
|
|
304
|
-
`Privy ${options.operation} request failed: network error`,
|
|
305
|
-
cause
|
|
306
|
-
);
|
|
307
|
-
}
|
|
308
|
-
const payload = await parseJsonResponse(response, options.operation);
|
|
309
|
-
if (!response.ok) {
|
|
310
|
-
const message = extractPrivyErrorMessage(payload) ?? `HTTP ${response.status}`;
|
|
311
|
-
if (response.status === 401 || response.status === 403) {
|
|
312
|
-
throw new TxError(
|
|
313
|
-
"PRIVY_AUTH_FAILED",
|
|
314
|
-
`Privy authentication failed (${response.status}): ${message}`
|
|
315
|
-
);
|
|
316
|
-
}
|
|
317
|
-
throw new TxError(
|
|
318
|
-
"PRIVY_TRANSPORT_FAILED",
|
|
319
|
-
`Privy ${options.operation} request failed (${response.status}): ${message}`
|
|
320
|
-
);
|
|
321
|
-
}
|
|
322
|
-
if (!isRecord(payload)) {
|
|
323
|
-
throw new TxError(
|
|
324
|
-
"PRIVY_TRANSPORT_FAILED",
|
|
325
|
-
`Privy ${options.operation} request failed: invalid JSON response shape`
|
|
326
|
-
);
|
|
327
|
-
}
|
|
328
|
-
return payload;
|
|
329
|
-
}
|
|
330
|
-
async function parseJsonResponse(response, operation) {
|
|
331
|
-
const text = await response.text();
|
|
332
|
-
if (text.trim().length === 0) {
|
|
333
|
-
return void 0;
|
|
334
|
-
}
|
|
335
|
-
try {
|
|
336
|
-
return JSON.parse(text);
|
|
337
|
-
} catch (cause) {
|
|
338
|
-
throw new TxError(
|
|
339
|
-
"PRIVY_TRANSPORT_FAILED",
|
|
340
|
-
`Privy ${operation} request failed: invalid JSON response`,
|
|
341
|
-
cause
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
function isRecord(value) {
|
|
346
|
-
return typeof value === "object" && value !== null;
|
|
347
|
-
}
|
|
348
|
-
function extractPrivyErrorMessage(payload) {
|
|
349
|
-
if (!isRecord(payload)) {
|
|
350
|
-
return void 0;
|
|
351
|
-
}
|
|
352
|
-
const directMessage = payload.message;
|
|
353
|
-
if (typeof directMessage === "string" && directMessage.length > 0) {
|
|
354
|
-
return directMessage;
|
|
355
|
-
}
|
|
356
|
-
const errorValue = payload.error;
|
|
357
|
-
if (typeof errorValue === "string" && errorValue.length > 0) {
|
|
358
|
-
return errorValue;
|
|
359
|
-
}
|
|
360
|
-
if (isRecord(errorValue)) {
|
|
361
|
-
const nestedMessage = errorValue.message;
|
|
362
|
-
if (typeof nestedMessage === "string" && nestedMessage.length > 0) {
|
|
363
|
-
return nestedMessage;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
return void 0;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
// src/signers/privy.ts
|
|
370
|
-
import { zeroAddress } from "viem";
|
|
371
|
-
var REQUIRED_FIELDS = [
|
|
372
|
-
"privyAppId",
|
|
373
|
-
"privyWalletId",
|
|
374
|
-
"privyAuthorizationKey"
|
|
375
|
-
];
|
|
376
|
-
var APP_ID_REGEX = /^[A-Za-z0-9_-]{8,128}$/;
|
|
377
|
-
var WALLET_ID_REGEX = /^[A-Za-z0-9_-]{8,128}$/;
|
|
378
|
-
async function createPrivySigner(options) {
|
|
379
|
-
const missing = REQUIRED_FIELDS.filter((field) => {
|
|
380
|
-
const value = options[field];
|
|
381
|
-
return typeof value !== "string" || value.trim().length === 0;
|
|
382
|
-
});
|
|
383
|
-
if (missing.length > 0) {
|
|
384
|
-
const missingLabels = missing.map((field) => {
|
|
385
|
-
if (field === "privyAppId") {
|
|
386
|
-
return "PRIVY_APP_ID";
|
|
387
|
-
}
|
|
388
|
-
if (field === "privyWalletId") {
|
|
389
|
-
return "PRIVY_WALLET_ID";
|
|
390
|
-
}
|
|
391
|
-
return "PRIVY_AUTHORIZATION_KEY";
|
|
392
|
-
}).join(", ");
|
|
393
|
-
throw new TxError(
|
|
394
|
-
"PRIVY_AUTH_FAILED",
|
|
395
|
-
`Privy signer requires configuration: missing ${missingLabels}`
|
|
396
|
-
);
|
|
397
|
-
}
|
|
398
|
-
const appId = options.privyAppId?.trim() ?? "";
|
|
399
|
-
const walletId = options.privyWalletId?.trim() ?? "";
|
|
400
|
-
const authorizationKey = options.privyAuthorizationKey?.trim() ?? "";
|
|
401
|
-
if (!APP_ID_REGEX.test(appId)) {
|
|
402
|
-
throw new TxError(
|
|
403
|
-
"PRIVY_AUTH_FAILED",
|
|
404
|
-
"Invalid PRIVY_APP_ID format: expected 8-128 chars using letters, numbers, hyphen, or underscore"
|
|
405
|
-
);
|
|
406
|
-
}
|
|
407
|
-
if (!WALLET_ID_REGEX.test(walletId)) {
|
|
408
|
-
throw new TxError(
|
|
409
|
-
"PRIVY_AUTH_FAILED",
|
|
410
|
-
"Invalid PRIVY_WALLET_ID format: expected 8-128 chars using letters, numbers, hyphen, or underscore"
|
|
411
|
-
);
|
|
412
|
-
}
|
|
413
|
-
parsePrivyAuthorizationKey(authorizationKey);
|
|
414
|
-
const apiUrl = normalizePrivyApiUrl(options.privyApiUrl);
|
|
415
|
-
const client = createPrivyClient({
|
|
416
|
-
appId,
|
|
417
|
-
walletId,
|
|
418
|
-
authorizationKey,
|
|
419
|
-
apiUrl
|
|
420
|
-
});
|
|
421
|
-
const account = {
|
|
422
|
-
address: zeroAddress,
|
|
423
|
-
type: "json-rpc"
|
|
424
|
-
};
|
|
425
|
-
return {
|
|
426
|
-
provider: "privy",
|
|
427
|
-
account,
|
|
428
|
-
address: account.address,
|
|
429
|
-
privy: {
|
|
430
|
-
appId,
|
|
431
|
-
walletId,
|
|
432
|
-
apiUrl,
|
|
433
|
-
client
|
|
434
|
-
}
|
|
435
|
-
};
|
|
436
|
-
}
|
|
437
|
-
|
|
438
74
|
// src/resolve-signer.ts
|
|
439
75
|
function hasPrivyConfig(opts) {
|
|
440
76
|
return opts.privyAppId !== void 0 || opts.privyWalletId !== void 0 || opts.privyAuthorizationKey !== void 0;
|
|
@@ -456,12 +92,13 @@ async function resolveSigner(opts) {
|
|
|
456
92
|
});
|
|
457
93
|
}
|
|
458
94
|
if (opts.privy === true || hasPrivyConfig(opts)) {
|
|
459
|
-
|
|
95
|
+
const privySigner = await createPrivySigner({
|
|
460
96
|
...opts.privyAppId !== void 0 ? { privyAppId: opts.privyAppId } : {},
|
|
461
97
|
...opts.privyWalletId !== void 0 ? { privyWalletId: opts.privyWalletId } : {},
|
|
462
98
|
...opts.privyAuthorizationKey !== void 0 ? { privyAuthorizationKey: opts.privyAuthorizationKey } : {},
|
|
463
99
|
...opts.privyApiUrl !== void 0 ? { privyApiUrl: opts.privyApiUrl } : {}
|
|
464
100
|
});
|
|
101
|
+
return privySigner;
|
|
465
102
|
}
|
|
466
103
|
throw new TxError(
|
|
467
104
|
"SIGNER_NOT_CONFIGURED",
|
|
@@ -504,20 +141,27 @@ function toSignerOptions(flags, env) {
|
|
|
504
141
|
export {
|
|
505
142
|
TxError,
|
|
506
143
|
abstractMainnet,
|
|
144
|
+
attachPrivyPolicyContext,
|
|
507
145
|
createAbstractClient,
|
|
508
146
|
createKeystoreSigner,
|
|
509
147
|
createPrivateKeySigner,
|
|
148
|
+
createPrivyAccount,
|
|
510
149
|
createPrivyAuthorizationPayload,
|
|
511
150
|
createPrivyClient,
|
|
512
151
|
createPrivySigner,
|
|
513
152
|
executeTx,
|
|
153
|
+
fetchPrivyPolicyVisibility,
|
|
514
154
|
generatePrivyAuthorizationSignature,
|
|
155
|
+
getPrivyPolicyContext,
|
|
515
156
|
normalizePrivyApiUrl,
|
|
157
|
+
normalizePrivyPolicy,
|
|
516
158
|
parsePrivyAuthorizationKey,
|
|
159
|
+
preflightPrivyTransactionPolicy,
|
|
517
160
|
resolveSigner,
|
|
518
161
|
serializePrivyAuthorizationPayload,
|
|
519
162
|
signerEnvSchema,
|
|
520
163
|
signerFlagSchema,
|
|
164
|
+
toPrivyPolicyViolationError,
|
|
521
165
|
toSignerOptions,
|
|
522
166
|
toTxError
|
|
523
167
|
};
|
package/package.json
CHANGED
package/dist/chunk-4XI6TBKX.js
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
TxError
|
|
3
|
-
} from "./chunk-6T4D5UCR.js";
|
|
4
|
-
|
|
5
|
-
// src/execute-tx.ts
|
|
6
|
-
async function executeTx(options) {
|
|
7
|
-
const {
|
|
8
|
-
publicClient,
|
|
9
|
-
walletClient,
|
|
10
|
-
account,
|
|
11
|
-
address,
|
|
12
|
-
abi,
|
|
13
|
-
functionName,
|
|
14
|
-
chain,
|
|
15
|
-
args,
|
|
16
|
-
value,
|
|
17
|
-
gasLimit,
|
|
18
|
-
maxFeePerGas,
|
|
19
|
-
nonce,
|
|
20
|
-
dryRun = false
|
|
21
|
-
} = options;
|
|
22
|
-
let estimatedGas;
|
|
23
|
-
try {
|
|
24
|
-
estimatedGas = await publicClient.estimateContractGas({
|
|
25
|
-
account,
|
|
26
|
-
address,
|
|
27
|
-
abi,
|
|
28
|
-
functionName,
|
|
29
|
-
args,
|
|
30
|
-
value
|
|
31
|
-
});
|
|
32
|
-
} catch (error) {
|
|
33
|
-
throw mapError(error, "estimation");
|
|
34
|
-
}
|
|
35
|
-
let simulationResult;
|
|
36
|
-
try {
|
|
37
|
-
const sim = await publicClient.simulateContract({
|
|
38
|
-
account,
|
|
39
|
-
address,
|
|
40
|
-
abi,
|
|
41
|
-
functionName,
|
|
42
|
-
args,
|
|
43
|
-
value
|
|
44
|
-
});
|
|
45
|
-
simulationResult = sim.result;
|
|
46
|
-
} catch (error) {
|
|
47
|
-
throw mapError(error, "simulation");
|
|
48
|
-
}
|
|
49
|
-
if (dryRun) {
|
|
50
|
-
return {
|
|
51
|
-
status: "dry-run",
|
|
52
|
-
estimatedGas,
|
|
53
|
-
simulationResult
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
let hash;
|
|
57
|
-
try {
|
|
58
|
-
hash = await walletClient.writeContract({
|
|
59
|
-
account,
|
|
60
|
-
address,
|
|
61
|
-
abi,
|
|
62
|
-
functionName,
|
|
63
|
-
args,
|
|
64
|
-
value,
|
|
65
|
-
chain,
|
|
66
|
-
gas: gasLimit ?? estimatedGas,
|
|
67
|
-
maxFeePerGas,
|
|
68
|
-
nonce
|
|
69
|
-
});
|
|
70
|
-
} catch (error) {
|
|
71
|
-
throw mapError(error, "submit");
|
|
72
|
-
}
|
|
73
|
-
let receipt;
|
|
74
|
-
try {
|
|
75
|
-
receipt = await publicClient.waitForTransactionReceipt({ hash });
|
|
76
|
-
} catch (error) {
|
|
77
|
-
throw mapError(error, "receipt");
|
|
78
|
-
}
|
|
79
|
-
if (receipt.status === "reverted") {
|
|
80
|
-
throw new TxError("TX_REVERTED", `Transaction ${hash} reverted on-chain`);
|
|
81
|
-
}
|
|
82
|
-
return receiptToTxResult(receipt);
|
|
83
|
-
}
|
|
84
|
-
function receiptToTxResult(receipt) {
|
|
85
|
-
return {
|
|
86
|
-
hash: receipt.transactionHash,
|
|
87
|
-
blockNumber: receipt.blockNumber,
|
|
88
|
-
gasUsed: receipt.gasUsed,
|
|
89
|
-
status: receipt.status === "success" ? "success" : "reverted",
|
|
90
|
-
from: receipt.from,
|
|
91
|
-
to: receipt.to,
|
|
92
|
-
effectiveGasPrice: receipt.effectiveGasPrice
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
function mapError(error, phase) {
|
|
96
|
-
const msg = errorMessage(error);
|
|
97
|
-
if (matchesInsufficientFunds(msg)) {
|
|
98
|
-
return new TxError("INSUFFICIENT_FUNDS", `Insufficient funds: ${msg}`, error);
|
|
99
|
-
}
|
|
100
|
-
if (matchesNonceConflict(msg)) {
|
|
101
|
-
return new TxError("NONCE_CONFLICT", `Nonce conflict: ${msg}`, error);
|
|
102
|
-
}
|
|
103
|
-
if (phase === "estimation" || phase === "simulation") {
|
|
104
|
-
return new TxError("GAS_ESTIMATION_FAILED", `Gas estimation/simulation failed: ${msg}`, error);
|
|
105
|
-
}
|
|
106
|
-
if (matchesRevert(msg)) {
|
|
107
|
-
return new TxError("TX_REVERTED", `Transaction reverted: ${msg}`, error);
|
|
108
|
-
}
|
|
109
|
-
return new TxError("TX_REVERTED", `Transaction failed (${phase}): ${msg}`, error);
|
|
110
|
-
}
|
|
111
|
-
function errorMessage(error) {
|
|
112
|
-
if (error instanceof Error) return error.message;
|
|
113
|
-
return String(error);
|
|
114
|
-
}
|
|
115
|
-
function matchesInsufficientFunds(msg) {
|
|
116
|
-
const lower = msg.toLowerCase();
|
|
117
|
-
return lower.includes("insufficient funds") || lower.includes("insufficient balance") || lower.includes("sender doesn't have enough funds");
|
|
118
|
-
}
|
|
119
|
-
function matchesNonceConflict(msg) {
|
|
120
|
-
const lower = msg.toLowerCase();
|
|
121
|
-
return lower.includes("nonce too low") || lower.includes("nonce has already been used") || lower.includes("already known") || lower.includes("replacement transaction underpriced");
|
|
122
|
-
}
|
|
123
|
-
function matchesRevert(msg) {
|
|
124
|
-
const lower = msg.toLowerCase();
|
|
125
|
-
return lower.includes("revert") || lower.includes("execution reverted") || lower.includes("transaction failed");
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export {
|
|
129
|
-
executeTx
|
|
130
|
-
};
|