@@ -14,19 +14,31 @@ import {
1414 UnsignedOrderRequest ,
1515 UnsignedTransferRequest ,
1616} from '@imtbl/core-sdk' ;
17- import { mockUserImx , testConfig } from '../test/mocks' ;
17+ import { Web3Provider } from '@ethersproject/providers' ;
18+ import registerPassportStarkEx from './workflows/registration' ;
19+ import { mockUserImx , testConfig , mockUser } from '../test/mocks' ;
1820import { PassportError , PassportErrorType } from '../errors/passportError' ;
1921import { PassportImxProvider } from './passportImxProvider' ;
2022import {
21- batchNftTransfer , cancelOrder , createOrder , createTrade , exchangeTransfer , transfer ,
23+ batchNftTransfer ,
24+ cancelOrder ,
25+ createOrder ,
26+ createTrade ,
27+ exchangeTransfer ,
28+ transfer ,
2229} from './workflows' ;
2330import { ConfirmationScreen } from '../confirmation' ;
2431import { PassportConfiguration } from '../config' ;
2532import { PassportEventMap , PassportEvents } from '../types' ;
2633import TypedEventEmitter from '../utils/typedEventEmitter' ;
2734import AuthManager from '../authManager' ;
35+ import MagicAdapter from '../magicAdapter' ;
36+ import { getStarkSigner } from './getStarkSigner' ;
2837
38+ jest . mock ( '@ethersproject/providers' ) ;
2939jest . mock ( './workflows' ) ;
40+ jest . mock ( './workflows/registration' ) ;
41+ jest . mock ( './getStarkSigner' ) ;
3042
3143describe ( 'PassportImxProvider' , ( ) => {
3244 afterEach ( jest . resetAllMocks ) ;
@@ -52,22 +64,81 @@ describe('PassportImxProvider', () => {
5264 getAddress : jest . fn ( ) ,
5365 } as StarkSigner ;
5466
67+ const mockEthSigner = {
68+ signMessage : jest . fn ( ) ,
69+ getAddress : jest . fn ( ) ,
70+ } ;
71+
72+ const magicAdapterMock = {
73+ login : jest . fn ( ) ,
74+ } ;
75+
76+ const getSignerMock = jest . fn ( ) ;
77+
5578 let passportEventEmitter : TypedEventEmitter < PassportEventMap > ;
5679
5780 beforeEach ( ( ) => {
81+ jest . restoreAllMocks ( ) ;
82+ getSignerMock . mockReturnValue ( mockEthSigner ) ;
83+ ( registerPassportStarkEx as jest . Mock ) . mockResolvedValue ( null ) ;
5884 passportEventEmitter = new TypedEventEmitter < PassportEventMap > ( ) ;
5985 mockAuthManager . getUser . mockResolvedValue ( mockUserImx ) ;
6086
87+ // Signers
88+ magicAdapterMock . login . mockResolvedValue ( { getSigner : getSignerMock } ) ;
89+ ( Web3Provider as unknown as jest . Mock ) . mockReturnValue ( { getSigner : getSignerMock } ) ;
90+ ( getStarkSigner as jest . Mock ) . mockResolvedValue ( mockStarkSigner ) ;
91+
6192 passportImxProvider = new PassportImxProvider ( {
6293 authManager : mockAuthManager as unknown as AuthManager ,
63- starkSigner : mockStarkSigner ,
94+ magicAdapter : magicAdapterMock as unknown as MagicAdapter ,
6495 confirmationScreen,
6596 immutableXClient,
6697 config : testConfig ,
6798 passportEventEmitter,
6899 } ) ;
69100 } ) ;
70101
102+ describe ( 'async signer initialisation' , ( ) => {
103+ it ( 'initialises the eth and stark signers correctly' , async ( ) => {
104+ // The promise is created in the constructor but not awaited until a method is called
105+ await passportImxProvider . getAddress ( ) ;
106+
107+ expect ( magicAdapterMock . login ) . toHaveBeenCalledWith ( mockUserImx . idToken ) ;
108+ expect ( getStarkSigner ) . toHaveBeenCalledWith ( mockEthSigner ) ;
109+ } ) ;
110+
111+ it ( 'initialises the eth and stark signers only once' , async ( ) => {
112+ await passportImxProvider . getAddress ( ) ;
113+ await passportImxProvider . getAddress ( ) ;
114+ await passportImxProvider . getAddress ( ) ;
115+
116+ expect ( magicAdapterMock . login ) . toHaveBeenCalledTimes ( 1 ) ;
117+ expect ( getStarkSigner ) . toHaveBeenCalledTimes ( 1 ) ;
118+ } ) ;
119+
120+ it ( 're-throws the initialisation error when a method is called' , async ( ) => {
121+ jest . resetAllMocks ( ) ;
122+ jest . restoreAllMocks ( ) ;
123+
124+ mockAuthManager . getUser . mockResolvedValue ( mockUserImx ) ;
125+ // Signers
126+ magicAdapterMock . login . mockResolvedValue ( { } ) ;
127+ ( getStarkSigner as jest . Mock ) . mockRejectedValue ( new Error ( 'error' ) ) ;
128+
129+ const pp = new PassportImxProvider ( {
130+ authManager : mockAuthManager as unknown as AuthManager ,
131+ magicAdapter : magicAdapterMock as unknown as MagicAdapter ,
132+ confirmationScreen,
133+ immutableXClient,
134+ config : testConfig ,
135+ passportEventEmitter : new TypedEventEmitter < PassportEventMap > ( ) ,
136+ } ) ;
137+
138+ await expect ( pp . getAddress ( ) ) . rejects . toThrow ( new Error ( 'error' ) ) ;
139+ } ) ;
140+ } ) ;
141+
71142 describe ( 'transfer' , ( ) => {
72143 it ( 'calls transfer workflow' , async ( ) => {
73144 const returnValue = { } as CreateTransferResponseV1 ;
@@ -90,27 +161,25 @@ describe('PassportImxProvider', () => {
90161 } ) ;
91162 } ) ;
92163
93- describe ( 'registerOffchain' , ( ) => {
94- it ( 'should throw error' , async ( ) => {
95- expect ( passportImxProvider . registerOffchain )
96- . toThrow (
97- new PassportError (
98- 'Operation not supported' ,
99- PassportErrorType . OPERATION_NOT_SUPPORTED_ERROR ,
100- ) ,
101- ) ;
164+ describe ( 'isRegisteredOffchain' , ( ) => {
165+ it ( 'should return true when a user is registered' , async ( ) => {
166+ const isRegistered = await passportImxProvider . isRegisteredOffchain ( ) ;
167+ expect ( isRegistered ) . toEqual ( true ) ;
102168 } ) ;
103- } ) ;
104169
105- describe ( 'isRegisteredOnchain' , ( ) => {
106- it ( 'should throw error' , async ( ) => {
107- expect ( passportImxProvider . isRegisteredOnchain )
108- . toThrow (
109- new PassportError (
110- 'Operation not supported' ,
111- PassportErrorType . OPERATION_NOT_SUPPORTED_ERROR ,
112- ) ,
113- ) ;
170+ it ( 'should return false when a user is not registered' , async ( ) => {
171+ mockAuthManager . getUser . mockResolvedValue ( { } ) ;
172+ const isRegistered = await passportImxProvider . isRegisteredOffchain ( ) ;
173+ expect ( isRegistered ) . toEqual ( false ) ;
174+ } ) ;
175+
176+ it ( 'should bubble up the error if user is not logged in' , async ( ) => {
177+ mockAuthManager . getUser . mockResolvedValue ( undefined ) ;
178+
179+ await expect ( passportImxProvider . isRegisteredOffchain ( ) ) . rejects . toThrow ( new PassportError (
180+ 'User has been logged out' ,
181+ PassportErrorType . NOT_LOGGED_IN_ERROR ,
182+ ) ) ;
114183 } ) ;
115184 } ) ;
116185
@@ -266,6 +335,26 @@ describe('PassportImxProvider', () => {
266335 } ) ;
267336 } ) ;
268337
338+ describe ( 'registerOffChain' , ( ) => {
339+ it ( 'should register the user and update the provider instance user' , async ( ) => {
340+ const magicProviderMock = { } ;
341+
342+ mockAuthManager . login . mockResolvedValue ( mockUser ) ;
343+ magicAdapterMock . login . mockResolvedValue ( magicProviderMock ) ;
344+ mockAuthManager . loginSilent . mockResolvedValue ( { ...mockUser , imx : { ethAddress : '' , starkAddress : '' , userAdminAddress : '' } } ) ;
345+
346+ await passportImxProvider . registerOffchain ( ) ;
347+
348+ expect ( registerPassportStarkEx ) . toHaveBeenCalledWith ( {
349+ ethSigner : mockEthSigner ,
350+ starkSigner : mockStarkSigner ,
351+ usersApi : immutableXClient . usersApi ,
352+ } , mockUserImx . accessToken ) ;
353+ expect ( mockAuthManager . loginSilent ) . toHaveBeenCalledTimes ( 1 ) ;
354+ expect ( mockAuthManager . loginSilent ) . toHaveBeenCalledWith ( { forceRefresh : true } ) ;
355+ } ) ;
356+ } ) ;
357+
269358 describe . each ( [
270359 [ 'transfer' as const , { } as UnsignedTransferRequest ] ,
271360 [ 'createOrder' as const , { } as UnsignedOrderRequest ] ,
0 commit comments