@imtbl/sdk 0.2.3-alpha.1 → 0.3.0-alpha.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.cjs CHANGED
@@ -9,8 +9,10 @@ var oidc = require('@magic-ext/oidc');
9
9
  var BN$2 = require('bn.js');
10
10
  var encUtils = require('enc-utils');
11
11
  var providers = require('@ethersproject/providers');
12
- var FormData$2 = require('form-data');
13
12
  var ethers = require('ethers');
13
+ var abi = require('@0xsequence/abi');
14
+ var config = require('@0xsequence/config');
15
+ var FormData$2 = require('form-data');
14
16
  var seaportJs = require('@opensea/seaport-js');
15
17
  var units = require('@ethersproject/units');
16
18
  var bignumber = require('@ethersproject/bignumber');
@@ -3265,6 +3267,94 @@ axios$1.default = axios$1;
3265
3267
  // this module should only have a default export
3266
3268
  var globalAxios$1 = axios$1;
3267
3269
 
3270
+ /* tslint:disable */
3271
+ /* eslint-disable */
3272
+ /**
3273
+ * Immutable X API
3274
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
3275
+ *
3276
+ * The version of the OpenAPI document: 3.0
3277
+ * Contact: support@immutable.com
3278
+ *
3279
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
3280
+ * https://openapi-generator.tech
3281
+ * Do not edit the class manually.
3282
+ */
3283
+ let Configuration$1 = class Configuration {
3284
+ /**
3285
+ * parameter for apiKey security
3286
+ * @param name security name
3287
+ * @memberof Configuration
3288
+ */
3289
+ apiKey;
3290
+ /**
3291
+ * parameter for basic security
3292
+ *
3293
+ * @type {string}
3294
+ * @memberof Configuration
3295
+ */
3296
+ username;
3297
+ /**
3298
+ * parameter for basic security
3299
+ *
3300
+ * @type {string}
3301
+ * @memberof Configuration
3302
+ */
3303
+ password;
3304
+ /**
3305
+ * parameter for oauth2 security
3306
+ * @param name security name
3307
+ * @param scopes oauth2 scope
3308
+ * @memberof Configuration
3309
+ */
3310
+ accessToken;
3311
+ /**
3312
+ * override base path
3313
+ *
3314
+ * @type {string}
3315
+ * @memberof Configuration
3316
+ */
3317
+ basePath;
3318
+ /**
3319
+ * base options for axios calls
3320
+ *
3321
+ * @type {any}
3322
+ * @memberof Configuration
3323
+ */
3324
+ baseOptions;
3325
+ /**
3326
+ * The FormData constructor that will be used to create multipart form data
3327
+ * requests. You can inject this here so that execution environments that
3328
+ * do not support the FormData class can still run the generated client.
3329
+ *
3330
+ * @type {new () => FormData}
3331
+ */
3332
+ formDataCtor;
3333
+ constructor(param = {}) {
3334
+ this.apiKey = param.apiKey;
3335
+ this.username = param.username;
3336
+ this.password = param.password;
3337
+ this.accessToken = param.accessToken;
3338
+ this.basePath = param.basePath;
3339
+ this.baseOptions = param.baseOptions;
3340
+ this.formDataCtor = param.formDataCtor;
3341
+ }
3342
+ /**
3343
+ * Check if the given MIME is a JSON MIME.
3344
+ * JSON MIME examples:
3345
+ * application/json
3346
+ * application/json; charset=UTF8
3347
+ * APPLICATION/JSON
3348
+ * application/vnd.company+json
3349
+ * @param mime - MIME (Multipurpose Internet Mail Extensions)
3350
+ * @return True if the given MIME is JSON, false otherwise.
3351
+ */
3352
+ isJsonMime(mime) {
3353
+ const jsonMime = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i');
3354
+ return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json');
3355
+ }
3356
+ };
3357
+
3268
3358
  /* tslint:disable */
3269
3359
  /* eslint-disable */
3270
3360
  /**
@@ -4973,7 +5063,7 @@ class TokensApi extends BaseAPI$1 {
4973
5063
  * https://openapi-generator.tech
4974
5064
  * Do not edit the class manually.
4975
5065
  */
4976
- let Configuration$1 = class Configuration {
5066
+ let Configuration$2 = class Configuration {
4977
5067
  /**
4978
5068
  * parameter for apiKey security
4979
5069
  * @param name security name
@@ -5406,7 +5496,7 @@ var index = /*#__PURE__*/Object.freeze({
5406
5496
  CollectionsApiAxiosParamCreator: CollectionsApiAxiosParamCreator,
5407
5497
  CollectionsApiFactory: CollectionsApiFactory,
5408
5498
  CollectionsApiFp: CollectionsApiFp,
5409
- Configuration: Configuration$1,
5499
+ Configuration: Configuration$2,
5410
5500
  CreateOrderProtocolDataOrderTypeEnum: CreateOrderProtocolDataOrderTypeEnum,
5411
5501
  ERC20ItemItemTypeEnum: ERC20ItemItemTypeEnum,
5412
5502
  ERC721ItemItemTypeEnum: ERC721ItemItemTypeEnum,
@@ -5438,6 +5528,69 @@ var index = /*#__PURE__*/Object.freeze({
5438
5528
  TokensApiFp: TokensApiFp
5439
5529
  });
5440
5530
 
5531
+ class MultiRollupApiClients {
5532
+ config;
5533
+ activitiesApi;
5534
+ chainsApi;
5535
+ collectionApi;
5536
+ nftOwnersApi;
5537
+ nftsApi;
5538
+ ordersApi;
5539
+ passportApi;
5540
+ constructor(config) {
5541
+ this.config = config;
5542
+ this.activitiesApi = new ActivitiesApi(config.indexer);
5543
+ this.chainsApi = new ChainsApi(config.indexer);
5544
+ this.collectionApi = new CollectionsApi(config.indexer);
5545
+ this.nftOwnersApi = new NftOwnersApi(config.indexer);
5546
+ this.nftsApi = new NftsApi(config.indexer);
5547
+ this.ordersApi = new OrdersApi(config.orderBook);
5548
+ this.passportApi = new PassportApi(config.passport);
5549
+ }
5550
+ }
5551
+
5552
+ // eslint-disable-next-line @typescript-eslint/naming-convention
5553
+ const defaultHeaders$1 = { 'x-sdk-version': 'ts-immutable-sdk-0.3.0-alpha.1' };
5554
+ const createConfig = ({ basePath, headers, }) => {
5555
+ if (!basePath.trim()) {
5556
+ throw Error('basePath can not be empty');
5557
+ }
5558
+ const composedHeaders = { ...defaultHeaders$1, ...(headers || {}) };
5559
+ const apiConfigOptions = {
5560
+ basePath,
5561
+ baseOptions: { headers: composedHeaders },
5562
+ };
5563
+ return new Configuration$1(apiConfigOptions);
5564
+ };
5565
+ /**
5566
+ * Creates a Configuration for the specified environment
5567
+ * @returns an MultiRollupAPIConfiguration
5568
+ */
5569
+ const multiRollupConfig = {
5570
+ getProduction: () => ({
5571
+ indexer: createConfig({
5572
+ basePath: 'https://indexer-mr.imtbl.com',
5573
+ }),
5574
+ orderBook: createConfig({
5575
+ basePath: 'https://order-book-mr.imtbl.com',
5576
+ }),
5577
+ passport: createConfig({
5578
+ basePath: 'https://api.immutable.com',
5579
+ }),
5580
+ }),
5581
+ getSandbox: () => ({
5582
+ indexer: createConfig({
5583
+ basePath: 'https://indexer-mr.sandbox.imtbl.com',
5584
+ }),
5585
+ orderBook: createConfig({
5586
+ basePath: 'https://order-book-mr.sandbox.imtbl.com',
5587
+ }),
5588
+ passport: createConfig({
5589
+ basePath: 'https://api.sandbox.immutable.com',
5590
+ }),
5591
+ }),
5592
+ };
5593
+
5441
5594
  /**
5442
5595
  * Custom Error class that is returned from the API when a request fails
5443
5596
  */
@@ -5457,7 +5610,7 @@ class APIError extends Error {
5457
5610
 
5458
5611
  /* eslint-disable implicit-arrow-linebreak */
5459
5612
  const defaultHeaders = {
5460
- sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.2.3-alpha.1',
5613
+ sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.3.0-alpha.1',
5461
5614
  };
5462
5615
  /**
5463
5616
  * createAPIConfiguration to create a custom Configuration
@@ -5723,7 +5876,7 @@ const createImmutableXConfiguration = ({ basePath, chainID, coreContractAddress,
5723
5876
  chainID,
5724
5877
  coreContractAddress,
5725
5878
  registrationContractAddress,
5726
- sdkVersion: 'ts-immutable-sdk-0.2.3-alpha.1',
5879
+ sdkVersion: 'ts-immutable-sdk-0.3.0-alpha.1',
5727
5880
  });
5728
5881
  /**
5729
5882
  * Sets `sdkVersion` at the time of build
@@ -10071,10 +10224,12 @@ class AuthManager {
10071
10224
  userManager;
10072
10225
  config;
10073
10226
  deviceCredentialsManager;
10227
+ logoutMode;
10074
10228
  constructor(config) {
10075
10229
  this.config = config;
10076
10230
  this.userManager = new oidcClientTs.UserManager(getAuthConfiguration(config));
10077
10231
  this.deviceCredentialsManager = new DeviceCredentialsManager();
10232
+ this.logoutMode = config.oidcConfiguration.logoutMode || 'redirect';
10078
10233
  }
10079
10234
  static mapOidcUserToDomainModel = (oidcUser) => {
10080
10235
  const passport = oidcUser.profile?.passport;
@@ -10228,7 +10383,15 @@ class AuthManager {
10228
10383
  return response.data;
10229
10384
  }
10230
10385
  async logout() {
10231
- return withPassportError(async () => this.userManager.signoutRedirect(), PassportErrorType.LOGOUT_ERROR);
10386
+ return withPassportError(async () => {
10387
+ if (this.logoutMode === 'silent') {
10388
+ return this.userManager.signoutSilent();
10389
+ }
10390
+ return this.userManager.signoutRedirect();
10391
+ }, PassportErrorType.LOGOUT_ERROR);
10392
+ }
10393
+ async logoutSilentCallback(url) {
10394
+ return this.userManager.signoutSilentCallback(url);
10232
10395
  }
10233
10396
  async logoutDeviceFlow() {
10234
10397
  return withPassportError(async () => {
@@ -10885,6 +11048,10 @@ class PassportConfiguration {
10885
11048
  magicProviderId;
10886
11049
  oidcConfiguration;
10887
11050
  baseConfig;
11051
+ zkEvmChainId;
11052
+ zkEvmRpcUrl;
11053
+ relayerUrl;
11054
+ multiRollupConfig;
10888
11055
  constructor({ baseConfig, overrides, ...oidcConfiguration }) {
10889
11056
  validateConfiguration(oidcConfiguration, [
10890
11057
  'clientId',
@@ -10897,10 +11064,16 @@ class PassportConfiguration {
10897
11064
  validateConfiguration(overrides, [
10898
11065
  'network',
10899
11066
  'authenticationDomain',
11067
+ 'passportDomain',
10900
11068
  'magicPublishableApiKey',
10901
11069
  'magicProviderId',
10902
- 'passportDomain',
11070
+ 'zkEvmRpcUrl',
11071
+ 'zkEvmChainId',
11072
+ 'relayerUrl',
10903
11073
  'imxPublicApiDomain',
11074
+ 'indexerMrBasePath',
11075
+ 'orderBookMrBasePath',
11076
+ 'passportMrBasePath',
10904
11077
  ], 'overrides');
10905
11078
  this.network = overrides.network;
10906
11079
  this.authenticationDomain = overrides.authenticationDomain;
@@ -10908,6 +11081,20 @@ class PassportConfiguration {
10908
11081
  this.imxPublicApiDomain = overrides.imxPublicApiDomain;
10909
11082
  this.magicPublishableApiKey = overrides.magicPublishableApiKey;
10910
11083
  this.magicProviderId = overrides.magicProviderId;
11084
+ this.zkEvmRpcUrl = overrides.zkEvmRpcUrl;
11085
+ this.zkEvmChainId = overrides.zkEvmChainId;
11086
+ this.relayerUrl = overrides.relayerUrl;
11087
+ this.multiRollupConfig = {
11088
+ indexer: createConfig({
11089
+ basePath: overrides.indexerMrBasePath,
11090
+ }),
11091
+ orderBook: createConfig({
11092
+ basePath: overrides.orderBookMrBasePath,
11093
+ }),
11094
+ passport: createConfig({
11095
+ basePath: overrides.passportMrBasePath,
11096
+ }),
11097
+ };
10911
11098
  }
10912
11099
  else {
10913
11100
  switch (baseConfig.environment) {
@@ -10918,6 +11105,10 @@ class PassportConfiguration {
10918
11105
  this.magicProviderId = 'fSMzaRQ4O7p4fttl7pCyGVtJS_G70P8SNsLXtPPGHo0=';
10919
11106
  this.passportDomain = 'https://passport.immutable.com';
10920
11107
  this.imxPublicApiDomain = 'https://api.immutable.com';
11108
+ this.zkEvmRpcUrl = ''; // TODO: ID-785 Update once mainnet has been deployed
11109
+ this.zkEvmChainId = ''; // TODO: ID-785 Update once mainnet has been deployed
11110
+ this.relayerUrl = 'https://relayer.immutable.com'; // TODO: ID-784 Update once we have added Relayer URL to config
11111
+ this.multiRollupConfig = multiRollupConfig.getProduction();
10921
11112
  break;
10922
11113
  }
10923
11114
  case exports.Environment.SANDBOX:
@@ -10928,6 +11119,10 @@ class PassportConfiguration {
10928
11119
  this.magicProviderId = 'fSMzaRQ4O7p4fttl7pCyGVtJS_G70P8SNsLXtPPGHo0=';
10929
11120
  this.passportDomain = 'https://passport.sandbox.immutable.com';
10930
11121
  this.imxPublicApiDomain = 'https://api.sandbox.immutable.com';
11122
+ this.zkEvmRpcUrl = 'https://zkevm-rpc.sandbox.x.immutable.com';
11123
+ this.zkEvmChainId = 'eip155:13392';
11124
+ this.relayerUrl = 'https://evm-relayer.sandbox.imtbl.com'; // TODO: ID-784 Update once we have added Relayer URL to config
11125
+ this.multiRollupConfig = multiRollupConfig.getSandbox();
10931
11126
  break;
10932
11127
  }
10933
11128
  }
@@ -11088,6 +11283,454 @@ class ConfirmationScreen {
11088
11283
  }
11089
11284
  }
11090
11285
 
11286
+ // These are ignored by the Relayer but for consistency we set them to the
11287
+ // appropriate values for a 1/1 wallet.
11288
+ //
11289
+ // Weight of a single signature in the multisig
11290
+ const SIGNATURE_WEIGHT = 1;
11291
+ // Total required weight in the multisig
11292
+ const SIGNATURE_THRESHOLD = 1;
11293
+ const ETH_SIGN_FLAG = '02';
11294
+ const ETH_SIGN_PREFIX = '\x19\x01';
11295
+ const META_TRANSACTIONS_TYPE = `tuple(
11296
+ bool delegateCall,
11297
+ bool revertOnError,
11298
+ uint256 gasLimit,
11299
+ address target,
11300
+ uint256 value,
11301
+ bytes data
11302
+ )[]`;
11303
+ function getNormalisedTransactions(txs) {
11304
+ return txs.map((t) => ({
11305
+ delegateCall: t.delegateCall === true,
11306
+ revertOnError: t.revertOnError === true,
11307
+ gasLimit: t.gasLimit ?? ethers.ethers.constants.Zero,
11308
+ target: t.to ?? ethers.ethers.constants.AddressZero,
11309
+ value: t.value ?? ethers.ethers.constants.Zero,
11310
+ data: t.data ?? [],
11311
+ }));
11312
+ }
11313
+ function digestOfTransactionsAndNonce(nonce, normalisedTransactions) {
11314
+ const packMetaTransactionsNonceData = ethers.ethers.utils.defaultAbiCoder.encode(['uint256', META_TRANSACTIONS_TYPE], [nonce, normalisedTransactions]);
11315
+ return ethers.ethers.utils.keccak256(packMetaTransactionsNonceData);
11316
+ }
11317
+ const getNonce = async (jsonRpcProvider, smartContractWalletAddress) => {
11318
+ const code = await jsonRpcProvider.send('eth_getCode', [smartContractWalletAddress]);
11319
+ if (code && code !== '0x') {
11320
+ const contract = new ethers.ethers.Contract(smartContractWalletAddress, abi.walletContracts.mainModule.abi, jsonRpcProvider);
11321
+ return contract.nonce();
11322
+ }
11323
+ return 0;
11324
+ };
11325
+ const getSignedMetaTransactions = async (metaTransactions, nonce, chainId, walletAddress, signer) => {
11326
+ const normalisedMetaTransactions = getNormalisedTransactions(metaTransactions);
11327
+ // Get the hash
11328
+ const digest = digestOfTransactionsAndNonce(nonce, normalisedMetaTransactions);
11329
+ const completePayload = ethers.ethers.utils.solidityPack(['string', 'uint256', 'address', 'bytes32'], [ETH_SIGN_PREFIX, chainId, walletAddress, digest]);
11330
+ const hash = ethers.ethers.utils.keccak256(completePayload);
11331
+ // Sign the digest
11332
+ const hashArray = ethers.ethers.utils.arrayify(hash);
11333
+ const ethsigNoType = await signer.signMessage(hashArray);
11334
+ const signedDigest = `${ethsigNoType}${ETH_SIGN_FLAG}`;
11335
+ // Add metadata
11336
+ const encodedSignature = config.encodeSignature({
11337
+ threshold: SIGNATURE_THRESHOLD,
11338
+ signers: [
11339
+ {
11340
+ weight: SIGNATURE_WEIGHT,
11341
+ signature: signedDigest,
11342
+ },
11343
+ ],
11344
+ });
11345
+ // Encode the transaction;
11346
+ const walletInterface = new ethers.ethers.utils.Interface(abi.walletContracts.mainModule.abi);
11347
+ return walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [
11348
+ normalisedMetaTransactions,
11349
+ nonce,
11350
+ encodedSignature,
11351
+ ]);
11352
+ };
11353
+ const chainIdNumber = (chainId) => {
11354
+ const caip2Components = chainId.split(':');
11355
+ if (caip2Components.length !== 2) {
11356
+ throw new Error('Invalid configuration, chain ID is not in CAIP-2 format');
11357
+ }
11358
+ return ethers.BigNumber.from(caip2Components[1]);
11359
+ };
11360
+
11361
+ var RelayerTransactionStatus;
11362
+ (function (RelayerTransactionStatus) {
11363
+ RelayerTransactionStatus["PENDING"] = "PENDING";
11364
+ RelayerTransactionStatus["SUBMITTED"] = "SUBMITTED";
11365
+ RelayerTransactionStatus["SUCCESSFUL"] = "SUCCESSFUL";
11366
+ RelayerTransactionStatus["REVERTED"] = "REVERTED";
11367
+ RelayerTransactionStatus["FAILED"] = "FAILED";
11368
+ })(RelayerTransactionStatus || (RelayerTransactionStatus = {}));
11369
+
11370
+ var RpcErrorCode;
11371
+ (function (RpcErrorCode) {
11372
+ RpcErrorCode[RpcErrorCode["RPC_SERVER_ERROR"] = -32000] = "RPC_SERVER_ERROR";
11373
+ RpcErrorCode[RpcErrorCode["INVALID_REQUEST"] = -32600] = "INVALID_REQUEST";
11374
+ RpcErrorCode[RpcErrorCode["METHOD_NOT_FOUND"] = -32601] = "METHOD_NOT_FOUND";
11375
+ RpcErrorCode[RpcErrorCode["INVALID_PARAMS"] = -32602] = "INVALID_PARAMS";
11376
+ RpcErrorCode[RpcErrorCode["INTERNAL_ERROR"] = -32603] = "INTERNAL_ERROR";
11377
+ RpcErrorCode[RpcErrorCode["UNAUTHORIZED"] = -32604] = "UNAUTHORIZED";
11378
+ RpcErrorCode[RpcErrorCode["PARSE_ERROR"] = -32700] = "PARSE_ERROR";
11379
+ })(RpcErrorCode || (RpcErrorCode = {}));
11380
+ class JsonRpcError extends Error {
11381
+ message;
11382
+ code;
11383
+ constructor(code, message) {
11384
+ super(message);
11385
+ this.message = message;
11386
+ this.code = code;
11387
+ }
11388
+ }
11389
+
11390
+ const MAX_TRANSACTION_HASH_RETRIEVAL_RETRIES = 30;
11391
+ const TRANSACTION_HASH_RETRIEVAL_WAIT = 1000;
11392
+ const ethSendTransaction = async ({ params, magicProvider, jsonRpcProvider, relayerClient, config, user, }) => {
11393
+ const transactionRequest = params[0];
11394
+ if (!transactionRequest.to) {
11395
+ throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'eth_sendTransaction requires a "to" field');
11396
+ }
11397
+ const chainId = chainIdNumber(config.zkEvmChainId);
11398
+ const magicWeb3Provider = new providers.Web3Provider(magicProvider);
11399
+ const signer = magicWeb3Provider.getSigner();
11400
+ const nonce = await getNonce(jsonRpcProvider, user.zkEvm.ethAddress);
11401
+ const metaTransaction = {
11402
+ to: transactionRequest.to,
11403
+ data: transactionRequest.data,
11404
+ nonce,
11405
+ value: transactionRequest.value,
11406
+ revertOnError: true,
11407
+ };
11408
+ // NOTE: We sign the transaction before getting the fee options because
11409
+ // accurate estimation of a transaction gas cost is only possible if the smart
11410
+ // wallet contract can actually execute it (in a simulated environment) - and
11411
+ // it can only execute signed transactions.
11412
+ const signedTransaction = await getSignedMetaTransactions([metaTransaction], nonce, chainId, user.zkEvm.ethAddress, signer);
11413
+ // TODO: ID-698 Add support for non-native gas payments (e.g ERC20, feeTransaction initialisation must change)
11414
+ // NOTE: "Fee Options" represent the multiple ways we could pay for the gas
11415
+ // used in this transaction. Each fee option has a "recipientAddress" we
11416
+ // should transfer the payment to, an amount and a currency. We choose one
11417
+ // option and build a transaction that sends the expected currency amount for
11418
+ // that option to the specified address.
11419
+ const feeOptions = await relayerClient.imGetFeeOptions(user.zkEvm.ethAddress, signedTransaction);
11420
+ const imxFeeOption = feeOptions.find((feeOption) => feeOption.tokenSymbol === 'IMX');
11421
+ if (!imxFeeOption) {
11422
+ throw new Error('Failed to retrieve fees for IMX token');
11423
+ }
11424
+ const feeMetaTransaction = {
11425
+ nonce,
11426
+ to: imxFeeOption.recipientAddress,
11427
+ value: imxFeeOption.tokenPrice,
11428
+ revertOnError: true,
11429
+ };
11430
+ // NOTE: We sign again because we now are adding the fee transaction, so the
11431
+ // whole payload is different and needs a new signature.
11432
+ const signedTransactions = await getSignedMetaTransactions([metaTransaction, feeMetaTransaction], nonce, chainId, user.zkEvm.ethAddress, signer);
11433
+ // TODO: ID-697 Evaluate transactions through Guardian
11434
+ const relayerId = await relayerClient.ethSendTransaction(user.zkEvm.ethAddress, signedTransactions);
11435
+ const retrieveRelayerTransaction = async () => {
11436
+ const tx = await relayerClient.imGetTransactionByHash(relayerId);
11437
+ // NOTE: The transaction hash is only available from the Relayer once the
11438
+ // transaction is actually submitted onchain. Hence we need to poll the
11439
+ // Relayer get transaction endpoint until the status transitions to one that
11440
+ // has the hash available.
11441
+ if (tx.status === RelayerTransactionStatus.PENDING) {
11442
+ throw new Error();
11443
+ }
11444
+ return tx;
11445
+ };
11446
+ const relayerTransaction = await retryWithDelay(retrieveRelayerTransaction, {
11447
+ retries: MAX_TRANSACTION_HASH_RETRIEVAL_RETRIES,
11448
+ interval: TRANSACTION_HASH_RETRIEVAL_WAIT,
11449
+ finalErr: new JsonRpcError(RpcErrorCode.RPC_SERVER_ERROR, 'transaction hash not generated in time'),
11450
+ });
11451
+ if (![RelayerTransactionStatus.SUBMITTED, RelayerTransactionStatus.SUCCESSFUL].includes(relayerTransaction.status)) {
11452
+ throw new JsonRpcError(RpcErrorCode.RPC_SERVER_ERROR, `Transaction failed to submit with status ${relayerTransaction.status}`);
11453
+ }
11454
+ return relayerTransaction.hash;
11455
+ };
11456
+
11457
+ class RelayerClient {
11458
+ config;
11459
+ constructor({ config }) {
11460
+ this.config = config;
11461
+ }
11462
+ async postToRelayer(request) {
11463
+ const body = {
11464
+ id: 1,
11465
+ jsonrpc: '2.0',
11466
+ ...request,
11467
+ };
11468
+ const response = await fetch(`${this.config.relayerUrl}/v1/transactions`, {
11469
+ method: 'POST',
11470
+ headers: {
11471
+ 'Content-Type': 'application/json',
11472
+ },
11473
+ body: JSON.stringify(body),
11474
+ });
11475
+ const jsonResponse = await response.json();
11476
+ if (jsonResponse.error) {
11477
+ throw jsonResponse.error;
11478
+ }
11479
+ return jsonResponse;
11480
+ }
11481
+ async ethSendTransaction(to, data) {
11482
+ const payload = {
11483
+ method: 'eth_sendTransaction',
11484
+ params: [{
11485
+ to,
11486
+ data,
11487
+ chainId: this.config.zkEvmChainId.toString(),
11488
+ }],
11489
+ };
11490
+ const { result } = await this.postToRelayer(payload);
11491
+ return result;
11492
+ }
11493
+ async imGetTransactionByHash(hash) {
11494
+ const payload = {
11495
+ method: 'im_getTransactionByHash',
11496
+ params: [hash],
11497
+ };
11498
+ const { result } = await this.postToRelayer(payload);
11499
+ return result;
11500
+ }
11501
+ async imGetFeeOptions(userAddress, data) {
11502
+ const payload = {
11503
+ method: 'im_getFeeOptions',
11504
+ params: [{
11505
+ userAddress,
11506
+ data,
11507
+ chainId: this.config.zkEvmChainId.toString(),
11508
+ }],
11509
+ };
11510
+ const { result } = await this.postToRelayer(payload);
11511
+ return result;
11512
+ }
11513
+ }
11514
+
11515
+ const MESSAGE_TO_SIGN = 'Only sign this message from Immutable Passport';
11516
+ async function createCounterfactualAddress({ authManager, magicProvider, multiRollupApiClients, accessToken, }) {
11517
+ const web3Provider = new providers.Web3Provider(magicProvider);
11518
+ const ethSigner = web3Provider.getSigner();
11519
+ const ethereumAddress = await ethSigner.getAddress();
11520
+ const ethereumSignature = await signRaw(MESSAGE_TO_SIGN, ethSigner);
11521
+ const headers = { Authorization: `Bearer ${accessToken}` };
11522
+ try {
11523
+ await multiRollupApiClients.passportApi.createCounterfactualAddress({
11524
+ createCounterfactualAddressRequest: {
11525
+ ethereumAddress,
11526
+ ethereumSignature,
11527
+ },
11528
+ }, { headers });
11529
+ }
11530
+ catch (error) {
11531
+ throw new JsonRpcError(RpcErrorCode.INTERNAL_ERROR, `Failed to create counterfactual address: ${error}`);
11532
+ }
11533
+ const user = await authManager.loginSilent();
11534
+ if (!user?.zkEvm) {
11535
+ throw new JsonRpcError(RpcErrorCode.INTERNAL_ERROR, 'Failed to refresh user details');
11536
+ }
11537
+ return user;
11538
+ }
11539
+
11540
+ const registerZkEvmUser = async ({ authManager, config, magicAdapter, multiRollupApiClients, }) => {
11541
+ const user = await authManager.getUser() || await authManager.login();
11542
+ if (!user.idToken) {
11543
+ throw new Error('User is missing idToken');
11544
+ }
11545
+ const magicProvider = await magicAdapter.login(user.idToken, config.network);
11546
+ if (!user.zkEvm) {
11547
+ // Generate counterfactual address and retrieve updated Auth0 user
11548
+ const userZkevm = await createCounterfactualAddress({
11549
+ authManager,
11550
+ magicProvider,
11551
+ multiRollupApiClients,
11552
+ accessToken: user.accessToken,
11553
+ });
11554
+ return {
11555
+ user: userZkevm,
11556
+ magicProvider,
11557
+ };
11558
+ }
11559
+ return {
11560
+ user: user,
11561
+ magicProvider,
11562
+ };
11563
+ };
11564
+
11565
+ class ZkEvmProvider {
11566
+ authManager;
11567
+ config;
11568
+ confirmationScreen;
11569
+ magicAdapter;
11570
+ relayerClient;
11571
+ multiRollupApiClients;
11572
+ jsonRpcProvider; // Used for read operations
11573
+ magicProvider; // Used for signing
11574
+ user;
11575
+ constructor({ authManager, magicAdapter, config, confirmationScreen, multiRollupApiClients, }) {
11576
+ this.authManager = authManager;
11577
+ this.magicAdapter = magicAdapter;
11578
+ this.config = config;
11579
+ this.confirmationScreen = confirmationScreen;
11580
+ this.relayerClient = new RelayerClient({ config });
11581
+ this.jsonRpcProvider = new providers.JsonRpcProvider(this.config.zkEvmRpcUrl);
11582
+ this.multiRollupApiClients = multiRollupApiClients;
11583
+ }
11584
+ isLoggedIn() {
11585
+ return this.magicProvider !== undefined && this.user !== undefined;
11586
+ }
11587
+ async performRequest(request) {
11588
+ const authWrapper = (fn) => {
11589
+ if (!this.isLoggedIn()) {
11590
+ throw new JsonRpcError(RpcErrorCode.UNAUTHORIZED, 'Unauthorised - call eth_requestAccounts first');
11591
+ }
11592
+ return fn({
11593
+ params: request.params || [],
11594
+ magicProvider: this.magicProvider,
11595
+ jsonRpcProvider: this.jsonRpcProvider,
11596
+ config: this.config,
11597
+ relayerClient: this.relayerClient,
11598
+ user: this.user,
11599
+ });
11600
+ };
11601
+ switch (request.method) {
11602
+ case 'eth_requestAccounts': {
11603
+ if (this.isLoggedIn()) {
11604
+ return [this.user.zkEvm.ethAddress];
11605
+ }
11606
+ const { magicProvider, user } = await registerZkEvmUser({
11607
+ authManager: this.authManager,
11608
+ config: this.config,
11609
+ magicAdapter: this.magicAdapter,
11610
+ multiRollupApiClients: this.multiRollupApiClients,
11611
+ });
11612
+ this.user = user;
11613
+ this.magicProvider = magicProvider;
11614
+ return [this.user.zkEvm.ethAddress];
11615
+ }
11616
+ case 'eth_sendTransaction': {
11617
+ return authWrapper(ethSendTransaction);
11618
+ }
11619
+ case 'eth_accounts': {
11620
+ return this.isLoggedIn() ? [this.user.zkEvm.ethAddress] : [];
11621
+ }
11622
+ // Pass through methods
11623
+ case 'eth_gasPrice':
11624
+ case 'eth_getBalance':
11625
+ case 'eth_getStorageAt':
11626
+ case 'eth_estimateGas':
11627
+ case 'eth_call':
11628
+ case 'eth_blockNumber':
11629
+ case 'eth_chainId':
11630
+ case 'eth_getBlockByHash':
11631
+ case 'eth_getBlockByNumber':
11632
+ case 'eth_getTransactionByHash':
11633
+ case 'eth_getTransactionReceipt':
11634
+ case 'eth_getTransactionCount': {
11635
+ return this.jsonRpcProvider.send(request.method, request.params || []);
11636
+ }
11637
+ default: {
11638
+ throw new JsonRpcError(RpcErrorCode.METHOD_NOT_FOUND, 'Method not supported');
11639
+ }
11640
+ }
11641
+ }
11642
+ async performJsonRpcRequest(request) {
11643
+ const { id, jsonrpc } = request;
11644
+ try {
11645
+ const result = await this.performRequest(request);
11646
+ return {
11647
+ id,
11648
+ jsonrpc,
11649
+ result,
11650
+ };
11651
+ }
11652
+ catch (error) {
11653
+ let jsonRpcError;
11654
+ if (error instanceof JsonRpcError) {
11655
+ jsonRpcError = error;
11656
+ }
11657
+ else if (error instanceof Error) {
11658
+ jsonRpcError = new JsonRpcError(RpcErrorCode.INTERNAL_ERROR, error.message);
11659
+ }
11660
+ else {
11661
+ jsonRpcError = new JsonRpcError(RpcErrorCode.INTERNAL_ERROR, 'Internal error');
11662
+ }
11663
+ return {
11664
+ id,
11665
+ jsonrpc,
11666
+ error: jsonRpcError,
11667
+ };
11668
+ }
11669
+ }
11670
+ async request(request) {
11671
+ try {
11672
+ return this.performRequest(request);
11673
+ }
11674
+ catch (error) {
11675
+ if (error instanceof JsonRpcError) {
11676
+ throw error;
11677
+ }
11678
+ if (error instanceof Error) {
11679
+ throw new JsonRpcError(RpcErrorCode.INTERNAL_ERROR, error.message);
11680
+ }
11681
+ throw new JsonRpcError(RpcErrorCode.INTERNAL_ERROR, 'Internal error');
11682
+ }
11683
+ }
11684
+ sendAsync(request, callback) {
11685
+ if (!callback) {
11686
+ throw new Error('No callback provided');
11687
+ }
11688
+ if (Array.isArray(request)) {
11689
+ Promise.all(request.map(this.performJsonRpcRequest)).then((result) => {
11690
+ callback(null, result);
11691
+ }).catch((error) => {
11692
+ callback(error, []);
11693
+ });
11694
+ }
11695
+ else {
11696
+ this.performJsonRpcRequest(request).then((result) => {
11697
+ callback(null, result);
11698
+ }).catch((error) => {
11699
+ callback(error, null);
11700
+ });
11701
+ }
11702
+ }
11703
+ async send(request, callbackOrParams, callback) {
11704
+ // Web3 >= 1.0.0-beta.38 calls `send` with method and parameters.
11705
+ if (typeof request === 'string') {
11706
+ if (typeof callbackOrParams === 'function') {
11707
+ return this.sendAsync({
11708
+ method: request,
11709
+ params: [],
11710
+ }, callbackOrParams);
11711
+ }
11712
+ if (callback) {
11713
+ return this.sendAsync({
11714
+ method: request,
11715
+ params: Array.isArray(callbackOrParams) ? callbackOrParams : [],
11716
+ }, callback);
11717
+ }
11718
+ return this.request({
11719
+ method: request,
11720
+ params: Array.isArray(callbackOrParams) ? callbackOrParams : [],
11721
+ });
11722
+ }
11723
+ // Web3 <= 1.0.0-beta.37 uses `send` with a callback for async queries.
11724
+ if (typeof callbackOrParams === 'function') {
11725
+ return this.sendAsync(request, callbackOrParams);
11726
+ }
11727
+ if (!Array.isArray(request) && typeof request === 'object') {
11728
+ return this.performJsonRpcRequest(request);
11729
+ }
11730
+ throw new JsonRpcError(RpcErrorCode.INVALID_REQUEST, 'Invalid request');
11731
+ }
11732
+ }
11733
+
11091
11734
  class Passport {
11092
11735
  authManager;
11093
11736
  config;
@@ -11095,6 +11738,7 @@ class Passport {
11095
11738
  immutableXClient;
11096
11739
  magicAdapter;
11097
11740
  passportImxProviderFactory;
11741
+ multiRollupApiClients;
11098
11742
  constructor(passportModuleConfiguration) {
11099
11743
  this.config = new PassportConfiguration(passportModuleConfiguration);
11100
11744
  this.authManager = new AuthManager(this.config);
@@ -11104,6 +11748,7 @@ class Passport {
11104
11748
  || new ImmutableXClient({
11105
11749
  baseConfig: passportModuleConfiguration.baseConfig,
11106
11750
  });
11751
+ this.multiRollupApiClients = new MultiRollupApiClients(this.config.multiRollupConfig);
11107
11752
  this.passportImxProviderFactory = new PassportImxProviderFactory({
11108
11753
  authManager: this.authManager,
11109
11754
  config: this.config,
@@ -11133,12 +11778,29 @@ class Passport {
11133
11778
  async connectImxWithCredentials(tokenResponse) {
11134
11779
  return this.passportImxProviderFactory.getProviderWithCredentials(tokenResponse);
11135
11780
  }
11781
+ // TODO ID-926 Make method public once development has been finalised
11782
+ connectEvm() {
11783
+ return new ZkEvmProvider({
11784
+ authManager: this.authManager,
11785
+ magicAdapter: this.magicAdapter,
11786
+ config: this.config,
11787
+ confirmationScreen: this.confirmationScreen,
11788
+ multiRollupApiClients: this.multiRollupApiClients,
11789
+ });
11790
+ }
11136
11791
  async loginCallback() {
11137
11792
  return this.authManager.loginCallback();
11138
11793
  }
11139
11794
  async logout() {
11140
11795
  return this.authManager.logout();
11141
11796
  }
11797
+ /**
11798
+ * This method should only be called from the logout redirect uri
11799
+ * when logout mode is 'silent'.
11800
+ */
11801
+ async logoutSilentCallback(url) {
11802
+ return this.authManager.logoutSilentCallback(url);
11803
+ }
11142
11804
  async logoutDeviceFlow() {
11143
11805
  return this.authManager.logoutDeviceFlow();
11144
11806
  }
@@ -27931,7 +28593,7 @@ class $a8cb37a3fc8eb863$export$1f60ba4ec72508a0 {
27931
28593
  function $parcel$export(e, n, v, s) {
27932
28594
  Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
27933
28595
  }
27934
- const $d663162fd5a0853f$export$38a083d9fb5551ca = "0.2.3-alpha.1";
28596
+ const $d663162fd5a0853f$export$38a083d9fb5551ca = "0.3.0-alpha.1";
27935
28597
  const $d663162fd5a0853f$export$83bf90b30cdfd29f = ()=>false;
27936
28598
  const $d663162fd5a0853f$export$1169f5475725171b = ()=>$d663162fd5a0853f$export$38a083d9fb5551ca;
27937
28599