@opensea/wallet-adapters 0.2.1 → 0.3.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/dist/index.js CHANGED
@@ -51,6 +51,14 @@ var BankrAdapter = class _BankrAdapter {
51
51
  this.cachedAddress = evmWallet.address;
52
52
  return evmWallet.address;
53
53
  }
54
+ async getWalletInfo() {
55
+ const address = await this.getAddress();
56
+ return {
57
+ provider: "bankr",
58
+ address,
59
+ scopeIntrospectable: false
60
+ };
61
+ }
54
62
  async sendTransaction(tx) {
55
63
  this.onRequest?.("sendTransaction", tx);
56
64
  const startTime = Date.now();
@@ -413,6 +421,15 @@ var FireblocksAdapter = class _FireblocksAdapter {
413
421
  this.cachedAddress = data[0].address;
414
422
  return data[0].address;
415
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
+ }
416
433
  async sendTransaction(tx) {
417
434
  this.onRequest?.("sendTransaction", tx);
418
435
  const startTime = Date.now();
@@ -703,6 +720,38 @@ var TurnkeyAdapter = class _TurnkeyAdapter {
703
720
  async getAddress() {
704
721
  return this.config.walletAddress;
705
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
+ }
706
755
  async sendTransaction(tx) {
707
756
  this.onRequest?.("sendTransaction", tx);
708
757
  const startTime = Date.now();
@@ -1072,9 +1121,6 @@ var PrivateKeyAdapter = class _PrivateKeyAdapter {
1072
1121
  if (!privateKey) {
1073
1122
  throw new Error("PRIVATE_KEY environment variable is required");
1074
1123
  }
1075
- if (!rpcUrl) {
1076
- throw new Error("RPC_URL environment variable is required");
1077
- }
1078
1124
  const clean = privateKey.startsWith("0x") ? privateKey.slice(2) : privateKey;
1079
1125
  if (!/^[0-9a-fA-F]{64}$/.test(clean)) {
1080
1126
  throw new Error(
@@ -1102,7 +1148,12 @@ var PrivateKeyAdapter = class _PrivateKeyAdapter {
1102
1148
  this.onRequest?.("sendTransaction", tx);
1103
1149
  const startTime = Date.now();
1104
1150
  const from = await this.getAddress();
1105
- const { rpcUrl } = this.config;
1151
+ const rpcUrl = this.config.rpcUrl;
1152
+ if (!rpcUrl) {
1153
+ throw new Error(
1154
+ "RPC_URL is required for sending transactions. Set the RPC_URL environment variable or pass --rpc-url."
1155
+ );
1156
+ }
1106
1157
  let nonce;
1107
1158
  let gasLimit;
1108
1159
  let maxFeePerGas;
@@ -1290,6 +1341,7 @@ function encodeEcdsaSignature(r, s, v) {
1290
1341
 
1291
1342
  // src/adapters/privy.ts
1292
1343
  var PRIVY_API_BASE = "https://api.privy.io";
1344
+ 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)`;
1293
1345
  var PrivyAdapter = class _PrivyAdapter {
1294
1346
  name = "privy";
1295
1347
  capabilities = {
@@ -1322,13 +1374,14 @@ var PrivyAdapter = class _PrivyAdapter {
1322
1374
  appId,
1323
1375
  appSecret,
1324
1376
  walletId,
1325
- baseUrl: process.env.PRIVY_API_BASE_URL
1377
+ baseUrl: process.env.PRIVY_API_BASE_URL,
1378
+ authSigningKey: process.env.PRIVY_AUTH_SIGNING_KEY
1326
1379
  });
1327
1380
  }
1328
1381
  get baseUrl() {
1329
1382
  return this.config.baseUrl ?? PRIVY_API_BASE;
1330
1383
  }
1331
- get authHeaders() {
1384
+ get basicAuthHeaders() {
1332
1385
  const credentials = Buffer.from(
1333
1386
  `${this.config.appId}:${this.config.appSecret}`
1334
1387
  ).toString("base64");
@@ -1338,46 +1391,105 @@ var PrivyAdapter = class _PrivyAdapter {
1338
1391
  "Content-Type": "application/json"
1339
1392
  };
1340
1393
  }
1394
+ /**
1395
+ * Build headers for a POST /rpc call, including the authorization
1396
+ * signature when `authSigningKey` is configured. Lazy-imports
1397
+ * `@privy-io/node` so users who don't enable auth-key signing don't
1398
+ * need the optional peer dependency installed.
1399
+ */
1400
+ async rpcHeaders(body, rpcUrl) {
1401
+ const headers = { ...this.basicAuthHeaders };
1402
+ if (!this.config.authSigningKey) return headers;
1403
+ let generateAuthorizationSignature;
1404
+ try {
1405
+ ;
1406
+ ({ generateAuthorizationSignature } = await import("@privy-io/node"));
1407
+ } catch (cause) {
1408
+ throw new Error(
1409
+ "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).",
1410
+ { cause }
1411
+ );
1412
+ }
1413
+ const signature = generateAuthorizationSignature({
1414
+ authorizationPrivateKey: this.config.authSigningKey,
1415
+ input: {
1416
+ version: 1,
1417
+ method: "POST",
1418
+ url: rpcUrl,
1419
+ body,
1420
+ headers: { "privy-app-id": this.config.appId }
1421
+ }
1422
+ });
1423
+ headers["privy-authorization-signature"] = signature;
1424
+ return headers;
1425
+ }
1341
1426
  async getAddress() {
1342
1427
  if (this.cachedAddress) return this.cachedAddress;
1343
1428
  const response = await fetch(
1344
1429
  `${this.baseUrl}/v1/wallets/${this.config.walletId}`,
1345
- { headers: this.authHeaders }
1430
+ { headers: this.basicAuthHeaders }
1346
1431
  );
1347
1432
  if (!response.ok) {
1348
1433
  const body = await response.text();
1349
- throw new Error(`Privy getAddress failed (${response.status}): ${body}`);
1434
+ const hint = response.status === 401 && body.includes("Invalid app ID or app secret") ? PRIVY_401_ECHO_HINT : "";
1435
+ throw new Error(
1436
+ `Privy getAddress failed (${response.status}): ${body}${hint}`
1437
+ );
1350
1438
  }
1351
1439
  const data = await response.json();
1352
1440
  this.cachedAddress = data.address;
1353
1441
  return data.address;
1354
1442
  }
1443
+ async getWalletInfo() {
1444
+ const response = await fetch(
1445
+ `${this.baseUrl}/v1/wallets/${this.config.walletId}`,
1446
+ { headers: this.basicAuthHeaders }
1447
+ );
1448
+ if (!response.ok) {
1449
+ const body = await response.text();
1450
+ const hint = response.status === 401 && body.includes("Invalid app ID or app secret") ? PRIVY_401_ECHO_HINT : "";
1451
+ throw new Error(
1452
+ `Privy getWalletInfo failed (${response.status}): ${body}${hint}`
1453
+ );
1454
+ }
1455
+ const data = await response.json();
1456
+ this.cachedAddress = data.address;
1457
+ const ownerKeyId = data.owner_id ?? null;
1458
+ return {
1459
+ provider: "privy",
1460
+ address: data.address,
1461
+ chainType: data.chain_type,
1462
+ policyIds: data.policy_ids ?? [],
1463
+ ownerKeyId,
1464
+ additionalSignerCount: data.additional_signers?.length ?? 0,
1465
+ ownerEnforcesAuthKey: ownerKeyId !== null
1466
+ };
1467
+ }
1355
1468
  async sendTransaction(tx) {
1356
1469
  this.onRequest?.("sendTransaction", tx);
1357
1470
  const startTime = Date.now();
1358
1471
  const caip2 = `eip155:${tx.chainId}`;
1359
- const response = await fetch(
1360
- `${this.baseUrl}/v1/wallets/${this.config.walletId}/rpc`,
1361
- {
1362
- method: "POST",
1363
- headers: this.authHeaders,
1364
- body: JSON.stringify({
1365
- method: "eth_sendTransaction",
1366
- caip2,
1367
- params: {
1368
- transaction: {
1369
- to: tx.to,
1370
- data: tx.data,
1371
- value: tx.value
1372
- }
1373
- }
1374
- })
1472
+ const rpcUrl = `${this.baseUrl}/v1/wallets/${this.config.walletId}/rpc`;
1473
+ const body = {
1474
+ method: "eth_sendTransaction",
1475
+ caip2,
1476
+ params: {
1477
+ transaction: {
1478
+ to: tx.to,
1479
+ data: tx.data,
1480
+ value: tx.value
1481
+ }
1375
1482
  }
1376
- );
1483
+ };
1484
+ const response = await fetch(rpcUrl, {
1485
+ method: "POST",
1486
+ headers: await this.rpcHeaders(body, rpcUrl),
1487
+ body: JSON.stringify(body)
1488
+ });
1377
1489
  if (!response.ok) {
1378
- const body = await response.text();
1490
+ const responseBody = await response.text();
1379
1491
  throw new Error(
1380
- `Privy sendTransaction failed (${response.status}): ${body}`
1492
+ `Privy sendTransaction failed (${response.status}): ${responseBody}`
1381
1493
  );
1382
1494
  }
1383
1495
  const data = await response.json();
@@ -1388,21 +1500,23 @@ var PrivyAdapter = class _PrivyAdapter {
1388
1500
  async signMessage(request) {
1389
1501
  this.onRequest?.("signMessage", request);
1390
1502
  const startTime = Date.now();
1391
- const message = typeof request.message === "string" ? request.message : `0x${Buffer.from(request.message).toString("hex")}`;
1392
- const response = await fetch(
1393
- `${this.baseUrl}/v1/wallets/${this.config.walletId}/rpc`,
1394
- {
1395
- method: "POST",
1396
- headers: this.authHeaders,
1397
- body: JSON.stringify({
1398
- method: "personal_sign",
1399
- params: { message }
1400
- })
1401
- }
1402
- );
1503
+ const isBytes = typeof request.message !== "string";
1504
+ const message = isBytes ? `0x${Buffer.from(request.message).toString("hex")}` : request.message;
1505
+ const rpcUrl = `${this.baseUrl}/v1/wallets/${this.config.walletId}/rpc`;
1506
+ const body = {
1507
+ method: "personal_sign",
1508
+ params: { message, encoding: isBytes ? "hex" : "utf-8" }
1509
+ };
1510
+ const response = await fetch(rpcUrl, {
1511
+ method: "POST",
1512
+ headers: await this.rpcHeaders(body, rpcUrl),
1513
+ body: JSON.stringify(body)
1514
+ });
1403
1515
  if (!response.ok) {
1404
- const body = await response.text();
1405
- throw new Error(`Privy signMessage failed (${response.status}): ${body}`);
1516
+ const responseBody = await response.text();
1517
+ throw new Error(
1518
+ `Privy signMessage failed (${response.status}): ${responseBody}`
1519
+ );
1406
1520
  }
1407
1521
  const data = await response.json();
1408
1522
  this.onResponse?.(
@@ -1415,28 +1529,27 @@ var PrivyAdapter = class _PrivyAdapter {
1415
1529
  async signTypedData(request) {
1416
1530
  this.onRequest?.("signTypedData", request);
1417
1531
  const startTime = Date.now();
1418
- const response = await fetch(
1419
- `${this.baseUrl}/v1/wallets/${this.config.walletId}/rpc`,
1420
- {
1421
- method: "POST",
1422
- headers: this.authHeaders,
1423
- body: JSON.stringify({
1424
- method: "eth_signTypedData_v4",
1425
- params: {
1426
- typedData: JSON.stringify({
1427
- domain: request.domain,
1428
- types: request.types,
1429
- primaryType: request.primaryType,
1430
- message: request.message
1431
- })
1432
- }
1532
+ const rpcUrl = `${this.baseUrl}/v1/wallets/${this.config.walletId}/rpc`;
1533
+ const body = {
1534
+ method: "eth_signTypedData_v4",
1535
+ params: {
1536
+ typedData: JSON.stringify({
1537
+ domain: request.domain,
1538
+ types: request.types,
1539
+ primaryType: request.primaryType,
1540
+ message: request.message
1433
1541
  })
1434
1542
  }
1435
- );
1543
+ };
1544
+ const response = await fetch(rpcUrl, {
1545
+ method: "POST",
1546
+ headers: await this.rpcHeaders(body, rpcUrl),
1547
+ body: JSON.stringify(body)
1548
+ });
1436
1549
  if (!response.ok) {
1437
- const body = await response.text();
1550
+ const responseBody = await response.text();
1438
1551
  throw new Error(
1439
- `Privy signTypedData failed (${response.status}): ${body}`
1552
+ `Privy signTypedData failed (${response.status}): ${responseBody}`
1440
1553
  );
1441
1554
  }
1442
1555
  const data = await response.json();
@@ -1467,7 +1580,7 @@ function createWalletFromEnv() {
1467
1580
  return PrivateKeyAdapter.fromEnv();
1468
1581
  }
1469
1582
  throw new Error(
1470
- "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"
1583
+ "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 (optionally RPC_URL for sending transactions)"
1471
1584
  );
1472
1585
  }
1473
1586
  function createWalletForProvider(provider) {