@openfort/openfort-js 0.8.18 → 0.8.20

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.cjs CHANGED
@@ -3339,7 +3339,7 @@ class KeyPair extends signingKey.SigningKey {
3339
3339
  }
3340
3340
  }
3341
3341
 
3342
- const VERSION = '0.8.18';
3342
+ const VERSION = '0.8.20';
3343
3343
 
3344
3344
  var Event;
3345
3345
  (function (Event) {
@@ -3350,6 +3350,8 @@ var Event;
3350
3350
  Event["AUTHENTICATION_UPDATED"] = "authentication-updated";
3351
3351
  Event["SIGN"] = "sign";
3352
3352
  Event["SET_RECOVERY_METHOD"] = "set-recovery-method";
3353
+ Event["SWITCH_CHAIN"] = "switch-chain";
3354
+ Event["CHAIN_SWITCHED"] = "chain-switched";
3353
3355
  Event["EXPORT"] = "export";
3354
3356
  Event["SIGNED"] = "signed";
3355
3357
  Event["LOGOUT"] = "logout";
@@ -3419,6 +3421,17 @@ class SignRequest {
3419
3421
  this.requestConfiguration = requestConfiguration;
3420
3422
  }
3421
3423
  }
3424
+ class SwitchChainRequest {
3425
+ uuid;
3426
+ action = Event.SWITCH_CHAIN;
3427
+ chainId;
3428
+ requestConfiguration;
3429
+ constructor(uuid, chainId, requestConfiguration) {
3430
+ this.uuid = uuid;
3431
+ this.chainId = chainId;
3432
+ this.requestConfiguration = requestConfiguration;
3433
+ }
3434
+ }
3422
3435
  class ExportPrivateKeyRequest {
3423
3436
  uuid;
3424
3437
  action = Event.EXPORT;
@@ -3489,6 +3502,27 @@ class ConfigureResponse {
3489
3502
  this.version = null;
3490
3503
  }
3491
3504
  }
3505
+ class SwitchChainResponse {
3506
+ uuid;
3507
+ success;
3508
+ deviceID;
3509
+ address;
3510
+ chainId;
3511
+ accountType;
3512
+ ownerAddress;
3513
+ version;
3514
+ action = Event.CHAIN_SWITCHED;
3515
+ constructor(uuid, deviceID, accountType, chainId, address, ownerAddress) {
3516
+ this.success = true;
3517
+ this.deviceID = deviceID;
3518
+ this.uuid = uuid;
3519
+ this.accountType = accountType;
3520
+ this.chainId = chainId;
3521
+ this.address = address;
3522
+ this.ownerAddress = ownerAddress;
3523
+ this.version = null;
3524
+ }
3525
+ }
3492
3526
  class UpdateAuthenticationResponse {
3493
3527
  uuid;
3494
3528
  success;
@@ -3659,6 +3693,7 @@ class IframeManager {
3659
3693
  [Event.AUTHENTICATION_UPDATED]: UpdateAuthenticationResponse,
3660
3694
  [Event.CURRENT_DEVICE]: GetCurrentDeviceResponse,
3661
3695
  [Event.SIGNED]: SignResponse,
3696
+ [Event.CHAIN_SWITCHED]: SwitchChainResponse,
3662
3697
  [Event.LOGGED_OUT]: LogoutResponse,
3663
3698
  [Event.SET_RECOVERY_METHOD]: SetRecoveryMethodResponse,
3664
3699
  [Event.EXPORT]: ExportPrivateKeyResponse,
@@ -3756,6 +3791,33 @@ class IframeManager {
3756
3791
  sessionStorage.setItem('iframe-version', response.version ?? 'undefined');
3757
3792
  return response.signature;
3758
3793
  }
3794
+ async switchChain(iframeConfiguration, chainId) {
3795
+ await this.waitForIframeLoad();
3796
+ const uuid = this.generateShortUUID();
3797
+ const requestConfiguration = {
3798
+ thirdPartyProvider: iframeConfiguration.thirdPartyProvider ?? undefined,
3799
+ thirdPartyTokenType: iframeConfiguration.thirdPartyTokenType ?? undefined,
3800
+ token: iframeConfiguration.accessToken ?? undefined,
3801
+ publishableKey: this.sdkConfiguration.baseConfiguration.publishableKey,
3802
+ openfortURL: this.sdkConfiguration.backendUrl,
3803
+ };
3804
+ const request = new SwitchChainRequest(uuid, chainId, requestConfiguration);
3805
+ this.iframe?.contentWindow?.postMessage(request, '*');
3806
+ let response;
3807
+ try {
3808
+ response = await this.waitForResponse(uuid);
3809
+ }
3810
+ catch (e) {
3811
+ console.log('switchChain', e);
3812
+ if (e instanceof NotConfiguredError) {
3813
+ await this.configure(iframeConfiguration);
3814
+ return this.switchChain(iframeConfiguration, chainId);
3815
+ }
3816
+ throw e;
3817
+ }
3818
+ sessionStorage.setItem('iframe-version', response.version ?? 'undefined');
3819
+ return response;
3820
+ }
3759
3821
  async export(iframeConfiguration) {
3760
3822
  await this.waitForIframeLoad();
3761
3823
  const uuid = this.generateShortUUID();
@@ -4004,6 +4066,30 @@ class Recovery {
4004
4066
  }
4005
4067
  }
4006
4068
 
4069
+ class Account {
4070
+ type;
4071
+ address;
4072
+ ownerAddress;
4073
+ chainId;
4074
+ constructor(type, address, chainId, ownerAddress) {
4075
+ this.type = type;
4076
+ this.address = address;
4077
+ this.chainId = chainId;
4078
+ this.ownerAddress = ownerAddress;
4079
+ }
4080
+ static fromStorage(storage) {
4081
+ const account = storage.get(StorageKeys.ACCOUNT);
4082
+ if (!account) {
4083
+ return null;
4084
+ }
4085
+ const accountObj = JSON.parse(account);
4086
+ return new Account(accountObj.type, accountObj.address, accountObj.chainId, accountObj.ownerAddress);
4087
+ }
4088
+ save(storage) {
4089
+ storage.save(StorageKeys.ACCOUNT, JSON.stringify(this));
4090
+ }
4091
+ }
4092
+
4007
4093
  class EmbeddedSigner {
4008
4094
  iframeManager;
4009
4095
  iframeConfiguration;
@@ -4019,6 +4105,12 @@ class EmbeddedSigner {
4019
4105
  async export() {
4020
4106
  return await this.iframeManager.export(this.iframeConfiguration);
4021
4107
  }
4108
+ async switchChain({ chainId }) {
4109
+ const deviceAccount = await this.iframeManager
4110
+ .switchChain(this.iframeConfiguration, chainId);
4111
+ new Account(deviceAccount.accountType, deviceAccount.address, deviceAccount.chainId, deviceAccount.ownerAddress).save(this.storage);
4112
+ SignerManager.storage.save(StorageKeys.SIGNER, JSON.stringify(deviceAccount));
4113
+ }
4022
4114
  async setEmbeddedRecovery({ recoveryMethod, recoveryPassword, encryptionSession }) {
4023
4115
  await this.iframeManager
4024
4116
  .setEmbeddedRecovery(this.iframeConfiguration, recoveryMethod, recoveryPassword, encryptionSession);
@@ -4088,6 +4180,10 @@ class SessionSigner {
4088
4180
  updateAuthentication() {
4089
4181
  return Promise.resolve();
4090
4182
  }
4183
+ // eslint-disable-next-line class-methods-use-this
4184
+ switchChain() {
4185
+ return Promise.resolve();
4186
+ }
4091
4187
  async export() {
4092
4188
  return this.sessionKey.getPrivateKey();
4093
4189
  }
@@ -4097,30 +4193,6 @@ class SessionSigner {
4097
4193
  }
4098
4194
  }
4099
4195
 
4100
- class Account {
4101
- type;
4102
- address;
4103
- ownerAddress;
4104
- chainId;
4105
- constructor(type, address, chainId, ownerAddress) {
4106
- this.type = type;
4107
- this.address = address;
4108
- this.chainId = chainId;
4109
- this.ownerAddress = ownerAddress;
4110
- }
4111
- static fromStorage(storage) {
4112
- const account = storage.get(StorageKeys.ACCOUNT);
4113
- if (!account) {
4114
- return null;
4115
- }
4116
- const accountObj = JSON.parse(account);
4117
- return new Account(accountObj.type, accountObj.address, accountObj.chainId, accountObj.ownerAddress);
4118
- }
4119
- save(storage) {
4120
- storage.save(StorageKeys.ACCOUNT, JSON.stringify(this));
4121
- }
4122
- }
4123
-
4124
4196
  let iframeManagerSingleton = null;
4125
4197
  class SignerManager {
4126
4198
  static storage = new LocalStorage();
@@ -4880,6 +4952,7 @@ var BackendTransactionStatus;
4880
4952
  var ProviderEvent;
4881
4953
  (function (ProviderEvent) {
4882
4954
  ProviderEvent["ACCOUNTS_CHANGED"] = "accountsChanged";
4955
+ ProviderEvent["ACCOUNTS_CONNECT"] = "connect";
4883
4956
  })(ProviderEvent || (ProviderEvent = {}));
4884
4957
 
4885
4958
  /**
@@ -4948,7 +5021,14 @@ const sendTransaction = async ({ params, signer, account, authentication, backen
4948
5021
  const openfortTransaction = await buildOpenfortTransactions$4(params, backendClient, account, authentication, policyId);
4949
5022
  let response;
4950
5023
  if (openfortTransaction?.nextAction?.payload?.signableHash) {
4951
- const signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
5024
+ let signature;
5025
+ // zkSync and Sophon test need a different signature
5026
+ if ([300, 531050104, 324, 50104].includes(account.chainId)) {
5027
+ signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash, false, false);
5028
+ }
5029
+ else {
5030
+ signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
5031
+ }
4952
5032
  const openfortSignatureResponse = (await backendClient.transactionIntentsApi.signature({
4953
5033
  id: openfortTransaction.id,
4954
5034
  signatureRequest: { signature },
@@ -5062,7 +5142,7 @@ class TypedEventEmitter {
5062
5142
  }
5063
5143
  }
5064
5144
 
5065
- const chain$s = {
5145
+ const chain$t = {
5066
5146
  name: 'ZKsync Sepolia Testnet',
5067
5147
  title: 'ZKsync Sepolia Testnet',
5068
5148
  chain: 'zksync-sepolia-testnet',
@@ -5090,6 +5170,34 @@ const chain$s = {
5090
5170
  slug: 'zksync-sepolia-testnet',
5091
5171
  };
5092
5172
 
5173
+ const chain$s = {
5174
+ name: 'ZKsync Era',
5175
+ title: 'ZKsync Era',
5176
+ chain: 'zksync-era',
5177
+ rpc: ['https://mainnet.era.zksync.io'],
5178
+ nativeCurrency: {
5179
+ name: 'Ether',
5180
+ symbol: 'ETH',
5181
+ decimals: 18,
5182
+ },
5183
+ shortName: 'zksync-era',
5184
+ chainId: 324,
5185
+ explorers: [
5186
+ {
5187
+ name: 'Etherscan',
5188
+ url: 'https://era.zksync.network/',
5189
+ standard: 'EIP3091',
5190
+ },
5191
+ {
5192
+ name: 'ZKsync Explorer',
5193
+ url: 'https://explorer.zksync.io/',
5194
+ standard: 'EIP3091',
5195
+ },
5196
+ ],
5197
+ testnet: false,
5198
+ slug: 'zksync-era',
5199
+ };
5200
+
5093
5201
  const chain$r = {
5094
5202
  chain: 'BSC',
5095
5203
  chainId: 56,
@@ -5476,12 +5584,9 @@ const chain$i = {
5476
5584
  networkId: 11155111,
5477
5585
  redFlags: [],
5478
5586
  rpc: [
5479
- 'https://rpc.sepolia.org',
5480
- 'https://rpc2.sepolia.org',
5481
- 'https://rpc-sepolia.rockx.com',
5587
+ 'https://ethereum-sepolia-rpc.publicnode.com',
5482
5588
  'https://rpc.sepolia.ethpandaops.io',
5483
5589
  'https://sepolia.gateway.tenderly.co',
5484
- 'https://ethereum-sepolia.publicnode.com',
5485
5590
  ],
5486
5591
  shortName: 'sep',
5487
5592
  slug: 'sepolia',
@@ -6218,6 +6323,29 @@ const sophonTestnet = {
6218
6323
  slug: 'sophon-testnet',
6219
6324
  };
6220
6325
 
6326
+ const sophonMainnet = {
6327
+ name: 'Sophon',
6328
+ title: 'Sophon',
6329
+ chain: 'sophon',
6330
+ rpc: ['https://rpc.sophon.xyz'],
6331
+ nativeCurrency: {
6332
+ name: 'Sophon',
6333
+ symbol: 'SOPH',
6334
+ decimals: 18,
6335
+ },
6336
+ shortName: 'sophon',
6337
+ chainId: 50104,
6338
+ explorers: [
6339
+ {
6340
+ name: 'Sophon Block Explorer',
6341
+ url: 'https://explorer.sophon.xyz',
6342
+ standard: 'EIP3091',
6343
+ },
6344
+ ],
6345
+ testnet: false,
6346
+ slug: 'sophon',
6347
+ };
6348
+
6221
6349
  const chain$1 = {
6222
6350
  chainId: 2358,
6223
6351
  name: 'Kroma Sepolia',
@@ -6258,7 +6386,9 @@ const chainMap = {
6258
6386
  // eslint-disable-next-line @typescript-eslint/naming-convention
6259
6387
  1: chain$j,
6260
6388
  // eslint-disable-next-line @typescript-eslint/naming-convention
6261
- 300: chain$s,
6389
+ 300: chain$t,
6390
+ // eslint-disable-next-line @typescript-eslint/naming-convention
6391
+ 324: chain$s,
6262
6392
  // eslint-disable-next-line @typescript-eslint/naming-convention
6263
6393
  56: chain$r,
6264
6394
  // eslint-disable-next-line @typescript-eslint/naming-convention
@@ -6316,6 +6446,8 @@ const chainMap = {
6316
6446
  // eslint-disable-next-line @typescript-eslint/naming-convention
6317
6447
  531050104: sophonTestnet,
6318
6448
  // eslint-disable-next-line @typescript-eslint/naming-convention
6449
+ 50104: sophonMainnet,
6450
+ // eslint-disable-next-line @typescript-eslint/naming-convention
6319
6451
  2358: chain$1,
6320
6452
  // eslint-disable-next-line @typescript-eslint/naming-convention
6321
6453
  255: chain,
@@ -6451,6 +6583,7 @@ const buildOpenfortTransactions$3 = async (params, backendApiClients, account, a
6451
6583
  const formattedPermissions = param.permissions.map(formatPermissionRequest);
6452
6584
  const whitelist = formattedPermissions.filter((p) => p.type === 'contract-call'
6453
6585
  || p.type === 'erc20-token-transfer').map((p) => p.data.address);
6586
+ const limit = formattedPermissions[0].policies.find((p) => p.type === 'usage-limit')?.data?.limit;
6454
6587
  if (param.signer && param.signer.type === 'keys') {
6455
6588
  throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'Failed to request permissions - missing session address');
6456
6589
  }
@@ -6458,7 +6591,7 @@ const buildOpenfortTransactions$3 = async (params, backendApiClients, account, a
6458
6591
  if (!sessionAddress) {
6459
6592
  throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'Failed to request permissions - missing session address');
6460
6593
  }
6461
- const sessionRequest = formatSessionRequest$1(sessionAddress, account.chainId, now, expiry, policyId, false, whitelist, authentication.player);
6594
+ const sessionRequest = formatSessionRequest$1(sessionAddress, account.chainId, now, expiry, policyId, false, whitelist, authentication.player, limit);
6462
6595
  const transactionResponse = await backendApiClients.sessionsApi.createSession({
6463
6596
  createSessionRequest: sessionRequest,
6464
6597
  }, {
@@ -6497,7 +6630,14 @@ const registerSession = async ({ params, signer, account, authentication, backen
6497
6630
  const openfortTransaction = await buildOpenfortTransactions$3(params, backendClient, account, authentication, policyId);
6498
6631
  let response;
6499
6632
  if (openfortTransaction?.nextAction?.payload?.signableHash) {
6500
- const signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
6633
+ let signature;
6634
+ // zkSync and Sophon test need a different signature
6635
+ if ([300, 531050104, 324, 50104].includes(account.chainId)) {
6636
+ signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash, false, false);
6637
+ }
6638
+ else {
6639
+ signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
6640
+ }
6501
6641
  const openfortSignatureResponse = await backendClient.sessionsApi.signatureSession({
6502
6642
  id: openfortTransaction.id,
6503
6643
  signatureRequest: { signature },
@@ -6547,7 +6687,14 @@ const revokeSession = async ({ params, signer, account, authentication, backendC
6547
6687
  const openfortTransaction = await buildOpenfortTransactions$2(params, backendClient, account, authentication, policyId);
6548
6688
  let response;
6549
6689
  if (openfortTransaction?.nextAction?.payload?.signableHash) {
6550
- const signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
6690
+ let signature;
6691
+ // zkSync and Sophon test need a different signature
6692
+ if ([300, 531050104, 324, 50104].includes(account.chainId)) {
6693
+ signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash, false, false);
6694
+ }
6695
+ else {
6696
+ signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
6697
+ }
6551
6698
  const openfortSignatureResponse = await backendClient.sessionsApi.signatureSession({
6552
6699
  id: openfortTransaction.id,
6553
6700
  signatureRequest: { signature },
@@ -6601,7 +6748,14 @@ const sendCalls = async ({ params, signer, account, authentication, backendClien
6601
6748
  const openfortTransaction = await buildOpenfortTransactions$1(params[0].calls, backendClient, account, authentication, policy);
6602
6749
  let response;
6603
6750
  if (openfortTransaction?.nextAction?.payload?.signableHash) {
6604
- const signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
6751
+ let signature;
6752
+ // zkSync and Sophon test need a different signature
6753
+ if ([300, 531050104, 324, 50104].includes(account.chainId)) {
6754
+ signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash, false, false);
6755
+ }
6756
+ else {
6757
+ signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
6758
+ }
6605
6759
  const openfortSignatureResponse = (await backendClient.transactionIntentsApi.signature({
6606
6760
  id: openfortTransaction.id,
6607
6761
  signatureRequest: { signature },
@@ -6660,16 +6814,38 @@ const getCallStatus = async ({ params, authentication, backendClient, }) => {
6660
6814
  };
6661
6815
  };
6662
6816
 
6817
+ const personalSign = async ({ params, signer, account, }) => {
6818
+ const message = params[0];
6819
+ const fromAddress = params[1];
6820
+ if (!fromAddress || !message) {
6821
+ throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'personal_sign requires an address and a message');
6822
+ }
6823
+ if (fromAddress.toLowerCase() !== account.address.toLowerCase()) {
6824
+ throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'personal_sign requires the signer to be the from address');
6825
+ }
6826
+ const signature = await signer.sign(message, false, true);
6827
+ return signature;
6828
+ };
6829
+
6663
6830
  class EvmProvider {
6664
6831
  #storage;
6665
6832
  #policyId;
6833
+ /**
6834
+ * Updates the policy ID for the provider
6835
+ * @param newPolicyId - The new policy ID to use
6836
+ */
6837
+ updatePolicy(newPolicy) {
6838
+ this.#policyId = newPolicy;
6839
+ }
6840
+ #validateAndRefreshSession;
6666
6841
  #eventEmitter;
6667
6842
  #rpcProvider; // Used for read
6668
6843
  #backendApiClients;
6669
6844
  isOpenfort = true;
6670
- constructor({ storage, backendApiClients, openfortEventEmitter, policyId, }) {
6845
+ constructor({ storage, backendApiClients, openfortEventEmitter, policyId, validateAndRefreshSession, }) {
6671
6846
  this.#storage = storage;
6672
6847
  this.#policyId = policyId;
6848
+ this.#validateAndRefreshSession = validateAndRefreshSession;
6673
6849
  this.#backendApiClients = backendApiClients;
6674
6850
  const account = Account.fromStorage(this.#storage);
6675
6851
  const chainId = account?.chainId || 8453;
@@ -6699,6 +6875,7 @@ class EvmProvider {
6699
6875
  case 'eth_requestAccounts': {
6700
6876
  let account = Account.fromStorage(this.#storage);
6701
6877
  if (account) {
6878
+ this.#eventEmitter.emit(ProviderEvent.ACCOUNTS_CONNECT, { chainId: bytes.hexlify(account.chainId) });
6702
6879
  return [account.address];
6703
6880
  }
6704
6881
  const signer = SignerManager.fromStorage();
@@ -6720,6 +6897,8 @@ class EvmProvider {
6720
6897
  if (!account || !signer || !authentication) {
6721
6898
  throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
6722
6899
  }
6900
+ this.#validateAndRefreshSession();
6901
+ console.log(`eth_sendTransaction ${this.#policyId}`);
6723
6902
  return await sendTransaction({
6724
6903
  params: request.params || [],
6725
6904
  signer,
@@ -6736,6 +6915,7 @@ class EvmProvider {
6736
6915
  if (!account || !signer) {
6737
6916
  throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
6738
6917
  }
6918
+ this.#validateAndRefreshSession();
6739
6919
  return await signTypedDataV4({
6740
6920
  method: request.method,
6741
6921
  params: request.params || [],
@@ -6744,6 +6924,19 @@ class EvmProvider {
6744
6924
  rpcProvider: this.#rpcProvider,
6745
6925
  });
6746
6926
  }
6927
+ case 'personal_sign': {
6928
+ const account = Account.fromStorage(this.#storage);
6929
+ const signer = SignerManager.fromStorage();
6930
+ if (!account || !signer) {
6931
+ throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
6932
+ }
6933
+ this.#validateAndRefreshSession();
6934
+ return await personalSign({
6935
+ params: request.params || [],
6936
+ signer,
6937
+ account,
6938
+ });
6939
+ }
6747
6940
  case 'eth_chainId': {
6748
6941
  // Call detect network to fetch the chainId so to take advantage of
6749
6942
  // the caching layer provided by StaticJsonRpcProvider.
@@ -6754,6 +6947,25 @@ class EvmProvider {
6754
6947
  const { chainId } = await this.#rpcProvider.detectNetwork();
6755
6948
  return bytes.hexlify(chainId);
6756
6949
  }
6950
+ case 'wallet_switchEthereumChain': {
6951
+ const signer = SignerManager.fromStorage();
6952
+ if (!signer) {
6953
+ throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - must be authenticated and configured with a signer');
6954
+ }
6955
+ if (!request.params || !Array.isArray(request.params) || request.params.length === 0) {
6956
+ throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'Invalid parameters for wallet_switchEthereumChain');
6957
+ }
6958
+ this.#validateAndRefreshSession();
6959
+ try {
6960
+ const chainIdNumber = parseInt(request.params[0].chainId, 16);
6961
+ await signer.switchChain({ chainId: chainIdNumber });
6962
+ this.#rpcProvider = new providers.StaticJsonRpcProvider(chainMap[chainIdNumber].rpc[0]);
6963
+ }
6964
+ catch (error) {
6965
+ throw new JsonRpcError(RpcErrorCode.INTERNAL_ERROR, 'Failed to switch chain');
6966
+ }
6967
+ return null;
6968
+ }
6757
6969
  case 'wallet_addEthereumChain': {
6758
6970
  const signer = SignerManager.fromStorage();
6759
6971
  if (!signer) {
@@ -6775,6 +6987,7 @@ class EvmProvider {
6775
6987
  if (!account || !signer || !authentication) {
6776
6988
  throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
6777
6989
  }
6990
+ this.#validateAndRefreshSession();
6778
6991
  return await getCallStatus({
6779
6992
  params: (request.params || {}),
6780
6993
  authentication,
@@ -6789,6 +7002,7 @@ class EvmProvider {
6789
7002
  if (!account || !signer || !authentication) {
6790
7003
  throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
6791
7004
  }
7005
+ this.#validateAndRefreshSession();
6792
7006
  return await sendCalls({
6793
7007
  params: request.params || [],
6794
7008
  signer,
@@ -6805,6 +7019,7 @@ class EvmProvider {
6805
7019
  if (!account || !signer || !authentication) {
6806
7020
  throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
6807
7021
  }
7022
+ this.#validateAndRefreshSession();
6808
7023
  return await registerSession({
6809
7024
  params: (request.params || []),
6810
7025
  signer,
@@ -6822,6 +7037,7 @@ class EvmProvider {
6822
7037
  if (!account || !signer || !authentication) {
6823
7038
  throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
6824
7039
  }
7040
+ this.#validateAndRefreshSession();
6825
7041
  return await revokeSession({
6826
7042
  params: (request.params || {}),
6827
7043
  signer,
@@ -6843,6 +7059,9 @@ class EvmProvider {
6843
7059
  paymasterService: {
6844
7060
  supported: true,
6845
7061
  },
7062
+ atomicBatch: {
7063
+ supported: true,
7064
+ },
6846
7065
  },
6847
7066
  };
6848
7067
  return capabilities;
@@ -6983,6 +7202,7 @@ function announceProvider(detail) {
6983
7202
 
6984
7203
  class Openfort {
6985
7204
  storage;
7205
+ provider = null;
6986
7206
  constructor(sdkConfiguration) {
6987
7207
  this.storage = new LocalStorage();
6988
7208
  const configuration = new Configuration(sdkConfiguration.baseConfiguration.publishableKey, sdkConfiguration.overrides?.backendUrl || 'https://api.openfort.xyz', sdkConfiguration.shieldConfiguration?.shieldPublishableKey || '', sdkConfiguration.shieldConfiguration?.shieldEncryptionKey || '', sdkConfiguration.overrides?.shieldUrl || 'https://shield.openfort.xyz', sdkConfiguration.overrides?.iframeUrl || 'https://embedded.openfort.xyz', sdkConfiguration.shieldConfiguration?.debug || false);
@@ -7011,20 +7231,26 @@ class Openfort {
7011
7231
  const authentication = Authentication.fromStorage(this.storage);
7012
7232
  const signer = SignerManager.fromStorage();
7013
7233
  const account = Account.fromStorage(this.storage);
7014
- const provider = new EvmProvider({
7015
- storage: this.storage,
7016
- openfortEventEmitter: new TypedEventEmitter(),
7017
- signer: signer || undefined,
7018
- account: account || undefined,
7019
- authentication: authentication || undefined,
7020
- backendApiClients: this.backendApiClients,
7021
- policyId: options.policy,
7022
- });
7023
- announceProvider({
7024
- info: { ...openfortProviderInfo, ...options.providerInfo },
7025
- provider,
7026
- });
7027
- return provider;
7234
+ if (!this.provider) {
7235
+ this.provider = new EvmProvider({
7236
+ storage: this.storage,
7237
+ openfortEventEmitter: new TypedEventEmitter(),
7238
+ signer: signer || undefined,
7239
+ account: account || undefined,
7240
+ authentication: authentication || undefined,
7241
+ backendApiClients: this.backendApiClients,
7242
+ policyId: options.policy,
7243
+ validateAndRefreshSession: this.validateAndRefreshToken.bind(this),
7244
+ });
7245
+ announceProvider({
7246
+ info: { ...openfortProviderInfo, ...options.providerInfo },
7247
+ provider: this.provider,
7248
+ });
7249
+ }
7250
+ else if (this.provider && options.policy) {
7251
+ this.provider.updatePolicy(options.policy);
7252
+ }
7253
+ return this.provider;
7028
7254
  }
7029
7255
  /**
7030
7256
  * Configures a session key and returns the session key details.
package/dist/index.d.ts CHANGED
@@ -577,6 +577,7 @@ type Provider = {
577
577
 
578
578
  declare class Openfort {
579
579
  private readonly storage;
580
+ private provider;
580
581
  constructor(sdkConfiguration: OpenfortSDKConfiguration);
581
582
  /**
582
583
  * Logs the user out by flushing the signer and removing credentials.
package/dist/index.js CHANGED
@@ -3316,7 +3316,7 @@ class KeyPair extends SigningKey {
3316
3316
  }
3317
3317
  }
3318
3318
 
3319
- const VERSION = '0.8.18';
3319
+ const VERSION = '0.8.20';
3320
3320
 
3321
3321
  var Event;
3322
3322
  (function (Event) {
@@ -3327,6 +3327,8 @@ var Event;
3327
3327
  Event["AUTHENTICATION_UPDATED"] = "authentication-updated";
3328
3328
  Event["SIGN"] = "sign";
3329
3329
  Event["SET_RECOVERY_METHOD"] = "set-recovery-method";
3330
+ Event["SWITCH_CHAIN"] = "switch-chain";
3331
+ Event["CHAIN_SWITCHED"] = "chain-switched";
3330
3332
  Event["EXPORT"] = "export";
3331
3333
  Event["SIGNED"] = "signed";
3332
3334
  Event["LOGOUT"] = "logout";
@@ -3396,6 +3398,17 @@ class SignRequest {
3396
3398
  this.requestConfiguration = requestConfiguration;
3397
3399
  }
3398
3400
  }
3401
+ class SwitchChainRequest {
3402
+ uuid;
3403
+ action = Event.SWITCH_CHAIN;
3404
+ chainId;
3405
+ requestConfiguration;
3406
+ constructor(uuid, chainId, requestConfiguration) {
3407
+ this.uuid = uuid;
3408
+ this.chainId = chainId;
3409
+ this.requestConfiguration = requestConfiguration;
3410
+ }
3411
+ }
3399
3412
  class ExportPrivateKeyRequest {
3400
3413
  uuid;
3401
3414
  action = Event.EXPORT;
@@ -3466,6 +3479,27 @@ class ConfigureResponse {
3466
3479
  this.version = null;
3467
3480
  }
3468
3481
  }
3482
+ class SwitchChainResponse {
3483
+ uuid;
3484
+ success;
3485
+ deviceID;
3486
+ address;
3487
+ chainId;
3488
+ accountType;
3489
+ ownerAddress;
3490
+ version;
3491
+ action = Event.CHAIN_SWITCHED;
3492
+ constructor(uuid, deviceID, accountType, chainId, address, ownerAddress) {
3493
+ this.success = true;
3494
+ this.deviceID = deviceID;
3495
+ this.uuid = uuid;
3496
+ this.accountType = accountType;
3497
+ this.chainId = chainId;
3498
+ this.address = address;
3499
+ this.ownerAddress = ownerAddress;
3500
+ this.version = null;
3501
+ }
3502
+ }
3469
3503
  class UpdateAuthenticationResponse {
3470
3504
  uuid;
3471
3505
  success;
@@ -3636,6 +3670,7 @@ class IframeManager {
3636
3670
  [Event.AUTHENTICATION_UPDATED]: UpdateAuthenticationResponse,
3637
3671
  [Event.CURRENT_DEVICE]: GetCurrentDeviceResponse,
3638
3672
  [Event.SIGNED]: SignResponse,
3673
+ [Event.CHAIN_SWITCHED]: SwitchChainResponse,
3639
3674
  [Event.LOGGED_OUT]: LogoutResponse,
3640
3675
  [Event.SET_RECOVERY_METHOD]: SetRecoveryMethodResponse,
3641
3676
  [Event.EXPORT]: ExportPrivateKeyResponse,
@@ -3733,6 +3768,33 @@ class IframeManager {
3733
3768
  sessionStorage.setItem('iframe-version', response.version ?? 'undefined');
3734
3769
  return response.signature;
3735
3770
  }
3771
+ async switchChain(iframeConfiguration, chainId) {
3772
+ await this.waitForIframeLoad();
3773
+ const uuid = this.generateShortUUID();
3774
+ const requestConfiguration = {
3775
+ thirdPartyProvider: iframeConfiguration.thirdPartyProvider ?? undefined,
3776
+ thirdPartyTokenType: iframeConfiguration.thirdPartyTokenType ?? undefined,
3777
+ token: iframeConfiguration.accessToken ?? undefined,
3778
+ publishableKey: this.sdkConfiguration.baseConfiguration.publishableKey,
3779
+ openfortURL: this.sdkConfiguration.backendUrl,
3780
+ };
3781
+ const request = new SwitchChainRequest(uuid, chainId, requestConfiguration);
3782
+ this.iframe?.contentWindow?.postMessage(request, '*');
3783
+ let response;
3784
+ try {
3785
+ response = await this.waitForResponse(uuid);
3786
+ }
3787
+ catch (e) {
3788
+ console.log('switchChain', e);
3789
+ if (e instanceof NotConfiguredError) {
3790
+ await this.configure(iframeConfiguration);
3791
+ return this.switchChain(iframeConfiguration, chainId);
3792
+ }
3793
+ throw e;
3794
+ }
3795
+ sessionStorage.setItem('iframe-version', response.version ?? 'undefined');
3796
+ return response;
3797
+ }
3736
3798
  async export(iframeConfiguration) {
3737
3799
  await this.waitForIframeLoad();
3738
3800
  const uuid = this.generateShortUUID();
@@ -3981,6 +4043,30 @@ class Recovery {
3981
4043
  }
3982
4044
  }
3983
4045
 
4046
+ class Account {
4047
+ type;
4048
+ address;
4049
+ ownerAddress;
4050
+ chainId;
4051
+ constructor(type, address, chainId, ownerAddress) {
4052
+ this.type = type;
4053
+ this.address = address;
4054
+ this.chainId = chainId;
4055
+ this.ownerAddress = ownerAddress;
4056
+ }
4057
+ static fromStorage(storage) {
4058
+ const account = storage.get(StorageKeys.ACCOUNT);
4059
+ if (!account) {
4060
+ return null;
4061
+ }
4062
+ const accountObj = JSON.parse(account);
4063
+ return new Account(accountObj.type, accountObj.address, accountObj.chainId, accountObj.ownerAddress);
4064
+ }
4065
+ save(storage) {
4066
+ storage.save(StorageKeys.ACCOUNT, JSON.stringify(this));
4067
+ }
4068
+ }
4069
+
3984
4070
  class EmbeddedSigner {
3985
4071
  iframeManager;
3986
4072
  iframeConfiguration;
@@ -3996,6 +4082,12 @@ class EmbeddedSigner {
3996
4082
  async export() {
3997
4083
  return await this.iframeManager.export(this.iframeConfiguration);
3998
4084
  }
4085
+ async switchChain({ chainId }) {
4086
+ const deviceAccount = await this.iframeManager
4087
+ .switchChain(this.iframeConfiguration, chainId);
4088
+ new Account(deviceAccount.accountType, deviceAccount.address, deviceAccount.chainId, deviceAccount.ownerAddress).save(this.storage);
4089
+ SignerManager.storage.save(StorageKeys.SIGNER, JSON.stringify(deviceAccount));
4090
+ }
3999
4091
  async setEmbeddedRecovery({ recoveryMethod, recoveryPassword, encryptionSession }) {
4000
4092
  await this.iframeManager
4001
4093
  .setEmbeddedRecovery(this.iframeConfiguration, recoveryMethod, recoveryPassword, encryptionSession);
@@ -4065,6 +4157,10 @@ class SessionSigner {
4065
4157
  updateAuthentication() {
4066
4158
  return Promise.resolve();
4067
4159
  }
4160
+ // eslint-disable-next-line class-methods-use-this
4161
+ switchChain() {
4162
+ return Promise.resolve();
4163
+ }
4068
4164
  async export() {
4069
4165
  return this.sessionKey.getPrivateKey();
4070
4166
  }
@@ -4074,30 +4170,6 @@ class SessionSigner {
4074
4170
  }
4075
4171
  }
4076
4172
 
4077
- class Account {
4078
- type;
4079
- address;
4080
- ownerAddress;
4081
- chainId;
4082
- constructor(type, address, chainId, ownerAddress) {
4083
- this.type = type;
4084
- this.address = address;
4085
- this.chainId = chainId;
4086
- this.ownerAddress = ownerAddress;
4087
- }
4088
- static fromStorage(storage) {
4089
- const account = storage.get(StorageKeys.ACCOUNT);
4090
- if (!account) {
4091
- return null;
4092
- }
4093
- const accountObj = JSON.parse(account);
4094
- return new Account(accountObj.type, accountObj.address, accountObj.chainId, accountObj.ownerAddress);
4095
- }
4096
- save(storage) {
4097
- storage.save(StorageKeys.ACCOUNT, JSON.stringify(this));
4098
- }
4099
- }
4100
-
4101
4173
  let iframeManagerSingleton = null;
4102
4174
  class SignerManager {
4103
4175
  static storage = new LocalStorage();
@@ -4857,6 +4929,7 @@ var BackendTransactionStatus;
4857
4929
  var ProviderEvent;
4858
4930
  (function (ProviderEvent) {
4859
4931
  ProviderEvent["ACCOUNTS_CHANGED"] = "accountsChanged";
4932
+ ProviderEvent["ACCOUNTS_CONNECT"] = "connect";
4860
4933
  })(ProviderEvent || (ProviderEvent = {}));
4861
4934
 
4862
4935
  /**
@@ -4925,7 +4998,14 @@ const sendTransaction = async ({ params, signer, account, authentication, backen
4925
4998
  const openfortTransaction = await buildOpenfortTransactions$4(params, backendClient, account, authentication, policyId);
4926
4999
  let response;
4927
5000
  if (openfortTransaction?.nextAction?.payload?.signableHash) {
4928
- const signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
5001
+ let signature;
5002
+ // zkSync and Sophon test need a different signature
5003
+ if ([300, 531050104, 324, 50104].includes(account.chainId)) {
5004
+ signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash, false, false);
5005
+ }
5006
+ else {
5007
+ signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
5008
+ }
4929
5009
  const openfortSignatureResponse = (await backendClient.transactionIntentsApi.signature({
4930
5010
  id: openfortTransaction.id,
4931
5011
  signatureRequest: { signature },
@@ -5039,7 +5119,7 @@ class TypedEventEmitter {
5039
5119
  }
5040
5120
  }
5041
5121
 
5042
- const chain$s = {
5122
+ const chain$t = {
5043
5123
  name: 'ZKsync Sepolia Testnet',
5044
5124
  title: 'ZKsync Sepolia Testnet',
5045
5125
  chain: 'zksync-sepolia-testnet',
@@ -5067,6 +5147,34 @@ const chain$s = {
5067
5147
  slug: 'zksync-sepolia-testnet',
5068
5148
  };
5069
5149
 
5150
+ const chain$s = {
5151
+ name: 'ZKsync Era',
5152
+ title: 'ZKsync Era',
5153
+ chain: 'zksync-era',
5154
+ rpc: ['https://mainnet.era.zksync.io'],
5155
+ nativeCurrency: {
5156
+ name: 'Ether',
5157
+ symbol: 'ETH',
5158
+ decimals: 18,
5159
+ },
5160
+ shortName: 'zksync-era',
5161
+ chainId: 324,
5162
+ explorers: [
5163
+ {
5164
+ name: 'Etherscan',
5165
+ url: 'https://era.zksync.network/',
5166
+ standard: 'EIP3091',
5167
+ },
5168
+ {
5169
+ name: 'ZKsync Explorer',
5170
+ url: 'https://explorer.zksync.io/',
5171
+ standard: 'EIP3091',
5172
+ },
5173
+ ],
5174
+ testnet: false,
5175
+ slug: 'zksync-era',
5176
+ };
5177
+
5070
5178
  const chain$r = {
5071
5179
  chain: 'BSC',
5072
5180
  chainId: 56,
@@ -5453,12 +5561,9 @@ const chain$i = {
5453
5561
  networkId: 11155111,
5454
5562
  redFlags: [],
5455
5563
  rpc: [
5456
- 'https://rpc.sepolia.org',
5457
- 'https://rpc2.sepolia.org',
5458
- 'https://rpc-sepolia.rockx.com',
5564
+ 'https://ethereum-sepolia-rpc.publicnode.com',
5459
5565
  'https://rpc.sepolia.ethpandaops.io',
5460
5566
  'https://sepolia.gateway.tenderly.co',
5461
- 'https://ethereum-sepolia.publicnode.com',
5462
5567
  ],
5463
5568
  shortName: 'sep',
5464
5569
  slug: 'sepolia',
@@ -6195,6 +6300,29 @@ const sophonTestnet = {
6195
6300
  slug: 'sophon-testnet',
6196
6301
  };
6197
6302
 
6303
+ const sophonMainnet = {
6304
+ name: 'Sophon',
6305
+ title: 'Sophon',
6306
+ chain: 'sophon',
6307
+ rpc: ['https://rpc.sophon.xyz'],
6308
+ nativeCurrency: {
6309
+ name: 'Sophon',
6310
+ symbol: 'SOPH',
6311
+ decimals: 18,
6312
+ },
6313
+ shortName: 'sophon',
6314
+ chainId: 50104,
6315
+ explorers: [
6316
+ {
6317
+ name: 'Sophon Block Explorer',
6318
+ url: 'https://explorer.sophon.xyz',
6319
+ standard: 'EIP3091',
6320
+ },
6321
+ ],
6322
+ testnet: false,
6323
+ slug: 'sophon',
6324
+ };
6325
+
6198
6326
  const chain$1 = {
6199
6327
  chainId: 2358,
6200
6328
  name: 'Kroma Sepolia',
@@ -6235,7 +6363,9 @@ const chainMap = {
6235
6363
  // eslint-disable-next-line @typescript-eslint/naming-convention
6236
6364
  1: chain$j,
6237
6365
  // eslint-disable-next-line @typescript-eslint/naming-convention
6238
- 300: chain$s,
6366
+ 300: chain$t,
6367
+ // eslint-disable-next-line @typescript-eslint/naming-convention
6368
+ 324: chain$s,
6239
6369
  // eslint-disable-next-line @typescript-eslint/naming-convention
6240
6370
  56: chain$r,
6241
6371
  // eslint-disable-next-line @typescript-eslint/naming-convention
@@ -6293,6 +6423,8 @@ const chainMap = {
6293
6423
  // eslint-disable-next-line @typescript-eslint/naming-convention
6294
6424
  531050104: sophonTestnet,
6295
6425
  // eslint-disable-next-line @typescript-eslint/naming-convention
6426
+ 50104: sophonMainnet,
6427
+ // eslint-disable-next-line @typescript-eslint/naming-convention
6296
6428
  2358: chain$1,
6297
6429
  // eslint-disable-next-line @typescript-eslint/naming-convention
6298
6430
  255: chain,
@@ -6428,6 +6560,7 @@ const buildOpenfortTransactions$3 = async (params, backendApiClients, account, a
6428
6560
  const formattedPermissions = param.permissions.map(formatPermissionRequest);
6429
6561
  const whitelist = formattedPermissions.filter((p) => p.type === 'contract-call'
6430
6562
  || p.type === 'erc20-token-transfer').map((p) => p.data.address);
6563
+ const limit = formattedPermissions[0].policies.find((p) => p.type === 'usage-limit')?.data?.limit;
6431
6564
  if (param.signer && param.signer.type === 'keys') {
6432
6565
  throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'Failed to request permissions - missing session address');
6433
6566
  }
@@ -6435,7 +6568,7 @@ const buildOpenfortTransactions$3 = async (params, backendApiClients, account, a
6435
6568
  if (!sessionAddress) {
6436
6569
  throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'Failed to request permissions - missing session address');
6437
6570
  }
6438
- const sessionRequest = formatSessionRequest$1(sessionAddress, account.chainId, now, expiry, policyId, false, whitelist, authentication.player);
6571
+ const sessionRequest = formatSessionRequest$1(sessionAddress, account.chainId, now, expiry, policyId, false, whitelist, authentication.player, limit);
6439
6572
  const transactionResponse = await backendApiClients.sessionsApi.createSession({
6440
6573
  createSessionRequest: sessionRequest,
6441
6574
  }, {
@@ -6474,7 +6607,14 @@ const registerSession = async ({ params, signer, account, authentication, backen
6474
6607
  const openfortTransaction = await buildOpenfortTransactions$3(params, backendClient, account, authentication, policyId);
6475
6608
  let response;
6476
6609
  if (openfortTransaction?.nextAction?.payload?.signableHash) {
6477
- const signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
6610
+ let signature;
6611
+ // zkSync and Sophon test need a different signature
6612
+ if ([300, 531050104, 324, 50104].includes(account.chainId)) {
6613
+ signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash, false, false);
6614
+ }
6615
+ else {
6616
+ signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
6617
+ }
6478
6618
  const openfortSignatureResponse = await backendClient.sessionsApi.signatureSession({
6479
6619
  id: openfortTransaction.id,
6480
6620
  signatureRequest: { signature },
@@ -6524,7 +6664,14 @@ const revokeSession = async ({ params, signer, account, authentication, backendC
6524
6664
  const openfortTransaction = await buildOpenfortTransactions$2(params, backendClient, account, authentication, policyId);
6525
6665
  let response;
6526
6666
  if (openfortTransaction?.nextAction?.payload?.signableHash) {
6527
- const signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
6667
+ let signature;
6668
+ // zkSync and Sophon test need a different signature
6669
+ if ([300, 531050104, 324, 50104].includes(account.chainId)) {
6670
+ signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash, false, false);
6671
+ }
6672
+ else {
6673
+ signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
6674
+ }
6528
6675
  const openfortSignatureResponse = await backendClient.sessionsApi.signatureSession({
6529
6676
  id: openfortTransaction.id,
6530
6677
  signatureRequest: { signature },
@@ -6578,7 +6725,14 @@ const sendCalls = async ({ params, signer, account, authentication, backendClien
6578
6725
  const openfortTransaction = await buildOpenfortTransactions$1(params[0].calls, backendClient, account, authentication, policy);
6579
6726
  let response;
6580
6727
  if (openfortTransaction?.nextAction?.payload?.signableHash) {
6581
- const signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
6728
+ let signature;
6729
+ // zkSync and Sophon test need a different signature
6730
+ if ([300, 531050104, 324, 50104].includes(account.chainId)) {
6731
+ signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash, false, false);
6732
+ }
6733
+ else {
6734
+ signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
6735
+ }
6582
6736
  const openfortSignatureResponse = (await backendClient.transactionIntentsApi.signature({
6583
6737
  id: openfortTransaction.id,
6584
6738
  signatureRequest: { signature },
@@ -6637,16 +6791,38 @@ const getCallStatus = async ({ params, authentication, backendClient, }) => {
6637
6791
  };
6638
6792
  };
6639
6793
 
6794
+ const personalSign = async ({ params, signer, account, }) => {
6795
+ const message = params[0];
6796
+ const fromAddress = params[1];
6797
+ if (!fromAddress || !message) {
6798
+ throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'personal_sign requires an address and a message');
6799
+ }
6800
+ if (fromAddress.toLowerCase() !== account.address.toLowerCase()) {
6801
+ throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'personal_sign requires the signer to be the from address');
6802
+ }
6803
+ const signature = await signer.sign(message, false, true);
6804
+ return signature;
6805
+ };
6806
+
6640
6807
  class EvmProvider {
6641
6808
  #storage;
6642
6809
  #policyId;
6810
+ /**
6811
+ * Updates the policy ID for the provider
6812
+ * @param newPolicyId - The new policy ID to use
6813
+ */
6814
+ updatePolicy(newPolicy) {
6815
+ this.#policyId = newPolicy;
6816
+ }
6817
+ #validateAndRefreshSession;
6643
6818
  #eventEmitter;
6644
6819
  #rpcProvider; // Used for read
6645
6820
  #backendApiClients;
6646
6821
  isOpenfort = true;
6647
- constructor({ storage, backendApiClients, openfortEventEmitter, policyId, }) {
6822
+ constructor({ storage, backendApiClients, openfortEventEmitter, policyId, validateAndRefreshSession, }) {
6648
6823
  this.#storage = storage;
6649
6824
  this.#policyId = policyId;
6825
+ this.#validateAndRefreshSession = validateAndRefreshSession;
6650
6826
  this.#backendApiClients = backendApiClients;
6651
6827
  const account = Account.fromStorage(this.#storage);
6652
6828
  const chainId = account?.chainId || 8453;
@@ -6676,6 +6852,7 @@ class EvmProvider {
6676
6852
  case 'eth_requestAccounts': {
6677
6853
  let account = Account.fromStorage(this.#storage);
6678
6854
  if (account) {
6855
+ this.#eventEmitter.emit(ProviderEvent.ACCOUNTS_CONNECT, { chainId: hexlify(account.chainId) });
6679
6856
  return [account.address];
6680
6857
  }
6681
6858
  const signer = SignerManager.fromStorage();
@@ -6697,6 +6874,8 @@ class EvmProvider {
6697
6874
  if (!account || !signer || !authentication) {
6698
6875
  throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
6699
6876
  }
6877
+ this.#validateAndRefreshSession();
6878
+ console.log(`eth_sendTransaction ${this.#policyId}`);
6700
6879
  return await sendTransaction({
6701
6880
  params: request.params || [],
6702
6881
  signer,
@@ -6713,6 +6892,7 @@ class EvmProvider {
6713
6892
  if (!account || !signer) {
6714
6893
  throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
6715
6894
  }
6895
+ this.#validateAndRefreshSession();
6716
6896
  return await signTypedDataV4({
6717
6897
  method: request.method,
6718
6898
  params: request.params || [],
@@ -6721,6 +6901,19 @@ class EvmProvider {
6721
6901
  rpcProvider: this.#rpcProvider,
6722
6902
  });
6723
6903
  }
6904
+ case 'personal_sign': {
6905
+ const account = Account.fromStorage(this.#storage);
6906
+ const signer = SignerManager.fromStorage();
6907
+ if (!account || !signer) {
6908
+ throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
6909
+ }
6910
+ this.#validateAndRefreshSession();
6911
+ return await personalSign({
6912
+ params: request.params || [],
6913
+ signer,
6914
+ account,
6915
+ });
6916
+ }
6724
6917
  case 'eth_chainId': {
6725
6918
  // Call detect network to fetch the chainId so to take advantage of
6726
6919
  // the caching layer provided by StaticJsonRpcProvider.
@@ -6731,6 +6924,25 @@ class EvmProvider {
6731
6924
  const { chainId } = await this.#rpcProvider.detectNetwork();
6732
6925
  return hexlify(chainId);
6733
6926
  }
6927
+ case 'wallet_switchEthereumChain': {
6928
+ const signer = SignerManager.fromStorage();
6929
+ if (!signer) {
6930
+ throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - must be authenticated and configured with a signer');
6931
+ }
6932
+ if (!request.params || !Array.isArray(request.params) || request.params.length === 0) {
6933
+ throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'Invalid parameters for wallet_switchEthereumChain');
6934
+ }
6935
+ this.#validateAndRefreshSession();
6936
+ try {
6937
+ const chainIdNumber = parseInt(request.params[0].chainId, 16);
6938
+ await signer.switchChain({ chainId: chainIdNumber });
6939
+ this.#rpcProvider = new StaticJsonRpcProvider(chainMap[chainIdNumber].rpc[0]);
6940
+ }
6941
+ catch (error) {
6942
+ throw new JsonRpcError(RpcErrorCode.INTERNAL_ERROR, 'Failed to switch chain');
6943
+ }
6944
+ return null;
6945
+ }
6734
6946
  case 'wallet_addEthereumChain': {
6735
6947
  const signer = SignerManager.fromStorage();
6736
6948
  if (!signer) {
@@ -6752,6 +6964,7 @@ class EvmProvider {
6752
6964
  if (!account || !signer || !authentication) {
6753
6965
  throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
6754
6966
  }
6967
+ this.#validateAndRefreshSession();
6755
6968
  return await getCallStatus({
6756
6969
  params: (request.params || {}),
6757
6970
  authentication,
@@ -6766,6 +6979,7 @@ class EvmProvider {
6766
6979
  if (!account || !signer || !authentication) {
6767
6980
  throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
6768
6981
  }
6982
+ this.#validateAndRefreshSession();
6769
6983
  return await sendCalls({
6770
6984
  params: request.params || [],
6771
6985
  signer,
@@ -6782,6 +6996,7 @@ class EvmProvider {
6782
6996
  if (!account || !signer || !authentication) {
6783
6997
  throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
6784
6998
  }
6999
+ this.#validateAndRefreshSession();
6785
7000
  return await registerSession({
6786
7001
  params: (request.params || []),
6787
7002
  signer,
@@ -6799,6 +7014,7 @@ class EvmProvider {
6799
7014
  if (!account || !signer || !authentication) {
6800
7015
  throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
6801
7016
  }
7017
+ this.#validateAndRefreshSession();
6802
7018
  return await revokeSession({
6803
7019
  params: (request.params || {}),
6804
7020
  signer,
@@ -6820,6 +7036,9 @@ class EvmProvider {
6820
7036
  paymasterService: {
6821
7037
  supported: true,
6822
7038
  },
7039
+ atomicBatch: {
7040
+ supported: true,
7041
+ },
6823
7042
  },
6824
7043
  };
6825
7044
  return capabilities;
@@ -6960,6 +7179,7 @@ function announceProvider(detail) {
6960
7179
 
6961
7180
  class Openfort {
6962
7181
  storage;
7182
+ provider = null;
6963
7183
  constructor(sdkConfiguration) {
6964
7184
  this.storage = new LocalStorage();
6965
7185
  const configuration = new Configuration(sdkConfiguration.baseConfiguration.publishableKey, sdkConfiguration.overrides?.backendUrl || 'https://api.openfort.xyz', sdkConfiguration.shieldConfiguration?.shieldPublishableKey || '', sdkConfiguration.shieldConfiguration?.shieldEncryptionKey || '', sdkConfiguration.overrides?.shieldUrl || 'https://shield.openfort.xyz', sdkConfiguration.overrides?.iframeUrl || 'https://embedded.openfort.xyz', sdkConfiguration.shieldConfiguration?.debug || false);
@@ -6988,20 +7208,26 @@ class Openfort {
6988
7208
  const authentication = Authentication.fromStorage(this.storage);
6989
7209
  const signer = SignerManager.fromStorage();
6990
7210
  const account = Account.fromStorage(this.storage);
6991
- const provider = new EvmProvider({
6992
- storage: this.storage,
6993
- openfortEventEmitter: new TypedEventEmitter(),
6994
- signer: signer || undefined,
6995
- account: account || undefined,
6996
- authentication: authentication || undefined,
6997
- backendApiClients: this.backendApiClients,
6998
- policyId: options.policy,
6999
- });
7000
- announceProvider({
7001
- info: { ...openfortProviderInfo, ...options.providerInfo },
7002
- provider,
7003
- });
7004
- return provider;
7211
+ if (!this.provider) {
7212
+ this.provider = new EvmProvider({
7213
+ storage: this.storage,
7214
+ openfortEventEmitter: new TypedEventEmitter(),
7215
+ signer: signer || undefined,
7216
+ account: account || undefined,
7217
+ authentication: authentication || undefined,
7218
+ backendApiClients: this.backendApiClients,
7219
+ policyId: options.policy,
7220
+ validateAndRefreshSession: this.validateAndRefreshToken.bind(this),
7221
+ });
7222
+ announceProvider({
7223
+ info: { ...openfortProviderInfo, ...options.providerInfo },
7224
+ provider: this.provider,
7225
+ });
7226
+ }
7227
+ else if (this.provider && options.policy) {
7228
+ this.provider.updatePolicy(options.policy);
7229
+ }
7230
+ return this.provider;
7005
7231
  }
7006
7232
  /**
7007
7233
  * Configures a session key and returns the session key details.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfort/openfort-js",
3
- "version": "0.8.18",
3
+ "version": "0.8.20",
4
4
  "author": "Openfort (https://www.openfort.xyz)",
5
5
  "bugs": "https://github.com/openfort-xyz/openfort-js/issues",
6
6
  "repository": "openfort-xyz/openfort-js.git",