Skip to content

Commit ef77fd5

Browse files
authored
feat: ID-1182 Add isRegisteredOffchain to IMXProvider
1 parent a25e195 commit ef77fd5

File tree

5 files changed

+106
-2
lines changed

5 files changed

+106
-2
lines changed

packages/passport/sdk/src/starkEx/passportImxProvider.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,15 @@ export class PassportImxProvider implements IMXProvider {
119119
);
120120
}
121121

122+
// TODO: Remove once implemented
123+
// eslint-disable-next-line class-methods-use-this
124+
isRegisteredOffchain(): Promise<boolean> {
125+
throw new PassportError(
126+
'Operation not supported',
127+
PassportErrorType.OPERATION_NOT_SUPPORTED_ERROR,
128+
);
129+
}
130+
122131
// TODO: Remove once implemented
123132
// eslint-disable-next-line class-methods-use-this
124133
isRegisteredOnchain(): Promise<boolean> {

packages/provider/src/genericImxProvider.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { Signers } from './signable-actions/types';
2424
import { batchTransfer, transfer } from './signable-actions/transfer';
2525
import { cancelOrder, createOrder } from './signable-actions/orders';
2626
import {
27+
isRegisteredOffchain,
2728
isRegisteredOnChain,
2829
registerOffchain,
2930
} from './signable-actions/registration';
@@ -50,7 +51,15 @@ export class GenericIMXProvider implements IMXProvider {
5051
}
5152

5253
async getAddress(): Promise<string> {
53-
return await this.signers.ethSigner.getAddress();
54+
return this.signers.ethSigner.getAddress();
55+
}
56+
57+
async isRegisteredOffchain(): Promise<boolean> {
58+
const ethAddress = await this.getAddress();
59+
return isRegisteredOffchain(
60+
ethAddress,
61+
this.config,
62+
);
5463
}
5564

5665
registerOffchain(): Promise<RegisterUserResponse> {

packages/provider/src/imxProvider.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ export interface IMXProvider {
3030
* @return {Promise<RegisterUserResponse>} Returns a promise that resolves with the user registration response
3131
*/
3232
registerOffchain(): Promise<RegisterUserResponse>;
33+
/**
34+
* Checks if a User is registered off-chain
35+
*
36+
* @return {Promise<boolean>} Returns a promise that resolves with true if the User is registered with IMX, false otherwise
37+
*/
38+
isRegisteredOffchain(): Promise<boolean>;
3339
/**
3440
* Checks if a User is registered on-chain
3541
*

packages/provider/src/signable-actions/registration.test.ts

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { Contracts, UsersApi } from '@imtbl/core-sdk';
22
import { signRaw } from '@imtbl/toolkit';
3+
import { AxiosError } from 'axios';
34
import { generateSigners, privateKey1, testConfig } from '../test/helpers';
4-
import { isRegisteredOnChain, registerOffchain } from './registration';
5+
import { isRegisteredOffchain, isRegisteredOnChain, registerOffchain } from './registration';
56

67
jest.mock('@imtbl/core-sdk');
78
jest.mock('@imtbl/toolkit');
@@ -39,6 +40,67 @@ describe('Registration', () => {
3940
});
4041
});
4142

43+
describe('isRegisteredOffchain', () => {
44+
const getUsersMock = jest.fn();
45+
const ethAddress = '0x123';
46+
47+
beforeEach(() => {
48+
jest.restoreAllMocks();
49+
50+
(UsersApi as jest.Mock).mockReturnValue({
51+
getUsers: getUsersMock,
52+
});
53+
});
54+
55+
describe('when the user has registered with IMX', () => {
56+
test('should return true', async () => {
57+
getUsersMock.mockResolvedValue({
58+
data: {
59+
accounts: [ethAddress],
60+
},
61+
});
62+
63+
const result = await isRegisteredOffchain(ethAddress, testConfig);
64+
65+
expect(result).toEqual(true);
66+
expect(getUsersMock).toHaveBeenCalledTimes(1);
67+
});
68+
});
69+
70+
describe('when the user has not registered with IMX', () => {
71+
test('should return false', async () => {
72+
const axiosError = new AxiosError();
73+
axiosError.response = {
74+
config: axiosError.config!,
75+
data: undefined,
76+
headers: {},
77+
request: undefined,
78+
status: 404,
79+
statusText: '',
80+
};
81+
getUsersMock.mockImplementation(() => Promise.reject(axiosError));
82+
83+
const result = await isRegisteredOffchain(ethAddress, testConfig);
84+
85+
expect(result).toEqual(false);
86+
expect(getUsersMock).toHaveBeenCalledTimes(1);
87+
});
88+
});
89+
90+
describe('when getUsers throws an error that is not a 404', () => {
91+
test('should throw the error', async () => {
92+
const axiosResponse = new Error('oops');
93+
getUsersMock.mockImplementation(() => Promise.reject(axiosResponse));
94+
95+
await expect(
96+
isRegisteredOffchain(ethAddress, testConfig),
97+
).rejects.toThrowError(axiosResponse);
98+
99+
expect(getUsersMock).toHaveBeenCalledTimes(1);
100+
});
101+
});
102+
});
103+
42104
describe('registerOffchain', () => {
43105
let getSignableRegistrationOffchainMock: jest.Mock;
44106
let registerUserMock: jest.Mock;

packages/provider/src/signable-actions/registration.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
UsersApi,
77
} from '@imtbl/core-sdk';
88
import { signRaw } from '@imtbl/toolkit';
9+
import { AxiosError } from 'axios';
910
import { Signers } from './types';
1011
import { validateChain } from './helpers';
1112
import { ProviderConfiguration } from '../config';
@@ -45,6 +46,23 @@ export async function registerOffchain(
4546
return registeredUser.data;
4647
}
4748

49+
export async function isRegisteredOffchain(ethAddress: string, config: ProviderConfiguration): Promise<boolean> {
50+
try {
51+
const usersApi = new UsersApi(config.immutableXConfig.apiConfiguration);
52+
const getUsersResult = await usersApi.getUsers({
53+
user: ethAddress,
54+
});
55+
const { accounts } = getUsersResult.data;
56+
57+
return accounts?.length > 0;
58+
} catch (ex) {
59+
if (ex instanceof AxiosError && ex.response?.status === 404) {
60+
return false;
61+
}
62+
throw ex;
63+
}
64+
}
65+
4866
interface IsRegisteredCheckError {
4967
reason: string;
5068
}

0 commit comments

Comments
 (0)