From dabd6f2c631a246c826c4b4459d9360409118aa3 Mon Sep 17 00:00:00 2001 From: Hayden Fowler Date: Fri, 23 Feb 2024 13:35:26 +1100 Subject: [PATCH] feat: ID-1428 Updated isRegisteredOffchain & getAddress to not wait for signers --- .../src/starkEx/passportImxProvider.test.ts | 4 +- .../sdk/src/starkEx/passportImxProvider.ts | 76 +++++++++++-------- .../workflows/registerOffchain.test.ts | 5 +- .../src/starkEx/workflows/registerOffchain.ts | 2 +- 4 files changed, 53 insertions(+), 34 deletions(-) diff --git a/packages/passport/sdk/src/starkEx/passportImxProvider.test.ts b/packages/passport/sdk/src/starkEx/passportImxProvider.test.ts index 9a57101c50..7e75f5195d 100644 --- a/packages/passport/sdk/src/starkEx/passportImxProvider.test.ts +++ b/packages/passport/sdk/src/starkEx/passportImxProvider.test.ts @@ -133,7 +133,7 @@ describe('PassportImxProvider', () => { imxApiClients: new ImxApiClients({} as any), }); - await expect(pp.getAddress()).rejects.toThrow(new Error('error')); + await expect(pp.registerOffchain()).rejects.toThrow(new Error('error')); }); }); @@ -354,6 +354,7 @@ describe('PassportImxProvider', () => { ['batchNftTransfer' as const, [] as NftTransferDetails[]], ['exchangeTransfer' as const, {} as UnsignedExchangeTransferRequest], ['getAddress' as const, {} as any], + ['isRegisteredOffchain' as const, {} as any], ])('when the user has been logged out - %s', (methodName, args) => { beforeEach(() => { passportEventEmitter.emit(PassportEvents.LOGGED_OUT); @@ -379,6 +380,7 @@ describe('PassportImxProvider', () => { ['batchNftTransfer' as const, [] as NftTransferDetails[]], ['exchangeTransfer' as const, {} as UnsignedExchangeTransferRequest], ['getAddress' as const, {} as any], + ['isRegisteredOffchain' as const, {} as any], ])('when the user\'s access token is expired and cannot be retrieved', (methodName, args) => { beforeEach(() => { mockAuthManager.getUser.mockResolvedValue(null); diff --git a/packages/passport/sdk/src/starkEx/passportImxProvider.ts b/packages/passport/sdk/src/starkEx/passportImxProvider.ts index 21249b062c..1f97440dd9 100644 --- a/packages/passport/sdk/src/starkEx/passportImxProvider.ts +++ b/packages/passport/sdk/src/starkEx/passportImxProvider.ts @@ -45,12 +45,6 @@ export interface PassportImxProviderOptions { guardianClient: GuardianClient; } -type AuthenticatedUserAndSigners = { - user: User; - starkSigner: StarkSigner; - ethSigner: EthSigner; -}; - type RegisteredUserAndSigners = { user: UserImx; starkSigner: StarkSigner; @@ -71,8 +65,8 @@ export class PassportImxProvider implements IMXProvider { /** * This property is set during initialisation and stores the signers in a promise. * This property is not meant to be accessed directly, but through the - * `getAuthenticatedUserAndSigners` method. - * @see getAuthenticatedUserAndSigners + * `#getSigners` method. + * @see #getSigners */ private signers: Promise | undefined; @@ -91,7 +85,7 @@ export class PassportImxProvider implements IMXProvider { this.magicAdapter = magicAdapter; this.imxApiClients = imxApiClients; this.guardianClient = guardianClient; - this.initialiseSigners(); + this.#initialiseSigners(); passportEventEmitter.on(PassportEvents.LOGGED_OUT, this.handleLogout); } @@ -109,10 +103,10 @@ export class PassportImxProvider implements IMXProvider { * so that it doesn't result in an unhandled promise rejection. * * This error is thrown when the signers are requested through: - * @see getAuthenticatedUserAndSigners + * @see #getSigners * */ - private initialiseSigners() { + #initialiseSigners() { const generateSigners = async (): Promise => { const user = await this.authManager.getUser(); // The user will be present because the factory validates it @@ -137,8 +131,9 @@ export class PassportImxProvider implements IMXProvider { }); } - protected async getAuthenticatedUserAndSigners(): Promise { + async #getAuthenticatedUser(): Promise { const user = await this.authManager.getUser(); + if (!user || !this.signers) { throw new PassportError( 'User has been logged out', @@ -146,6 +141,10 @@ export class PassportImxProvider implements IMXProvider { ); } + return user; + } + + async #getSigners(): Promise { const signers = await this.signers; // Throw the stored error if the signers failed to initialise if (typeof signers === 'undefined') { @@ -155,11 +154,14 @@ export class PassportImxProvider implements IMXProvider { throw new Error('Signers failed to initialise'); } - return { user, ...signers }; + return signers; } - protected async getRegisteredImxUserAndSigners(): Promise { - const { user, starkSigner, ethSigner } = await this.getAuthenticatedUserAndSigners(); + async #getRegisteredImxUserAndSigners(): Promise { + const [user, signers] = await Promise.all([ + this.#getAuthenticatedUser(), + this.#getSigners(), + ]); if (!isUserImx(user)) { throw new PassportError( @@ -168,11 +170,15 @@ export class PassportImxProvider implements IMXProvider { ); } - return { user, starkSigner, ethSigner }; + return { + user, + starkSigner: signers.starkSigner, + ethSigner: signers.ethSigner, + }; } async transfer(request: UnsignedTransferRequest): Promise { - const { user, starkSigner } = await this.getRegisteredImxUserAndSigners(); + const { user, starkSigner } = await this.#getRegisteredImxUserAndSigners(); return transfer({ request, @@ -184,10 +190,14 @@ export class PassportImxProvider implements IMXProvider { } async registerOffchain(): Promise { - const { user, ethSigner, starkSigner } = await this.getAuthenticatedUserAndSigners(); + const [user, signers] = await Promise.all([ + this.#getAuthenticatedUser(), + this.#getSigners(), + ]); + return await registerOffchain( - ethSigner, - starkSigner, + signers.ethSigner, + signers.starkSigner, user, this.authManager, this.imxApiClients, @@ -195,11 +205,11 @@ export class PassportImxProvider implements IMXProvider { } async isRegisteredOffchain(): Promise { - const { user } = await this.getAuthenticatedUserAndSigners(); + const user = await this.#getAuthenticatedUser(); + return !!user.imx; } - // TODO: Remove once implemented // eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars isRegisteredOnchain(): Promise { throw new PassportError( @@ -209,7 +219,7 @@ export class PassportImxProvider implements IMXProvider { } async createOrder(request: UnsignedOrderRequest): Promise { - const { user, starkSigner } = await this.getRegisteredImxUserAndSigners(); + const { user, starkSigner } = await this.#getRegisteredImxUserAndSigners(); return createOrder({ request, @@ -223,7 +233,7 @@ export class PassportImxProvider implements IMXProvider { async cancelOrder( request: GetSignableCancelOrderRequest, ): Promise { - const { user, starkSigner } = await this.getRegisteredImxUserAndSigners(); + const { user, starkSigner } = await this.#getRegisteredImxUserAndSigners(); return cancelOrder({ request, @@ -235,7 +245,7 @@ export class PassportImxProvider implements IMXProvider { } async createTrade(request: GetSignableTradeRequest): Promise { - const { user, starkSigner } = await this.getRegisteredImxUserAndSigners(); + const { user, starkSigner } = await this.#getRegisteredImxUserAndSigners(); return createTrade({ request, @@ -249,7 +259,7 @@ export class PassportImxProvider implements IMXProvider { async batchNftTransfer( request: NftTransferDetails[], ): Promise { - const { user, starkSigner } = await this.getRegisteredImxUserAndSigners(); + const { user, starkSigner } = await this.#getRegisteredImxUserAndSigners(); return batchNftTransfer({ request, @@ -263,7 +273,7 @@ export class PassportImxProvider implements IMXProvider { async exchangeTransfer( request: UnsignedExchangeTransferRequest, ): Promise { - const { user, starkSigner } = await this.getRegisteredImxUserAndSigners(); + const { user, starkSigner } = await this.#getRegisteredImxUserAndSigners(); return exchangeTransfer({ request, @@ -273,7 +283,6 @@ export class PassportImxProvider implements IMXProvider { }); } - // TODO: Remove once implemented // eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars deposit(deposit: TokenAmount): Promise { throw new PassportError( @@ -282,7 +291,6 @@ export class PassportImxProvider implements IMXProvider { ); } - // TODO: Remove once implemented // eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars prepareWithdrawal(request: TokenAmount): Promise { throw new PassportError( @@ -291,7 +299,6 @@ export class PassportImxProvider implements IMXProvider { ); } - // TODO: Remove once implemented // eslint-disable-next-line class-methods-use-this completeWithdrawal( // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -306,7 +313,14 @@ export class PassportImxProvider implements IMXProvider { } async getAddress(): Promise { - const { user } = await this.getRegisteredImxUserAndSigners(); + const user = await this.#getAuthenticatedUser(); + if (!isUserImx(user)) { + throw new PassportError( + 'User has not been registered with StarkEx', + PassportErrorType.USER_NOT_REGISTERED_ERROR, + ); + } + return Promise.resolve(user.imx.ethAddress); } } diff --git a/packages/passport/sdk/src/starkEx/workflows/registerOffchain.test.ts b/packages/passport/sdk/src/starkEx/workflows/registerOffchain.test.ts index 8001ce51eb..e6a6754974 100644 --- a/packages/passport/sdk/src/starkEx/workflows/registerOffchain.test.ts +++ b/packages/passport/sdk/src/starkEx/workflows/registerOffchain.test.ts @@ -87,7 +87,10 @@ describe('registerOffchain', () => { const imxApiClients = new ImxApiClients({} as any); // create axios error with status 409 const err = new AxiosError('User already registered'); - err.status = 409; + err.response = { + ...err.response, + status: 409, + } as typeof err.response; (registerPassportStarkEx as jest.Mock).mockRejectedValue(err); mockForceUserRefresh.mockResolvedValue(mockUserImx); diff --git a/packages/passport/sdk/src/starkEx/workflows/registerOffchain.ts b/packages/passport/sdk/src/starkEx/workflows/registerOffchain.ts index 575e01a3e0..a78c7feb00 100644 --- a/packages/passport/sdk/src/starkEx/workflows/registerOffchain.ts +++ b/packages/passport/sdk/src/starkEx/workflows/registerOffchain.ts @@ -38,7 +38,7 @@ export default async function registerOffchain( return response; } catch (err: any) { - if (axios.isAxiosError(err) && err.status === 409) { + if (axios.isAxiosError(err) && err.response?.status === 409) { // The user already registered, but the user token is not updated yet. await forceUserRefresh(authManager); return { tx_hash: '' };