@phantom/embedded-provider-core 1.0.0-beta.1 → 1.0.0-beta.3

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.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/embedded-provider.ts
2
2
  import { PhantomClient } from "@phantom/client";
3
3
  import { base64urlEncode } from "@phantom/base64url";
4
- import bs58 from "bs58";
4
+ import bs582 from "bs58";
5
5
  import {
6
6
  parseMessage,
7
7
  parseTransactionToBase64Url,
@@ -133,7 +133,8 @@ async function retryWithBackoff(operation, operationName, logger, maxRetries = 3
133
133
  // src/chains/SolanaChain.ts
134
134
  import { EventEmitter } from "eventemitter3";
135
135
  import { NetworkId } from "@phantom/constants";
136
- import { Buffer } from "buffer";
136
+ import bs58 from "bs58";
137
+ import { parseSolanaTransactionSignature } from "@phantom/parsers";
137
138
  var EmbeddedSolanaChain = class {
138
139
  constructor(provider) {
139
140
  this.provider = provider;
@@ -164,15 +165,20 @@ var EmbeddedSolanaChain = class {
164
165
  message: messageStr,
165
166
  networkId: this.currentNetworkId
166
167
  });
167
- const signature = typeof result.signature === "string" ? new Uint8Array(Buffer.from(result.signature, "base64")) : result.signature;
168
+ const signature = typeof result.signature === "string" ? new Uint8Array(bs58.decode(result.signature)) : result.signature;
168
169
  return {
169
170
  signature,
170
171
  publicKey: this._publicKey || ""
171
172
  };
172
173
  }
173
- signTransaction(_transaction) {
174
+ async signTransaction(transaction) {
174
175
  this.ensureConnected();
175
- throw new Error("signTransaction not yet implemented for embedded provider");
176
+ const result = await this.provider.signTransaction({
177
+ transaction,
178
+ networkId: this.currentNetworkId
179
+ });
180
+ const signatureResult = parseSolanaTransactionSignature(result.rawTransaction);
181
+ return signatureResult.signature;
176
182
  }
177
183
  async signAndSendTransaction(transaction) {
178
184
  this.ensureConnected();
@@ -189,6 +195,10 @@ var EmbeddedSolanaChain = class {
189
195
  const results = await Promise.all(transactions.map((tx) => this.signTransaction(tx)));
190
196
  return results;
191
197
  }
198
+ async signAndSendAllTransactions(transactions) {
199
+ const results = await Promise.all(transactions.map((tx) => this.signAndSendTransaction(tx)));
200
+ return { signatures: results.map((result) => result.signature) };
201
+ }
192
202
  connect(_options) {
193
203
  if (!this.provider.isConnected()) {
194
204
  throw new Error("Provider not connected. Call provider connect first.");
@@ -255,6 +265,8 @@ var EmbeddedSolanaChain = class {
255
265
  // src/chains/EthereumChain.ts
256
266
  import { EventEmitter as EventEmitter2 } from "eventemitter3";
257
267
  import { NetworkId as NetworkId2, chainIdToNetworkId, networkIdToChainId } from "@phantom/constants";
268
+ import { base64urlDecode } from "@phantom/base64url";
269
+ import { Buffer } from "buffer";
258
270
  var EmbeddedEthereumChain = class {
259
271
  constructor(provider) {
260
272
  this.provider = provider;
@@ -311,6 +323,18 @@ var EmbeddedEthereumChain = class {
311
323
  params: [address, JSON.stringify(typedData)]
312
324
  });
313
325
  }
326
+ async signTransaction(transaction) {
327
+ const result = await this.provider.signTransaction({
328
+ transaction,
329
+ networkId: this.currentNetworkId
330
+ });
331
+ try {
332
+ const signatureBytes = base64urlDecode(result.rawTransaction);
333
+ return "0x" + Buffer.from(signatureBytes).toString("hex");
334
+ } catch (error) {
335
+ return result.rawTransaction.startsWith("0x") ? result.rawTransaction : "0x" + result.rawTransaction;
336
+ }
337
+ }
314
338
  async sendTransaction(transaction) {
315
339
  const result = await this.provider.signAndSendTransaction({
316
340
  transaction,
@@ -388,6 +412,17 @@ var EmbeddedEthereumChain = class {
388
412
  });
389
413
  return typedDataResult.signature;
390
414
  }
415
+ case "eth_signTransaction": {
416
+ const [transaction] = args.params;
417
+ const networkIdFromTx = transaction.chainId ? chainIdToNetworkId(
418
+ typeof transaction.chainId === "number" ? transaction.chainId : parseInt(transaction.chainId, 16)
419
+ ) : null;
420
+ const signResult = await this.provider.signTransaction({
421
+ transaction,
422
+ networkId: networkIdFromTx || this.currentNetworkId
423
+ });
424
+ return signResult.rawTransaction;
425
+ }
391
426
  case "eth_sendTransaction": {
392
427
  const [transaction] = args.params;
393
428
  const networkIdFromTx = transaction.chainId ? chainIdToNetworkId(
@@ -435,6 +470,9 @@ var EmbeddedProvider = class {
435
470
  this.eventListeners = /* @__PURE__ */ new Map();
436
471
  this.logger = logger;
437
472
  this.logger.log("EMBEDDED_PROVIDER", "Initializing EmbeddedProvider", { config });
473
+ if (config.embeddedWalletType === "app-wallet") {
474
+ throw new Error("app-wallet type is not currently supported. Please use 'user-wallet' instead.");
475
+ }
438
476
  this.config = config;
439
477
  this.platform = platform;
440
478
  this.storage = platform.storage;
@@ -442,7 +480,6 @@ var EmbeddedProvider = class {
442
480
  this.urlParamsAccessor = platform.urlParamsAccessor;
443
481
  this.stamper = platform.stamper;
444
482
  this.jwtAuth = new JWTAuth();
445
- config.solanaProvider;
446
483
  this.solana = new EmbeddedSolanaChain(this);
447
484
  this.ethereum = new EmbeddedEthereumChain(this);
448
485
  this.logger.info("EMBEDDED_PROVIDER", "EmbeddedProvider initialized");
@@ -709,7 +746,10 @@ var EmbeddedProvider = class {
709
746
  this.logger.log("EMBEDDED_PROVIDER", "Creating temporary PhantomClient");
710
747
  const tempClient = new PhantomClient(
711
748
  {
712
- apiBaseUrl: this.config.apiBaseUrl
749
+ apiBaseUrl: this.config.apiBaseUrl,
750
+ headers: {
751
+ ...this.platform.analyticsHeaders || {}
752
+ }
713
753
  },
714
754
  this.stamper
715
755
  );
@@ -721,8 +761,8 @@ var EmbeddedProvider = class {
721
761
  publicKey: stamperInfo.publicKey,
722
762
  platform: platformName
723
763
  });
724
- const base64urlPublicKey = base64urlEncode(bs58.decode(stamperInfo.publicKey));
725
- const expiresAtMs = Date.now() + AUTHENTICATOR_EXPIRATION_TIME_MS;
764
+ const base64urlPublicKey = base64urlEncode(bs582.decode(stamperInfo.publicKey));
765
+ const expiresInMs = AUTHENTICATOR_EXPIRATION_TIME_MS;
726
766
  const username = `user-${shortPubKey}`;
727
767
  const { organizationId } = await tempClient.createOrganization(organizationName, [
728
768
  {
@@ -735,13 +775,13 @@ var EmbeddedProvider = class {
735
775
  publicKey: base64urlPublicKey,
736
776
  algorithm: "Ed25519"
737
777
  // Commented for now until KMS supports fully expirable organizations
738
- // expiresAtMs: expiresAtMs,
778
+ // expiresInMs: expiresInMs,
739
779
  }
740
780
  ]
741
781
  }
742
782
  ]);
743
783
  this.logger.info("EMBEDDED_PROVIDER", "Organization created", { organizationId });
744
- return { organizationId, stamperInfo, expiresAtMs, username };
784
+ return { organizationId, stamperInfo, expiresInMs, username };
745
785
  }
746
786
  async connect(authOptions) {
747
787
  try {
@@ -770,8 +810,8 @@ var EmbeddedProvider = class {
770
810
  }
771
811
  this.validateAuthOptions(authOptions);
772
812
  this.logger.info("EMBEDDED_PROVIDER", "No existing connection, creating new auth flow");
773
- const { organizationId, stamperInfo, expiresAtMs, username } = await this.createOrganizationAndStamper();
774
- const session = await this.handleAuthFlow(organizationId, stamperInfo, authOptions, expiresAtMs, username);
813
+ const { organizationId, stamperInfo, expiresInMs, username } = await this.createOrganizationAndStamper();
814
+ const session = await this.handleAuthFlow(organizationId, stamperInfo, authOptions, expiresInMs, username);
775
815
  if (!session) {
776
816
  return {
777
817
  addresses: [],
@@ -869,6 +909,36 @@ var EmbeddedProvider = class {
869
909
  });
870
910
  return parseSignMessageResponse(rawResponse, params.networkId);
871
911
  }
912
+ async signTransaction(params) {
913
+ if (!this.client || !this.walletId) {
914
+ throw new Error("Not connected");
915
+ }
916
+ await this.ensureValidAuthenticator();
917
+ this.logger.info("EMBEDDED_PROVIDER", "Signing transaction", {
918
+ walletId: this.walletId,
919
+ networkId: params.networkId
920
+ });
921
+ const parsedTransaction = await parseTransactionToBase64Url(params.transaction, params.networkId);
922
+ const session = await this.storage.getSession();
923
+ const derivationIndex = session?.accountDerivationIndex ?? 0;
924
+ this.logger.log("EMBEDDED_PROVIDER", "Parsed transaction for signing", {
925
+ walletId: this.walletId,
926
+ transaction: parsedTransaction,
927
+ derivationIndex
928
+ });
929
+ const rawResponse = await this.client.signTransaction({
930
+ walletId: this.walletId,
931
+ transaction: parsedTransaction.base64url,
932
+ networkId: params.networkId,
933
+ derivationIndex
934
+ });
935
+ this.logger.info("EMBEDDED_PROVIDER", "Transaction signed successfully", {
936
+ walletId: this.walletId,
937
+ networkId: params.networkId,
938
+ rawTransaction: rawResponse.rawTransaction
939
+ });
940
+ return await parseTransactionResponse(rawResponse.rawTransaction, params.networkId);
941
+ }
872
942
  async signAndSendTransaction(params) {
873
943
  if (!this.client || !this.walletId) {
874
944
  throw new Error("Not connected");
@@ -911,13 +981,13 @@ var EmbeddedProvider = class {
911
981
  * It handles app-wallet creation directly or routes to JWT/redirect authentication for user-wallets.
912
982
  * Returns null for redirect flows since they don't complete synchronously.
913
983
  */
914
- async handleAuthFlow(organizationId, stamperInfo, authOptions, expiresAtMs, username) {
984
+ async handleAuthFlow(organizationId, stamperInfo, authOptions, expiresInMs, username) {
915
985
  if (this.config.embeddedWalletType === "user-wallet") {
916
986
  this.logger.info("EMBEDDED_PROVIDER", "Creating user-wallet, routing authentication", {
917
987
  authProvider: authOptions?.provider || "phantom-connect"
918
988
  });
919
989
  if (authOptions?.provider === "jwt") {
920
- return await this.handleJWTAuth(organizationId, stamperInfo, authOptions, expiresAtMs, username);
990
+ return await this.handleJWTAuth(organizationId, stamperInfo, authOptions, expiresInMs, username);
921
991
  } else {
922
992
  this.logger.info("EMBEDDED_PROVIDER", "Starting redirect-based authentication flow", {
923
993
  organizationId,
@@ -933,7 +1003,10 @@ var EmbeddedProvider = class {
933
1003
  const tempClient = new PhantomClient(
934
1004
  {
935
1005
  apiBaseUrl: this.config.apiBaseUrl,
936
- organizationId
1006
+ organizationId,
1007
+ headers: {
1008
+ ...this.platform.analyticsHeaders || {}
1009
+ }
937
1010
  },
938
1011
  this.stamper
939
1012
  );
@@ -954,7 +1027,7 @@ var EmbeddedProvider = class {
954
1027
  createdAt: now,
955
1028
  lastUsed: now,
956
1029
  authenticatorCreatedAt: now,
957
- authenticatorExpiresAt: expiresAtMs,
1030
+ authenticatorExpiresAt: Date.now() + expiresInMs,
958
1031
  lastRenewalAttempt: void 0,
959
1032
  username
960
1033
  };
@@ -967,7 +1040,7 @@ var EmbeddedProvider = class {
967
1040
  * We use this method to handle JWT-based authentication for user-wallets.
968
1041
  * It authenticates using the provided JWT token and creates a completed session.
969
1042
  */
970
- async handleJWTAuth(organizationId, stamperInfo, authOptions, expiresAtMs, username) {
1043
+ async handleJWTAuth(organizationId, stamperInfo, authOptions, expiresInMs, username) {
971
1044
  this.logger.info("EMBEDDED_PROVIDER", "Using JWT authentication flow");
972
1045
  if (!authOptions.jwtToken) {
973
1046
  this.logger.error("EMBEDDED_PROVIDER", "JWT token missing for JWT authentication");
@@ -997,7 +1070,7 @@ var EmbeddedProvider = class {
997
1070
  createdAt: now,
998
1071
  lastUsed: now,
999
1072
  authenticatorCreatedAt: now,
1000
- authenticatorExpiresAt: expiresAtMs,
1073
+ authenticatorExpiresAt: Date.now() + expiresInMs,
1001
1074
  lastRenewalAttempt: void 0,
1002
1075
  username
1003
1076
  };
@@ -1013,8 +1086,8 @@ var EmbeddedProvider = class {
1013
1086
  async handleRedirectAuth(organizationId, stamperInfo, authOptions, username) {
1014
1087
  this.logger.info("EMBEDDED_PROVIDER", "Using Phantom Connect authentication flow (redirect-based)", {
1015
1088
  provider: authOptions?.provider,
1016
- hasRedirectUrl: !!this.config.authOptions?.redirectUrl,
1017
- authUrl: this.config.authOptions?.authUrl
1089
+ hasRedirectUrl: !!this.config.authOptions.redirectUrl,
1090
+ authUrl: this.config.authOptions.authUrl
1018
1091
  });
1019
1092
  const now = Date.now();
1020
1093
  const sessionId = generateSessionId();
@@ -1048,16 +1121,16 @@ var EmbeddedProvider = class {
1048
1121
  parentOrganizationId: this.config.organizationId,
1049
1122
  appId: this.config.appId,
1050
1123
  provider: authOptions?.provider,
1051
- authUrl: this.config.authOptions?.authUrl
1124
+ authUrl: this.config.authOptions.authUrl
1052
1125
  });
1053
1126
  const authResult = await this.authProvider.authenticate({
1054
1127
  organizationId,
1055
1128
  appId: this.config.appId,
1056
1129
  parentOrganizationId: this.config.organizationId,
1057
1130
  provider: authOptions?.provider,
1058
- redirectUrl: this.config.authOptions?.redirectUrl,
1131
+ redirectUrl: this.config.authOptions.redirectUrl,
1059
1132
  customAuthData: authOptions?.customAuthData,
1060
- authUrl: this.config.authOptions?.authUrl,
1133
+ authUrl: this.config.authOptions.authUrl,
1061
1134
  sessionId
1062
1135
  });
1063
1136
  if (authResult && "walletId" in authResult) {
@@ -1152,8 +1225,8 @@ var EmbeddedProvider = class {
1152
1225
  newKeyId: newKeyInfo.keyId,
1153
1226
  newPublicKey: newKeyInfo.publicKey
1154
1227
  });
1155
- const base64urlPublicKey = base64urlEncode(bs58.decode(newKeyInfo.publicKey));
1156
- const expiresAtMs = Date.now() + AUTHENTICATOR_EXPIRATION_TIME_MS;
1228
+ const base64urlPublicKey = base64urlEncode(bs582.decode(newKeyInfo.publicKey));
1229
+ const expiresInMs = AUTHENTICATOR_EXPIRATION_TIME_MS;
1157
1230
  let authenticatorResult;
1158
1231
  try {
1159
1232
  authenticatorResult = await this.client.createAuthenticator({
@@ -1166,7 +1239,7 @@ var EmbeddedProvider = class {
1166
1239
  publicKey: base64urlPublicKey,
1167
1240
  algorithm: "Ed25519"
1168
1241
  // Commented for now until KMS supports fully expiring organizations
1169
- // expiresAtMs: expiresAtMs,
1242
+ // expiresInMs: expiresInMs,
1170
1243
  },
1171
1244
  replaceExpirable: true
1172
1245
  });
@@ -1186,12 +1259,12 @@ var EmbeddedProvider = class {
1186
1259
  const now = Date.now();
1187
1260
  session.stamperInfo = newKeyInfo;
1188
1261
  session.authenticatorCreatedAt = now;
1189
- session.authenticatorExpiresAt = expiresAtMs;
1262
+ session.authenticatorExpiresAt = Date.now() + expiresInMs;
1190
1263
  session.lastRenewalAttempt = now;
1191
1264
  await this.storage.saveSession(session);
1192
1265
  this.logger.info("EMBEDDED_PROVIDER", "Authenticator renewal completed successfully", {
1193
1266
  newKeyId: newKeyInfo.keyId,
1194
- expiresAt: new Date(expiresAtMs).toISOString()
1267
+ expiresAt: new Date(Date.now() + expiresInMs).toISOString()
1195
1268
  });
1196
1269
  } catch (error) {
1197
1270
  await this.stamper.rollbackRotation();
@@ -1214,7 +1287,10 @@ var EmbeddedProvider = class {
1214
1287
  this.client = new PhantomClient(
1215
1288
  {
1216
1289
  apiBaseUrl: this.config.apiBaseUrl,
1217
- organizationId: session.organizationId
1290
+ organizationId: session.organizationId,
1291
+ headers: {
1292
+ ...this.platform.analyticsHeaders || {}
1293
+ }
1218
1294
  },
1219
1295
  this.stamper
1220
1296
  );