@nadohq/mobile-client 0.29.0 → 0.31.0
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/README.md +15 -8
- package/dist/{MobileClient-9JSAzblH.cjs → MobileClient-_i0ZV6Dq.cjs} +104 -44
- package/dist/MobileClient-_i0ZV6Dq.cjs.map +1 -0
- package/dist/MobileClient.cjs +1 -1
- package/dist/MobileClient.d.cts +77 -36
- package/dist/MobileClient.d.cts.map +1 -1
- package/dist/MobileClient.d.ts +77 -36
- package/dist/MobileClient.d.ts.map +1 -1
- package/dist/MobileClient.js +105 -45
- package/dist/MobileClient.js.map +1 -1
- package/dist/{MobileServerFailureError-ZggEcEda.d.cts → MobileServerFailureError-BoyAfEZA.d.cts} +3 -2
- package/dist/MobileServerFailureError-BoyAfEZA.d.cts.map +1 -0
- package/dist/{MobileServerFailureError-f9KhKnJj.d.ts → MobileServerFailureError-MgYVBh5p.d.ts} +3 -2
- package/dist/MobileServerFailureError-MgYVBh5p.d.ts.map +1 -0
- package/dist/{buildSignedMobileRequest-BsbBkU0K.d.cts → buildSignedMobileRequest-CBMt97aY.d.cts} +2 -2
- package/dist/{buildSignedMobileRequest-BsbBkU0K.d.cts.map → buildSignedMobileRequest-CBMt97aY.d.cts.map} +1 -1
- package/dist/{buildSignedMobileRequest-CDRsRNHm.d.ts → buildSignedMobileRequest-qEC4gWaI.d.ts} +2 -2
- package/dist/{buildSignedMobileRequest-CDRsRNHm.d.ts.map → buildSignedMobileRequest-qEC4gWaI.d.ts.map} +1 -1
- package/dist/{canonicalize-PX6dTIdF.d.ts → canonicalize-QNARV_Xc.d.cts} +4 -4
- package/dist/canonicalize-QNARV_Xc.d.cts.map +1 -0
- package/dist/{canonicalize-Dm7sXwPg.d.cts → canonicalize-wVdGejB1.d.ts} +4 -4
- package/dist/canonicalize-wVdGejB1.d.ts.map +1 -0
- package/dist/clientTypes-6utzUU-b.d.ts +240 -0
- package/dist/clientTypes-6utzUU-b.d.ts.map +1 -0
- package/dist/clientTypes-D9qgtNlE.d.cts +240 -0
- package/dist/clientTypes-D9qgtNlE.d.cts.map +1 -0
- package/dist/dataMappers.cjs +35 -1
- package/dist/dataMappers.cjs.map +1 -1
- package/dist/dataMappers.d.cts +8 -3
- package/dist/dataMappers.d.cts.map +1 -1
- package/dist/dataMappers.d.ts +8 -3
- package/dist/dataMappers.d.ts.map +1 -1
- package/dist/dataMappers.js +35 -2
- package/dist/dataMappers.js.map +1 -1
- package/dist/{eip712MethodByType-DLh9MRsD.d.cts → eip712MethodByType-CroIPqsJ.d.cts} +2 -2
- package/dist/eip712MethodByType-CroIPqsJ.d.cts.map +1 -0
- package/dist/{eip712MethodByType-DJgXal9r.d.ts → eip712MethodByType-DBUy4AdI.d.ts} +2 -2
- package/dist/eip712MethodByType-DBUy4AdI.d.ts.map +1 -0
- package/dist/feed-BF5k6Ryu.d.ts +14 -0
- package/dist/feed-BF5k6Ryu.d.ts.map +1 -0
- package/dist/feed-CBIwOhTO.d.cts +14 -0
- package/dist/feed-CBIwOhTO.d.cts.map +1 -0
- package/dist/index.cjs +8 -1
- package/dist/index.d.cts +17 -15
- package/dist/index.d.ts +17 -15
- package/dist/index.js +3 -1
- package/dist/{mobileErrorCodes-BeyBKmwh.d.cts → mobileErrorCodes-CuQ5lyBV.d.ts} +8 -8
- package/dist/mobileErrorCodes-CuQ5lyBV.d.ts.map +1 -0
- package/dist/{mobileErrorCodes-QG5XbEY6.d.ts → mobileErrorCodes-D_SyBm0k.d.cts} +8 -8
- package/dist/mobileErrorCodes-D_SyBm0k.d.cts.map +1 -0
- package/dist/{patterns-BbxH3_VA.d.ts → patterns-B5gi7OfV.d.ts} +1 -1
- package/dist/patterns-B5gi7OfV.d.ts.map +1 -0
- package/dist/{patterns-B9J2ldpx.d.cts → patterns-Db6fgz8i.d.cts} +1 -1
- package/dist/patterns-Db6fgz8i.d.cts.map +1 -0
- package/dist/{payloadHash-nj8WuLUP.d.cts → payloadHash-B0tlFOK8.d.cts} +2 -2
- package/dist/payloadHash-B0tlFOK8.d.cts.map +1 -0
- package/dist/{payloadHash-Bmhzs78N.d.ts → payloadHash-D1yTQSF4.d.ts} +2 -2
- package/dist/payloadHash-D1yTQSF4.d.ts.map +1 -0
- package/dist/serverBaseTypes-CzRgwUvA.d.ts +25 -0
- package/dist/serverBaseTypes-CzRgwUvA.d.ts.map +1 -0
- package/dist/serverBaseTypes-DSRgU2Fb.d.cts +25 -0
- package/dist/serverBaseTypes-DSRgU2Fb.d.cts.map +1 -0
- package/dist/serverExecuteTypes-BCb6bUMP.d.cts +19 -0
- package/dist/serverExecuteTypes-BCb6bUMP.d.cts.map +1 -0
- package/dist/serverExecuteTypes-CI3NBW2Z.d.ts +19 -0
- package/dist/serverExecuteTypes-CI3NBW2Z.d.ts.map +1 -0
- package/dist/serverModelTypes-BYQcsRrx.d.cts +146 -0
- package/dist/serverModelTypes-BYQcsRrx.d.cts.map +1 -0
- package/dist/serverModelTypes-DvPs5qs3.d.ts +146 -0
- package/dist/serverModelTypes-DvPs5qs3.d.ts.map +1 -0
- package/dist/serverQueryTypes-9H6P1vJ5.d.cts +92 -0
- package/dist/serverQueryTypes-9H6P1vJ5.d.cts.map +1 -0
- package/dist/serverQueryTypes-Cbjx0bIj.d.ts +92 -0
- package/dist/serverQueryTypes-Cbjx0bIj.d.ts.map +1 -0
- package/dist/serverRequestTypes-CHDk6JwE.d.cts +85 -0
- package/dist/serverRequestTypes-CHDk6JwE.d.cts.map +1 -0
- package/dist/serverRequestTypes-DYTLrCpz.d.ts +85 -0
- package/dist/serverRequestTypes-DYTLrCpz.d.ts.map +1 -0
- package/dist/{serverResponseGuards-DjCNL3CR.d.cts → serverResponseGuards-DRMHmfXh.d.cts} +2 -2
- package/dist/{serverResponseGuards-DjCNL3CR.d.cts.map → serverResponseGuards-DRMHmfXh.d.cts.map} +1 -1
- package/dist/{serverResponseGuards-C_vZIgGl.d.ts → serverResponseGuards-DpbZvJfL.d.ts} +2 -2
- package/dist/{serverResponseGuards-C_vZIgGl.d.ts.map → serverResponseGuards-DpbZvJfL.d.ts.map} +1 -1
- package/dist/signing/buildSignedMobileRequest.cjs +1 -1
- package/dist/signing/buildSignedMobileRequest.d.cts +1 -1
- package/dist/signing/buildSignedMobileRequest.d.ts +1 -1
- package/dist/signing/canonicalize.cjs +4 -37
- package/dist/signing/canonicalize.cjs.map +1 -1
- package/dist/signing/canonicalize.d.cts +1 -1
- package/dist/signing/canonicalize.d.ts +1 -1
- package/dist/signing/canonicalize.js +4 -37
- package/dist/signing/canonicalize.js.map +1 -1
- package/dist/signing/eip712MethodByType.cjs +1 -5
- package/dist/signing/eip712MethodByType.cjs.map +1 -1
- package/dist/signing/eip712MethodByType.d.cts +1 -1
- package/dist/signing/eip712MethodByType.d.ts +1 -1
- package/dist/signing/eip712MethodByType.js +1 -5
- package/dist/signing/eip712MethodByType.js.map +1 -1
- package/dist/signing/index.d.cts +5 -5
- package/dist/signing/index.d.ts +5 -5
- package/dist/signing/payloadHash.cjs +1 -1
- package/dist/signing/payloadHash.d.cts +1 -1
- package/dist/signing/payloadHash.d.ts +1 -1
- package/dist/signing/types.d.cts +1 -1
- package/dist/signing/types.d.ts +1 -1
- package/dist/types/MobileServerFailureError.cjs +1 -1
- package/dist/types/MobileServerFailureError.cjs.map +1 -1
- package/dist/types/MobileServerFailureError.d.cts +1 -1
- package/dist/types/MobileServerFailureError.d.ts +1 -1
- package/dist/types/MobileServerFailureError.js.map +1 -1
- package/dist/types/clientTypes.d.cts +2 -2
- package/dist/types/clientTypes.d.ts +2 -2
- package/dist/types/index.cjs +4 -0
- package/dist/types/index.d.cts +9 -8
- package/dist/types/index.d.ts +9 -8
- package/dist/types/index.js +2 -1
- package/dist/types/mobileErrorCodes.cjs +10 -7
- package/dist/types/mobileErrorCodes.cjs.map +1 -1
- package/dist/types/mobileErrorCodes.d.cts +1 -1
- package/dist/types/mobileErrorCodes.d.ts +1 -1
- package/dist/types/mobileErrorCodes.js +9 -6
- package/dist/types/mobileErrorCodes.js.map +1 -1
- package/dist/types/serverBaseTypes.d.cts +2 -2
- package/dist/types/serverBaseTypes.d.ts +2 -2
- package/dist/types/serverExecuteTypes.d.cts +2 -2
- package/dist/types/serverExecuteTypes.d.ts +2 -2
- package/dist/types/serverModelTypes.cjs +29 -0
- package/dist/types/serverModelTypes.cjs.map +1 -0
- package/dist/types/serverModelTypes.d.cts +2 -2
- package/dist/types/serverModelTypes.d.ts +2 -2
- package/dist/types/serverModelTypes.js +26 -1
- package/dist/types/serverModelTypes.js.map +1 -0
- package/dist/types/serverQueryTypes.d.cts +2 -2
- package/dist/types/serverQueryTypes.d.ts +2 -2
- package/dist/types/serverRequestTypes.cjs +0 -0
- package/dist/types/serverRequestTypes.d.cts +2 -0
- package/dist/types/serverRequestTypes.d.ts +2 -0
- package/dist/types/serverRequestTypes.js +1 -0
- package/dist/{types-B76Pn7Sy.d.ts → types-CQE3HD2V.d.ts} +4 -15
- package/dist/types-CQE3HD2V.d.ts.map +1 -0
- package/dist/{types-uCD4BNZR.d.cts → types-bNB98pYk.d.cts} +4 -15
- package/dist/types-bNB98pYk.d.cts.map +1 -0
- package/dist/utils/feed.cjs +17 -0
- package/dist/utils/feed.cjs.map +1 -0
- package/dist/utils/feed.d.cts +2 -0
- package/dist/utils/feed.d.ts +2 -0
- package/dist/utils/feed.js +15 -0
- package/dist/utils/feed.js.map +1 -0
- package/dist/utils/index.cjs +3 -0
- package/dist/utils/index.d.cts +4 -3
- package/dist/utils/index.d.ts +4 -3
- package/dist/utils/index.js +2 -1
- package/dist/utils/patterns.d.cts +1 -1
- package/dist/utils/patterns.d.ts +1 -1
- package/dist/utils/serverResponseGuards.d.cts +1 -1
- package/dist/utils/serverResponseGuards.d.ts +1 -1
- package/package.json +3 -3
- package/src/MobileClient.ts +163 -112
- package/src/dataMappers.ts +41 -0
- package/src/signing/canonicalize.ts +4 -37
- package/src/signing/eip712MethodByType.ts +1 -5
- package/src/signing/signing.test.ts +17 -60
- package/src/signing/types.ts +2 -12
- package/src/types/MobileServerFailureError.ts +2 -4
- package/src/types/clientTypes.ts +105 -27
- package/src/types/index.ts +1 -0
- package/src/types/mobileErrorCodes.ts +8 -5
- package/src/types/serverBaseTypes.ts +7 -28
- package/src/types/serverExecuteTypes.ts +17 -0
- package/src/types/serverModelTypes.ts +104 -8
- package/src/types/serverQueryTypes.ts +84 -39
- package/src/types/serverRequestTypes.ts +91 -0
- package/src/utils/feed.ts +11 -0
- package/src/utils/index.ts +1 -0
- package/dist/MobileClient-9JSAzblH.cjs.map +0 -1
- package/dist/MobileServerFailureError-ZggEcEda.d.cts.map +0 -1
- package/dist/MobileServerFailureError-f9KhKnJj.d.ts.map +0 -1
- package/dist/canonicalize-Dm7sXwPg.d.cts.map +0 -1
- package/dist/canonicalize-PX6dTIdF.d.ts.map +0 -1
- package/dist/clientTypes-DWW2N66c.d.ts +0 -168
- package/dist/clientTypes-DWW2N66c.d.ts.map +0 -1
- package/dist/clientTypes-Et0PUa2d.d.cts +0 -168
- package/dist/clientTypes-Et0PUa2d.d.cts.map +0 -1
- package/dist/eip712MethodByType-DJgXal9r.d.ts.map +0 -1
- package/dist/eip712MethodByType-DLh9MRsD.d.cts.map +0 -1
- package/dist/mobileErrorCodes-BeyBKmwh.d.cts.map +0 -1
- package/dist/mobileErrorCodes-QG5XbEY6.d.ts.map +0 -1
- package/dist/patterns-B9J2ldpx.d.cts.map +0 -1
- package/dist/patterns-BbxH3_VA.d.ts.map +0 -1
- package/dist/payloadHash-Bmhzs78N.d.ts.map +0 -1
- package/dist/payloadHash-nj8WuLUP.d.cts.map +0 -1
- package/dist/serverBaseTypes-BicXMrZV.d.cts +0 -43
- package/dist/serverBaseTypes-BicXMrZV.d.cts.map +0 -1
- package/dist/serverBaseTypes-ewbo8l4R.d.ts +0 -43
- package/dist/serverBaseTypes-ewbo8l4R.d.ts.map +0 -1
- package/dist/serverExecuteTypes-CXnMjKnt.d.ts +0 -11
- package/dist/serverExecuteTypes-CXnMjKnt.d.ts.map +0 -1
- package/dist/serverExecuteTypes-DKYK1V7C.d.cts +0 -11
- package/dist/serverExecuteTypes-DKYK1V7C.d.cts.map +0 -1
- package/dist/serverModelTypes-CQgfqgW3.d.cts +0 -69
- package/dist/serverModelTypes-CQgfqgW3.d.cts.map +0 -1
- package/dist/serverModelTypes-vEPhHIit.d.ts +0 -69
- package/dist/serverModelTypes-vEPhHIit.d.ts.map +0 -1
- package/dist/serverQueryTypes-BI-2TD8F.d.ts +0 -53
- package/dist/serverQueryTypes-BI-2TD8F.d.ts.map +0 -1
- package/dist/serverQueryTypes-D7Yharse.d.cts +0 -53
- package/dist/serverQueryTypes-D7Yharse.d.cts.map +0 -1
- package/dist/types-B76Pn7Sy.d.ts.map +0 -1
- package/dist/types-uCD4BNZR.d.cts.map +0 -1
package/src/MobileClient.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
|
+
subaccountToHex,
|
|
2
3
|
WalletClientWithAccount,
|
|
3
4
|
WalletNotProvidedError,
|
|
4
5
|
} from '@nadohq/shared';
|
|
5
6
|
import axios, { AxiosInstance, AxiosResponse } from 'axios';
|
|
6
7
|
import {
|
|
8
|
+
mapMobileFeedPage,
|
|
7
9
|
mapMobileIdentity,
|
|
8
10
|
mapMobileNotificationPreferences,
|
|
9
11
|
mapMobileNotificationPreferencesToServer,
|
|
@@ -17,36 +19,41 @@ import {
|
|
|
17
19
|
MobileSignedRequest,
|
|
18
20
|
} from './signing';
|
|
19
21
|
import {
|
|
22
|
+
GetMobileFeedParams,
|
|
20
23
|
GetMobileNotificationPreferencesParams,
|
|
21
24
|
GetMobilePublicProfileParams,
|
|
22
25
|
GetMobileRegisteredDevicesParams,
|
|
23
26
|
GetMobileSelfIdentityParams,
|
|
24
27
|
GetMobileUsernameAvailabilityParams,
|
|
25
|
-
|
|
28
|
+
MobileFeedPage,
|
|
26
29
|
MobileIdentity,
|
|
27
30
|
MobileNotificationPreferences,
|
|
28
31
|
MobilePublicProfile,
|
|
29
32
|
MobileRegisteredDevice,
|
|
30
33
|
MobileRegisterExpoTokenParams,
|
|
31
34
|
MobileSetPrivateModeParams,
|
|
35
|
+
MobileSetUsernameParams,
|
|
32
36
|
MobileSignedRequestParams,
|
|
33
37
|
MobileUnregisterExpoTokenParams,
|
|
34
38
|
MobileUpdateNotificationPreferencesParams,
|
|
35
|
-
MobileUpdateUsernameParams,
|
|
36
39
|
MobileUsernameAvailability,
|
|
37
40
|
} from './types/clientTypes';
|
|
38
41
|
import { MobileServerFailureError } from './types/MobileServerFailureError';
|
|
39
42
|
import { MobileServerSuccessResponse } from './types/serverBaseTypes';
|
|
40
|
-
import { MobileServerExecuteResult } from './types/serverExecuteTypes';
|
|
41
43
|
import {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
MobileServerExecuteResult,
|
|
45
|
+
MobileServerPublicExecuteRequest,
|
|
46
|
+
} from './types/serverExecuteTypes';
|
|
47
|
+
import {
|
|
48
|
+
MobileServerPublicQueryRequest,
|
|
49
|
+
MobileServerPublicQuerySuccessResponse,
|
|
50
|
+
MobileServerSignedQuerySuccessResponse,
|
|
49
51
|
} from './types/serverQueryTypes';
|
|
52
|
+
import {
|
|
53
|
+
MobileServerPublicQueryRequestByType,
|
|
54
|
+
MobileServerPublicQueryRequestType,
|
|
55
|
+
MobileServerSignedQueryRequestType,
|
|
56
|
+
} from './types/serverRequestTypes';
|
|
50
57
|
import {
|
|
51
58
|
isMobileServerFailureResponse,
|
|
52
59
|
isMobileServerSuccessResponse,
|
|
@@ -71,8 +78,8 @@ export interface MobileClientOpts {
|
|
|
71
78
|
}
|
|
72
79
|
|
|
73
80
|
/**
|
|
74
|
-
* Client for the Nado mobile service API:
|
|
75
|
-
* push notification device/preference management.
|
|
81
|
+
* Client for the Nado mobile service API: usernames, public profile lookups, the global trade feed, privacy
|
|
82
|
+
* settings, and push notification device/preference management.
|
|
76
83
|
*/
|
|
77
84
|
export class MobileClient {
|
|
78
85
|
readonly opts: MobileClientOpts;
|
|
@@ -108,39 +115,133 @@ export class MobileClient {
|
|
|
108
115
|
async getUsernameAvailability(
|
|
109
116
|
params: GetMobileUsernameAvailabilityParams,
|
|
110
117
|
): Promise<MobileUsernameAvailability> {
|
|
111
|
-
const body:
|
|
118
|
+
const body: MobileServerPublicQueryRequest<'username_availability'> = {
|
|
112
119
|
type: 'username_availability',
|
|
113
120
|
display_name: params.displayName,
|
|
114
121
|
};
|
|
115
|
-
const data =
|
|
116
|
-
await this.publicQuery<MobileServerUsernameAvailabilityResponse>(body);
|
|
122
|
+
const data = await this.publicQuery(body);
|
|
117
123
|
return { username: data.username, available: data.available };
|
|
118
124
|
}
|
|
119
125
|
|
|
120
126
|
/**
|
|
121
|
-
* Looks up a subaccount's public profile
|
|
127
|
+
* Looks up a subaccount's public profile. Every non-isolated subaccount resolves, with `username` and
|
|
128
|
+
* `displayName` `null` until a username is claimed. Private Mode does not hide the profile itself, only the
|
|
129
|
+
* account's activity.
|
|
122
130
|
*
|
|
123
|
-
* @throws {MobileServerFailureError} With error code `PROFILE_NOT_FOUND` if
|
|
124
|
-
*
|
|
131
|
+
* @throws {MobileServerFailureError} With error code `PROFILE_NOT_FOUND` if the subaccount is in the
|
|
132
|
+
* engine-created isolated namespace, which cannot own a profile.
|
|
125
133
|
*/
|
|
126
134
|
async getPublicProfile(
|
|
127
135
|
params: GetMobilePublicProfileParams,
|
|
128
136
|
): Promise<MobilePublicProfile> {
|
|
129
|
-
const body:
|
|
137
|
+
const body: MobileServerPublicQueryRequest<'profile'> = {
|
|
130
138
|
type: 'profile',
|
|
131
|
-
|
|
139
|
+
subaccount: subaccountToHex(params),
|
|
132
140
|
};
|
|
133
|
-
const data = await this.publicQuery
|
|
141
|
+
const data = await this.publicQuery(body);
|
|
134
142
|
return mapMobilePublicProfile(data.profile);
|
|
135
143
|
}
|
|
136
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Fetches a page of the global trade feed: public perpetual trades, newest first, optionally filtered by a
|
|
147
|
+
* whole-dollar minimum notional (omitted means unfiltered). Trades by subaccounts that have not claimed a
|
|
148
|
+
* username are included with `null` name fields; only private accounts are filtered out. The feed is
|
|
149
|
+
* best-effort rather than authoritative history, and pagination is live (not snapshot), so deduplicate pages
|
|
150
|
+
* by {@link MobileFeedTrade.orderDigest}.
|
|
151
|
+
*
|
|
152
|
+
* @throws {MobileServerFailureError} With error code `INVALID_FEED_FILTER` if `minimumNotional` or
|
|
153
|
+
* `limit` is outside its allowed domain (fix the request; do not retry unchanged), or
|
|
154
|
+
* `INVALID_FEED_CURSOR` if the cursor is malformed or was issued for a different `minimumNotional`
|
|
155
|
+
* (discard the cursor and restart from the first page).
|
|
156
|
+
*/
|
|
157
|
+
async getFeed(params: GetMobileFeedParams = {}): Promise<MobileFeedPage> {
|
|
158
|
+
const body: MobileServerPublicQueryRequest<'feed'> = {
|
|
159
|
+
type: 'feed',
|
|
160
|
+
minimum_notional: params.minimumNotional,
|
|
161
|
+
limit: params.limit,
|
|
162
|
+
cursor: params.cursor,
|
|
163
|
+
};
|
|
164
|
+
const data = await this.publicQuery(body);
|
|
165
|
+
return mapMobileFeedPage(data);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Fetches the push notification preferences of the wallet that owns the given Expo push token. Unsigned —
|
|
170
|
+
* the token identifies the wallet on its own. Falls back to the backend's defaults if the wallet has never
|
|
171
|
+
* updated its preferences.
|
|
172
|
+
*
|
|
173
|
+
* @throws {MobileServerFailureError} With error code `INVALID_EXPO_TOKEN` if the token is malformed, or is
|
|
174
|
+
* not currently registered to a wallet.
|
|
175
|
+
*/
|
|
176
|
+
async getNotificationPreferences(
|
|
177
|
+
params: GetMobileNotificationPreferencesParams,
|
|
178
|
+
): Promise<MobileNotificationPreferences> {
|
|
179
|
+
const body: MobileServerPublicQueryRequest<'notification_preferences'> = {
|
|
180
|
+
type: 'notification_preferences',
|
|
181
|
+
expo_token: params.expoToken,
|
|
182
|
+
};
|
|
183
|
+
const data = await this.publicQuery(body);
|
|
184
|
+
return mapMobileNotificationPreferences(data.preferences);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/*
|
|
188
|
+
Public executes
|
|
189
|
+
*/
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Unregisters an Expo push token, stopping delivery to that device. Unsigned, so it still works at logout
|
|
193
|
+
* when a wallet signature may no longer be obtainable. Idempotent: unregistering an inactive or unknown
|
|
194
|
+
* well-formed token succeeds.
|
|
195
|
+
*
|
|
196
|
+
* A registration that commits after this call re-activates the token, so stop or await any in-flight
|
|
197
|
+
* {@link MobileClient.registerExpoToken} before unregistering.
|
|
198
|
+
*
|
|
199
|
+
* @throws {MobileServerFailureError} With error code `INVALID_EXPO_TOKEN` if the token is malformed.
|
|
200
|
+
*/
|
|
201
|
+
async unregisterExpoToken(
|
|
202
|
+
params: MobileUnregisterExpoTokenParams,
|
|
203
|
+
): Promise<MobileServerSuccessResponse> {
|
|
204
|
+
const body: MobileServerPublicExecuteRequest<'unregister_expo_token'> = {
|
|
205
|
+
type: 'unregister_expo_token',
|
|
206
|
+
expo_token: params.expoToken,
|
|
207
|
+
};
|
|
208
|
+
return this.publicExecute(body);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Replaces the push notification preferences of the wallet that owns the given Expo push token. Possession
|
|
213
|
+
* of an active token is the credential rather than a signature, so anyone holding the token can overwrite
|
|
214
|
+
* that wallet's preferences. The backend requires `schemaVersion` of 1, exactly one entry per known
|
|
215
|
+
* category, and empty `scopes` on every entry.
|
|
216
|
+
*
|
|
217
|
+
* Writes are last-write-wins on commit order rather than ordered by a client nonce, so callers must
|
|
218
|
+
* serialize their own preference writes.
|
|
219
|
+
*
|
|
220
|
+
* @throws {MobileServerFailureError} With error code `INVALID_PREFERENCES` if those rules are violated, or
|
|
221
|
+
* `INVALID_EXPO_TOKEN` if the token is malformed or is not currently registered to a wallet.
|
|
222
|
+
*/
|
|
223
|
+
async updateNotificationPreferences(
|
|
224
|
+
params: MobileUpdateNotificationPreferencesParams,
|
|
225
|
+
): Promise<MobileServerSuccessResponse> {
|
|
226
|
+
const body: MobileServerPublicExecuteRequest<'update_preferences'> = {
|
|
227
|
+
type: 'update_preferences',
|
|
228
|
+
expo_token: params.expoToken,
|
|
229
|
+
preferences: mapMobileNotificationPreferencesToServer(params.preferences),
|
|
230
|
+
};
|
|
231
|
+
return this.publicExecute(body);
|
|
232
|
+
}
|
|
233
|
+
|
|
137
234
|
/*
|
|
138
235
|
Signed queries
|
|
139
236
|
*/
|
|
140
237
|
|
|
141
238
|
/**
|
|
142
|
-
* Fetches the caller's own identity for a subaccount.
|
|
143
|
-
*
|
|
239
|
+
* Fetches the caller's own identity for a subaccount. Every non-isolated subaccount has an implicit
|
|
240
|
+
* identity, so this resolves for any valid sender with `username` and `displayName` `null` until a username
|
|
241
|
+
* is claimed.
|
|
242
|
+
*
|
|
243
|
+
* @throws {MobileServerFailureError} With error code `INVALID_IDENTITY_TARGET` if the sender is in the
|
|
244
|
+
* engine-created isolated namespace, which cannot own an identity.
|
|
144
245
|
*/
|
|
145
246
|
async getSelfIdentity(
|
|
146
247
|
params: GetMobileSelfIdentityParams,
|
|
@@ -150,30 +251,10 @@ export class MobileClient {
|
|
|
150
251
|
params,
|
|
151
252
|
{},
|
|
152
253
|
);
|
|
153
|
-
const data =
|
|
154
|
-
await this.query<MobileServerSelfIdentityResponse>(signedRequest);
|
|
254
|
+
const data = await this.query<'self_identity'>(signedRequest);
|
|
155
255
|
return data.identity ? mapMobileIdentity(data.identity) : null;
|
|
156
256
|
}
|
|
157
257
|
|
|
158
|
-
/**
|
|
159
|
-
* Fetches a wallet's push notification preferences. Falls back to the backend's defaults if the wallet has
|
|
160
|
-
* never updated its preferences.
|
|
161
|
-
*/
|
|
162
|
-
async getNotificationPreferences(
|
|
163
|
-
params: GetMobileNotificationPreferencesParams,
|
|
164
|
-
): Promise<MobileNotificationPreferences> {
|
|
165
|
-
const signedRequest = await this.getSignedRequest(
|
|
166
|
-
'notification_preferences',
|
|
167
|
-
params,
|
|
168
|
-
{},
|
|
169
|
-
);
|
|
170
|
-
const data =
|
|
171
|
-
await this.query<MobileServerNotificationPreferencesResponse>(
|
|
172
|
-
signedRequest,
|
|
173
|
-
);
|
|
174
|
-
return mapMobileNotificationPreferences(data.preferences);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
258
|
/**
|
|
178
259
|
* Fetches the devices registered for push notifications for a wallet.
|
|
179
260
|
*/
|
|
@@ -185,8 +266,7 @@ export class MobileClient {
|
|
|
185
266
|
params,
|
|
186
267
|
{},
|
|
187
268
|
);
|
|
188
|
-
const data =
|
|
189
|
-
await this.query<MobileServerRegisteredDevicesResponse>(signedRequest);
|
|
269
|
+
const data = await this.query<'registered_devices'>(signedRequest);
|
|
190
270
|
return data.devices.map(mapMobileRegisteredDevice);
|
|
191
271
|
}
|
|
192
272
|
|
|
@@ -195,32 +275,21 @@ export class MobileClient {
|
|
|
195
275
|
*/
|
|
196
276
|
|
|
197
277
|
/**
|
|
198
|
-
*
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
{
|
|
207
|
-
display_name: params.displayName,
|
|
208
|
-
},
|
|
209
|
-
);
|
|
210
|
-
return this.execute(signedRequest);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Updates the display name for a subaccount's already-claimed identity.
|
|
278
|
+
* Sets a subaccount's username, derived from the given display name. Upserts: the same call claims a first
|
|
279
|
+
* username and renames an existing one, so callers never need to read the current identity first.
|
|
280
|
+
*
|
|
281
|
+
* @throws {MobileServerFailureError} With error code `INVALID_DISPLAY_NAME` if the display name violates
|
|
282
|
+
* `MOBILE_DISPLAY_NAME_PATTERN`, `USERNAME_UNAVAILABLE` if the derived username is reserved or already
|
|
283
|
+
* taken by another subaccount, `INVALID_IDENTITY_TARGET` if the sender is in the engine-created isolated
|
|
284
|
+
* namespace, or `STALE_IDENTITY_UPDATE` if another identity write for this subaccount committed with a
|
|
285
|
+
* later nonce (re-read the identity before retrying).
|
|
215
286
|
*/
|
|
216
|
-
async
|
|
217
|
-
params:
|
|
287
|
+
async setUsername(
|
|
288
|
+
params: MobileSetUsernameParams,
|
|
218
289
|
): Promise<MobileServerSuccessResponse> {
|
|
219
|
-
const signedRequest = await this.getSignedRequest(
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
{ display_name: params.displayName },
|
|
223
|
-
);
|
|
290
|
+
const signedRequest = await this.getSignedRequest('set_username', params, {
|
|
291
|
+
display_name: params.displayName,
|
|
292
|
+
});
|
|
224
293
|
return this.execute(signedRequest);
|
|
225
294
|
}
|
|
226
295
|
|
|
@@ -262,41 +331,6 @@ export class MobileClient {
|
|
|
262
331
|
return this.execute(signedRequest);
|
|
263
332
|
}
|
|
264
333
|
|
|
265
|
-
/**
|
|
266
|
-
* Unregisters an Expo push token for the wallet. Idempotent — unregistering an unknown token succeeds.
|
|
267
|
-
*/
|
|
268
|
-
async unregisterExpoToken(
|
|
269
|
-
params: MobileUnregisterExpoTokenParams,
|
|
270
|
-
): Promise<MobileServerSuccessResponse> {
|
|
271
|
-
const signedRequest = await this.getSignedRequest(
|
|
272
|
-
'unregister_expo_token',
|
|
273
|
-
params,
|
|
274
|
-
{ expo_token: params.expoToken },
|
|
275
|
-
);
|
|
276
|
-
return this.execute(signedRequest);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Replaces the wallet's push notification preferences. The backend requires `schemaVersion` of 1, exactly
|
|
281
|
-
* one entry per known category, and empty `scopes` on every entry.
|
|
282
|
-
*
|
|
283
|
-
* @throws {MobileServerFailureError} With error code `INVALID_PREFERENCES` if those rules are violated.
|
|
284
|
-
*/
|
|
285
|
-
async updateNotificationPreferences(
|
|
286
|
-
params: MobileUpdateNotificationPreferencesParams,
|
|
287
|
-
): Promise<MobileServerSuccessResponse> {
|
|
288
|
-
const signedRequest = await this.getSignedRequest(
|
|
289
|
-
'update_preferences',
|
|
290
|
-
params,
|
|
291
|
-
{
|
|
292
|
-
preferences: mapMobileNotificationPreferencesToServer(
|
|
293
|
-
params.preferences,
|
|
294
|
-
),
|
|
295
|
-
},
|
|
296
|
-
);
|
|
297
|
-
return this.execute(signedRequest);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
334
|
/*
|
|
301
335
|
Base Fns
|
|
302
336
|
*/
|
|
@@ -318,9 +352,11 @@ export class MobileClient {
|
|
|
318
352
|
return buildSignedMobileRequest({ ...params, walletClient, inner });
|
|
319
353
|
}
|
|
320
354
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
355
|
+
// Spelled out as an intersection rather than `MobileServerPublicQueryRequest<T>`: the latter is an indexed
|
|
356
|
+
// access on a mapped type, which is not an inference site, so `T` would always widen to the full union.
|
|
357
|
+
protected async publicQuery<T extends MobileServerPublicQueryRequestType>(
|
|
358
|
+
body: { type: T } & MobileServerPublicQueryRequestByType[T],
|
|
359
|
+
): Promise<MobileServerPublicQuerySuccessResponse<T>> {
|
|
324
360
|
const response = await this.axiosInstance.post<unknown>(
|
|
325
361
|
`${this.opts.url}/mobile/public_query`,
|
|
326
362
|
body,
|
|
@@ -330,12 +366,27 @@ export class MobileClient {
|
|
|
330
366
|
this.checkServerStatus(response);
|
|
331
367
|
|
|
332
368
|
// checkServerStatus throws on failure responses so the cast to the success response is acceptable here
|
|
333
|
-
return response.data as
|
|
369
|
+
return response.data as MobileServerPublicQuerySuccessResponse<T>;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
protected async publicExecute(
|
|
373
|
+
body: MobileServerPublicExecuteRequest,
|
|
374
|
+
): Promise<MobileServerSuccessResponse> {
|
|
375
|
+
const response = await this.axiosInstance.post<MobileServerExecuteResult>(
|
|
376
|
+
`${this.opts.url}/mobile/public_execute`,
|
|
377
|
+
body,
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
this.checkResponseStatus(response);
|
|
381
|
+
this.checkServerStatus(response);
|
|
382
|
+
|
|
383
|
+
// checkServerStatus catches the failure result and throws the error, so the cast to the success response is acceptable here
|
|
384
|
+
return response.data as MobileServerSuccessResponse;
|
|
334
385
|
}
|
|
335
386
|
|
|
336
|
-
protected async query<
|
|
387
|
+
protected async query<T extends MobileServerSignedQueryRequestType>(
|
|
337
388
|
body: MobileSignedRequest,
|
|
338
|
-
): Promise<
|
|
389
|
+
): Promise<MobileServerSignedQuerySuccessResponse<T>> {
|
|
339
390
|
const response = await this.axiosInstance.post<unknown>(
|
|
340
391
|
`${this.opts.url}/mobile/query`,
|
|
341
392
|
body,
|
|
@@ -345,7 +396,7 @@ export class MobileClient {
|
|
|
345
396
|
this.checkServerStatus(response);
|
|
346
397
|
|
|
347
398
|
// checkServerStatus throws on failure responses so the cast to the success response is acceptable here
|
|
348
|
-
return response.data as
|
|
399
|
+
return response.data as MobileServerSignedQuerySuccessResponse<T>;
|
|
349
400
|
}
|
|
350
401
|
|
|
351
402
|
protected async execute(
|
package/src/dataMappers.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
+
MobileFeedPage,
|
|
3
|
+
MobileFeedTrade,
|
|
2
4
|
MobileIdentity,
|
|
3
5
|
MobileNotificationPreferenceScope,
|
|
4
6
|
MobileNotificationPreferences,
|
|
@@ -6,12 +8,14 @@ import {
|
|
|
6
8
|
MobileRegisteredDevice,
|
|
7
9
|
} from './types/clientTypes';
|
|
8
10
|
import {
|
|
11
|
+
MobileServerFeedTrade,
|
|
9
12
|
MobileServerIdentity,
|
|
10
13
|
MobileServerNotificationPreferenceScope,
|
|
11
14
|
MobileServerNotificationPreferences,
|
|
12
15
|
MobileServerProfile,
|
|
13
16
|
MobileServerRegisteredDevice,
|
|
14
17
|
} from './types/serverModelTypes';
|
|
18
|
+
import { MobileServerFeedResponse } from './types/serverQueryTypes';
|
|
15
19
|
|
|
16
20
|
/**
|
|
17
21
|
* Maps a server-side identity (snake_case) to its client-side (camelCase) representation.
|
|
@@ -37,6 +41,7 @@ export function mapMobilePublicProfile(
|
|
|
37
41
|
subaccount: server.subaccount,
|
|
38
42
|
username: server.username,
|
|
39
43
|
displayName: server.display_name,
|
|
44
|
+
privateMode: server.private_mode,
|
|
40
45
|
};
|
|
41
46
|
}
|
|
42
47
|
|
|
@@ -90,6 +95,42 @@ function mapMobileNotificationPreferenceScopeToServer(
|
|
|
90
95
|
return { type: 'product', product_id: scope.productId };
|
|
91
96
|
}
|
|
92
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Maps a server-side feed trade (snake_case) to its client-side (camelCase) representation.
|
|
100
|
+
*/
|
|
101
|
+
function mapMobileFeedTrade(server: MobileServerFeedTrade): MobileFeedTrade {
|
|
102
|
+
return {
|
|
103
|
+
orderDigest: server.order_digest,
|
|
104
|
+
subaccount: server.subaccount,
|
|
105
|
+
username: server.username,
|
|
106
|
+
displayName: server.display_name,
|
|
107
|
+
avatarUrl: server.avatar_url,
|
|
108
|
+
productId: server.product_id,
|
|
109
|
+
quantity: server.quantity,
|
|
110
|
+
notional: server.notional,
|
|
111
|
+
averagePrice: server.average_price,
|
|
112
|
+
margin: {
|
|
113
|
+
mode: server.margin.mode,
|
|
114
|
+
estimatedLeverage: server.margin.estimated_leverage,
|
|
115
|
+
},
|
|
116
|
+
position: server.position,
|
|
117
|
+
realizedPnl: server.realized_pnl,
|
|
118
|
+
filledAt: server.filled_at_ms,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Maps a server-side feed response to a client-side {@link MobileFeedPage}.
|
|
124
|
+
*/
|
|
125
|
+
export function mapMobileFeedPage(
|
|
126
|
+
server: MobileServerFeedResponse,
|
|
127
|
+
): MobileFeedPage {
|
|
128
|
+
return {
|
|
129
|
+
trades: server.trades.map(mapMobileFeedTrade),
|
|
130
|
+
nextCursor: server.next_cursor,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
93
134
|
/**
|
|
94
135
|
* Maps a server-side registered device (snake_case) to its client-side (camelCase) representation.
|
|
95
136
|
*/
|
|
@@ -1,21 +1,18 @@
|
|
|
1
|
-
import { MobileServerNotificationPreferences } from '../types/serverModelTypes';
|
|
2
1
|
import { MobileSignedInner } from './types';
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* Rebuilds an inner payload with its keys in the backend's struct declaration order (`type` first, then the
|
|
6
5
|
* remaining fields in the exact order the backend serializes them). msgpack encodes object keys in insertion
|
|
7
6
|
* order and the payload hash must be reproducible regardless of how the caller constructed the object, so
|
|
8
|
-
* every inner payload — and each of its sub-types — is canonicalized here before hashing. This function
|
|
9
|
-
*
|
|
7
|
+
* every inner payload — and each of its sub-types — is canonicalized here before hashing. This function is
|
|
8
|
+
* the source of truth for that order.
|
|
10
9
|
*/
|
|
11
10
|
export function canonicalizeMobileInner(
|
|
12
11
|
inner: MobileSignedInner,
|
|
13
12
|
): MobileSignedInner {
|
|
14
13
|
switch (inner.type) {
|
|
15
|
-
case '
|
|
16
|
-
return { type: '
|
|
17
|
-
case 'update_username':
|
|
18
|
-
return { type: 'update_username', display_name: inner.display_name };
|
|
14
|
+
case 'set_username':
|
|
15
|
+
return { type: 'set_username', display_name: inner.display_name };
|
|
19
16
|
case 'set_private_mode':
|
|
20
17
|
return { type: 'set_private_mode', private_mode: inner.private_mode };
|
|
21
18
|
case 'self_identity':
|
|
@@ -28,15 +25,6 @@ export function canonicalizeMobileInner(
|
|
|
28
25
|
locale: inner.locale,
|
|
29
26
|
app_version: inner.app_version,
|
|
30
27
|
};
|
|
31
|
-
case 'unregister_expo_token':
|
|
32
|
-
return { type: 'unregister_expo_token', expo_token: inner.expo_token };
|
|
33
|
-
case 'update_preferences':
|
|
34
|
-
return {
|
|
35
|
-
type: 'update_preferences',
|
|
36
|
-
preferences: canonicalizeNotificationPreferences(inner.preferences),
|
|
37
|
-
};
|
|
38
|
-
case 'notification_preferences':
|
|
39
|
-
return { type: 'notification_preferences' };
|
|
40
28
|
case 'registered_devices':
|
|
41
29
|
return { type: 'registered_devices' };
|
|
42
30
|
default: {
|
|
@@ -46,24 +34,3 @@ export function canonicalizeMobileInner(
|
|
|
46
34
|
}
|
|
47
35
|
}
|
|
48
36
|
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Rebuilds notification preferences with keys in the backend's struct declaration order, so the msgpack
|
|
52
|
-
* encoding matches the backend's `rmp_serde::to_vec_named` output field-for-field.
|
|
53
|
-
*/
|
|
54
|
-
function canonicalizeNotificationPreferences(
|
|
55
|
-
preferences: MobileServerNotificationPreferences,
|
|
56
|
-
): MobileServerNotificationPreferences {
|
|
57
|
-
return {
|
|
58
|
-
schema_version: preferences.schema_version,
|
|
59
|
-
categories: preferences.categories.map((category) => ({
|
|
60
|
-
category: category.category,
|
|
61
|
-
enabled: category.enabled,
|
|
62
|
-
scopes: category.scopes.map((scope) =>
|
|
63
|
-
scope.type === 'subaccount'
|
|
64
|
-
? { type: 'subaccount', subaccount: scope.subaccount }
|
|
65
|
-
: { type: 'product', product_id: scope.product_id },
|
|
66
|
-
),
|
|
67
|
-
})),
|
|
68
|
-
};
|
|
69
|
-
}
|
|
@@ -7,13 +7,9 @@ export const MOBILE_EIP712_METHOD_BY_TYPE: Record<
|
|
|
7
7
|
MobileSignedInner['type'],
|
|
8
8
|
string
|
|
9
9
|
> = {
|
|
10
|
-
|
|
11
|
-
update_username: 'mobile:execute_update_username',
|
|
10
|
+
set_username: 'mobile:execute_set_username',
|
|
12
11
|
set_private_mode: 'mobile:execute_set_private_mode',
|
|
13
12
|
self_identity: 'mobile:query_self_identity',
|
|
14
13
|
register_expo_token: 'mobile:execute_register_expo_token',
|
|
15
|
-
unregister_expo_token: 'mobile:execute_unregister_expo_token',
|
|
16
|
-
update_preferences: 'mobile:execute_update_preferences',
|
|
17
|
-
notification_preferences: 'mobile:query_notification_preferences',
|
|
18
14
|
registered_devices: 'mobile:query_registered_devices',
|
|
19
15
|
};
|
|
@@ -19,46 +19,30 @@ const FIXED_PRIVATE_KEY =
|
|
|
19
19
|
'0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b786907' as const;
|
|
20
20
|
const FIXED_VERIFYING_ADDR = '0x0000000000000000000000000000000000000001';
|
|
21
21
|
|
|
22
|
+
// `set_username`, `set_private_mode`, and `register_expo_token` mirror the backend's pinned fixtures in
|
|
23
|
+
// mobile/src/api/types.rs, so a divergence here is a real wire-format break rather than a stale expectation.
|
|
22
24
|
const PINNED_HASHES = {
|
|
23
|
-
|
|
24
|
-
'
|
|
25
|
-
update_username:
|
|
26
|
-
'0x92c3831d30de8206f9ee9d4cf29ed2a2fb1612a3b818e2e46121fc1d5eb4edb6',
|
|
25
|
+
set_username:
|
|
26
|
+
'0xb4a55d9eb0be4e5c9457761c0c34c75cf39f7c07bd170700d8dd5e9c7de4a659',
|
|
27
27
|
set_private_mode:
|
|
28
28
|
'0x4d12a06234d751e6ddcc01d8f70836bb5b7e207e573641d1efb5aaf2b0f30d10',
|
|
29
29
|
self_identity:
|
|
30
30
|
'0x10e94c4502cade0a0b4d7469717bcc1d266fc6a3b7635236fa1d3600b58c9954',
|
|
31
|
-
// The three execute hashes below mirror the backend's pinned fixtures in mobile/src/api/types.rs.
|
|
32
31
|
register_expo_token:
|
|
33
32
|
'0x1b9471afc9bde66f9bffd576d3326420e1bade4e16afa3a73ddc65f27155611c',
|
|
34
|
-
unregister_expo_token:
|
|
35
|
-
'0xd131071d0898c97496f3d41dfc05f30a5f82c95e550944c4fba47419ddd0ebf3',
|
|
36
|
-
update_preferences:
|
|
37
|
-
'0x071b8ac6f3d2518267dd238c8c96e15e07e0552aede3ba32383706bb05726f83',
|
|
38
|
-
notification_preferences:
|
|
39
|
-
'0x3694dda0e5732b36eb3b60da6b147ec4e35520fc54529610c69d19d722d4fe97',
|
|
40
33
|
registered_devices:
|
|
41
34
|
'0xe77b42e32d27f054f86d5ed52c9aac7b3eed857eb6209ee883c92f01b84d3334',
|
|
42
35
|
} as const;
|
|
43
36
|
|
|
44
37
|
describe('[mobile-client]: signing (offline)', () => {
|
|
45
38
|
describe('pinned payload hashes', () => {
|
|
46
|
-
it('
|
|
39
|
+
it('set_username', () => {
|
|
47
40
|
const inner: MobileSignedInner = {
|
|
48
|
-
type: '
|
|
41
|
+
type: 'set_username',
|
|
49
42
|
display_name: 'Alice.One',
|
|
50
43
|
};
|
|
51
44
|
const hash = getMobilePayloadHash(canonicalizeMobileInner(inner));
|
|
52
|
-
expect(hash).toBe(PINNED_HASHES.
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('update_username', () => {
|
|
56
|
-
const inner: MobileSignedInner = {
|
|
57
|
-
type: 'update_username',
|
|
58
|
-
display_name: 'Alice.Two',
|
|
59
|
-
};
|
|
60
|
-
const hash = getMobilePayloadHash(canonicalizeMobileInner(inner));
|
|
61
|
-
expect(hash).toBe(PINNED_HASHES.update_username);
|
|
45
|
+
expect(hash).toBe(PINNED_HASHES.set_username);
|
|
62
46
|
});
|
|
63
47
|
|
|
64
48
|
it('set_private_mode', () => {
|
|
@@ -88,33 +72,6 @@ describe('[mobile-client]: signing (offline)', () => {
|
|
|
88
72
|
expect(hash).toBe(PINNED_HASHES.register_expo_token);
|
|
89
73
|
});
|
|
90
74
|
|
|
91
|
-
it('unregister_expo_token', () => {
|
|
92
|
-
const inner: MobileSignedInner = {
|
|
93
|
-
type: 'unregister_expo_token',
|
|
94
|
-
expo_token: 'ExponentPushToken[abcdef1234567890abcdef]',
|
|
95
|
-
};
|
|
96
|
-
const hash = getMobilePayloadHash(canonicalizeMobileInner(inner));
|
|
97
|
-
expect(hash).toBe(PINNED_HASHES.unregister_expo_token);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('update_preferences', () => {
|
|
101
|
-
const inner: MobileSignedInner = {
|
|
102
|
-
type: 'update_preferences',
|
|
103
|
-
preferences: {
|
|
104
|
-
schema_version: 1,
|
|
105
|
-
categories: [{ category: 'order_fill', enabled: true, scopes: [] }],
|
|
106
|
-
},
|
|
107
|
-
};
|
|
108
|
-
const hash = getMobilePayloadHash(canonicalizeMobileInner(inner));
|
|
109
|
-
expect(hash).toBe(PINNED_HASHES.update_preferences);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('notification_preferences', () => {
|
|
113
|
-
const inner: MobileSignedInner = { type: 'notification_preferences' };
|
|
114
|
-
const hash = getMobilePayloadHash(canonicalizeMobileInner(inner));
|
|
115
|
-
expect(hash).toBe(PINNED_HASHES.notification_preferences);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
75
|
it('registered_devices', () => {
|
|
119
76
|
const inner: MobileSignedInner = { type: 'registered_devices' };
|
|
120
77
|
const hash = getMobilePayloadHash(canonicalizeMobileInner(inner));
|
|
@@ -134,19 +91,19 @@ describe('[mobile-client]: signing (offline)', () => {
|
|
|
134
91
|
expect(hash).toBe(PINNED_HASHES.set_private_mode);
|
|
135
92
|
});
|
|
136
93
|
|
|
137
|
-
it('canonicalizes
|
|
138
|
-
//
|
|
139
|
-
//
|
|
94
|
+
it('canonicalizes multi-field key order regardless of input key order', () => {
|
|
95
|
+
// register_expo_token is the only signed payload with more than one field, so it is where a caller can
|
|
96
|
+
// actually get the order wrong; canonicalizeMobileInner must rebuild it in the backend's declaration order.
|
|
140
97
|
const outOfOrderInner = {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
type: '
|
|
146
|
-
} as
|
|
98
|
+
app_version: '1.2.3',
|
|
99
|
+
locale: 'en-GB',
|
|
100
|
+
platform: 'ios',
|
|
101
|
+
expo_token: 'ExponentPushToken[abcdef1234567890abcdef]',
|
|
102
|
+
type: 'register_expo_token',
|
|
103
|
+
} as MobileSignedInner;
|
|
147
104
|
|
|
148
105
|
const hash = getMobilePayloadHash(canonicalizeMobileInner(outOfOrderInner));
|
|
149
|
-
expect(hash).toBe(PINNED_HASHES.
|
|
106
|
+
expect(hash).toBe(PINNED_HASHES.register_expo_token);
|
|
150
107
|
});
|
|
151
108
|
|
|
152
109
|
describe('nonce generation', () => {
|