@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/README.md +0 -2
- package/dist/index.d.mts +16 -7
- package/dist/index.d.ts +16 -7
- package/dist/index.js +112 -36
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +106 -30
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -8
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
|
|
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
|
|
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(
|
|
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(
|
|
174
|
+
async signTransaction(transaction) {
|
|
174
175
|
this.ensureConnected();
|
|
175
|
-
|
|
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(
|
|
725
|
-
const
|
|
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
|
-
//
|
|
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,
|
|
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,
|
|
774
|
-
const session = await this.handleAuthFlow(organizationId, stamperInfo, authOptions,
|
|
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,
|
|
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,
|
|
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:
|
|
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,
|
|
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:
|
|
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
|
|
1017
|
-
authUrl: this.config.authOptions
|
|
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
|
|
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
|
|
1131
|
+
redirectUrl: this.config.authOptions.redirectUrl,
|
|
1059
1132
|
customAuthData: authOptions?.customAuthData,
|
|
1060
|
-
authUrl: this.config.authOptions
|
|
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(
|
|
1156
|
-
const
|
|
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
|
-
//
|
|
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 =
|
|
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(
|
|
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
|
);
|