@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.js CHANGED
@@ -8,8 +8,10 @@ import { OpenIdExtension } from '@magic-ext/oidc';
8
8
  import BN$2 from 'bn.js';
9
9
  import * as encUtils from 'enc-utils';
10
10
  import { Web3Provider, JsonRpcProvider } from '@ethersproject/providers';
11
+ import { ethers, BigNumber as BigNumber$1, providers, constants, utils as utils$2, Contract as Contract$1, ContractFactory } from 'ethers';
12
+ import { walletContracts } from '@0xsequence/abi';
13
+ import { encodeSignature } from '@0xsequence/config';
11
14
  import FormData$2 from 'form-data';
12
- import { providers, BigNumber as BigNumber$1, constants, utils as utils$2, Contract as Contract$1, ethers, ContractFactory } from 'ethers';
13
15
  import { Seaport as Seaport$1 } from '@opensea/seaport-js';
14
16
  import { parseUnits } from '@ethersproject/units';
15
17
  import { BigNumber as BigNumber$2 } from '@ethersproject/bignumber';
@@ -3245,6 +3247,94 @@ axios$1.default = axios$1;
3245
3247
  // this module should only have a default export
3246
3248
  var globalAxios$1 = axios$1;
3247
3249
 
3250
+ /* tslint:disable */
3251
+ /* eslint-disable */
3252
+ /**
3253
+ * Immutable X API
3254
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
3255
+ *
3256
+ * The version of the OpenAPI document: 3.0
3257
+ * Contact: support@immutable.com
3258
+ *
3259
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
3260
+ * https://openapi-generator.tech
3261
+ * Do not edit the class manually.
3262
+ */
3263
+ let Configuration$1 = class Configuration {
3264
+ /**
3265
+ * parameter for apiKey security
3266
+ * @param name security name
3267
+ * @memberof Configuration
3268
+ */
3269
+ apiKey;
3270
+ /**
3271
+ * parameter for basic security
3272
+ *
3273
+ * @type {string}
3274
+ * @memberof Configuration
3275
+ */
3276
+ username;
3277
+ /**
3278
+ * parameter for basic security
3279
+ *
3280
+ * @type {string}
3281
+ * @memberof Configuration
3282
+ */
3283
+ password;
3284
+ /**
3285
+ * parameter for oauth2 security
3286
+ * @param name security name
3287
+ * @param scopes oauth2 scope
3288
+ * @memberof Configuration
3289
+ */
3290
+ accessToken;
3291
+ /**
3292
+ * override base path
3293
+ *
3294
+ * @type {string}
3295
+ * @memberof Configuration
3296
+ */
3297
+ basePath;
3298
+ /**
3299
+ * base options for axios calls
3300
+ *
3301
+ * @type {any}
3302
+ * @memberof Configuration
3303
+ */
3304
+ baseOptions;
3305
+ /**
3306
+ * The FormData constructor that will be used to create multipart form data
3307
+ * requests. You can inject this here so that execution environments that
3308
+ * do not support the FormData class can still run the generated client.
3309
+ *
3310
+ * @type {new () => FormData}
3311
+ */
3312
+ formDataCtor;
3313
+ constructor(param = {}) {
3314
+ this.apiKey = param.apiKey;
3315
+ this.username = param.username;
3316
+ this.password = param.password;
3317
+ this.accessToken = param.accessToken;
3318
+ this.basePath = param.basePath;
3319
+ this.baseOptions = param.baseOptions;
3320
+ this.formDataCtor = param.formDataCtor;
3321
+ }
3322
+ /**
3323
+ * Check if the given MIME is a JSON MIME.
3324
+ * JSON MIME examples:
3325
+ * application/json
3326
+ * application/json; charset=UTF8
3327
+ * APPLICATION/JSON
3328
+ * application/vnd.company+json
3329
+ * @param mime - MIME (Multipurpose Internet Mail Extensions)
3330
+ * @return True if the given MIME is JSON, false otherwise.
3331
+ */
3332
+ isJsonMime(mime) {
3333
+ const jsonMime = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i');
3334
+ return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json');
3335
+ }
3336
+ };
3337
+
3248
3338
  /* tslint:disable */
3249
3339
  /* eslint-disable */
3250
3340
  /**
@@ -4953,7 +5043,7 @@ class TokensApi extends BaseAPI$1 {
4953
5043
  * https://openapi-generator.tech
4954
5044
  * Do not edit the class manually.
4955
5045
  */
4956
- let Configuration$1 = class Configuration {
5046
+ let Configuration$2 = class Configuration {
4957
5047
  /**
4958
5048
  * parameter for apiKey security
4959
5049
  * @param name security name
@@ -5386,7 +5476,7 @@ var index = /*#__PURE__*/Object.freeze({
5386
5476
  CollectionsApiAxiosParamCreator: CollectionsApiAxiosParamCreator,
5387
5477
  CollectionsApiFactory: CollectionsApiFactory,
5388
5478
  CollectionsApiFp: CollectionsApiFp,
5389
- Configuration: Configuration$1,
5479
+ Configuration: Configuration$2,
5390
5480
  CreateOrderProtocolDataOrderTypeEnum: CreateOrderProtocolDataOrderTypeEnum,
5391
5481
  ERC20ItemItemTypeEnum: ERC20ItemItemTypeEnum,
5392
5482
  ERC721ItemItemTypeEnum: ERC721ItemItemTypeEnum,
@@ -5418,6 +5508,69 @@ var index = /*#__PURE__*/Object.freeze({
5418
5508
  TokensApiFp: TokensApiFp
5419
5509
  });
5420
5510
 
5511
+ class MultiRollupApiClients {
5512
+ config;
5513
+ activitiesApi;
5514
+ chainsApi;
5515
+ collectionApi;
5516
+ nftOwnersApi;
5517
+ nftsApi;
5518
+ ordersApi;
5519
+ passportApi;
5520
+ constructor(config) {
5521
+ this.config = config;
5522
+ this.activitiesApi = new ActivitiesApi(config.indexer);
5523
+ this.chainsApi = new ChainsApi(config.indexer);
5524
+ this.collectionApi = new CollectionsApi(config.indexer);
5525
+ this.nftOwnersApi = new NftOwnersApi(config.indexer);
5526
+ this.nftsApi = new NftsApi(config.indexer);
5527
+ this.ordersApi = new OrdersApi(config.orderBook);
5528
+ this.passportApi = new PassportApi(config.passport);
5529
+ }
5530
+ }
5531
+
5532
+ // eslint-disable-next-line @typescript-eslint/naming-convention
5533
+ const defaultHeaders$1 = { 'x-sdk-version': 'ts-immutable-sdk-0.3.0-alpha.1' };
5534
+ const createConfig = ({ basePath, headers, }) => {
5535
+ if (!basePath.trim()) {
5536
+ throw Error('basePath can not be empty');
5537
+ }
5538
+ const composedHeaders = { ...defaultHeaders$1, ...(headers || {}) };
5539
+ const apiConfigOptions = {
5540
+ basePath,
5541
+ baseOptions: { headers: composedHeaders },
5542
+ };
5543
+ return new Configuration$1(apiConfigOptions);
5544
+ };
5545
+ /**
5546
+ * Creates a Configuration for the specified environment
5547
+ * @returns an MultiRollupAPIConfiguration
5548
+ */
5549
+ const multiRollupConfig = {
5550
+ getProduction: () => ({
5551
+ indexer: createConfig({
5552
+ basePath: 'https://indexer-mr.imtbl.com',
5553
+ }),
5554
+ orderBook: createConfig({
5555
+ basePath: 'https://order-book-mr.imtbl.com',
5556
+ }),
5557
+ passport: createConfig({
5558
+ basePath: 'https://api.immutable.com',
5559
+ }),
5560
+ }),
5561
+ getSandbox: () => ({
5562
+ indexer: createConfig({
5563
+ basePath: 'https://indexer-mr.sandbox.imtbl.com',
5564
+ }),
5565
+ orderBook: createConfig({
5566
+ basePath: 'https://order-book-mr.sandbox.imtbl.com',
5567
+ }),
5568
+ passport: createConfig({
5569
+ basePath: 'https://api.sandbox.immutable.com',
5570
+ }),
5571
+ }),
5572
+ };
5573
+
5421
5574
  /**
5422
5575
  * Custom Error class that is returned from the API when a request fails
5423
5576
  */
@@ -5437,7 +5590,7 @@ class APIError extends Error {
5437
5590
 
5438
5591
  /* eslint-disable implicit-arrow-linebreak */
5439
5592
  const defaultHeaders = {
5440
- sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.2.3-alpha.1',
5593
+ sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.3.0-alpha.1',
5441
5594
  };
5442
5595
  /**
5443
5596
  * createAPIConfiguration to create a custom Configuration
@@ -5703,7 +5856,7 @@ const createImmutableXConfiguration = ({ basePath, chainID, coreContractAddress,
5703
5856
  chainID,
5704
5857
  coreContractAddress,
5705
5858
  registrationContractAddress,
5706
- sdkVersion: 'ts-immutable-sdk-0.2.3-alpha.1',
5859
+ sdkVersion: 'ts-immutable-sdk-0.3.0-alpha.1',
5707
5860
  });
5708
5861
  /**
5709
5862
  * Sets `sdkVersion` at the time of build
@@ -10051,10 +10204,12 @@ class AuthManager {
10051
10204
  userManager;
10052
10205
  config;
10053
10206
  deviceCredentialsManager;
10207
+ logoutMode;
10054
10208
  constructor(config) {
10055
10209
  this.config = config;
10056
10210
  this.userManager = new UserManager(getAuthConfiguration(config));
10057
10211
  this.deviceCredentialsManager = new DeviceCredentialsManager();
10212
+ this.logoutMode = config.oidcConfiguration.logoutMode || 'redirect';
10058
10213
  }
10059
10214
  static mapOidcUserToDomainModel = (oidcUser) => {
10060
10215
  const passport = oidcUser.profile?.passport;
@@ -10208,7 +10363,15 @@ class AuthManager {
10208
10363
  return response.data;
10209
10364
  }
10210
10365
  async logout() {
10211
- return withPassportError(async () => this.userManager.signoutRedirect(), PassportErrorType.LOGOUT_ERROR);
10366
+ return withPassportError(async () => {
10367
+ if (this.logoutMode === 'silent') {
10368
+ return this.userManager.signoutSilent();
10369
+ }
10370
+ return this.userManager.signoutRedirect();
10371
+ }, PassportErrorType.LOGOUT_ERROR);
10372
+ }
10373
+ async logoutSilentCallback(url) {
10374
+ return this.userManager.signoutSilentCallback(url);
10212
10375
  }
10213
10376
  async logoutDeviceFlow() {
10214
10377
  return withPassportError(async () => {
@@ -10865,6 +11028,10 @@ class PassportConfiguration {
10865
11028
  magicProviderId;
10866
11029
  oidcConfiguration;
10867
11030
  baseConfig;
11031
+ zkEvmChainId;
11032
+ zkEvmRpcUrl;
11033
+ relayerUrl;
11034
+ multiRollupConfig;
10868
11035
  constructor({ baseConfig, overrides, ...oidcConfiguration }) {
10869
11036
  validateConfiguration(oidcConfiguration, [
10870
11037
  'clientId',
@@ -10877,10 +11044,16 @@ class PassportConfiguration {
10877
11044
  validateConfiguration(overrides, [
10878
11045
  'network',
10879
11046
  'authenticationDomain',
11047
+ 'passportDomain',
10880
11048
  'magicPublishableApiKey',
10881
11049
  'magicProviderId',
10882
- 'passportDomain',
11050
+ 'zkEvmRpcUrl',
11051
+ 'zkEvmChainId',
11052
+ 'relayerUrl',
10883
11053
  'imxPublicApiDomain',
11054
+ 'indexerMrBasePath',
11055
+ 'orderBookMrBasePath',
11056
+ 'passportMrBasePath',
10884
11057
  ], 'overrides');
10885
11058
  this.network = overrides.network;
10886
11059
  this.authenticationDomain = overrides.authenticationDomain;
@@ -10888,6 +11061,20 @@ class PassportConfiguration {
10888
11061
  this.imxPublicApiDomain = overrides.imxPublicApiDomain;
10889
11062
  this.magicPublishableApiKey = overrides.magicPublishableApiKey;
10890
11063
  this.magicProviderId = overrides.magicProviderId;
11064
+ this.zkEvmRpcUrl = overrides.zkEvmRpcUrl;
11065
+ this.zkEvmChainId = overrides.zkEvmChainId;
11066
+ this.relayerUrl = overrides.relayerUrl;
11067
+ this.multiRollupConfig = {
11068
+ indexer: createConfig({
11069
+ basePath: overrides.indexerMrBasePath,
11070
+ }),
11071
+ orderBook: createConfig({
11072
+ basePath: overrides.orderBookMrBasePath,
11073
+ }),
11074
+ passport: createConfig({
11075
+ basePath: overrides.passportMrBasePath,
11076
+ }),
11077
+ };
10891
11078
  }
10892
11079
  else {
10893
11080
  switch (baseConfig.environment) {
@@ -10898,6 +11085,10 @@ class PassportConfiguration {
10898
11085
  this.magicProviderId = 'fSMzaRQ4O7p4fttl7pCyGVtJS_G70P8SNsLXtPPGHo0=';
10899
11086
  this.passportDomain = 'https://passport.immutable.com';
10900
11087
  this.imxPublicApiDomain = 'https://api.immutable.com';
11088
+ this.zkEvmRpcUrl = ''; // TODO: ID-785 Update once mainnet has been deployed
11089
+ this.zkEvmChainId = ''; // TODO: ID-785 Update once mainnet has been deployed
11090
+ this.relayerUrl = 'https://relayer.immutable.com'; // TODO: ID-784 Update once we have added Relayer URL to config
11091
+ this.multiRollupConfig = multiRollupConfig.getProduction();
10901
11092
  break;
10902
11093
  }
10903
11094
  case Environment$1.SANDBOX:
@@ -10908,6 +11099,10 @@ class PassportConfiguration {
10908
11099
  this.magicProviderId = 'fSMzaRQ4O7p4fttl7pCyGVtJS_G70P8SNsLXtPPGHo0=';
10909
11100
  this.passportDomain = 'https://passport.sandbox.immutable.com';
10910
11101
  this.imxPublicApiDomain = 'https://api.sandbox.immutable.com';
11102
+ this.zkEvmRpcUrl = 'https://zkevm-rpc.sandbox.x.immutable.com';
11103
+ this.zkEvmChainId = 'eip155:13392';
11104
+ this.relayerUrl = 'https://evm-relayer.sandbox.imtbl.com'; // TODO: ID-784 Update once we have added Relayer URL to config
11105
+ this.multiRollupConfig = multiRollupConfig.getSandbox();
10911
11106
  break;
10912
11107
  }
10913
11108
  }
@@ -11068,6 +11263,454 @@ class ConfirmationScreen {
11068
11263
  }
11069
11264
  }
11070
11265
 
11266
+ // These are ignored by the Relayer but for consistency we set them to the
11267
+ // appropriate values for a 1/1 wallet.
11268
+ //
11269
+ // Weight of a single signature in the multisig
11270
+ const SIGNATURE_WEIGHT = 1;
11271
+ // Total required weight in the multisig
11272
+ const SIGNATURE_THRESHOLD = 1;
11273
+ const ETH_SIGN_FLAG = '02';
11274
+ const ETH_SIGN_PREFIX = '\x19\x01';
11275
+ const META_TRANSACTIONS_TYPE = `tuple(
11276
+ bool delegateCall,
11277
+ bool revertOnError,
11278
+ uint256 gasLimit,
11279
+ address target,
11280
+ uint256 value,
11281
+ bytes data
11282
+ )[]`;
11283
+ function getNormalisedTransactions(txs) {
11284
+ return txs.map((t) => ({
11285
+ delegateCall: t.delegateCall === true,
11286
+ revertOnError: t.revertOnError === true,
11287
+ gasLimit: t.gasLimit ?? ethers.constants.Zero,
11288
+ target: t.to ?? ethers.constants.AddressZero,
11289
+ value: t.value ?? ethers.constants.Zero,
11290
+ data: t.data ?? [],
11291
+ }));
11292
+ }
11293
+ function digestOfTransactionsAndNonce(nonce, normalisedTransactions) {
11294
+ const packMetaTransactionsNonceData = ethers.utils.defaultAbiCoder.encode(['uint256', META_TRANSACTIONS_TYPE], [nonce, normalisedTransactions]);
11295
+ return ethers.utils.keccak256(packMetaTransactionsNonceData);
11296
+ }
11297
+ const getNonce = async (jsonRpcProvider, smartContractWalletAddress) => {
11298
+ const code = await jsonRpcProvider.send('eth_getCode', [smartContractWalletAddress]);
11299
+ if (code && code !== '0x') {
11300
+ const contract = new ethers.Contract(smartContractWalletAddress, walletContracts.mainModule.abi, jsonRpcProvider);
11301
+ return contract.nonce();
11302
+ }
11303
+ return 0;
11304
+ };
11305
+ const getSignedMetaTransactions = async (metaTransactions, nonce, chainId, walletAddress, signer) => {
11306
+ const normalisedMetaTransactions = getNormalisedTransactions(metaTransactions);
11307
+ // Get the hash
11308
+ const digest = digestOfTransactionsAndNonce(nonce, normalisedMetaTransactions);
11309
+ const completePayload = ethers.utils.solidityPack(['string', 'uint256', 'address', 'bytes32'], [ETH_SIGN_PREFIX, chainId, walletAddress, digest]);
11310
+ const hash = ethers.utils.keccak256(completePayload);
11311
+ // Sign the digest
11312
+ const hashArray = ethers.utils.arrayify(hash);
11313
+ const ethsigNoType = await signer.signMessage(hashArray);
11314
+ const signedDigest = `${ethsigNoType}${ETH_SIGN_FLAG}`;
11315
+ // Add metadata
11316
+ const encodedSignature = encodeSignature({
11317
+ threshold: SIGNATURE_THRESHOLD,
11318
+ signers: [
11319
+ {
11320
+ weight: SIGNATURE_WEIGHT,
11321
+ signature: signedDigest,
11322
+ },
11323
+ ],
11324
+ });
11325
+ // Encode the transaction;
11326
+ const walletInterface = new ethers.utils.Interface(walletContracts.mainModule.abi);
11327
+ return walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [
11328
+ normalisedMetaTransactions,
11329
+ nonce,
11330
+ encodedSignature,
11331
+ ]);
11332
+ };
11333
+ const chainIdNumber = (chainId) => {
11334
+ const caip2Components = chainId.split(':');
11335
+ if (caip2Components.length !== 2) {
11336
+ throw new Error('Invalid configuration, chain ID is not in CAIP-2 format');
11337
+ }
11338
+ return BigNumber$1.from(caip2Components[1]);
11339
+ };
11340
+
11341
+ var RelayerTransactionStatus;
11342
+ (function (RelayerTransactionStatus) {
11343
+ RelayerTransactionStatus["PENDING"] = "PENDING";
11344
+ RelayerTransactionStatus["SUBMITTED"] = "SUBMITTED";
11345
+ RelayerTransactionStatus["SUCCESSFUL"] = "SUCCESSFUL";
11346
+ RelayerTransactionStatus["REVERTED"] = "REVERTED";
11347
+ RelayerTransactionStatus["FAILED"] = "FAILED";
11348
+ })(RelayerTransactionStatus || (RelayerTransactionStatus = {}));
11349
+
11350
+ var RpcErrorCode;
11351
+ (function (RpcErrorCode) {
11352
+ RpcErrorCode[RpcErrorCode["RPC_SERVER_ERROR"] = -32000] = "RPC_SERVER_ERROR";
11353
+ RpcErrorCode[RpcErrorCode["INVALID_REQUEST"] = -32600] = "INVALID_REQUEST";
11354
+ RpcErrorCode[RpcErrorCode["METHOD_NOT_FOUND"] = -32601] = "METHOD_NOT_FOUND";
11355
+ RpcErrorCode[RpcErrorCode["INVALID_PARAMS"] = -32602] = "INVALID_PARAMS";
11356
+ RpcErrorCode[RpcErrorCode["INTERNAL_ERROR"] = -32603] = "INTERNAL_ERROR";
11357
+ RpcErrorCode[RpcErrorCode["UNAUTHORIZED"] = -32604] = "UNAUTHORIZED";
11358
+ RpcErrorCode[RpcErrorCode["PARSE_ERROR"] = -32700] = "PARSE_ERROR";
11359
+ })(RpcErrorCode || (RpcErrorCode = {}));
11360
+ class JsonRpcError extends Error {
11361
+ message;
11362
+ code;
11363
+ constructor(code, message) {
11364
+ super(message);
11365
+ this.message = message;
11366
+ this.code = code;
11367
+ }
11368
+ }
11369
+
11370
+ const MAX_TRANSACTION_HASH_RETRIEVAL_RETRIES = 30;
11371
+ const TRANSACTION_HASH_RETRIEVAL_WAIT = 1000;
11372
+ const ethSendTransaction = async ({ params, magicProvider, jsonRpcProvider, relayerClient, config, user, }) => {
11373
+ const transactionRequest = params[0];
11374
+ if (!transactionRequest.to) {
11375
+ throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'eth_sendTransaction requires a "to" field');
11376
+ }
11377
+ const chainId = chainIdNumber(config.zkEvmChainId);
11378
+ const magicWeb3Provider = new Web3Provider(magicProvider);
11379
+ const signer = magicWeb3Provider.getSigner();
11380
+ const nonce = await getNonce(jsonRpcProvider, user.zkEvm.ethAddress);
11381
+ const metaTransaction = {
11382
+ to: transactionRequest.to,
11383
+ data: transactionRequest.data,
11384
+ nonce,
11385
+ value: transactionRequest.value,
11386
+ revertOnError: true,
11387
+ };
11388
+ // NOTE: We sign the transaction before getting the fee options because
11389
+ // accurate estimation of a transaction gas cost is only possible if the smart
11390
+ // wallet contract can actually execute it (in a simulated environment) - and
11391
+ // it can only execute signed transactions.
11392
+ const signedTransaction = await getSignedMetaTransactions([metaTransaction], nonce, chainId, user.zkEvm.ethAddress, signer);
11393
+ // TODO: ID-698 Add support for non-native gas payments (e.g ERC20, feeTransaction initialisation must change)
11394
+ // NOTE: "Fee Options" represent the multiple ways we could pay for the gas
11395
+ // used in this transaction. Each fee option has a "recipientAddress" we
11396
+ // should transfer the payment to, an amount and a currency. We choose one
11397
+ // option and build a transaction that sends the expected currency amount for
11398
+ // that option to the specified address.
11399
+ const feeOptions = await relayerClient.imGetFeeOptions(user.zkEvm.ethAddress, signedTransaction);
11400
+ const imxFeeOption = feeOptions.find((feeOption) => feeOption.tokenSymbol === 'IMX');
11401
+ if (!imxFeeOption) {
11402
+ throw new Error('Failed to retrieve fees for IMX token');
11403
+ }
11404
+ const feeMetaTransaction = {
11405
+ nonce,
11406
+ to: imxFeeOption.recipientAddress,
11407
+ value: imxFeeOption.tokenPrice,
11408
+ revertOnError: true,
11409
+ };
11410
+ // NOTE: We sign again because we now are adding the fee transaction, so the
11411
+ // whole payload is different and needs a new signature.
11412
+ const signedTransactions = await getSignedMetaTransactions([metaTransaction, feeMetaTransaction], nonce, chainId, user.zkEvm.ethAddress, signer);
11413
+ // TODO: ID-697 Evaluate transactions through Guardian
11414
+ const relayerId = await relayerClient.ethSendTransaction(user.zkEvm.ethAddress, signedTransactions);
11415
+ const retrieveRelayerTransaction = async () => {
11416
+ const tx = await relayerClient.imGetTransactionByHash(relayerId);
11417
+ // NOTE: The transaction hash is only available from the Relayer once the
11418
+ // transaction is actually submitted onchain. Hence we need to poll the
11419
+ // Relayer get transaction endpoint until the status transitions to one that
11420
+ // has the hash available.
11421
+ if (tx.status === RelayerTransactionStatus.PENDING) {
11422
+ throw new Error();
11423
+ }
11424
+ return tx;
11425
+ };
11426
+ const relayerTransaction = await retryWithDelay(retrieveRelayerTransaction, {
11427
+ retries: MAX_TRANSACTION_HASH_RETRIEVAL_RETRIES,
11428
+ interval: TRANSACTION_HASH_RETRIEVAL_WAIT,
11429
+ finalErr: new JsonRpcError(RpcErrorCode.RPC_SERVER_ERROR, 'transaction hash not generated in time'),
11430
+ });
11431
+ if (![RelayerTransactionStatus.SUBMITTED, RelayerTransactionStatus.SUCCESSFUL].includes(relayerTransaction.status)) {
11432
+ throw new JsonRpcError(RpcErrorCode.RPC_SERVER_ERROR, `Transaction failed to submit with status ${relayerTransaction.status}`);
11433
+ }
11434
+ return relayerTransaction.hash;
11435
+ };
11436
+
11437
+ class RelayerClient {
11438
+ config;
11439
+ constructor({ config }) {
11440
+ this.config = config;
11441
+ }
11442
+ async postToRelayer(request) {
11443
+ const body = {
11444
+ id: 1,
11445
+ jsonrpc: '2.0',
11446
+ ...request,
11447
+ };
11448
+ const response = await fetch(`${this.config.relayerUrl}/v1/transactions`, {
11449
+ method: 'POST',
11450
+ headers: {
11451
+ 'Content-Type': 'application/json',
11452
+ },
11453
+ body: JSON.stringify(body),
11454
+ });
11455
+ const jsonResponse = await response.json();
11456
+ if (jsonResponse.error) {
11457
+ throw jsonResponse.error;
11458
+ }
11459
+ return jsonResponse;
11460
+ }
11461
+ async ethSendTransaction(to, data) {
11462
+ const payload = {
11463
+ method: 'eth_sendTransaction',
11464
+ params: [{
11465
+ to,
11466
+ data,
11467
+ chainId: this.config.zkEvmChainId.toString(),
11468
+ }],
11469
+ };
11470
+ const { result } = await this.postToRelayer(payload);
11471
+ return result;
11472
+ }
11473
+ async imGetTransactionByHash(hash) {
11474
+ const payload = {
11475
+ method: 'im_getTransactionByHash',
11476
+ params: [hash],
11477
+ };
11478
+ const { result } = await this.postToRelayer(payload);
11479
+ return result;
11480
+ }
11481
+ async imGetFeeOptions(userAddress, data) {
11482
+ const payload = {
11483
+ method: 'im_getFeeOptions',
11484
+ params: [{
11485
+ userAddress,
11486
+ data,
11487
+ chainId: this.config.zkEvmChainId.toString(),
11488
+ }],
11489
+ };
11490
+ const { result } = await this.postToRelayer(payload);
11491
+ return result;
11492
+ }
11493
+ }
11494
+
11495
+ const MESSAGE_TO_SIGN = 'Only sign this message from Immutable Passport';
11496
+ async function createCounterfactualAddress({ authManager, magicProvider, multiRollupApiClients, accessToken, }) {
11497
+ const web3Provider = new Web3Provider(magicProvider);
11498
+ const ethSigner = web3Provider.getSigner();
11499
+ const ethereumAddress = await ethSigner.getAddress();
11500
+ const ethereumSignature = await signRaw(MESSAGE_TO_SIGN, ethSigner);
11501
+ const headers = { Authorization: `Bearer ${accessToken}` };
11502
+ try {
11503
+ await multiRollupApiClients.passportApi.createCounterfactualAddress({
11504
+ createCounterfactualAddressRequest: {
11505
+ ethereumAddress,
11506
+ ethereumSignature,
11507
+ },
11508
+ }, { headers });
11509
+ }
11510
+ catch (error) {
11511
+ throw new JsonRpcError(RpcErrorCode.INTERNAL_ERROR, `Failed to create counterfactual address: ${error}`);
11512
+ }
11513
+ const user = await authManager.loginSilent();
11514
+ if (!user?.zkEvm) {
11515
+ throw new JsonRpcError(RpcErrorCode.INTERNAL_ERROR, 'Failed to refresh user details');
11516
+ }
11517
+ return user;
11518
+ }
11519
+
11520
+ const registerZkEvmUser = async ({ authManager, config, magicAdapter, multiRollupApiClients, }) => {
11521
+ const user = await authManager.getUser() || await authManager.login();
11522
+ if (!user.idToken) {
11523
+ throw new Error('User is missing idToken');
11524
+ }
11525
+ const magicProvider = await magicAdapter.login(user.idToken, config.network);
11526
+ if (!user.zkEvm) {
11527
+ // Generate counterfactual address and retrieve updated Auth0 user
11528
+ const userZkevm = await createCounterfactualAddress({
11529
+ authManager,
11530
+ magicProvider,
11531
+ multiRollupApiClients,
11532
+ accessToken: user.accessToken,
11533
+ });
11534
+ return {
11535
+ user: userZkevm,
11536
+ magicProvider,
11537
+ };
11538
+ }
11539
+ return {
11540
+ user: user,
11541
+ magicProvider,
11542
+ };
11543
+ };
11544
+
11545
+ class ZkEvmProvider {
11546
+ authManager;
11547
+ config;
11548
+ confirmationScreen;
11549
+ magicAdapter;
11550
+ relayerClient;
11551
+ multiRollupApiClients;
11552
+ jsonRpcProvider; // Used for read operations
11553
+ magicProvider; // Used for signing
11554
+ user;
11555
+ constructor({ authManager, magicAdapter, config, confirmationScreen, multiRollupApiClients, }) {
11556
+ this.authManager = authManager;
11557
+ this.magicAdapter = magicAdapter;
11558
+ this.config = config;
11559
+ this.confirmationScreen = confirmationScreen;
11560
+ this.relayerClient = new RelayerClient({ config });
11561
+ this.jsonRpcProvider = new JsonRpcProvider(this.config.zkEvmRpcUrl);
11562
+ this.multiRollupApiClients = multiRollupApiClients;
11563
+ }
11564
+ isLoggedIn() {
11565
+ return this.magicProvider !== undefined && this.user !== undefined;
11566
+ }
11567
+ async performRequest(request) {
11568
+ const authWrapper = (fn) => {
11569
+ if (!this.isLoggedIn()) {
11570
+ throw new JsonRpcError(RpcErrorCode.UNAUTHORIZED, 'Unauthorised - call eth_requestAccounts first');
11571
+ }
11572
+ return fn({
11573
+ params: request.params || [],
11574
+ magicProvider: this.magicProvider,
11575
+ jsonRpcProvider: this.jsonRpcProvider,
11576
+ config: this.config,
11577
+ relayerClient: this.relayerClient,
11578
+ user: this.user,
11579
+ });
11580
+ };
11581
+ switch (request.method) {
11582
+ case 'eth_requestAccounts': {
11583
+ if (this.isLoggedIn()) {
11584
+ return [this.user.zkEvm.ethAddress];
11585
+ }
11586
+ const { magicProvider, user } = await registerZkEvmUser({
11587
+ authManager: this.authManager,
11588
+ config: this.config,
11589
+ magicAdapter: this.magicAdapter,
11590
+ multiRollupApiClients: this.multiRollupApiClients,
11591
+ });
11592
+ this.user = user;
11593
+ this.magicProvider = magicProvider;
11594
+ return [this.user.zkEvm.ethAddress];
11595
+ }
11596
+ case 'eth_sendTransaction': {
11597
+ return authWrapper(ethSendTransaction);
11598
+ }
11599
+ case 'eth_accounts': {
11600
+ return this.isLoggedIn() ? [this.user.zkEvm.ethAddress] : [];
11601
+ }
11602
+ // Pass through methods
11603
+ case 'eth_gasPrice':
11604
+ case 'eth_getBalance':
11605
+ case 'eth_getStorageAt':
11606
+ case 'eth_estimateGas':
11607
+ case 'eth_call':
11608
+ case 'eth_blockNumber':
11609
+ case 'eth_chainId':
11610
+ case 'eth_getBlockByHash':
11611
+ case 'eth_getBlockByNumber':
11612
+ case 'eth_getTransactionByHash':
11613
+ case 'eth_getTransactionReceipt':
11614
+ case 'eth_getTransactionCount': {
11615
+ return this.jsonRpcProvider.send(request.method, request.params || []);
11616
+ }
11617
+ default: {
11618
+ throw new JsonRpcError(RpcErrorCode.METHOD_NOT_FOUND, 'Method not supported');
11619
+ }
11620
+ }
11621
+ }
11622
+ async performJsonRpcRequest(request) {
11623
+ const { id, jsonrpc } = request;
11624
+ try {
11625
+ const result = await this.performRequest(request);
11626
+ return {
11627
+ id,
11628
+ jsonrpc,
11629
+ result,
11630
+ };
11631
+ }
11632
+ catch (error) {
11633
+ let jsonRpcError;
11634
+ if (error instanceof JsonRpcError) {
11635
+ jsonRpcError = error;
11636
+ }
11637
+ else if (error instanceof Error) {
11638
+ jsonRpcError = new JsonRpcError(RpcErrorCode.INTERNAL_ERROR, error.message);
11639
+ }
11640
+ else {
11641
+ jsonRpcError = new JsonRpcError(RpcErrorCode.INTERNAL_ERROR, 'Internal error');
11642
+ }
11643
+ return {
11644
+ id,
11645
+ jsonrpc,
11646
+ error: jsonRpcError,
11647
+ };
11648
+ }
11649
+ }
11650
+ async request(request) {
11651
+ try {
11652
+ return this.performRequest(request);
11653
+ }
11654
+ catch (error) {
11655
+ if (error instanceof JsonRpcError) {
11656
+ throw error;
11657
+ }
11658
+ if (error instanceof Error) {
11659
+ throw new JsonRpcError(RpcErrorCode.INTERNAL_ERROR, error.message);
11660
+ }
11661
+ throw new JsonRpcError(RpcErrorCode.INTERNAL_ERROR, 'Internal error');
11662
+ }
11663
+ }
11664
+ sendAsync(request, callback) {
11665
+ if (!callback) {
11666
+ throw new Error('No callback provided');
11667
+ }
11668
+ if (Array.isArray(request)) {
11669
+ Promise.all(request.map(this.performJsonRpcRequest)).then((result) => {
11670
+ callback(null, result);
11671
+ }).catch((error) => {
11672
+ callback(error, []);
11673
+ });
11674
+ }
11675
+ else {
11676
+ this.performJsonRpcRequest(request).then((result) => {
11677
+ callback(null, result);
11678
+ }).catch((error) => {
11679
+ callback(error, null);
11680
+ });
11681
+ }
11682
+ }
11683
+ async send(request, callbackOrParams, callback) {
11684
+ // Web3 >= 1.0.0-beta.38 calls `send` with method and parameters.
11685
+ if (typeof request === 'string') {
11686
+ if (typeof callbackOrParams === 'function') {
11687
+ return this.sendAsync({
11688
+ method: request,
11689
+ params: [],
11690
+ }, callbackOrParams);
11691
+ }
11692
+ if (callback) {
11693
+ return this.sendAsync({
11694
+ method: request,
11695
+ params: Array.isArray(callbackOrParams) ? callbackOrParams : [],
11696
+ }, callback);
11697
+ }
11698
+ return this.request({
11699
+ method: request,
11700
+ params: Array.isArray(callbackOrParams) ? callbackOrParams : [],
11701
+ });
11702
+ }
11703
+ // Web3 <= 1.0.0-beta.37 uses `send` with a callback for async queries.
11704
+ if (typeof callbackOrParams === 'function') {
11705
+ return this.sendAsync(request, callbackOrParams);
11706
+ }
11707
+ if (!Array.isArray(request) && typeof request === 'object') {
11708
+ return this.performJsonRpcRequest(request);
11709
+ }
11710
+ throw new JsonRpcError(RpcErrorCode.INVALID_REQUEST, 'Invalid request');
11711
+ }
11712
+ }
11713
+
11071
11714
  class Passport {
11072
11715
  authManager;
11073
11716
  config;
@@ -11075,6 +11718,7 @@ class Passport {
11075
11718
  immutableXClient;
11076
11719
  magicAdapter;
11077
11720
  passportImxProviderFactory;
11721
+ multiRollupApiClients;
11078
11722
  constructor(passportModuleConfiguration) {
11079
11723
  this.config = new PassportConfiguration(passportModuleConfiguration);
11080
11724
  this.authManager = new AuthManager(this.config);
@@ -11084,6 +11728,7 @@ class Passport {
11084
11728
  || new ImmutableXClient({
11085
11729
  baseConfig: passportModuleConfiguration.baseConfig,
11086
11730
  });
11731
+ this.multiRollupApiClients = new MultiRollupApiClients(this.config.multiRollupConfig);
11087
11732
  this.passportImxProviderFactory = new PassportImxProviderFactory({
11088
11733
  authManager: this.authManager,
11089
11734
  config: this.config,
@@ -11113,12 +11758,29 @@ class Passport {
11113
11758
  async connectImxWithCredentials(tokenResponse) {
11114
11759
  return this.passportImxProviderFactory.getProviderWithCredentials(tokenResponse);
11115
11760
  }
11761
+ // TODO ID-926 Make method public once development has been finalised
11762
+ connectEvm() {
11763
+ return new ZkEvmProvider({
11764
+ authManager: this.authManager,
11765
+ magicAdapter: this.magicAdapter,
11766
+ config: this.config,
11767
+ confirmationScreen: this.confirmationScreen,
11768
+ multiRollupApiClients: this.multiRollupApiClients,
11769
+ });
11770
+ }
11116
11771
  async loginCallback() {
11117
11772
  return this.authManager.loginCallback();
11118
11773
  }
11119
11774
  async logout() {
11120
11775
  return this.authManager.logout();
11121
11776
  }
11777
+ /**
11778
+ * This method should only be called from the logout redirect uri
11779
+ * when logout mode is 'silent'.
11780
+ */
11781
+ async logoutSilentCallback(url) {
11782
+ return this.authManager.logoutSilentCallback(url);
11783
+ }
11122
11784
  async logoutDeviceFlow() {
11123
11785
  return this.authManager.logoutDeviceFlow();
11124
11786
  }
@@ -27911,7 +28573,7 @@ class $a8cb37a3fc8eb863$export$1f60ba4ec72508a0 {
27911
28573
  function $parcel$export(e, n, v, s) {
27912
28574
  Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
27913
28575
  }
27914
- const $d663162fd5a0853f$export$38a083d9fb5551ca = "0.2.3-alpha.1";
28576
+ const $d663162fd5a0853f$export$38a083d9fb5551ca = "0.3.0-alpha.1";
27915
28577
  const $d663162fd5a0853f$export$83bf90b30cdfd29f = ()=>false;
27916
28578
  const $d663162fd5a0853f$export$1169f5475725171b = ()=>$d663162fd5a0853f$export$38a083d9fb5551ca;
27917
28579