@imtbl/sdk 0.2.0-alpha → 0.2.2-alpha

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
@@ -2,6 +2,7 @@ import axios$2 from 'axios';
2
2
  import { ImmutableX, Config, generateLegacyStarkPrivateKey, createStarkSigner, TransfersApi, OrdersApi as OrdersApi$1, UsersApi, Contracts, TradesApi, ExchangesApi, WithdrawalsApi, MintsApi, DepositsApi, EncodingApi, TokensApi as TokensApi$1 } from '@imtbl/core-sdk';
3
3
  export { createStarkSigner as imxClientCreateStarkSigner, generateLegacyStarkPrivateKey as imxClientGenerateLegacyStarkPrivateKey } from '@imtbl/core-sdk';
4
4
  import { UserManager } from 'oidc-client-ts';
5
+ import jwt_decode from 'jwt-decode';
5
6
  import { Magic } from 'magic-sdk';
6
7
  import { OpenIdExtension } from '@magic-ext/oidc';
7
8
  import BN$2 from 'bn.js';
@@ -5436,7 +5437,7 @@ class APIError extends Error {
5436
5437
 
5437
5438
  /* eslint-disable implicit-arrow-linebreak */
5438
5439
  const defaultHeaders = {
5439
- sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.2.0-alpha',
5440
+ sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.2.2-alpha',
5440
5441
  };
5441
5442
  /**
5442
5443
  * createAPIConfiguration to create a custom Configuration
@@ -5702,7 +5703,7 @@ const createImmutableXConfiguration = ({ basePath, chainID, coreContractAddress,
5702
5703
  chainID,
5703
5704
  coreContractAddress,
5704
5705
  registrationContractAddress,
5705
- sdkVersion: 'ts-immutable-sdk-0.2.0-alpha',
5706
+ sdkVersion: 'ts-immutable-sdk-0.2.2-alpha',
5706
5707
  });
5707
5708
  /**
5708
5709
  * Sets `sdkVersion` at the time of build
@@ -9979,6 +9980,43 @@ const withPassportError = async (fn, customErrorType) => {
9979
9980
  }
9980
9981
  };
9981
9982
 
9983
+ const keyCrendentials = 'passport_credentials';
9984
+ const validCredentialsMinTtlSec = 3600; // 1 hour
9985
+ class DeviceCredentialsManager {
9986
+ saveCredentials(tokenResponse) {
9987
+ localStorage.setItem(keyCrendentials, JSON.stringify(tokenResponse));
9988
+ }
9989
+ getCredentials() {
9990
+ const credentialsJson = localStorage.getItem(keyCrendentials);
9991
+ if (credentialsJson) {
9992
+ return JSON.parse(credentialsJson);
9993
+ }
9994
+ return null;
9995
+ }
9996
+ areValid(tokenResponse) {
9997
+ if (tokenResponse) {
9998
+ const accessTokenValid = this.isTokenValid(tokenResponse.access_token);
9999
+ const idTokenValid = this.isTokenValid(tokenResponse.id_token);
10000
+ return accessTokenValid && idTokenValid;
10001
+ }
10002
+ return false;
10003
+ }
10004
+ isTokenValid(jwt) {
10005
+ const tokenPayload = jwt_decode(jwt);
10006
+ const expiresAt = tokenPayload.exp ?? 0;
10007
+ const now = (Date.now() / 1000) + validCredentialsMinTtlSec;
10008
+ return expiresAt > now;
10009
+ }
10010
+ clearCredentials() {
10011
+ localStorage.removeItem(keyCrendentials);
10012
+ }
10013
+ }
10014
+
10015
+ const formUrlEncodedHeader = {
10016
+ headers: {
10017
+ 'Content-Type': 'application/x-www-form-urlencoded',
10018
+ },
10019
+ };
9982
10020
  const getAuthConfiguration = ({ oidcConfiguration, authenticationDomain, }) => {
9983
10021
  const baseConfiguration = {
9984
10022
  authority: authenticationDomain,
@@ -10004,12 +10042,19 @@ const getAuthConfiguration = ({ oidcConfiguration, authenticationDomain, }) => {
10004
10042
  }
10005
10043
  return baseConfiguration;
10006
10044
  };
10045
+ function wait$1(ms) {
10046
+ return new Promise((resolve) => {
10047
+ setTimeout(resolve, ms);
10048
+ });
10049
+ }
10007
10050
  class AuthManager {
10008
10051
  userManager;
10009
10052
  config;
10053
+ deviceCredentialsManager;
10010
10054
  constructor(config) {
10011
10055
  this.config = config;
10012
10056
  this.userManager = new UserManager(getAuthConfiguration(config));
10057
+ this.deviceCredentialsManager = new DeviceCredentialsManager();
10013
10058
  }
10014
10059
  static mapOidcUserToDomainModel = (oidcUser) => {
10015
10060
  const passport = oidcUser.profile?.passport;
@@ -10039,6 +10084,27 @@ class AuthManager {
10039
10084
  }
10040
10085
  return user;
10041
10086
  };
10087
+ static mapDeviceTokenResponseToDomainUserModel = (tokenResponse) => {
10088
+ const idTokenPayload = jwt_decode(tokenResponse.id_token);
10089
+ const user = {
10090
+ idToken: tokenResponse.id_token,
10091
+ accessToken: tokenResponse.access_token,
10092
+ refreshToken: tokenResponse.refresh_token,
10093
+ profile: {
10094
+ sub: idTokenPayload.sub,
10095
+ email: idTokenPayload.email,
10096
+ nickname: idTokenPayload.nickname,
10097
+ },
10098
+ };
10099
+ if (idTokenPayload?.passport?.imx_eth_address) {
10100
+ user.imx = {
10101
+ ethAddress: idTokenPayload?.passport?.imx_eth_address,
10102
+ starkAddress: idTokenPayload?.passport?.imx_stark_address,
10103
+ userAdminAddress: idTokenPayload?.passport?.imx_user_admin_address,
10104
+ };
10105
+ }
10106
+ return user;
10107
+ };
10042
10108
  async login() {
10043
10109
  return withPassportError(async () => {
10044
10110
  const popupWindowFeatures = { width: 410, height: 450 };
@@ -10051,9 +10117,104 @@ class AuthManager {
10051
10117
  async loginCallback() {
10052
10118
  return withPassportError(async () => this.userManager.signinPopupCallback(), PassportErrorType.AUTHENTICATION_ERROR);
10053
10119
  }
10120
+ async loginWithDeviceFlow() {
10121
+ return withPassportError(async () => {
10122
+ const response = await axios$2.post(`${this.config.authenticationDomain}/oauth/device/code`, {
10123
+ client_id: this.config.oidcConfiguration.clientId,
10124
+ scope: this.config.oidcConfiguration.scope,
10125
+ audience: this.config.oidcConfiguration.audience,
10126
+ }, formUrlEncodedHeader);
10127
+ return {
10128
+ code: response.data.user_code,
10129
+ deviceCode: response.data.device_code,
10130
+ url: response.data.verification_uri_complete,
10131
+ interval: response.data.interval,
10132
+ };
10133
+ }, PassportErrorType.AUTHENTICATION_ERROR);
10134
+ }
10135
+ /* eslint-disable no-await-in-loop */
10136
+ async connectImxDeviceFlow(deviceCode, interval, timeoutMs) {
10137
+ return withPassportError(async () => {
10138
+ const startTime = Date.now();
10139
+ const loopCondition = true;
10140
+ while (loopCondition) {
10141
+ if (timeoutMs != null && Date.now() - startTime > timeoutMs) {
10142
+ throw new Error('Timed out');
10143
+ }
10144
+ await wait$1(interval * 1000);
10145
+ try {
10146
+ const tokenResponse = await this.getDeviceFlowToken(deviceCode);
10147
+ const user = AuthManager.mapDeviceTokenResponseToDomainUserModel(tokenResponse);
10148
+ // Only persist credentials that contain the necessary data
10149
+ if (user.imx?.ethAddress && user.imx?.starkAddress && user.imx?.userAdminAddress) {
10150
+ this.deviceCredentialsManager.saveCredentials(tokenResponse);
10151
+ }
10152
+ return user;
10153
+ }
10154
+ catch (error) {
10155
+ if (axios$2.isAxiosError(error)) {
10156
+ const responseError = error.response?.data;
10157
+ switch (responseError.error) {
10158
+ case 'authorization_pending':
10159
+ break;
10160
+ case 'slow_down':
10161
+ break;
10162
+ case 'expired_token':
10163
+ throw new Error('Token expired, please log in again');
10164
+ case 'access_denied':
10165
+ throw new Error('User denied access');
10166
+ default:
10167
+ throw new Error('Error getting token');
10168
+ }
10169
+ }
10170
+ else {
10171
+ throw error;
10172
+ }
10173
+ }
10174
+ }
10175
+ throw new Error('Failed to get credentials');
10176
+ }, PassportErrorType.AUTHENTICATION_ERROR);
10177
+ }
10178
+ /* eslint-enable no-await-in-loop */
10179
+ async getDeviceFlowToken(deviceCode) {
10180
+ const response = await axios$2.post(`${this.config.authenticationDomain}/oauth/token`, {
10181
+ client_id: this.config.oidcConfiguration.clientId,
10182
+ grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
10183
+ device_code: deviceCode,
10184
+ }, formUrlEncodedHeader);
10185
+ return response.data;
10186
+ }
10187
+ async connectImxWithCredentials(tokenResponse) {
10188
+ return withPassportError(async () => {
10189
+ if (this.deviceCredentialsManager.areValid(tokenResponse)) {
10190
+ // Credentials exist and are still valid
10191
+ return AuthManager.mapDeviceTokenResponseToDomainUserModel(tokenResponse);
10192
+ }
10193
+ const refreshToken = tokenResponse?.refresh_token ?? null;
10194
+ if (refreshToken) {
10195
+ // Token is no longer valid, but refresh token can be used to a new one
10196
+ const newTokenResponse = await this.refreshToken(refreshToken);
10197
+ return AuthManager.mapDeviceTokenResponseToDomainUserModel(newTokenResponse);
10198
+ }
10199
+ return null;
10200
+ }, PassportErrorType.AUTHENTICATION_ERROR);
10201
+ }
10202
+ async refreshToken(refreshToken) {
10203
+ const response = await axios$2.post(`${this.config.authenticationDomain}/oauth/token`, {
10204
+ client_id: this.config.oidcConfiguration.clientId,
10205
+ grant_type: 'refresh_token',
10206
+ refresh_token: refreshToken,
10207
+ }, formUrlEncodedHeader);
10208
+ return response.data;
10209
+ }
10054
10210
  async logout() {
10055
10211
  return withPassportError(async () => this.userManager.signoutRedirect(), PassportErrorType.LOGOUT_ERROR);
10056
10212
  }
10213
+ async logoutDeviceFlow() {
10214
+ return withPassportError(async () => {
10215
+ this.deviceCredentialsManager.clearCredentials();
10216
+ }, PassportErrorType.LOGOUT_ERROR);
10217
+ }
10057
10218
  async loginSilent() {
10058
10219
  return withPassportError(async () => {
10059
10220
  const existedUser = await this.getUser();
@@ -10070,12 +10231,28 @@ class AuthManager {
10070
10231
  async getUser() {
10071
10232
  return withPassportError(async () => {
10072
10233
  const oidcUser = await this.userManager.getUser();
10073
- if (!oidcUser) {
10074
- return null;
10234
+ if (oidcUser) {
10235
+ return AuthManager.mapOidcUserToDomainModel(oidcUser);
10075
10236
  }
10076
- return AuthManager.mapOidcUserToDomainModel(oidcUser);
10237
+ const deviceToken = this.deviceCredentialsManager.getCredentials();
10238
+ if (deviceToken) {
10239
+ return AuthManager.mapDeviceTokenResponseToDomainUserModel(deviceToken);
10240
+ }
10241
+ return null;
10077
10242
  }, PassportErrorType.NOT_LOGGED_IN_ERROR);
10078
10243
  }
10244
+ async getUserDeviceFlow() {
10245
+ return withPassportError(async () => {
10246
+ const deviceToken = this.deviceCredentialsManager.getCredentials();
10247
+ if (deviceToken) {
10248
+ return AuthManager.mapDeviceTokenResponseToDomainUserModel(deviceToken);
10249
+ }
10250
+ return null;
10251
+ }, PassportErrorType.NOT_LOGGED_IN_ERROR);
10252
+ }
10253
+ checkStoredDeviceFlowCredentials() {
10254
+ return this.deviceCredentialsManager.getCredentials();
10255
+ }
10079
10256
  }
10080
10257
 
10081
10258
  class MagicAdapter {
@@ -10603,6 +10780,17 @@ class PassportImxProviderFactory {
10603
10780
  }
10604
10781
  return this.createProviderInstance(user);
10605
10782
  }
10783
+ async getProviderWithDeviceFlow(deviceCode, interval, timeoutMs) {
10784
+ const user = await this.authManager.connectImxDeviceFlow(deviceCode, interval, timeoutMs);
10785
+ return this.createProviderInstance(user);
10786
+ }
10787
+ async getProviderWithCredentials(tokenResponse) {
10788
+ const user = await this.authManager.connectImxWithCredentials(tokenResponse);
10789
+ if (!user) {
10790
+ return null;
10791
+ }
10792
+ return this.createProviderInstance(user);
10793
+ }
10606
10794
  async createProviderInstance(user) {
10607
10795
  if (!user.idToken) {
10608
10796
  throw new PassportError('Failed to initialise', PassportErrorType.WALLET_CONNECTION_ERROR);
@@ -10910,16 +11098,38 @@ class Passport {
10910
11098
  async connectImx() {
10911
11099
  return this.passportImxProviderFactory.getProvider();
10912
11100
  }
11101
+ async loginWithDeviceFlow() {
11102
+ return this.authManager.loginWithDeviceFlow();
11103
+ }
11104
+ async connectImxDeviceFlow(deviceCode, interval, timeoutMs) {
11105
+ return this.passportImxProviderFactory.getProviderWithDeviceFlow(deviceCode, interval, timeoutMs);
11106
+ }
11107
+ /**
11108
+ * @returns {boolean} the stored device flow credentials if they exist
11109
+ */
11110
+ checkStoredDeviceFlowCredentials() {
11111
+ return this.authManager.checkStoredDeviceFlowCredentials();
11112
+ }
11113
+ async connectImxWithCredentials(tokenResponse) {
11114
+ return this.passportImxProviderFactory.getProviderWithCredentials(tokenResponse);
11115
+ }
10913
11116
  async loginCallback() {
10914
11117
  return this.authManager.loginCallback();
10915
11118
  }
10916
11119
  async logout() {
10917
11120
  return this.authManager.logout();
10918
11121
  }
11122
+ async logoutDeviceFlow() {
11123
+ return this.authManager.logoutDeviceFlow();
11124
+ }
10919
11125
  async getUserInfo() {
10920
11126
  const user = await this.authManager.getUser();
10921
11127
  return user?.profile;
10922
11128
  }
11129
+ async getUserInfoDeviceFlow() {
11130
+ const user = await this.authManager.getUserDeviceFlow();
11131
+ return user?.profile;
11132
+ }
10923
11133
  async getIdToken() {
10924
11134
  const user = await this.authManager.getUser();
10925
11135
  return user?.idToken;
@@ -12814,16 +13024,14 @@ class Orderbook {
12814
13024
  if (!maybeConfig) {
12815
13025
  throw new Error('Orderbook configuration not passed, either select one of the preseet chainNames or pass in localConfig');
12816
13026
  }
13027
+ const { chainName, provider } = config.overrides;
13028
+ maybeConfig.provider = provider
13029
+ || maybeConfig.provider;
12817
13030
  this.orderbookConfig = maybeConfig;
12818
13031
  const { apiEndpoint } = this.orderbookConfig;
12819
13032
  if (!apiEndpoint) {
12820
13033
  throw new Error('API endpoint must be provided as an override');
12821
13034
  }
12822
- // TODO: Move chainId lookup to a map based on env. Just using override to get dev started
12823
- const chainName = config.overrides?.chainName;
12824
- if (!chainName) {
12825
- throw new Error('chainName must be provided as an override');
12826
- }
12827
13035
  this.apiClient = new ImmutableApiClientFactory(apiEndpoint, chainName, this.orderbookConfig.seaportContractAddress).create();
12828
13036
  const seaportLibFactory = new SeaportLibFactory(this.orderbookConfig.seaportContractAddress, this.orderbookConfig.provider);
12829
13037
  this.seaport = new Seaport(seaportLibFactory, this.orderbookConfig.provider, this.orderbookConfig.seaportContractAddress, this.orderbookConfig.zoneContractAddress);
@@ -27709,7 +27917,7 @@ class $a8cb37a3fc8eb863$export$1f60ba4ec72508a0 {
27709
27917
  function $parcel$export(e, n, v, s) {
27710
27918
  Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
27711
27919
  }
27712
- const $d663162fd5a0853f$export$38a083d9fb5551ca = "0.2.0-alpha";
27920
+ const $d663162fd5a0853f$export$38a083d9fb5551ca = "0.2.2-alpha";
27713
27921
  const $d663162fd5a0853f$export$83bf90b30cdfd29f = ()=>false;
27714
27922
  const $d663162fd5a0853f$export$1169f5475725171b = ()=>$d663162fd5a0853f$export$38a083d9fb5551ca;
27715
27923
 
package/dist/orderbook.js CHANGED
@@ -1887,16 +1887,14 @@ class Orderbook {
1887
1887
  if (!maybeConfig) {
1888
1888
  throw new Error('Orderbook configuration not passed, either select one of the preseet chainNames or pass in localConfig');
1889
1889
  }
1890
+ const { chainName, provider } = config.overrides;
1891
+ maybeConfig.provider = provider
1892
+ || maybeConfig.provider;
1890
1893
  this.orderbookConfig = maybeConfig;
1891
1894
  const { apiEndpoint } = this.orderbookConfig;
1892
1895
  if (!apiEndpoint) {
1893
1896
  throw new Error('API endpoint must be provided as an override');
1894
1897
  }
1895
- // TODO: Move chainId lookup to a map based on env. Just using override to get dev started
1896
- const chainName = config.overrides?.chainName;
1897
- if (!chainName) {
1898
- throw new Error('chainName must be provided as an override');
1899
- }
1900
1898
  this.apiClient = new ImmutableApiClientFactory(apiEndpoint, chainName, this.orderbookConfig.seaportContractAddress).create();
1901
1899
  const seaportLibFactory = new SeaportLibFactory(this.orderbookConfig.seaportContractAddress, this.orderbookConfig.provider);
1902
1900
  this.seaport = new Seaport(seaportLibFactory, this.orderbookConfig.provider, this.orderbookConfig.seaportContractAddress, this.orderbookConfig.zoneContractAddress);
@@ -10488,6 +10488,19 @@ interface PassportOverrides {
10488
10488
  }
10489
10489
  interface PassportModuleConfiguration extends ModuleConfiguration<PassportOverrides>, OidcConfiguration {
10490
10490
  }
10491
+ type DeviceConnectResponse = {
10492
+ code: string;
10493
+ deviceCode: string;
10494
+ url: string;
10495
+ interval: number;
10496
+ };
10497
+ type DeviceTokenResponse = {
10498
+ access_token: string;
10499
+ refresh_token?: string;
10500
+ id_token: string;
10501
+ token_type: string;
10502
+ expires_in: number;
10503
+ };
10491
10504
 
10492
10505
  declare class Passport {
10493
10506
  private readonly authManager;
@@ -10499,11 +10512,20 @@ declare class Passport {
10499
10512
  constructor(passportModuleConfiguration: PassportModuleConfiguration);
10500
10513
  connectImxSilent(): Promise<IMXProvider | null>;
10501
10514
  connectImx(): Promise<IMXProvider>;
10515
+ loginWithDeviceFlow(): Promise<DeviceConnectResponse>;
10516
+ connectImxDeviceFlow(deviceCode: string, interval: number, timeoutMs?: number): Promise<IMXProvider | null>;
10517
+ /**
10518
+ * @returns {boolean} the stored device flow credentials if they exist
10519
+ */
10520
+ checkStoredDeviceFlowCredentials(): DeviceTokenResponse | null;
10521
+ connectImxWithCredentials(tokenResponse: DeviceTokenResponse): Promise<IMXProvider | null>;
10502
10522
  loginCallback(): Promise<void>;
10503
10523
  logout(): Promise<void>;
10524
+ logoutDeviceFlow(): Promise<void>;
10504
10525
  getUserInfo(): Promise<UserProfile | undefined>;
10526
+ getUserInfoDeviceFlow(): Promise<UserProfile | undefined>;
10505
10527
  getIdToken(): Promise<string | undefined>;
10506
10528
  getAccessToken(): Promise<string | undefined>;
10507
10529
  }
10508
10530
 
10509
- export { Networks, Passport, PassportError, PassportModuleConfiguration, PassportOverrides, UserProfile };
10531
+ export { DeviceConnectResponse, DeviceTokenResponse, Networks, Passport, PassportError, PassportModuleConfiguration, PassportOverrides, UserProfile };