@portal-hq/web 3.11.0 → 3.12.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/lib/commonjs/index.js +12 -7
- package/lib/commonjs/index.test.js +1 -1
- package/lib/commonjs/mpc/index.js +58 -10
- package/lib/commonjs/mpc/index.test.js +202 -100
- package/lib/commonjs/namespaces/evmAccountType/index.test.js +25 -12
- package/lib/commonjs/provider/index.js +14 -17
- package/lib/commonjs/provider/index.test.js +25 -2
- package/lib/commonjs/shared/logger.js +59 -0
- package/lib/commonjs/shared/trace/index.js +55 -0
- package/lib/commonjs/shared/types/index.js +2 -1
- package/lib/esm/index.js +12 -7
- package/lib/esm/index.test.js +1 -1
- package/lib/esm/mpc/index.js +58 -10
- package/lib/esm/mpc/index.test.js +202 -100
- package/lib/esm/namespaces/evmAccountType/index.test.js +25 -12
- package/lib/esm/provider/index.js +14 -17
- package/lib/esm/provider/index.test.js +25 -2
- package/lib/esm/shared/logger.js +56 -0
- package/lib/esm/shared/trace/index.js +51 -0
- package/lib/esm/shared/types/index.js +2 -1
- package/package.json +1 -1
- package/src/index.test.ts +1 -0
- package/src/index.ts +14 -3
- package/src/logger/index.ts +1 -8
- package/src/mpc/index.test.ts +202 -100
- package/src/mpc/index.ts +73 -5
- package/src/namespaces/evmAccountType/index.test.ts +25 -12
- package/src/provider/index.test.ts +30 -2
- package/src/provider/index.ts +17 -3
- package/src/shared/logger.ts +69 -0
- package/src/shared/trace/index.ts +59 -0
- package/src/shared/types/api.ts +5 -0
- package/src/shared/types/common.ts +14 -0
- package/src/shared/types/index.ts +2 -1
- package/types.d.ts +1 -0
package/src/mpc/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PortalMpcError } from './errors'
|
|
2
|
+
import { sdkLogger } from '../logger'
|
|
2
3
|
|
|
3
4
|
import Portal, {
|
|
4
5
|
BackupMethods,
|
|
@@ -107,14 +108,16 @@ import {
|
|
|
107
108
|
ScreenAddressApiResponse,
|
|
108
109
|
ScreenAddressRequestOptions,
|
|
109
110
|
} from '../../hypernative'
|
|
111
|
+
import { generateTraceId } from '../shared/trace'
|
|
110
112
|
|
|
111
|
-
const WEB_SDK_VERSION = '3.
|
|
113
|
+
const WEB_SDK_VERSION = '3.12.0'
|
|
112
114
|
|
|
113
115
|
class Mpc {
|
|
114
116
|
public iframe?: HTMLIFrameElement
|
|
115
117
|
|
|
116
118
|
private portal: Portal
|
|
117
119
|
private _ready = false
|
|
120
|
+
private presignatureLogHandler: ((event: MessageEvent) => void) | null = null
|
|
118
121
|
|
|
119
122
|
public get ready() {
|
|
120
123
|
return this._ready
|
|
@@ -143,10 +146,16 @@ class Mpc {
|
|
|
143
146
|
progress: ProgressCallback = () => {
|
|
144
147
|
// Noop
|
|
145
148
|
},
|
|
149
|
+
traceId?: string,
|
|
146
150
|
): Promise<BackupResponse> {
|
|
147
151
|
// validates password config for password backup
|
|
148
152
|
this.validateBackupConfig(data)
|
|
149
153
|
|
|
154
|
+
const resolvedTraceId = traceId ?? generateTraceId()
|
|
155
|
+
sdkLogger.info(
|
|
156
|
+
`[Portal MPC] backup started | backupMethod=${data.backupMethod} | traceId=${resolvedTraceId}`,
|
|
157
|
+
)
|
|
158
|
+
|
|
150
159
|
return this.handleRequestToIframeAndPost({
|
|
151
160
|
methodMessage: 'portal:wasm:backup',
|
|
152
161
|
errorMessage: 'portal:wasm:backupError',
|
|
@@ -154,6 +163,7 @@ class Mpc {
|
|
|
154
163
|
data,
|
|
155
164
|
progressMessage: 'portal:wasm:backupProgress',
|
|
156
165
|
progressCallback: progress,
|
|
166
|
+
traceId: resolvedTraceId,
|
|
157
167
|
mapReturnValue: (result: Record<string, unknown>) => {
|
|
158
168
|
const resultData = result as Record<string, unknown>
|
|
159
169
|
const backupIds = Array.isArray(resultData.backupIds)
|
|
@@ -183,6 +193,9 @@ class Mpc {
|
|
|
183
193
|
resultMessage: 'portal:destroyResult',
|
|
184
194
|
data: {},
|
|
185
195
|
mapReturnValue: () => true,
|
|
196
|
+
}).then((result) => {
|
|
197
|
+
this.teardownPresignatureLogForwarding()
|
|
198
|
+
return result
|
|
186
199
|
})
|
|
187
200
|
}
|
|
188
201
|
|
|
@@ -191,7 +204,11 @@ class Mpc {
|
|
|
191
204
|
progress: ProgressCallback = () => {
|
|
192
205
|
// Noop
|
|
193
206
|
},
|
|
207
|
+
traceId?: string,
|
|
194
208
|
): Promise<string> {
|
|
209
|
+
const resolvedTraceId = traceId ?? generateTraceId()
|
|
210
|
+
sdkLogger.info(`[Portal MPC] generate started | traceId=${resolvedTraceId}`)
|
|
211
|
+
|
|
195
212
|
return this.handleRequestToIframeAndPost({
|
|
196
213
|
methodMessage: 'portal:wasm:generate',
|
|
197
214
|
errorMessage: 'portal:wasm:generateError',
|
|
@@ -199,6 +216,7 @@ class Mpc {
|
|
|
199
216
|
data,
|
|
200
217
|
progressMessage: 'portal:wasm:generateProgress',
|
|
201
218
|
progressCallback: progress,
|
|
219
|
+
traceId: resolvedTraceId,
|
|
202
220
|
})
|
|
203
221
|
}
|
|
204
222
|
|
|
@@ -216,7 +234,13 @@ class Mpc {
|
|
|
216
234
|
progress: ProgressCallback = () => {
|
|
217
235
|
// Noop
|
|
218
236
|
},
|
|
237
|
+
traceId?: string,
|
|
219
238
|
): Promise<string> {
|
|
239
|
+
const resolvedTraceId = traceId ?? generateTraceId()
|
|
240
|
+
sdkLogger.info(
|
|
241
|
+
`[Portal MPC] recover started | backupMethod=${data.backupMethod} | traceId=${resolvedTraceId}`,
|
|
242
|
+
)
|
|
243
|
+
|
|
220
244
|
return this.handleRequestToIframeAndPost({
|
|
221
245
|
methodMessage: 'portal:wasm:recover',
|
|
222
246
|
errorMessage: 'portal:wasm:recoverError',
|
|
@@ -224,26 +248,30 @@ class Mpc {
|
|
|
224
248
|
data,
|
|
225
249
|
progressMessage: 'portal:wasm:recoverProgress',
|
|
226
250
|
progressCallback: progress,
|
|
251
|
+
traceId: resolvedTraceId,
|
|
227
252
|
})
|
|
228
253
|
}
|
|
229
254
|
|
|
230
|
-
public async eject(data: EjectArgs): Promise<EjectResult> {
|
|
255
|
+
public async eject(data: EjectArgs, traceId?: string): Promise<EjectResult> {
|
|
231
256
|
return this.handleRequestToIframeAndPost({
|
|
232
257
|
methodMessage: 'portal:wasm:eject',
|
|
233
258
|
errorMessage: 'portal:wasm:ejectError',
|
|
234
259
|
resultMessage: 'portal:wasm:ejectResult',
|
|
235
260
|
data,
|
|
261
|
+
traceId,
|
|
236
262
|
})
|
|
237
263
|
}
|
|
238
264
|
|
|
239
265
|
public async ejectPrivateKeys(
|
|
240
266
|
data: EjectPrivateKeysArgs,
|
|
267
|
+
traceId?: string,
|
|
241
268
|
): Promise<EjectPrivateKeysResult> {
|
|
242
269
|
return this.handleRequestToIframeAndPost({
|
|
243
270
|
methodMessage: 'portal:wasm:ejectPrivateKeys',
|
|
244
271
|
errorMessage: 'portal:wasm:ejectPrivateKeysError',
|
|
245
272
|
resultMessage: 'portal:wasm:ejectPrivateKeysResult',
|
|
246
273
|
data,
|
|
274
|
+
traceId,
|
|
247
275
|
})
|
|
248
276
|
}
|
|
249
277
|
|
|
@@ -272,13 +300,19 @@ class Mpc {
|
|
|
272
300
|
// Noop
|
|
273
301
|
},
|
|
274
302
|
): Promise<string> {
|
|
303
|
+
const resolvedTraceId = data.traceId ?? generateTraceId()
|
|
304
|
+
sdkLogger.info(
|
|
305
|
+
`[Portal MPC] sign started | method=${data.method} | traceId=${resolvedTraceId} | chainId=${data.chainId}`,
|
|
306
|
+
)
|
|
307
|
+
|
|
275
308
|
return this.handleRequestToIframeAndPost({
|
|
276
309
|
methodMessage: 'portal:wasm:sign',
|
|
277
310
|
errorMessage: 'portal:wasm:signError',
|
|
278
311
|
resultMessage: 'portal:wasm:signResult',
|
|
279
|
-
data,
|
|
312
|
+
data: { ...data, traceId: resolvedTraceId },
|
|
280
313
|
progressMessage: 'portal:wasm:signProgress',
|
|
281
314
|
progressCallback: progress,
|
|
315
|
+
traceId: resolvedTraceId,
|
|
282
316
|
})
|
|
283
317
|
}
|
|
284
318
|
|
|
@@ -360,12 +394,14 @@ class Mpc {
|
|
|
360
394
|
to: string,
|
|
361
395
|
token: string,
|
|
362
396
|
amount: string,
|
|
397
|
+
traceId?: string,
|
|
363
398
|
): Promise<BuiltTransaction> {
|
|
364
399
|
return this.handleRequestToIframeAndPost({
|
|
365
400
|
methodMessage: 'portal:buildTransaction',
|
|
366
401
|
errorMessage: 'portal:buildTransactionError',
|
|
367
402
|
resultMessage: 'portal:buildTransactionResult',
|
|
368
403
|
data: { chainId, to, token, amount },
|
|
404
|
+
traceId,
|
|
369
405
|
})
|
|
370
406
|
}
|
|
371
407
|
|
|
@@ -879,6 +915,7 @@ class Mpc {
|
|
|
879
915
|
progressMessage,
|
|
880
916
|
progressCallback,
|
|
881
917
|
mapReturnValue,
|
|
918
|
+
traceId: providedTraceId,
|
|
882
919
|
}: {
|
|
883
920
|
methodMessage: string
|
|
884
921
|
errorMessage: string
|
|
@@ -887,7 +924,16 @@ class Mpc {
|
|
|
887
924
|
progressMessage?: string
|
|
888
925
|
progressCallback?: (status: MpcStatus) => void
|
|
889
926
|
mapReturnValue?: (result: any) => ResponseType
|
|
927
|
+
traceId?: string
|
|
890
928
|
}): Promise<ResponseType> {
|
|
929
|
+
// Single traceId per operation: use provided or generate. Propagates to iframe and all internal REST/MPC calls.
|
|
930
|
+
const traceId = providedTraceId ?? generateTraceId()
|
|
931
|
+
sdkLogger.debug(
|
|
932
|
+
'[Portal] request traceId:',
|
|
933
|
+
traceId,
|
|
934
|
+
'method:',
|
|
935
|
+
methodMessage,
|
|
936
|
+
)
|
|
891
937
|
return new Promise((resolve, reject) => {
|
|
892
938
|
const handleRequest = (event: MessageEvent<WorkerResult>) => {
|
|
893
939
|
const { type, data: result } = event.data
|
|
@@ -920,10 +966,11 @@ class Mpc {
|
|
|
920
966
|
// Bind the function to the message event
|
|
921
967
|
window.addEventListener('message', handleRequest)
|
|
922
968
|
|
|
923
|
-
// Send the request to the iframe
|
|
969
|
+
// Send the request to the iframe (traceId at top-level so data shape stays unchanged)
|
|
924
970
|
this.postMessage({
|
|
925
971
|
type: methodMessage,
|
|
926
972
|
data,
|
|
973
|
+
traceId,
|
|
927
974
|
})
|
|
928
975
|
})
|
|
929
976
|
}
|
|
@@ -960,6 +1007,7 @@ class Mpc {
|
|
|
960
1007
|
mpcHost: this.portal.mpcHost,
|
|
961
1008
|
mpcVersion: this.portal.mpcVersion,
|
|
962
1009
|
featureFlags: this.portal.featureFlags,
|
|
1010
|
+
logLevel: this.portal.getLogLevel(),
|
|
963
1011
|
}
|
|
964
1012
|
|
|
965
1013
|
const message = {
|
|
@@ -969,9 +1017,29 @@ class Mpc {
|
|
|
969
1017
|
|
|
970
1018
|
this.postMessage(message)
|
|
971
1019
|
|
|
1020
|
+
this.setupPresignatureLogForwarding()
|
|
972
1021
|
this.waitForReadyMessage()
|
|
973
1022
|
}
|
|
974
1023
|
|
|
1024
|
+
private setupPresignatureLogForwarding() {
|
|
1025
|
+
if (this.presignatureLogHandler) return
|
|
1026
|
+
const handler = (event: MessageEvent) => {
|
|
1027
|
+
if (event.origin !== this.getOrigin()) return
|
|
1028
|
+
const { type, data } = event.data || {}
|
|
1029
|
+
if (type === 'portal:presignature:log' && data?.message) {
|
|
1030
|
+
sdkLogger.warn(data.message)
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
this.presignatureLogHandler = handler
|
|
1034
|
+
window.addEventListener('message', handler)
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
private teardownPresignatureLogForwarding() {
|
|
1038
|
+
if (!this.presignatureLogHandler) return
|
|
1039
|
+
window.removeEventListener('message', this.presignatureLogHandler)
|
|
1040
|
+
this.presignatureLogHandler = null
|
|
1041
|
+
}
|
|
1042
|
+
|
|
975
1043
|
private getOrigin(): string {
|
|
976
1044
|
const host = this.portal.host
|
|
977
1045
|
const origin = host.startsWith('localhost:')
|
|
@@ -1028,7 +1096,7 @@ class Mpc {
|
|
|
1028
1096
|
})
|
|
1029
1097
|
}
|
|
1030
1098
|
|
|
1031
|
-
private postMessage(event: { type: string; data: any }) {
|
|
1099
|
+
private postMessage(event: { type: string; data: any; traceId?: string }) {
|
|
1032
1100
|
this.iframe?.contentWindow?.postMessage(event, this.getOrigin())
|
|
1033
1101
|
}
|
|
1034
1102
|
|
|
@@ -50,7 +50,8 @@ describe('EvmAccountType', () => {
|
|
|
50
50
|
const { type, data } = message
|
|
51
51
|
|
|
52
52
|
expect(type).toEqual('portal:evmAccountType:getStatus')
|
|
53
|
-
expect(data).
|
|
53
|
+
expect(data).toMatchObject(args)
|
|
54
|
+
expect(typeof message.traceId).toBe('string')
|
|
54
55
|
expect(origin).toEqual(mockHostOrigin)
|
|
55
56
|
|
|
56
57
|
window.dispatchEvent(
|
|
@@ -83,7 +84,8 @@ describe('EvmAccountType', () => {
|
|
|
83
84
|
const { type, data } = message
|
|
84
85
|
|
|
85
86
|
expect(type).toEqual('portal:evmAccountType:getStatus')
|
|
86
|
-
expect(data).
|
|
87
|
+
expect(data).toMatchObject(args)
|
|
88
|
+
expect(typeof message.traceId).toBe('string')
|
|
87
89
|
expect(origin).toEqual(mockHostOrigin)
|
|
88
90
|
|
|
89
91
|
window.dispatchEvent(
|
|
@@ -130,7 +132,8 @@ describe('EvmAccountType', () => {
|
|
|
130
132
|
const { type, data } = message
|
|
131
133
|
|
|
132
134
|
expect(type).toEqual('portal:evmAccountType:getAddresses')
|
|
133
|
-
expect(data).
|
|
135
|
+
expect(data).toMatchObject(args)
|
|
136
|
+
expect(typeof message.traceId).toBe('string')
|
|
134
137
|
expect(origin).toEqual(mockHostOrigin)
|
|
135
138
|
|
|
136
139
|
window.dispatchEvent(
|
|
@@ -163,7 +166,8 @@ describe('EvmAccountType', () => {
|
|
|
163
166
|
const { type, data } = message
|
|
164
167
|
|
|
165
168
|
expect(type).toEqual('portal:evmAccountType:getAddresses')
|
|
166
|
-
expect(data).
|
|
169
|
+
expect(data).toMatchObject(args)
|
|
170
|
+
expect(typeof message.traceId).toBe('string')
|
|
167
171
|
expect(origin).toEqual(mockHostOrigin)
|
|
168
172
|
|
|
169
173
|
window.dispatchEvent(
|
|
@@ -189,6 +193,7 @@ describe('EvmAccountType', () => {
|
|
|
189
193
|
.catch((error) => {
|
|
190
194
|
expect(error).toBeInstanceOf(PortalMpcError)
|
|
191
195
|
expect(error.message).toEqual('test')
|
|
196
|
+
expect(error.code).toEqual(1)
|
|
192
197
|
done()
|
|
193
198
|
})
|
|
194
199
|
})
|
|
@@ -209,7 +214,8 @@ describe('EvmAccountType', () => {
|
|
|
209
214
|
const { type, data } = message
|
|
210
215
|
|
|
211
216
|
expect(type).toEqual('portal:evmAccountType:buildAuthorizationList')
|
|
212
|
-
expect(data).
|
|
217
|
+
expect(data).toMatchObject(args)
|
|
218
|
+
expect(typeof message.traceId).toBe('string')
|
|
213
219
|
expect(origin).toEqual(mockHostOrigin)
|
|
214
220
|
|
|
215
221
|
window.dispatchEvent(
|
|
@@ -249,7 +255,8 @@ describe('EvmAccountType', () => {
|
|
|
249
255
|
expect(type).toEqual(
|
|
250
256
|
'portal:evmAccountType:buildAuthorizationList',
|
|
251
257
|
)
|
|
252
|
-
expect(data).
|
|
258
|
+
expect(data).toMatchObject(argsWithoutSubsidize)
|
|
259
|
+
expect(typeof message.traceId).toBe('string')
|
|
253
260
|
expect(origin).toEqual(mockHostOrigin)
|
|
254
261
|
|
|
255
262
|
window.dispatchEvent(
|
|
@@ -290,7 +297,8 @@ describe('EvmAccountType', () => {
|
|
|
290
297
|
expect(type).toEqual(
|
|
291
298
|
'portal:evmAccountType:buildAuthorizationList',
|
|
292
299
|
)
|
|
293
|
-
expect(data).
|
|
300
|
+
expect(data).toMatchObject(args)
|
|
301
|
+
expect(typeof message.traceId).toBe('string')
|
|
294
302
|
expect(origin).toEqual(mockHostOrigin)
|
|
295
303
|
|
|
296
304
|
window.dispatchEvent(
|
|
@@ -337,7 +345,8 @@ describe('EvmAccountType', () => {
|
|
|
337
345
|
const { type, data } = message
|
|
338
346
|
|
|
339
347
|
expect(type).toEqual('portal:evmAccountType:build7702UpgradeTx')
|
|
340
|
-
expect(data).
|
|
348
|
+
expect(data).toMatchObject(args)
|
|
349
|
+
expect(typeof message.traceId).toBe('string')
|
|
341
350
|
expect(origin).toEqual(mockHostOrigin)
|
|
342
351
|
|
|
343
352
|
window.dispatchEvent(
|
|
@@ -378,7 +387,8 @@ describe('EvmAccountType', () => {
|
|
|
378
387
|
expect(type).toEqual(
|
|
379
388
|
'portal:evmAccountType:build7702UpgradeTx',
|
|
380
389
|
)
|
|
381
|
-
expect(data).
|
|
390
|
+
expect(data).toMatchObject(argsWithoutSubsidize)
|
|
391
|
+
expect(typeof message.traceId).toBe('string')
|
|
382
392
|
expect(origin).toEqual(mockHostOrigin)
|
|
383
393
|
|
|
384
394
|
window.dispatchEvent(
|
|
@@ -419,7 +429,8 @@ describe('EvmAccountType', () => {
|
|
|
419
429
|
expect(type).toEqual(
|
|
420
430
|
'portal:evmAccountType:build7702UpgradeTx',
|
|
421
431
|
)
|
|
422
|
-
expect(data).
|
|
432
|
+
expect(data).toMatchObject(args)
|
|
433
|
+
expect(typeof message.traceId).toBe('string')
|
|
423
434
|
expect(origin).toEqual(mockHostOrigin)
|
|
424
435
|
|
|
425
436
|
window.dispatchEvent(
|
|
@@ -468,7 +479,8 @@ describe('EvmAccountType', () => {
|
|
|
468
479
|
const { type, data } = message
|
|
469
480
|
|
|
470
481
|
if (type === 'portal:evmAccountType:getStatus') {
|
|
471
|
-
expect(data).
|
|
482
|
+
expect(data).toMatchObject({ chain: args.chain })
|
|
483
|
+
expect(typeof message.traceId).toBe('string')
|
|
472
484
|
window.dispatchEvent(
|
|
473
485
|
new MessageEvent('message', {
|
|
474
486
|
origin: mockHostOrigin,
|
|
@@ -479,7 +491,8 @@ describe('EvmAccountType', () => {
|
|
|
479
491
|
}),
|
|
480
492
|
)
|
|
481
493
|
} else if (type === 'portal:evmAccountType:buildAuthorizationList') {
|
|
482
|
-
expect(data).
|
|
494
|
+
expect(data).toMatchObject({ chain: args.chain, subsidize: true })
|
|
495
|
+
expect(typeof message.traceId).toBe('string')
|
|
483
496
|
window.dispatchEvent(
|
|
484
497
|
new MessageEvent('message', {
|
|
485
498
|
origin: mockHostOrigin,
|
|
@@ -9,6 +9,13 @@ import { ProviderRpcError, RpcErrorCodes } from './errors'
|
|
|
9
9
|
import { RequestMethod } from '../'
|
|
10
10
|
import mpcMock from '../__mocks/portal/mpc'
|
|
11
11
|
import { sdkLogger } from '../logger'
|
|
12
|
+
import { X_PORTAL_TRACE_ID_HEADER } from '../shared/trace'
|
|
13
|
+
|
|
14
|
+
jest.mock('../shared/trace', () => ({
|
|
15
|
+
...jest.requireActual('../shared/trace'),
|
|
16
|
+
generateTraceId: jest.fn(() => 'mock-trace-id-12345'),
|
|
17
|
+
X_PORTAL_TRACE_ID_HEADER: 'X-Portal-Trace-Id',
|
|
18
|
+
}))
|
|
12
19
|
|
|
13
20
|
describe('Provider', () => {
|
|
14
21
|
beforeEach(() => {
|
|
@@ -221,6 +228,7 @@ describe('Provider', () => {
|
|
|
221
228
|
method: RequestMethod.eth_sendTransaction,
|
|
222
229
|
params: 'test',
|
|
223
230
|
rpcUrl: mockRpcUrl,
|
|
231
|
+
traceId: 'mock-trace-id-12345',
|
|
224
232
|
})
|
|
225
233
|
expect(provider.emit).toHaveBeenCalledWith(
|
|
226
234
|
'portal_signatureReceived',
|
|
@@ -276,6 +284,7 @@ describe('Provider', () => {
|
|
|
276
284
|
method: RequestMethod.eth_signTransaction,
|
|
277
285
|
params: 'test',
|
|
278
286
|
rpcUrl: mockRpcUrl,
|
|
287
|
+
traceId: 'mock-trace-id-12345',
|
|
279
288
|
})
|
|
280
289
|
expect(provider.emit).toHaveBeenCalledWith(
|
|
281
290
|
'portal_signatureReceived',
|
|
@@ -331,6 +340,7 @@ describe('Provider', () => {
|
|
|
331
340
|
method: RequestMethod.eth_sign,
|
|
332
341
|
params: ['test'],
|
|
333
342
|
rpcUrl: mockRpcUrl,
|
|
343
|
+
traceId: 'mock-trace-id-12345',
|
|
334
344
|
})
|
|
335
345
|
expect(provider.emit).toHaveBeenCalledWith(
|
|
336
346
|
'portal_signatureReceived',
|
|
@@ -386,6 +396,7 @@ describe('Provider', () => {
|
|
|
386
396
|
method: RequestMethod.eth_signTypedData_v3,
|
|
387
397
|
params: ['test'],
|
|
388
398
|
rpcUrl: mockRpcUrl,
|
|
399
|
+
traceId: 'mock-trace-id-12345',
|
|
389
400
|
})
|
|
390
401
|
expect(provider.emit).toHaveBeenCalledWith(
|
|
391
402
|
'portal_signatureReceived',
|
|
@@ -441,6 +452,7 @@ describe('Provider', () => {
|
|
|
441
452
|
method: RequestMethod.eth_signTypedData_v4,
|
|
442
453
|
params: ['test'],
|
|
443
454
|
rpcUrl: mockRpcUrl,
|
|
455
|
+
traceId: 'mock-trace-id-12345',
|
|
444
456
|
})
|
|
445
457
|
expect(provider.emit).toHaveBeenCalledWith(
|
|
446
458
|
'portal_signatureReceived',
|
|
@@ -496,6 +508,7 @@ describe('Provider', () => {
|
|
|
496
508
|
method: RequestMethod.personal_sign,
|
|
497
509
|
params: ['test'],
|
|
498
510
|
rpcUrl: mockRpcUrl,
|
|
511
|
+
traceId: 'mock-trace-id-12345',
|
|
499
512
|
})
|
|
500
513
|
expect(provider.emit).toHaveBeenCalledWith(
|
|
501
514
|
'portal_signatureReceived',
|
|
@@ -551,6 +564,7 @@ describe('Provider', () => {
|
|
|
551
564
|
method: RequestMethod.sol_signAndConfirmTransaction,
|
|
552
565
|
params: ['test'],
|
|
553
566
|
rpcUrl: mockRpcUrl,
|
|
567
|
+
traceId: 'mock-trace-id-12345',
|
|
554
568
|
})
|
|
555
569
|
expect(provider.emit).toHaveBeenCalledWith(
|
|
556
570
|
'portal_signatureReceived',
|
|
@@ -606,6 +620,7 @@ describe('Provider', () => {
|
|
|
606
620
|
method: RequestMethod.sol_signAndSendTransaction,
|
|
607
621
|
params: ['test'],
|
|
608
622
|
rpcUrl: mockRpcUrl,
|
|
623
|
+
traceId: 'mock-trace-id-12345',
|
|
609
624
|
})
|
|
610
625
|
expect(provider.emit).toHaveBeenCalledWith(
|
|
611
626
|
'portal_signatureReceived',
|
|
@@ -661,6 +676,7 @@ describe('Provider', () => {
|
|
|
661
676
|
method: RequestMethod.sol_signMessage,
|
|
662
677
|
params: ['test'],
|
|
663
678
|
rpcUrl: mockRpcUrl,
|
|
679
|
+
traceId: 'mock-trace-id-12345',
|
|
664
680
|
})
|
|
665
681
|
expect(provider.emit).toHaveBeenCalledWith(
|
|
666
682
|
'portal_signatureReceived',
|
|
@@ -716,6 +732,7 @@ describe('Provider', () => {
|
|
|
716
732
|
method: RequestMethod.sol_signTransaction,
|
|
717
733
|
params: ['test'],
|
|
718
734
|
rpcUrl: mockRpcUrl,
|
|
735
|
+
traceId: 'mock-trace-id-12345',
|
|
719
736
|
})
|
|
720
737
|
expect(provider.emit).toHaveBeenCalledWith(
|
|
721
738
|
'portal_signatureReceived',
|
|
@@ -830,6 +847,7 @@ describe('Provider', () => {
|
|
|
830
847
|
method: RequestMethod.eth_sendTransaction,
|
|
831
848
|
params: 'test',
|
|
832
849
|
rpcUrl: mockRpcUrl,
|
|
850
|
+
traceId: 'mock-trace-id-12345',
|
|
833
851
|
})
|
|
834
852
|
expect(mockSignatureReceivedHandler).toHaveBeenCalledWith({
|
|
835
853
|
chainId: 'eip155:1',
|
|
@@ -887,6 +905,7 @@ describe('Provider', () => {
|
|
|
887
905
|
method: RequestMethod.eth_signTransaction,
|
|
888
906
|
params: 'test',
|
|
889
907
|
rpcUrl: mockRpcUrl,
|
|
908
|
+
traceId: 'mock-trace-id-12345',
|
|
890
909
|
})
|
|
891
910
|
expect(mockSignatureReceivedHandler).toHaveBeenCalledWith({
|
|
892
911
|
chainId: 'eip155:1',
|
|
@@ -944,6 +963,7 @@ describe('Provider', () => {
|
|
|
944
963
|
method: RequestMethod.eth_sign,
|
|
945
964
|
params: ['test'],
|
|
946
965
|
rpcUrl: mockRpcUrl,
|
|
966
|
+
traceId: 'mock-trace-id-12345',
|
|
947
967
|
})
|
|
948
968
|
expect(mockSignatureReceivedHandler).toHaveBeenCalledWith({
|
|
949
969
|
chainId: 'eip155:1',
|
|
@@ -1001,6 +1021,7 @@ describe('Provider', () => {
|
|
|
1001
1021
|
method: RequestMethod.eth_signTypedData_v3,
|
|
1002
1022
|
params: ['test'],
|
|
1003
1023
|
rpcUrl: mockRpcUrl,
|
|
1024
|
+
traceId: 'mock-trace-id-12345',
|
|
1004
1025
|
})
|
|
1005
1026
|
expect(mockSignatureReceivedHandler).toHaveBeenCalledWith({
|
|
1006
1027
|
chainId: 'eip155:1',
|
|
@@ -1058,6 +1079,7 @@ describe('Provider', () => {
|
|
|
1058
1079
|
method: RequestMethod.eth_signTypedData_v4,
|
|
1059
1080
|
params: ['test'],
|
|
1060
1081
|
rpcUrl: mockRpcUrl,
|
|
1082
|
+
traceId: 'mock-trace-id-12345',
|
|
1061
1083
|
})
|
|
1062
1084
|
expect(mockSignatureReceivedHandler).toHaveBeenCalledWith({
|
|
1063
1085
|
chainId: 'eip155:1',
|
|
@@ -1115,6 +1137,7 @@ describe('Provider', () => {
|
|
|
1115
1137
|
method: RequestMethod.personal_sign,
|
|
1116
1138
|
params: ['test'],
|
|
1117
1139
|
rpcUrl: mockRpcUrl,
|
|
1140
|
+
traceId: 'mock-trace-id-12345',
|
|
1118
1141
|
})
|
|
1119
1142
|
expect(mockSignatureReceivedHandler).toHaveBeenCalledWith({
|
|
1120
1143
|
chainId: 'eip155:1',
|
|
@@ -1172,6 +1195,7 @@ describe('Provider', () => {
|
|
|
1172
1195
|
method: RequestMethod.sol_signAndConfirmTransaction,
|
|
1173
1196
|
params: ['test'],
|
|
1174
1197
|
rpcUrl: mockRpcUrl,
|
|
1198
|
+
traceId: 'mock-trace-id-12345',
|
|
1175
1199
|
})
|
|
1176
1200
|
expect(mockSignatureReceivedHandler).toHaveBeenCalledWith({
|
|
1177
1201
|
chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
|
|
@@ -1229,6 +1253,7 @@ describe('Provider', () => {
|
|
|
1229
1253
|
method: RequestMethod.sol_signAndSendTransaction,
|
|
1230
1254
|
params: ['test'],
|
|
1231
1255
|
rpcUrl: mockRpcUrl,
|
|
1256
|
+
traceId: 'mock-trace-id-12345',
|
|
1232
1257
|
})
|
|
1233
1258
|
expect(mockSignatureReceivedHandler).toHaveBeenCalledWith({
|
|
1234
1259
|
chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
|
|
@@ -1286,6 +1311,7 @@ describe('Provider', () => {
|
|
|
1286
1311
|
method: RequestMethod.sol_signMessage,
|
|
1287
1312
|
params: ['test'],
|
|
1288
1313
|
rpcUrl: mockRpcUrl,
|
|
1314
|
+
traceId: 'mock-trace-id-12345',
|
|
1289
1315
|
})
|
|
1290
1316
|
expect(mockSignatureReceivedHandler).toHaveBeenCalledWith({
|
|
1291
1317
|
chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
|
|
@@ -1343,6 +1369,7 @@ describe('Provider', () => {
|
|
|
1343
1369
|
method: RequestMethod.sol_signTransaction,
|
|
1344
1370
|
params: ['test'],
|
|
1345
1371
|
rpcUrl: mockRpcUrl,
|
|
1372
|
+
traceId: 'mock-trace-id-12345',
|
|
1346
1373
|
})
|
|
1347
1374
|
expect(mockSignatureReceivedHandler).toHaveBeenCalledWith({
|
|
1348
1375
|
chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
|
|
@@ -1393,9 +1420,10 @@ describe('Provider', () => {
|
|
|
1393
1420
|
expect(result).toEqual('test')
|
|
1394
1421
|
expect(global.fetch).toHaveBeenCalledWith(mockRpcUrl, {
|
|
1395
1422
|
method: 'POST',
|
|
1396
|
-
headers: {
|
|
1423
|
+
headers: expect.objectContaining({
|
|
1397
1424
|
'Content-Type': 'application/json',
|
|
1398
|
-
|
|
1425
|
+
[X_PORTAL_TRACE_ID_HEADER]: 'mock-trace-id-12345',
|
|
1426
|
+
}),
|
|
1399
1427
|
body: JSON.stringify({
|
|
1400
1428
|
jsonrpc: '2.0',
|
|
1401
1429
|
id: '0',
|
package/src/provider/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { ProviderRpcError, RpcErrorCodes } from './errors'
|
|
|
2
2
|
|
|
3
3
|
import Portal from '../index'
|
|
4
4
|
import { sdkLogger } from '../logger'
|
|
5
|
+
import { generateTraceId, X_PORTAL_TRACE_ID_HEADER } from '../shared/trace'
|
|
5
6
|
|
|
6
7
|
import type {
|
|
7
8
|
EventHandler,
|
|
@@ -251,7 +252,13 @@ class Provider {
|
|
|
251
252
|
params,
|
|
252
253
|
sponsorGas,
|
|
253
254
|
signatureApprovalMemo,
|
|
255
|
+
traceId: providedTraceId,
|
|
254
256
|
}: RequestArguments): Promise<any> {
|
|
257
|
+
const traceId = providedTraceId ?? generateTraceId()
|
|
258
|
+
sdkLogger.info(
|
|
259
|
+
`[PortalProvider] request started | method=${method} | traceId=${traceId}`,
|
|
260
|
+
)
|
|
261
|
+
|
|
255
262
|
const isSignerMethod = signerMethods.includes(method)
|
|
256
263
|
const chainId = this.getCAIP2ChainId(requestChainId)
|
|
257
264
|
|
|
@@ -261,6 +268,7 @@ class Provider {
|
|
|
261
268
|
chainId,
|
|
262
269
|
method,
|
|
263
270
|
params,
|
|
271
|
+
traceId,
|
|
264
272
|
})
|
|
265
273
|
|
|
266
274
|
this.emit('portal_signatureReceived', {
|
|
@@ -283,6 +291,7 @@ class Provider {
|
|
|
283
291
|
params,
|
|
284
292
|
sponsorGas,
|
|
285
293
|
signatureApprovalMemo,
|
|
294
|
+
traceId,
|
|
286
295
|
})
|
|
287
296
|
|
|
288
297
|
if (transactionHash) {
|
|
@@ -408,8 +417,8 @@ class Provider {
|
|
|
408
417
|
chainId,
|
|
409
418
|
method,
|
|
410
419
|
params,
|
|
420
|
+
traceId,
|
|
411
421
|
}: RequestArguments): Promise<any> {
|
|
412
|
-
// Prepare the request body
|
|
413
422
|
const requestBody = {
|
|
414
423
|
body: JSON.stringify({
|
|
415
424
|
jsonrpc: '2.0',
|
|
@@ -420,10 +429,10 @@ class Provider {
|
|
|
420
429
|
method: 'POST',
|
|
421
430
|
headers: {
|
|
422
431
|
'Content-Type': 'application/json',
|
|
432
|
+
...(traceId && { [X_PORTAL_TRACE_ID_HEADER]: traceId }),
|
|
423
433
|
},
|
|
424
434
|
}
|
|
425
435
|
|
|
426
|
-
// Pass request off to the gateway
|
|
427
436
|
const result = await fetch(this.portal.getRpcUrl(chainId), requestBody)
|
|
428
437
|
|
|
429
438
|
return result.json()
|
|
@@ -441,6 +450,7 @@ class Provider {
|
|
|
441
450
|
params,
|
|
442
451
|
sponsorGas,
|
|
443
452
|
signatureApprovalMemo,
|
|
453
|
+
traceId,
|
|
444
454
|
}: RequestArguments): Promise<any> {
|
|
445
455
|
const isApproved = passiveSignerMethods.includes(method)
|
|
446
456
|
? true
|
|
@@ -480,6 +490,7 @@ class Provider {
|
|
|
480
490
|
...(signatureApprovalMemo !== undefined && {
|
|
481
491
|
signatureApprovalMemo,
|
|
482
492
|
}),
|
|
493
|
+
traceId,
|
|
483
494
|
})
|
|
484
495
|
return result
|
|
485
496
|
}
|
|
@@ -494,7 +505,10 @@ class Provider {
|
|
|
494
505
|
params: this.buildParams(method, params),
|
|
495
506
|
rpcUrl: this.portal.getRpcUrl(chainId),
|
|
496
507
|
sponsorGas,
|
|
497
|
-
|
|
508
|
+
traceId,
|
|
509
|
+
...(signatureApprovalMemo !== undefined && {
|
|
510
|
+
signatureApprovalMemo,
|
|
511
|
+
}),
|
|
498
512
|
})
|
|
499
513
|
return result
|
|
500
514
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configurable logger for the iframe SDK. Respects logLevel so that when the
|
|
3
|
+
* parent sets logLevel to 'none', no messages are written to the console.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type LogLevel = 'none' | 'error' | 'warn' | 'info' | 'debug'
|
|
7
|
+
|
|
8
|
+
const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {
|
|
9
|
+
none: 0,
|
|
10
|
+
error: 1,
|
|
11
|
+
warn: 2,
|
|
12
|
+
info: 3,
|
|
13
|
+
debug: 4,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface SdkLoggerInterface {
|
|
17
|
+
debug(message: string, ...args: unknown[]): void
|
|
18
|
+
warn(message: string, ...args: unknown[]): void
|
|
19
|
+
error(message: string, ...args: unknown[]): void
|
|
20
|
+
configure(logLevel: LogLevel): void
|
|
21
|
+
getLogLevel(): LogLevel
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class SdkLoggerImpl implements SdkLoggerInterface {
|
|
25
|
+
private logLevel: LogLevel = 'none'
|
|
26
|
+
|
|
27
|
+
configure(logLevel: LogLevel): void {
|
|
28
|
+
this.logLevel = logLevel
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
getLogLevel(): LogLevel {
|
|
32
|
+
return this.logLevel
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private shouldLog(level: Exclude<LogLevel, 'none'>): boolean {
|
|
36
|
+
return LOG_LEVEL_PRIORITY[level] <= LOG_LEVEL_PRIORITY[this.logLevel]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private log(level: 'debug' | 'warn' | 'error', message: string, ...args: unknown[]): void {
|
|
40
|
+
if (!this.shouldLog(level)) return
|
|
41
|
+
if (typeof console === 'undefined') return
|
|
42
|
+
const prefix = `[PortalMpc] ${message}`
|
|
43
|
+
try {
|
|
44
|
+
if (level === 'debug' && console.debug) {
|
|
45
|
+
console.debug(prefix, ...args)
|
|
46
|
+
} else if (level === 'warn' && console.warn) {
|
|
47
|
+
console.warn(prefix, ...args)
|
|
48
|
+
} else if (level === 'error' && console.error) {
|
|
49
|
+
console.error(prefix, ...args)
|
|
50
|
+
}
|
|
51
|
+
} catch {
|
|
52
|
+
// no-op if console is unavailable or throws
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
debug(message: string, ...args: unknown[]): void {
|
|
57
|
+
this.log('debug', message, ...args)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
warn(message: string, ...args: unknown[]): void {
|
|
61
|
+
this.log('warn', message, ...args)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
error(message: string, ...args: unknown[]): void {
|
|
65
|
+
this.log('error', message, ...args)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export const sdkLogger = new SdkLoggerImpl()
|