@meshconnect/web-link-sdk 2.1.0-rc.0 → 2.1.0-rc.2

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.
Files changed (51) hide show
  1. package/jest.setup.ts +4 -0
  2. package/package.json +20 -9
  3. package/src/Link.test.ts +395 -0
  4. package/src/Link.ts +350 -0
  5. package/src/index.ts +3 -0
  6. package/src/utils/__snapshots__/popup.test.ts.snap +90 -0
  7. package/src/utils/event-types.test.ts +24 -0
  8. package/src/utils/event-types.ts +226 -0
  9. package/src/utils/popup.test.ts +50 -0
  10. package/src/utils/popup.ts +132 -0
  11. package/src/utils/sdk-specs.test.ts +17 -0
  12. package/src/utils/sdk-specs.ts +6 -0
  13. package/src/utils/style.test.ts +33 -0
  14. package/src/utils/style.ts +15 -0
  15. package/src/utils/types.ts +156 -0
  16. package/src/utils/version.ts +1 -0
  17. package/src/utils/wagmiCoreConnectorsUtils.ts +332 -0
  18. package/src/utils/wallet-browser-event-types.ts +102 -0
  19. package/tools/copy.js +25 -0
  20. package/tools/update-version.js +10 -0
  21. package/tsconfig.json +14 -0
  22. package/Link.d.ts +0 -2
  23. package/Link.js +0 -420
  24. package/cjs/Link.js +0 -424
  25. package/cjs/index.js +0 -21
  26. package/cjs/utils/event-types.js +0 -31
  27. package/cjs/utils/popup.js +0 -39
  28. package/cjs/utils/sdk-specs.js +0 -8
  29. package/cjs/utils/style.js +0 -18
  30. package/cjs/utils/types.js +0 -2
  31. package/cjs/utils/version.js +0 -4
  32. package/cjs/utils/wagmiCoreConnectorsUtils.js +0 -425
  33. package/cjs/utils/wallet-browser-event-types.js +0 -17
  34. package/index.d.ts +0 -3
  35. package/index.js +0 -3
  36. package/utils/event-types.d.ts +0 -152
  37. package/utils/event-types.js +0 -27
  38. package/utils/popup.d.ts +0 -3
  39. package/utils/popup.js +0 -34
  40. package/utils/sdk-specs.d.ts +0 -4
  41. package/utils/sdk-specs.js +0 -5
  42. package/utils/style.d.ts +0 -3
  43. package/utils/style.js +0 -13
  44. package/utils/types.d.ts +0 -134
  45. package/utils/types.js +0 -1
  46. package/utils/version.d.ts +0 -1
  47. package/utils/version.js +0 -1
  48. package/utils/wagmiCoreConnectorsUtils.d.ts +0 -11
  49. package/utils/wagmiCoreConnectorsUtils.js +0 -414
  50. package/utils/wallet-browser-event-types.d.ts +0 -59
  51. package/utils/wallet-browser-event-types.js +0 -13
package/src/Link.ts ADDED
@@ -0,0 +1,350 @@
1
+ import {
2
+ LinkOptions,
3
+ Link,
4
+ EventType,
5
+ AccessTokenPayload,
6
+ DelayedAuthPayload,
7
+ TransferFinishedPayload,
8
+ LinkPayload
9
+ } from './utils/types'
10
+ import { addPopup, iframeId, removePopup } from './utils/popup'
11
+ import { LinkEventType, isLinkEventTypeKey } from './utils/event-types'
12
+ import {
13
+ WalletBrowserEventType,
14
+ isWalletBrowserEventTypeKey
15
+ } from './utils/wallet-browser-event-types'
16
+ import { sdkSpecs } from './utils/sdk-specs'
17
+ import {
18
+ connectToSpecificWallet,
19
+ sendTransactionFromSDK,
20
+ switchChainFromSDK,
21
+ getWagmiCoreInjectedData,
22
+ sendNonNativeTransactionFromSDK,
23
+ disconnectAllAccounts
24
+ } from './utils/wagmiCoreConnectorsUtils'
25
+
26
+ let currentOptions: LinkOptions | undefined
27
+ const possibleOrigins = new Set<string>([
28
+ 'https://web.meshconnect.com',
29
+ 'https://web.getfront.com'
30
+ ])
31
+
32
+ const iframeElement = () => {
33
+ return document.getElementById(iframeId) as HTMLIFrameElement
34
+ }
35
+
36
+ function sendMessageToIframe(message: unknown) {
37
+ possibleOrigins.forEach(origin => {
38
+ try {
39
+ iframeElement().contentWindow?.postMessage(message, origin)
40
+ } catch (e) {
41
+ console.error('Mesh SDK: Failed to deliver message to the iframe')
42
+ console.error(e)
43
+ }
44
+ })
45
+ }
46
+
47
+ async function handleLinkEvent(
48
+ event:
49
+ | MessageEvent<{
50
+ type: EventType
51
+ payload?:
52
+ | AccessTokenPayload
53
+ | DelayedAuthPayload
54
+ | TransferFinishedPayload
55
+ link?: string
56
+ }>
57
+ | MessageEvent<LinkEventType>
58
+ ) {
59
+ switch (event.data.type) {
60
+ case 'brokerageAccountAccessToken': {
61
+ const payload: LinkPayload = {
62
+ accessToken: event.data.payload as AccessTokenPayload
63
+ }
64
+ currentOptions?.onEvent?.({
65
+ type: 'integrationConnected',
66
+ payload: payload
67
+ })
68
+ currentOptions?.onIntegrationConnected?.(payload)
69
+ break
70
+ }
71
+ case 'delayedAuthentication': {
72
+ const payload: LinkPayload = {
73
+ delayedAuth: event.data.payload as DelayedAuthPayload
74
+ }
75
+ currentOptions?.onEvent?.({
76
+ type: 'integrationConnected',
77
+ payload: payload
78
+ })
79
+ currentOptions?.onIntegrationConnected?.(payload)
80
+ break
81
+ }
82
+ case 'transferFinished': {
83
+ const payload = event.data.payload as TransferFinishedPayload
84
+
85
+ currentOptions?.onEvent?.({
86
+ type: 'transferCompleted',
87
+ payload: payload
88
+ })
89
+ currentOptions?.onTransferFinished?.(payload)
90
+ break
91
+ }
92
+ case 'close':
93
+ case 'done': {
94
+ const payload = event.data?.payload
95
+ currentOptions?.onExit?.(payload?.errorMessage, payload)
96
+ removePopup()
97
+ break
98
+ }
99
+ case 'oauthLinkOpen': {
100
+ if (event.data.link) {
101
+ const w = 700
102
+ const h = 800
103
+ const left = screen.width / 2 - w / 2
104
+ const top = screen.height / 2 - h / 2
105
+ window
106
+ .open(
107
+ event.data.link,
108
+ '_blank',
109
+ `popup,noopener,noreferrer,resizable,scrollbars,width=${w},height=${h},top=${top},left=${left}`
110
+ )
111
+ ?.focus()
112
+ }
113
+
114
+ break
115
+ }
116
+ case 'loaded': {
117
+ sendMessageToIframe({
118
+ type: 'meshSDKSpecs',
119
+ payload: { ...sdkSpecs }
120
+ })
121
+ if (currentOptions?.accessTokens) {
122
+ sendMessageToIframe({
123
+ type: 'frontAccessTokens',
124
+ payload: currentOptions.accessTokens
125
+ })
126
+ }
127
+ if (currentOptions?.transferDestinationTokens) {
128
+ sendMessageToIframe({
129
+ type: 'frontTransferDestinationTokens',
130
+ payload: currentOptions.transferDestinationTokens
131
+ })
132
+ }
133
+ const injectedConnectors = await getWagmiCoreInjectedData()
134
+ if (injectedConnectors) {
135
+ sendMessageToIframe({
136
+ type: 'SDKinjectedWagmiConnectorsData',
137
+ payload: injectedConnectors
138
+ })
139
+ }
140
+ currentOptions?.onEvent?.({ type: 'pageLoaded' })
141
+ break
142
+ }
143
+ default: {
144
+ if (isLinkEventTypeKey(event.data.type)) {
145
+ currentOptions?.onEvent?.(event.data)
146
+ }
147
+ break
148
+ }
149
+ }
150
+ }
151
+
152
+ async function handleWalletBrowserEvent(
153
+ event: MessageEvent<WalletBrowserEventType>
154
+ ) {
155
+ switch (event.data.type) {
156
+ case 'walletBrowserInjectedWalletSelected': {
157
+ const payload = event.data.payload
158
+ try {
159
+ const result = await connectToSpecificWallet(payload.integrationName)
160
+ if (result instanceof Error) {
161
+ throw result
162
+ }
163
+ sendMessageToIframe({
164
+ type: 'SDKinjectedConnectionCompleted',
165
+ payload: {
166
+ accounts: result.accounts,
167
+ chainId: result.chainId,
168
+ signedTxHash: result.txSigned
169
+ }
170
+ })
171
+ } catch (error) {
172
+ handleErrorAndSendMessage(error, 'SDKinjectedConnectionCompleted')
173
+ }
174
+ break
175
+ }
176
+ case 'walletBrowserChainSwitchRequest': {
177
+ const payload = event.data.payload
178
+ try {
179
+ const result = await switchChainFromSDK(payload.chainId)
180
+ if (result instanceof Error) {
181
+ throw result
182
+ }
183
+ sendMessageToIframe({
184
+ type: 'SDKswitchChainCompleted',
185
+ payload: result
186
+ })
187
+ } catch (error) {
188
+ handleErrorAndSendMessage(error, 'SDKswitchChainCompleted')
189
+ }
190
+ break
191
+ }
192
+ case 'walletBrowserNativeTransferRequest': {
193
+ const payload = event.data.payload
194
+ try {
195
+ const result = await sendTransactionFromSDK(
196
+ payload.toAddress,
197
+ payload.amount,
198
+ payload.decimalPlaces,
199
+ payload.chainId,
200
+ payload.account
201
+ )
202
+ if (result instanceof Error) {
203
+ throw result
204
+ }
205
+ sendMessageToIframe({
206
+ type: 'SDKnativeTransferCompleted',
207
+ payload: result
208
+ })
209
+ } catch (error) {
210
+ handleErrorAndSendMessage(error, 'SDKnativeTransferCompleted')
211
+ }
212
+ break
213
+ }
214
+ case 'walletBrowserNonNativeTransferRequest': {
215
+ const payload = event.data.payload
216
+ try {
217
+ const result = await sendNonNativeTransactionFromSDK(
218
+ payload.address,
219
+ JSON.parse(payload.abi),
220
+ payload.functionName,
221
+ payload.args
222
+ )
223
+ if (result instanceof Error) {
224
+ throw result
225
+ }
226
+ sendMessageToIframe({
227
+ type: 'SDKnonNativeTransferCompleted',
228
+ payload: result
229
+ })
230
+ } catch (error) {
231
+ handleErrorAndSendMessage(error, 'SDKnonNativeTransferCompleted')
232
+ }
233
+ break
234
+ }
235
+ case 'walletBrowserNativeSmartDeposit': {
236
+ const payload = event.data.payload
237
+ try {
238
+ const result = await sendNonNativeTransactionFromSDK(
239
+ payload.address,
240
+ JSON.parse(payload.abi),
241
+ payload.functionName,
242
+ payload.args,
243
+ payload.value
244
+ )
245
+ if (result instanceof Error) {
246
+ throw result
247
+ }
248
+ sendMessageToIframe({
249
+ type: 'SDKnativeSmartDepositCompleted',
250
+ payload: {
251
+ txHash: result
252
+ }
253
+ })
254
+ } catch (error) {
255
+ handleErrorAndSendMessage(error, 'SDKnativeSmartDepositCompleted')
256
+ }
257
+ break
258
+ }
259
+ case 'walletBrowserNonNativeSmartDeposit': {
260
+ const payload = event.data.payload
261
+ try {
262
+ const result = await sendNonNativeTransactionFromSDK(
263
+ payload.address,
264
+ JSON.parse(payload.abi),
265
+ payload.functionName,
266
+ payload.args
267
+ )
268
+ if (result) {
269
+ sendMessageToIframe({
270
+ type: 'SDKnonNativeSmartDepositCompleted',
271
+ payload: {
272
+ txHash: result
273
+ }
274
+ })
275
+ } else {
276
+ throw new Error('Transfer failed')
277
+ }
278
+ } catch (error) {
279
+ handleErrorAndSendMessage(error, 'SDKnonNativeSmartDepositCompleted')
280
+ }
281
+ break
282
+ }
283
+ case 'walletBrowserDisconnect': {
284
+ disconnectAllAccounts()
285
+ sendMessageToIframe({
286
+ type: 'SDKdisconnectSuccess'
287
+ })
288
+ break
289
+ }
290
+ }
291
+ }
292
+
293
+ async function eventsListener(
294
+ event: MessageEvent<
295
+ LinkEventType | WalletBrowserEventType | { type: EventType }
296
+ >
297
+ ) {
298
+ if (isWalletBrowserEventTypeKey(event.data.type)) {
299
+ await handleWalletBrowserEvent(
300
+ event as MessageEvent<WalletBrowserEventType>
301
+ )
302
+ } else {
303
+ await handleLinkEvent(event as MessageEvent<{ type: EventType }>)
304
+ }
305
+ }
306
+
307
+ function handleErrorAndSendMessage(error: unknown, messageType: string) {
308
+ let errorMessage = 'An unexpected error occurred'
309
+ if (error instanceof Error) {
310
+ errorMessage = error.message
311
+ }
312
+ sendMessageToIframe({
313
+ type: messageType,
314
+ payload: {
315
+ error: errorMessage
316
+ }
317
+ })
318
+ }
319
+
320
+ export const createLink = (options: LinkOptions): Link => {
321
+ const openLink = async (linkToken: string) => {
322
+ if (!linkToken) {
323
+ options?.onExit?.('Invalid link token!')
324
+ return
325
+ }
326
+
327
+ currentOptions = options
328
+ const linkUrl = window.atob(linkToken)
329
+ const iframeUrlObject = new URL(linkUrl)
330
+ if (iframeUrlObject.origin) {
331
+ possibleOrigins.add(iframeUrlObject.origin)
332
+ }
333
+
334
+ window.removeEventListener('message', eventsListener)
335
+ addPopup(linkUrl)
336
+ window.addEventListener('message', eventsListener)
337
+ }
338
+
339
+ const closeLink = () => {
340
+ removePopup()
341
+ window.removeEventListener('message', eventsListener)
342
+ options.onExit?.()
343
+ disconnectAllAccounts()
344
+ }
345
+
346
+ return {
347
+ openLink: openLink,
348
+ closeLink: closeLink
349
+ }
350
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './utils/types'
2
+ export * from './utils/event-types'
3
+ export { createLink } from './Link'
@@ -0,0 +1,90 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`Popup tests addPopup should add correct popup 1`] = `
4
+ <style
5
+ id="mesh-link-popup__styles"
6
+ >
7
+
8
+ body {
9
+ position: fixed;
10
+ left: 0;
11
+ top: 0;
12
+ bottom: 0;
13
+ right: 0;
14
+ overflow: hidden;
15
+ }
16
+
17
+ #mesh-link-popup {
18
+ all: unset;
19
+ position: fixed;
20
+ left: 0;
21
+ top: 0;
22
+ bottom: 0;
23
+ right: 0;
24
+ display: flex;
25
+ flex-direction: column;
26
+ align-items: center;
27
+ justify-content: center;
28
+ z-index: 10000;
29
+ }
30
+
31
+ #mesh-link-popup__backdrop {
32
+ position: absolute;
33
+ left: 0;
34
+ top: 0;
35
+ bottom: 0;
36
+ right: 0;
37
+ z-index: 10000;
38
+ background: black;
39
+ opacity: 0.8;
40
+ }
41
+
42
+ #mesh-link-popup__popup-content {
43
+ position: absolute;
44
+ height: 80%;
45
+ max-height: 710px;
46
+ min-height: 685px;
47
+ margin: auto;
48
+ z-index: 10001;
49
+ width: 30%;
50
+ max-width: 430px;
51
+ min-width: 380px;
52
+ display: flex;
53
+ flex-direction: column;
54
+ border-radius: 2px;
55
+ background: white;
56
+ flex-grow: 1;
57
+ }
58
+
59
+ #mesh-link-popup__popup-content iframe {
60
+ border: none;
61
+ width: 100%;
62
+ flex-grow: 1;
63
+ border-radius: 2px;
64
+ }
65
+
66
+ @media only screen and (max-width: 768px) {
67
+ #mesh-link-popup__popup-content {
68
+ height: 100vh;
69
+ width: 100vw;
70
+ max-width: 100%;
71
+ min-width: 100%;
72
+ max-height: 100%;
73
+ min-height: 100%;
74
+ border-radius: 0px;
75
+ }
76
+
77
+ #mesh-link-popup__popup-content iframe {
78
+ border-radius: 0px;
79
+ }
80
+ }
81
+
82
+ @media only screen and (max-height: 710px) {
83
+ #mesh-link-popup__popup-content {
84
+ max-height: 100%;
85
+ min-height: 100%;
86
+ }
87
+ }
88
+
89
+ </style>
90
+ `;
@@ -0,0 +1,24 @@
1
+ import { isLinkEventTypeKey } from './event-types'
2
+
3
+ describe('Event types tests', () => {
4
+ test.each([
5
+ 'integrationConnected',
6
+ 'integrationConnectionError',
7
+ 'transferCompleted',
8
+ 'integrationSelected',
9
+ 'credentialsEntered',
10
+ 'transferStarted',
11
+ 'transferPreviewed',
12
+ 'transferPreviewError',
13
+ 'transferExecutionError'
14
+ ])(
15
+ 'isLinkEventTypeKey should return true if parameter is "%s"',
16
+ eventType => {
17
+ expect(isLinkEventTypeKey(eventType)).toBe(true)
18
+ }
19
+ )
20
+
21
+ test('isLinkEventTypeKey should return false if parameter is not event', () => {
22
+ expect(isLinkEventTypeKey('test')).toBe(false)
23
+ })
24
+ })
@@ -0,0 +1,226 @@
1
+ import { LinkPayload, TransferFinishedPayload } from './types'
2
+
3
+ export type LinkEventType =
4
+ | IntegrationConnected
5
+ | IntegrationConnectionError
6
+ | TransferCompleted
7
+ | IntegrationSelected
8
+ | CredentialsEntered
9
+ | TransferStarted
10
+ | TransferPreviewed
11
+ | TransferPreviewError
12
+ | TransferExecutionError
13
+ | PageLoaded
14
+ | IntegrationMfaRequired
15
+ | IntegrationMfaEntered
16
+ | IntegrationOAuthStarted
17
+ | IntegrationAccountSelectionRequired
18
+ | TransferAssetSelected
19
+ | TransferNetworkSelected
20
+ | TransferAmountEntered
21
+ | TransferMfaRequired
22
+ | TransferMfaEntered
23
+ | TransferKycRequired
24
+ | DoneEvent
25
+ | CloseEvent
26
+
27
+ const LINK_EVENT_TYPE_KEYS = [
28
+ 'integrationConnected',
29
+ 'integrationConnectionError',
30
+ 'integrationMfaRequired',
31
+ 'integrationMfaEntered',
32
+ 'integrationOAuthStarted',
33
+ 'integrationAccountSelectionRequired',
34
+ 'transferCompleted',
35
+ 'integrationSelected',
36
+ 'credentialsEntered',
37
+ 'transferStarted',
38
+ 'transferPreviewed',
39
+ 'transferPreviewError',
40
+ 'transferExecutionError',
41
+ 'pageLoaded',
42
+ 'transferAssetSelected',
43
+ 'transferNetworkSelected',
44
+ 'transferAmountEntered',
45
+ 'transferMfaRequired',
46
+ 'transferMfaEntered',
47
+ 'transferKycRequired',
48
+ 'done',
49
+ 'close'
50
+ ] as const
51
+
52
+ export type LinkEventTypeKeys = (typeof LINK_EVENT_TYPE_KEYS)[number]
53
+
54
+ export function isLinkEventTypeKey(key: string): key is LinkEventTypeKeys {
55
+ return LINK_EVENT_TYPE_KEYS.includes(key as LinkEventTypeKeys)
56
+ }
57
+
58
+ interface LinkEventBase {
59
+ type: LinkEventTypeKeys
60
+ }
61
+
62
+ export interface PageLoaded {
63
+ type: 'pageLoaded'
64
+ }
65
+
66
+ export interface IntegrationConnected extends LinkEventBase {
67
+ type: 'integrationConnected'
68
+ payload: LinkPayload
69
+ }
70
+
71
+ export interface IntegrationConnectionError extends LinkEventBase {
72
+ type: 'integrationConnectionError'
73
+ payload: {
74
+ errorMessage: string
75
+ }
76
+ }
77
+
78
+ export interface TransferCompleted extends LinkEventBase {
79
+ type: 'transferCompleted'
80
+ payload: TransferFinishedPayload
81
+ }
82
+
83
+ export interface IntegrationSelected extends LinkEventBase {
84
+ type: 'integrationSelected'
85
+ payload: {
86
+ integrationType: string
87
+ integrationName: string
88
+ }
89
+ }
90
+
91
+ export interface CredentialsEntered extends LinkEventBase {
92
+ type: 'credentialsEntered'
93
+ }
94
+
95
+ export interface TransferStarted extends LinkEventBase {
96
+ type: 'transferStarted'
97
+ }
98
+
99
+ export interface TransferPreviewed extends LinkEventBase {
100
+ type: 'transferPreviewed'
101
+ payload: {
102
+ amount: number
103
+ symbol: string
104
+ toAddress: string
105
+ networkId: string
106
+ previewId: string
107
+ networkName?: string
108
+ amountInFiat?: number
109
+ estimatedNetworkGasFee?: {
110
+ fee?: number
111
+ feeCurrency?: string
112
+ feeInFiat?: number
113
+ }
114
+ }
115
+ }
116
+
117
+ export interface TransferPreviewError extends LinkEventBase {
118
+ type: 'transferPreviewError'
119
+ payload: {
120
+ errorMessage: string
121
+ }
122
+ }
123
+
124
+ export interface TransferExecutionError extends LinkEventBase {
125
+ type: 'transferExecutionError'
126
+ payload: {
127
+ errorMessage: string
128
+ }
129
+ }
130
+
131
+ export interface IntegrationMfaRequired extends LinkEventBase {
132
+ type: 'integrationMfaRequired'
133
+ }
134
+
135
+ export interface IntegrationMfaEntered extends LinkEventBase {
136
+ type: 'integrationMfaEntered'
137
+ }
138
+
139
+ export interface IntegrationOAuthStarted extends LinkEventBase {
140
+ type: 'integrationOAuthStarted'
141
+ }
142
+
143
+ export interface IntegrationAccountSelectionRequired extends LinkEventBase {
144
+ type: 'integrationAccountSelectionRequired'
145
+ }
146
+
147
+ export interface TransferAssetSelected extends LinkEventBase {
148
+ type: 'transferAssetSelected'
149
+ payload: {
150
+ symbol: string
151
+ }
152
+ }
153
+
154
+ export interface TransferNetworkSelected extends LinkEventBase {
155
+ type: 'transferNetworkSelected'
156
+ payload: {
157
+ id: string
158
+ name: string
159
+ }
160
+ }
161
+
162
+ export interface TransferAmountEntered extends LinkEventBase {
163
+ type: 'transferAmountEntered'
164
+ }
165
+
166
+ export interface TransferMfaRequired extends LinkEventBase {
167
+ type: 'transferMfaRequired'
168
+ }
169
+
170
+ export interface TransferMfaEntered extends LinkEventBase {
171
+ type: 'transferMfaEntered'
172
+ }
173
+
174
+ export interface TransferKycRequired extends LinkEventBase {
175
+ type: 'transferKycRequired'
176
+ }
177
+
178
+ export interface DoneEvent extends LinkEventBase {
179
+ type: 'done'
180
+ payload: SessionSymmary
181
+ }
182
+
183
+ export interface CloseEvent extends LinkEventBase {
184
+ type: 'close'
185
+ payload: SessionSymmary
186
+ }
187
+
188
+ export interface SessionSymmary {
189
+ /**
190
+ * Current page of application. Possible values:
191
+ * `startPage`
192
+ * `integrationsCatalogPage`
193
+ * `integrationLoginPage`
194
+ * `integrationMfaPage`
195
+ * `integrationAccountSelectPage`
196
+ * `integrationConnectedPage`
197
+ * `errorPage`
198
+ * `transferKycPage`
199
+ * `transferHoldingSelectionPage`
200
+ * `transferNetworkSelectionPage`
201
+ * `transferAmountSelectionPage`
202
+ * `transferPreviewPage`
203
+ * `transferMfaPage`
204
+ * `transferFundingPage`
205
+ * `transferExecutedPage`
206
+ * `termsAndConditionPage`
207
+ *
208
+ * This list may change in future.
209
+ */
210
+ page: string
211
+ /** Selected integration */
212
+ selectedIntegration?: {
213
+ id?: string
214
+ name?: string
215
+ }
216
+ /** Transfer information */
217
+ transfer?: {
218
+ previewId?: string
219
+ symbol?: string
220
+ amount?: number
221
+ amountInFiat?: number
222
+ transactionId?: string
223
+ networkId?: string
224
+ }
225
+ errorMessage?: string
226
+ }