@opensea/wallet-adapters 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,3 +1,145 @@
1
+ // src/adapters/bankr.ts
2
+ var BANKR_API_BASE = "https://api.bankr.bot";
3
+ var BankrAdapter = class _BankrAdapter {
4
+ name = "bankr";
5
+ capabilities = {
6
+ signMessage: true,
7
+ signTypedData: true,
8
+ managedGas: true,
9
+ managedNonce: true
10
+ };
11
+ onRequest;
12
+ onResponse;
13
+ config;
14
+ cachedAddress;
15
+ constructor(config) {
16
+ this.config = config;
17
+ }
18
+ static fromEnv() {
19
+ const apiKey = process.env.BANKR_API_KEY;
20
+ if (!apiKey) {
21
+ throw new Error("BANKR_API_KEY environment variable is required");
22
+ }
23
+ return new _BankrAdapter({
24
+ apiKey,
25
+ baseUrl: process.env.BANKR_API_BASE_URL
26
+ });
27
+ }
28
+ get baseUrl() {
29
+ return this.config.baseUrl ?? BANKR_API_BASE;
30
+ }
31
+ get authHeaders() {
32
+ return {
33
+ "X-API-Key": this.config.apiKey,
34
+ "Content-Type": "application/json"
35
+ };
36
+ }
37
+ async getAddress() {
38
+ if (this.cachedAddress) return this.cachedAddress;
39
+ const response = await fetch(`${this.baseUrl}/wallet/me`, {
40
+ headers: this.authHeaders
41
+ });
42
+ if (!response.ok) {
43
+ const body = await response.text();
44
+ throw new Error(`Bankr getAddress failed (${response.status}): ${body}`);
45
+ }
46
+ const data = await response.json();
47
+ const evmWallet = data.wallets.find((w) => w.chain === "evm");
48
+ if (!evmWallet) {
49
+ throw new Error("Bankr wallet has no EVM address");
50
+ }
51
+ this.cachedAddress = evmWallet.address;
52
+ return evmWallet.address;
53
+ }
54
+ async getWalletInfo() {
55
+ const address = await this.getAddress();
56
+ return {
57
+ provider: "bankr",
58
+ address,
59
+ scopeIntrospectable: false
60
+ };
61
+ }
62
+ async sendTransaction(tx) {
63
+ this.onRequest?.("sendTransaction", tx);
64
+ const startTime = Date.now();
65
+ const transaction = {
66
+ to: tx.to,
67
+ data: tx.data,
68
+ value: tx.value,
69
+ chainId: tx.chainId
70
+ };
71
+ if (tx.gas) transaction.gas = tx.gas;
72
+ if (tx.nonce !== void 0) transaction.nonce = tx.nonce;
73
+ if (tx.maxFeePerGas) transaction.maxFeePerGas = tx.maxFeePerGas;
74
+ if (tx.maxPriorityFeePerGas)
75
+ transaction.maxPriorityFeePerGas = tx.maxPriorityFeePerGas;
76
+ const response = await fetch(`${this.baseUrl}/wallet/submit`, {
77
+ method: "POST",
78
+ headers: this.authHeaders,
79
+ body: JSON.stringify({
80
+ transaction,
81
+ waitForConfirmation: true
82
+ })
83
+ });
84
+ if (!response.ok) {
85
+ const body = await response.text();
86
+ throw new Error(
87
+ `Bankr sendTransaction failed (${response.status}): ${body}`
88
+ );
89
+ }
90
+ const data = await response.json();
91
+ const result = { hash: data.transactionHash };
92
+ this.onResponse?.("sendTransaction", result, Date.now() - startTime);
93
+ return result;
94
+ }
95
+ async signMessage(request) {
96
+ this.onRequest?.("signMessage", request);
97
+ const startTime = Date.now();
98
+ const message = typeof request.message === "string" ? request.message : `0x${Buffer.from(request.message).toString("hex")}`;
99
+ const response = await fetch(`${this.baseUrl}/wallet/sign`, {
100
+ method: "POST",
101
+ headers: this.authHeaders,
102
+ body: JSON.stringify({
103
+ signatureType: "personal_sign",
104
+ message
105
+ })
106
+ });
107
+ if (!response.ok) {
108
+ const body = await response.text();
109
+ throw new Error(`Bankr signMessage failed (${response.status}): ${body}`);
110
+ }
111
+ const data = await response.json();
112
+ this.onResponse?.("signMessage", data.signature, Date.now() - startTime);
113
+ return data.signature;
114
+ }
115
+ async signTypedData(request) {
116
+ this.onRequest?.("signTypedData", request);
117
+ const startTime = Date.now();
118
+ const response = await fetch(`${this.baseUrl}/wallet/sign`, {
119
+ method: "POST",
120
+ headers: this.authHeaders,
121
+ body: JSON.stringify({
122
+ signatureType: "eth_signTypedData_v4",
123
+ typedData: {
124
+ domain: request.domain,
125
+ types: request.types,
126
+ primaryType: request.primaryType,
127
+ message: request.message
128
+ }
129
+ })
130
+ });
131
+ if (!response.ok) {
132
+ const body = await response.text();
133
+ throw new Error(
134
+ `Bankr signTypedData failed (${response.status}): ${body}`
135
+ );
136
+ }
137
+ const data = await response.json();
138
+ this.onResponse?.("signTypedData", data.signature, Date.now() - startTime);
139
+ return data.signature;
140
+ }
141
+ };
142
+
1
143
  // src/util/eip712.ts
2
144
  import { keccak_256 } from "@noble/hashes/sha3.js";
3
145
  function hashTypedData(domain, primaryType, message, types) {
@@ -143,7 +285,7 @@ function hexToBytes(hex) {
143
285
  return bytes;
144
286
  }
145
287
 
146
- // src/adapters/fireblocks.ts
288
+ // src/adapters/fireblocks.generated.ts
147
289
  var CHAIN_TO_FIREBLOCKS_ASSET = {
148
290
  1: "ETH",
149
291
  10: "ETH-OPT",
@@ -161,6 +303,8 @@ var CHAIN_TO_FIREBLOCKS_ASSET = {
161
303
  81457: "BLAST_ETH",
162
304
  7777777: "ZORA_ETH"
163
305
  };
306
+
307
+ // src/adapters/fireblocks.ts
164
308
  var FIREBLOCKS_API_BASE = "https://api.fireblocks.io";
165
309
  var FireblocksAdapter = class _FireblocksAdapter {
166
310
  name = "fireblocks";
@@ -277,6 +421,15 @@ var FireblocksAdapter = class _FireblocksAdapter {
277
421
  this.cachedAddress = data[0].address;
278
422
  return data[0].address;
279
423
  }
424
+ async getWalletInfo() {
425
+ const address = await this.getAddress();
426
+ return {
427
+ provider: "fireblocks",
428
+ address,
429
+ vaultId: this.config.vaultId,
430
+ roleIntrospectable: false
431
+ };
432
+ }
280
433
  async sendTransaction(tx) {
281
434
  this.onRequest?.("sendTransaction", tx);
282
435
  const startTime = Date.now();
@@ -567,6 +720,38 @@ var TurnkeyAdapter = class _TurnkeyAdapter {
567
720
  async getAddress() {
568
721
  return this.config.walletAddress;
569
722
  }
723
+ async getWalletInfo() {
724
+ const whoamiResponse = await this.signedRequest("/public/v1/query/whoami", {
725
+ organizationId: this.config.organizationId
726
+ });
727
+ if (!whoamiResponse.ok) {
728
+ const body = await whoamiResponse.text();
729
+ throw new Error(
730
+ `Turnkey getWalletInfo whoami failed (${whoamiResponse.status}): ${body}`
731
+ );
732
+ }
733
+ const whoami = await whoamiResponse.json();
734
+ const orgResponse = await this.signedRequest(
735
+ "/public/v1/query/get_organization",
736
+ { organizationId: this.config.organizationId }
737
+ );
738
+ if (!orgResponse.ok) {
739
+ const body = await orgResponse.text();
740
+ throw new Error(
741
+ `Turnkey getWalletInfo get_organization failed (${orgResponse.status}): ${body}`
742
+ );
743
+ }
744
+ const orgData = await orgResponse.json();
745
+ const rootUserIds = orgData.organizationData?.rootQuorum?.userIds ?? [];
746
+ return {
747
+ provider: "turnkey",
748
+ address: this.config.walletAddress,
749
+ organizationId: whoami.organizationId,
750
+ userId: whoami.userId,
751
+ username: whoami.username ?? "",
752
+ isRootUser: rootUserIds.includes(whoami.userId)
753
+ };
754
+ }
570
755
  async sendTransaction(tx) {
571
756
  this.onRequest?.("sendTransaction", tx);
572
757
  const startTime = Date.now();
@@ -1154,6 +1339,7 @@ function encodeEcdsaSignature(r, s, v) {
1154
1339
 
1155
1340
  // src/adapters/privy.ts
1156
1341
  var PRIVY_API_BASE = "https://api.privy.io";
1342
+ var PRIVY_401_ECHO_HINT = ` (hint: if you're verifying credentials via curl, use 'printf %s "$PRIVY_APP_ID:$PRIVY_APP_SECRET" | base64' \u2014 'echo' adds a trailing newline that breaks basic auth)`;
1157
1343
  var PrivyAdapter = class _PrivyAdapter {
1158
1344
  name = "privy";
1159
1345
  capabilities = {
@@ -1186,13 +1372,14 @@ var PrivyAdapter = class _PrivyAdapter {
1186
1372
  appId,
1187
1373
  appSecret,
1188
1374
  walletId,
1189
- baseUrl: process.env.PRIVY_API_BASE_URL
1375
+ baseUrl: process.env.PRIVY_API_BASE_URL,
1376
+ authSigningKey: process.env.PRIVY_AUTH_SIGNING_KEY
1190
1377
  });
1191
1378
  }
1192
1379
  get baseUrl() {
1193
1380
  return this.config.baseUrl ?? PRIVY_API_BASE;
1194
1381
  }
1195
- get authHeaders() {
1382
+ get basicAuthHeaders() {
1196
1383
  const credentials = Buffer.from(
1197
1384
  `${this.config.appId}:${this.config.appSecret}`
1198
1385
  ).toString("base64");
@@ -1202,46 +1389,105 @@ var PrivyAdapter = class _PrivyAdapter {
1202
1389
  "Content-Type": "application/json"
1203
1390
  };
1204
1391
  }
1392
+ /**
1393
+ * Build headers for a POST /rpc call, including the authorization
1394
+ * signature when `authSigningKey` is configured. Lazy-imports
1395
+ * `@privy-io/node` so users who don't enable auth-key signing don't
1396
+ * need the optional peer dependency installed.
1397
+ */
1398
+ async rpcHeaders(body, rpcUrl) {
1399
+ const headers = { ...this.basicAuthHeaders };
1400
+ if (!this.config.authSigningKey) return headers;
1401
+ let generateAuthorizationSignature;
1402
+ try {
1403
+ ;
1404
+ ({ generateAuthorizationSignature } = await import("@privy-io/node"));
1405
+ } catch (cause) {
1406
+ throw new Error(
1407
+ "PRIVY_AUTH_SIGNING_KEY is set but @privy-io/node is not installed. Install it with `pnpm add @privy-io/node` (or your package manager equivalent).",
1408
+ { cause }
1409
+ );
1410
+ }
1411
+ const signature = generateAuthorizationSignature({
1412
+ authorizationPrivateKey: this.config.authSigningKey,
1413
+ input: {
1414
+ version: 1,
1415
+ method: "POST",
1416
+ url: rpcUrl,
1417
+ body,
1418
+ headers: { "privy-app-id": this.config.appId }
1419
+ }
1420
+ });
1421
+ headers["privy-authorization-signature"] = signature;
1422
+ return headers;
1423
+ }
1205
1424
  async getAddress() {
1206
1425
  if (this.cachedAddress) return this.cachedAddress;
1207
1426
  const response = await fetch(
1208
1427
  `${this.baseUrl}/v1/wallets/${this.config.walletId}`,
1209
- { headers: this.authHeaders }
1428
+ { headers: this.basicAuthHeaders }
1210
1429
  );
1211
1430
  if (!response.ok) {
1212
1431
  const body = await response.text();
1213
- throw new Error(`Privy getAddress failed (${response.status}): ${body}`);
1432
+ const hint = response.status === 401 && body.includes("Invalid app ID or app secret") ? PRIVY_401_ECHO_HINT : "";
1433
+ throw new Error(
1434
+ `Privy getAddress failed (${response.status}): ${body}${hint}`
1435
+ );
1214
1436
  }
1215
1437
  const data = await response.json();
1216
1438
  this.cachedAddress = data.address;
1217
1439
  return data.address;
1218
1440
  }
1441
+ async getWalletInfo() {
1442
+ const response = await fetch(
1443
+ `${this.baseUrl}/v1/wallets/${this.config.walletId}`,
1444
+ { headers: this.basicAuthHeaders }
1445
+ );
1446
+ if (!response.ok) {
1447
+ const body = await response.text();
1448
+ const hint = response.status === 401 && body.includes("Invalid app ID or app secret") ? PRIVY_401_ECHO_HINT : "";
1449
+ throw new Error(
1450
+ `Privy getWalletInfo failed (${response.status}): ${body}${hint}`
1451
+ );
1452
+ }
1453
+ const data = await response.json();
1454
+ this.cachedAddress = data.address;
1455
+ const ownerKeyId = data.owner_id ?? null;
1456
+ return {
1457
+ provider: "privy",
1458
+ address: data.address,
1459
+ chainType: data.chain_type,
1460
+ policyIds: data.policy_ids ?? [],
1461
+ ownerKeyId,
1462
+ additionalSignerCount: data.additional_signers?.length ?? 0,
1463
+ ownerEnforcesAuthKey: ownerKeyId !== null
1464
+ };
1465
+ }
1219
1466
  async sendTransaction(tx) {
1220
1467
  this.onRequest?.("sendTransaction", tx);
1221
1468
  const startTime = Date.now();
1222
1469
  const caip2 = `eip155:${tx.chainId}`;
1223
- const response = await fetch(
1224
- `${this.baseUrl}/v1/wallets/${this.config.walletId}/rpc`,
1225
- {
1226
- method: "POST",
1227
- headers: this.authHeaders,
1228
- body: JSON.stringify({
1229
- method: "eth_sendTransaction",
1230
- caip2,
1231
- params: {
1232
- transaction: {
1233
- to: tx.to,
1234
- data: tx.data,
1235
- value: tx.value
1236
- }
1237
- }
1238
- })
1470
+ const rpcUrl = `${this.baseUrl}/v1/wallets/${this.config.walletId}/rpc`;
1471
+ const body = {
1472
+ method: "eth_sendTransaction",
1473
+ caip2,
1474
+ params: {
1475
+ transaction: {
1476
+ to: tx.to,
1477
+ data: tx.data,
1478
+ value: tx.value
1479
+ }
1239
1480
  }
1240
- );
1481
+ };
1482
+ const response = await fetch(rpcUrl, {
1483
+ method: "POST",
1484
+ headers: await this.rpcHeaders(body, rpcUrl),
1485
+ body: JSON.stringify(body)
1486
+ });
1241
1487
  if (!response.ok) {
1242
- const body = await response.text();
1488
+ const responseBody = await response.text();
1243
1489
  throw new Error(
1244
- `Privy sendTransaction failed (${response.status}): ${body}`
1490
+ `Privy sendTransaction failed (${response.status}): ${responseBody}`
1245
1491
  );
1246
1492
  }
1247
1493
  const data = await response.json();
@@ -1252,21 +1498,23 @@ var PrivyAdapter = class _PrivyAdapter {
1252
1498
  async signMessage(request) {
1253
1499
  this.onRequest?.("signMessage", request);
1254
1500
  const startTime = Date.now();
1255
- const message = typeof request.message === "string" ? request.message : `0x${Buffer.from(request.message).toString("hex")}`;
1256
- const response = await fetch(
1257
- `${this.baseUrl}/v1/wallets/${this.config.walletId}/rpc`,
1258
- {
1259
- method: "POST",
1260
- headers: this.authHeaders,
1261
- body: JSON.stringify({
1262
- method: "personal_sign",
1263
- params: { message }
1264
- })
1265
- }
1266
- );
1501
+ const isBytes = typeof request.message !== "string";
1502
+ const message = isBytes ? `0x${Buffer.from(request.message).toString("hex")}` : request.message;
1503
+ const rpcUrl = `${this.baseUrl}/v1/wallets/${this.config.walletId}/rpc`;
1504
+ const body = {
1505
+ method: "personal_sign",
1506
+ params: { message, encoding: isBytes ? "hex" : "utf-8" }
1507
+ };
1508
+ const response = await fetch(rpcUrl, {
1509
+ method: "POST",
1510
+ headers: await this.rpcHeaders(body, rpcUrl),
1511
+ body: JSON.stringify(body)
1512
+ });
1267
1513
  if (!response.ok) {
1268
- const body = await response.text();
1269
- throw new Error(`Privy signMessage failed (${response.status}): ${body}`);
1514
+ const responseBody = await response.text();
1515
+ throw new Error(
1516
+ `Privy signMessage failed (${response.status}): ${responseBody}`
1517
+ );
1270
1518
  }
1271
1519
  const data = await response.json();
1272
1520
  this.onResponse?.(
@@ -1279,28 +1527,27 @@ var PrivyAdapter = class _PrivyAdapter {
1279
1527
  async signTypedData(request) {
1280
1528
  this.onRequest?.("signTypedData", request);
1281
1529
  const startTime = Date.now();
1282
- const response = await fetch(
1283
- `${this.baseUrl}/v1/wallets/${this.config.walletId}/rpc`,
1284
- {
1285
- method: "POST",
1286
- headers: this.authHeaders,
1287
- body: JSON.stringify({
1288
- method: "eth_signTypedData_v4",
1289
- params: {
1290
- typedData: JSON.stringify({
1291
- domain: request.domain,
1292
- types: request.types,
1293
- primaryType: request.primaryType,
1294
- message: request.message
1295
- })
1296
- }
1530
+ const rpcUrl = `${this.baseUrl}/v1/wallets/${this.config.walletId}/rpc`;
1531
+ const body = {
1532
+ method: "eth_signTypedData_v4",
1533
+ params: {
1534
+ typedData: JSON.stringify({
1535
+ domain: request.domain,
1536
+ types: request.types,
1537
+ primaryType: request.primaryType,
1538
+ message: request.message
1297
1539
  })
1298
1540
  }
1299
- );
1541
+ };
1542
+ const response = await fetch(rpcUrl, {
1543
+ method: "POST",
1544
+ headers: await this.rpcHeaders(body, rpcUrl),
1545
+ body: JSON.stringify(body)
1546
+ });
1300
1547
  if (!response.ok) {
1301
- const body = await response.text();
1548
+ const responseBody = await response.text();
1302
1549
  throw new Error(
1303
- `Privy signTypedData failed (${response.status}): ${body}`
1550
+ `Privy signTypedData failed (${response.status}): ${responseBody}`
1304
1551
  );
1305
1552
  }
1306
1553
  const data = await response.json();
@@ -1324,15 +1571,20 @@ function createWalletFromEnv() {
1324
1571
  if (process.env.TURNKEY_API_PUBLIC_KEY && process.env.TURNKEY_WALLET_ADDRESS) {
1325
1572
  return TurnkeyAdapter.fromEnv();
1326
1573
  }
1574
+ if (process.env.BANKR_API_KEY) {
1575
+ return BankrAdapter.fromEnv();
1576
+ }
1327
1577
  if (process.env.PRIVATE_KEY) {
1328
1578
  return PrivateKeyAdapter.fromEnv();
1329
1579
  }
1330
1580
  throw new Error(
1331
- "No wallet provider configured. Set environment variables for one of:\n \u2022 Privy: PRIVY_APP_ID, PRIVY_APP_SECRET, PRIVY_WALLET_ID\n \u2022 Fireblocks: FIREBLOCKS_API_KEY, FIREBLOCKS_API_SECRET, FIREBLOCKS_VAULT_ID\n \u2022 Turnkey: TURNKEY_API_PUBLIC_KEY, TURNKEY_API_PRIVATE_KEY, TURNKEY_ORGANIZATION_ID, TURNKEY_WALLET_ADDRESS, TURNKEY_RPC_URL\n \u2022 PrivateKey: PRIVATE_KEY, RPC_URL"
1581
+ "No wallet provider configured. Set environment variables for one of:\n \u2022 Privy: PRIVY_APP_ID, PRIVY_APP_SECRET, PRIVY_WALLET_ID\n \u2022 Fireblocks: FIREBLOCKS_API_KEY, FIREBLOCKS_API_SECRET, FIREBLOCKS_VAULT_ID\n \u2022 Turnkey: TURNKEY_API_PUBLIC_KEY, TURNKEY_API_PRIVATE_KEY, TURNKEY_ORGANIZATION_ID, TURNKEY_WALLET_ADDRESS, TURNKEY_RPC_URL\n \u2022 Bankr: BANKR_API_KEY\n \u2022 PrivateKey: PRIVATE_KEY, RPC_URL"
1332
1582
  );
1333
1583
  }
1334
1584
  function createWalletForProvider(provider) {
1335
1585
  switch (provider) {
1586
+ case "bankr":
1587
+ return BankrAdapter.fromEnv();
1336
1588
  case "privy":
1337
1589
  return PrivyAdapter.fromEnv();
1338
1590
  case "fireblocks":
@@ -1351,6 +1603,7 @@ function detectProvider() {
1351
1603
  return "fireblocks";
1352
1604
  if (process.env.TURNKEY_API_PUBLIC_KEY && process.env.TURNKEY_WALLET_ADDRESS)
1353
1605
  return "turnkey";
1606
+ if (process.env.BANKR_API_KEY) return "bankr";
1354
1607
  if (process.env.PRIVATE_KEY) return "private-key";
1355
1608
  return null;
1356
1609
  }
@@ -1360,9 +1613,11 @@ var WALLET_PROVIDERS = [
1360
1613
  "privy",
1361
1614
  "turnkey",
1362
1615
  "fireblocks",
1616
+ "bankr",
1363
1617
  "private-key"
1364
1618
  ];
1365
1619
  export {
1620
+ BankrAdapter,
1366
1621
  CHAIN_TO_FIREBLOCKS_ASSET,
1367
1622
  FireblocksAdapter,
1368
1623
  PrivateKeyAdapter,