@portal-hq/provider 2.0.4 → 2.0.7
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/providers/index.js +6 -6
- package/lib/commonjs/signers/abstract.js +1 -12
- package/lib/commonjs/signers/mpc.js +4 -3
- package/lib/esm/providers/index.js +6 -6
- package/lib/esm/signers/abstract.js +1 -12
- package/lib/esm/signers/mpc.js +4 -3
- package/package.json +4 -4
- package/src/providers/index.ts +18 -15
- package/src/signers/abstract.ts +2 -2
- package/src/signers/mpc.ts +8 -7
- package/types.d.ts +3 -3
|
@@ -107,6 +107,7 @@ class Provider {
|
|
|
107
107
|
return this.gatewayConfig;
|
|
108
108
|
}
|
|
109
109
|
else if (typeof this.gatewayConfig === 'object' &&
|
|
110
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
110
111
|
!this.gatewayConfig.hasOwnProperty(this.chainId)) {
|
|
111
112
|
// If there's no explicit mapping for the current chainId, error out
|
|
112
113
|
throw new Error(`[PortalProvider] No RPC endpoint configured for chainId: ${this.chainId}`);
|
|
@@ -258,7 +259,7 @@ class Provider {
|
|
|
258
259
|
}
|
|
259
260
|
// Dispatch 'connect' event
|
|
260
261
|
this.dispatchConnect();
|
|
261
|
-
return this;
|
|
262
|
+
return new Promise((resolve) => resolve(this));
|
|
262
263
|
});
|
|
263
264
|
}
|
|
264
265
|
/**
|
|
@@ -321,10 +322,8 @@ class Provider {
|
|
|
321
322
|
});
|
|
322
323
|
}
|
|
323
324
|
dispatchConnect() {
|
|
324
|
-
|
|
325
|
-
this.
|
|
326
|
-
chainId: `0x${this.chainId.toString(16)}`,
|
|
327
|
-
});
|
|
325
|
+
this.emit('connect', {
|
|
326
|
+
chainId: `0x${this.chainId.toString(16)}`,
|
|
328
327
|
});
|
|
329
328
|
}
|
|
330
329
|
/**
|
|
@@ -372,7 +371,7 @@ class Provider {
|
|
|
372
371
|
case 'eth_signTransaction':
|
|
373
372
|
case 'eth_signTypedData_v3':
|
|
374
373
|
case 'eth_signTypedData_v4':
|
|
375
|
-
case 'personal_sign':
|
|
374
|
+
case 'personal_sign': {
|
|
376
375
|
const result = yield ((_a = this.signer) === null || _a === void 0 ? void 0 : _a.sign({ chainId: this.chainId, method, params }, this));
|
|
377
376
|
if (result) {
|
|
378
377
|
try {
|
|
@@ -394,6 +393,7 @@ class Provider {
|
|
|
394
393
|
}
|
|
395
394
|
}
|
|
396
395
|
return result;
|
|
396
|
+
}
|
|
397
397
|
default:
|
|
398
398
|
throw new Error('[PortalProvider] Method "' + method + '" not supported');
|
|
399
399
|
}
|
|
@@ -1,19 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
class Signer {
|
|
13
4
|
sign(_, __) {
|
|
14
|
-
|
|
15
|
-
throw new Error('[Portal] sign() method must be implemented in a subclass of Signer');
|
|
16
|
-
});
|
|
5
|
+
throw new Error('[Portal] sign() method must be implemented in a subclass of Signer');
|
|
17
6
|
}
|
|
18
7
|
}
|
|
19
8
|
exports.default = Signer;
|
|
@@ -62,12 +62,13 @@ class MpcSigner {
|
|
|
62
62
|
break;
|
|
63
63
|
}
|
|
64
64
|
const signingShare = yield this.signingShare;
|
|
65
|
-
const metadata =
|
|
65
|
+
const metadata = {
|
|
66
66
|
clientPlatform: 'REACT_NATIVE',
|
|
67
67
|
mpcServerVersion: this.version,
|
|
68
68
|
optimized: this.featureFlags.optimized,
|
|
69
|
-
}
|
|
70
|
-
const
|
|
69
|
+
};
|
|
70
|
+
const stringifiedMetadata = JSON.stringify(metadata);
|
|
71
|
+
const result = yield this.mpc.sign(apiKey, this.mpcHost, signingShare, message.method, JSON.stringify(this.buildParams(method, params)), provider.gatewayUrl, provider.chainId.toString(), stringifiedMetadata);
|
|
71
72
|
const { data, error } = JSON.parse(String(result));
|
|
72
73
|
if (error && error.code > 0) {
|
|
73
74
|
throw new utils_1.PortalMpcError(error);
|
|
@@ -105,6 +105,7 @@ class Provider {
|
|
|
105
105
|
return this.gatewayConfig;
|
|
106
106
|
}
|
|
107
107
|
else if (typeof this.gatewayConfig === 'object' &&
|
|
108
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
108
109
|
!this.gatewayConfig.hasOwnProperty(this.chainId)) {
|
|
109
110
|
// If there's no explicit mapping for the current chainId, error out
|
|
110
111
|
throw new Error(`[PortalProvider] No RPC endpoint configured for chainId: ${this.chainId}`);
|
|
@@ -256,7 +257,7 @@ class Provider {
|
|
|
256
257
|
}
|
|
257
258
|
// Dispatch 'connect' event
|
|
258
259
|
this.dispatchConnect();
|
|
259
|
-
return this;
|
|
260
|
+
return new Promise((resolve) => resolve(this));
|
|
260
261
|
});
|
|
261
262
|
}
|
|
262
263
|
/**
|
|
@@ -319,10 +320,8 @@ class Provider {
|
|
|
319
320
|
});
|
|
320
321
|
}
|
|
321
322
|
dispatchConnect() {
|
|
322
|
-
|
|
323
|
-
this.
|
|
324
|
-
chainId: `0x${this.chainId.toString(16)}`,
|
|
325
|
-
});
|
|
323
|
+
this.emit('connect', {
|
|
324
|
+
chainId: `0x${this.chainId.toString(16)}`,
|
|
326
325
|
});
|
|
327
326
|
}
|
|
328
327
|
/**
|
|
@@ -370,7 +369,7 @@ class Provider {
|
|
|
370
369
|
case 'eth_signTransaction':
|
|
371
370
|
case 'eth_signTypedData_v3':
|
|
372
371
|
case 'eth_signTypedData_v4':
|
|
373
|
-
case 'personal_sign':
|
|
372
|
+
case 'personal_sign': {
|
|
374
373
|
const result = yield ((_a = this.signer) === null || _a === void 0 ? void 0 : _a.sign({ chainId: this.chainId, method, params }, this));
|
|
375
374
|
if (result) {
|
|
376
375
|
try {
|
|
@@ -392,6 +391,7 @@ class Provider {
|
|
|
392
391
|
}
|
|
393
392
|
}
|
|
394
393
|
return result;
|
|
394
|
+
}
|
|
395
395
|
default:
|
|
396
396
|
throw new Error('[PortalProvider] Method "' + method + '" not supported');
|
|
397
397
|
}
|
|
@@ -1,17 +1,6 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
class Signer {
|
|
11
2
|
sign(_, __) {
|
|
12
|
-
|
|
13
|
-
throw new Error('[Portal] sign() method must be implemented in a subclass of Signer');
|
|
14
|
-
});
|
|
3
|
+
throw new Error('[Portal] sign() method must be implemented in a subclass of Signer');
|
|
15
4
|
}
|
|
16
5
|
}
|
|
17
6
|
export default Signer;
|
package/lib/esm/signers/mpc.js
CHANGED
|
@@ -60,12 +60,13 @@ class MpcSigner {
|
|
|
60
60
|
break;
|
|
61
61
|
}
|
|
62
62
|
const signingShare = yield this.signingShare;
|
|
63
|
-
const metadata =
|
|
63
|
+
const metadata = {
|
|
64
64
|
clientPlatform: 'REACT_NATIVE',
|
|
65
65
|
mpcServerVersion: this.version,
|
|
66
66
|
optimized: this.featureFlags.optimized,
|
|
67
|
-
}
|
|
68
|
-
const
|
|
67
|
+
};
|
|
68
|
+
const stringifiedMetadata = JSON.stringify(metadata);
|
|
69
|
+
const result = yield this.mpc.sign(apiKey, this.mpcHost, signingShare, message.method, JSON.stringify(this.buildParams(method, params)), provider.gatewayUrl, provider.chainId.toString(), stringifiedMetadata);
|
|
69
70
|
const { data, error } = JSON.parse(String(result));
|
|
70
71
|
if (error && error.code > 0) {
|
|
71
72
|
throw new PortalMpcError(error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portal-hq/provider",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.7",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/esm/index",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"test": "jest"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@portal-hq/connect": "^2.0.
|
|
23
|
-
"@portal-hq/utils": "^2.0.
|
|
22
|
+
"@portal-hq/connect": "^2.0.7",
|
|
23
|
+
"@portal-hq/utils": "^2.0.7"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@babel/preset-typescript": "^7.18.6",
|
|
@@ -30,5 +30,5 @@
|
|
|
30
30
|
"ts-jest": "^29.0.3",
|
|
31
31
|
"typescript": "^4.8.4"
|
|
32
32
|
},
|
|
33
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "fdd0c978b9d62ff729189eae6664dafb039dc1fa"
|
|
34
34
|
}
|
package/src/providers/index.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
type SwitchEthereumChainParameter,
|
|
21
21
|
} from '../../types'
|
|
22
22
|
import PortalConnect from '@portal-hq/connect'
|
|
23
|
+
import { RpcErrorOptions } from '@portal-hq/utils/types'
|
|
23
24
|
|
|
24
25
|
const passiveSignerMethods = [
|
|
25
26
|
'eth_accounts',
|
|
@@ -154,11 +155,12 @@ class Provider implements IPortalProvider {
|
|
|
154
155
|
return this.gatewayConfig
|
|
155
156
|
} else if (
|
|
156
157
|
typeof this.gatewayConfig === 'object' &&
|
|
158
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
157
159
|
!this.gatewayConfig.hasOwnProperty(this.chainId)
|
|
158
160
|
) {
|
|
159
161
|
// If there's no explicit mapping for the current chainId, error out
|
|
160
162
|
throw new Error(
|
|
161
|
-
`[PortalProvider] No RPC endpoint configured for chainId: ${this.chainId}
|
|
163
|
+
`[PortalProvider] No RPC endpoint configured for chainId: ${this.chainId}`
|
|
162
164
|
)
|
|
163
165
|
}
|
|
164
166
|
|
|
@@ -171,7 +173,7 @@ class Provider implements IPortalProvider {
|
|
|
171
173
|
|
|
172
174
|
// If we got this far, there's no way to support the chain with the current config
|
|
173
175
|
throw new Error(
|
|
174
|
-
`[PortalProvider] Could not find a valid gatewayConfig entry for chainId: ${this.chainId}
|
|
176
|
+
`[PortalProvider] Could not find a valid gatewayConfig entry for chainId: ${this.chainId}`
|
|
175
177
|
)
|
|
176
178
|
}
|
|
177
179
|
|
|
@@ -225,7 +227,7 @@ class Provider implements IPortalProvider {
|
|
|
225
227
|
|
|
226
228
|
public removeEventListener(
|
|
227
229
|
event: string,
|
|
228
|
-
listenerToRemove?: EventHandler
|
|
230
|
+
listenerToRemove?: EventHandler
|
|
229
231
|
): void {
|
|
230
232
|
if (!this.events[event]) {
|
|
231
233
|
return
|
|
@@ -235,7 +237,7 @@ class Provider implements IPortalProvider {
|
|
|
235
237
|
this.events[event] = []
|
|
236
238
|
} else {
|
|
237
239
|
const filterEventHandlers = (
|
|
238
|
-
registeredEventHandler: RegisteredEventHandler
|
|
240
|
+
registeredEventHandler: RegisteredEventHandler
|
|
239
241
|
) => {
|
|
240
242
|
return registeredEventHandler.handler !== listenerToRemove
|
|
241
243
|
}
|
|
@@ -275,7 +277,7 @@ class Provider implements IPortalProvider {
|
|
|
275
277
|
})
|
|
276
278
|
|
|
277
279
|
if (response.error) {
|
|
278
|
-
throw new ProviderRpcError(response.error)
|
|
280
|
+
throw new ProviderRpcError(response.error as RpcErrorOptions)
|
|
279
281
|
}
|
|
280
282
|
|
|
281
283
|
result = response.result
|
|
@@ -320,7 +322,7 @@ class Provider implements IPortalProvider {
|
|
|
320
322
|
*/
|
|
321
323
|
public async setChainId(
|
|
322
324
|
chainId: number,
|
|
323
|
-
connect?: PortalConnect
|
|
325
|
+
connect?: PortalConnect
|
|
324
326
|
): Promise<Provider> {
|
|
325
327
|
// Update the chainId
|
|
326
328
|
this.chainId = chainId
|
|
@@ -343,7 +345,7 @@ class Provider implements IPortalProvider {
|
|
|
343
345
|
// Dispatch 'connect' event
|
|
344
346
|
this.dispatchConnect()
|
|
345
347
|
|
|
346
|
-
return this
|
|
348
|
+
return new Promise((resolve) => resolve(this))
|
|
347
349
|
}
|
|
348
350
|
|
|
349
351
|
/**
|
|
@@ -366,7 +368,7 @@ class Provider implements IPortalProvider {
|
|
|
366
368
|
|
|
367
369
|
if (!connect && (!signingHandlers || signingHandlers.length === 0)) {
|
|
368
370
|
throw new Error(
|
|
369
|
-
`[PortalProvider] Auto-approve is disabled. Cannot perform Provider signing requests without an event handler for the 'portal_signingRequested' event
|
|
371
|
+
`[PortalProvider] Auto-approve is disabled. Cannot perform Provider signing requests without an event handler for the 'portal_signingRequested' event.`
|
|
370
372
|
)
|
|
371
373
|
}
|
|
372
374
|
|
|
@@ -390,7 +392,7 @@ class Provider implements IPortalProvider {
|
|
|
390
392
|
) {
|
|
391
393
|
resolve(true)
|
|
392
394
|
}
|
|
393
|
-
}
|
|
395
|
+
}
|
|
394
396
|
)
|
|
395
397
|
|
|
396
398
|
// If the signing request has been rejected, resolve to false
|
|
@@ -408,7 +410,7 @@ class Provider implements IPortalProvider {
|
|
|
408
410
|
) {
|
|
409
411
|
resolve(false)
|
|
410
412
|
}
|
|
411
|
-
}
|
|
413
|
+
}
|
|
412
414
|
)
|
|
413
415
|
|
|
414
416
|
// Tell any listening clients that signing has been requested
|
|
@@ -428,7 +430,7 @@ class Provider implements IPortalProvider {
|
|
|
428
430
|
})
|
|
429
431
|
}
|
|
430
432
|
|
|
431
|
-
private
|
|
433
|
+
private dispatchConnect() {
|
|
432
434
|
this.emit('connect', {
|
|
433
435
|
chainId: `0x${this.chainId.toString(16)}`,
|
|
434
436
|
})
|
|
@@ -473,7 +475,7 @@ class Provider implements IPortalProvider {
|
|
|
473
475
|
|
|
474
476
|
if (!isApproved) {
|
|
475
477
|
this.log.info(
|
|
476
|
-
`[PortalProvider] Request for signing method '${method}' could not be completed because it was not approved by the user
|
|
478
|
+
`[PortalProvider] Request for signing method '${method}' could not be completed because it was not approved by the user.`
|
|
477
479
|
)
|
|
478
480
|
return
|
|
479
481
|
}
|
|
@@ -488,10 +490,10 @@ class Provider implements IPortalProvider {
|
|
|
488
490
|
case 'eth_signTransaction':
|
|
489
491
|
case 'eth_signTypedData_v3':
|
|
490
492
|
case 'eth_signTypedData_v4':
|
|
491
|
-
case 'personal_sign':
|
|
493
|
+
case 'personal_sign': {
|
|
492
494
|
const result = await this.signer?.sign(
|
|
493
495
|
{ chainId: this.chainId, method, params },
|
|
494
|
-
this
|
|
496
|
+
this
|
|
495
497
|
)
|
|
496
498
|
|
|
497
499
|
if (result) {
|
|
@@ -514,9 +516,10 @@ class Provider implements IPortalProvider {
|
|
|
514
516
|
}
|
|
515
517
|
|
|
516
518
|
return result
|
|
519
|
+
}
|
|
517
520
|
default:
|
|
518
521
|
throw new Error(
|
|
519
|
-
'[PortalProvider] Method "' + method + '" not supported'
|
|
522
|
+
'[PortalProvider] Method "' + method + '" not supported'
|
|
520
523
|
)
|
|
521
524
|
}
|
|
522
525
|
}
|
package/src/signers/abstract.ts
CHANGED
|
@@ -2,9 +2,9 @@ import { SigningRequestArguments } from '@portal-hq/utils'
|
|
|
2
2
|
import { type SignResult } from '../../types'
|
|
3
3
|
|
|
4
4
|
abstract class Signer {
|
|
5
|
-
public
|
|
5
|
+
public sign(_: SigningRequestArguments, __?: any): Promise<SignResult> {
|
|
6
6
|
throw new Error(
|
|
7
|
-
'[Portal] sign() method must be implemented in a subclass of Signer'
|
|
7
|
+
'[Portal] sign() method must be implemented in a subclass of Signer'
|
|
8
8
|
)
|
|
9
9
|
}
|
|
10
10
|
}
|
package/src/signers/mpc.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
import Signer from './abstract'
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
|
+
PortalMobileMpcMetadata,
|
|
12
13
|
type MpcSignerOptions,
|
|
13
14
|
type PortalMobileMpc,
|
|
14
15
|
type SigningResponse,
|
|
@@ -20,7 +21,7 @@ class MpcSigner implements Signer {
|
|
|
20
21
|
private keychain: KeychainAdapter
|
|
21
22
|
private mpc: PortalMobileMpc
|
|
22
23
|
private mpcHost: string // should we add a default here mpc.portalhq.io
|
|
23
|
-
private version
|
|
24
|
+
private version = 'v4'
|
|
24
25
|
private featureFlags: FeatureFlags
|
|
25
26
|
|
|
26
27
|
private get address(): Promise<string | undefined> {
|
|
@@ -47,14 +48,14 @@ class MpcSigner implements Signer {
|
|
|
47
48
|
|
|
48
49
|
if (!this.mpc) {
|
|
49
50
|
throw new Error(
|
|
50
|
-
`[Portal.Provider.MpcSigner] The MPC module could not be found by the signer. This is usually an issue with React Native linking. Please verify that the 'PortalReactNative' module is properly linked to this project
|
|
51
|
+
`[Portal.Provider.MpcSigner] The MPC module could not be found by the signer. This is usually an issue with React Native linking. Please verify that the 'PortalReactNative' module is properly linked to this project.`
|
|
51
52
|
)
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
public async sign(
|
|
56
57
|
message: SigningRequestArguments,
|
|
57
|
-
provider: IPortalProvider
|
|
58
|
+
provider: IPortalProvider
|
|
58
59
|
): Promise<any> {
|
|
59
60
|
const address = await this.address
|
|
60
61
|
const apiKey = provider.apiKey
|
|
@@ -72,12 +73,12 @@ class MpcSigner implements Signer {
|
|
|
72
73
|
|
|
73
74
|
const signingShare = await this.signingShare
|
|
74
75
|
|
|
75
|
-
const metadata =
|
|
76
|
+
const metadata: PortalMobileMpcMetadata = {
|
|
76
77
|
clientPlatform: 'REACT_NATIVE',
|
|
77
78
|
mpcServerVersion: this.version,
|
|
78
79
|
optimized: this.featureFlags.optimized,
|
|
79
|
-
}
|
|
80
|
-
|
|
80
|
+
}
|
|
81
|
+
const stringifiedMetadata = JSON.stringify(metadata)
|
|
81
82
|
const result = await this.mpc.sign(
|
|
82
83
|
apiKey,
|
|
83
84
|
this.mpcHost,
|
|
@@ -86,7 +87,7 @@ class MpcSigner implements Signer {
|
|
|
86
87
|
JSON.stringify(this.buildParams(method, params)),
|
|
87
88
|
provider.gatewayUrl,
|
|
88
89
|
provider.chainId.toString(),
|
|
89
|
-
|
|
90
|
+
stringifiedMetadata
|
|
90
91
|
)
|
|
91
92
|
|
|
92
93
|
const { data, error } = JSON.parse(String(result)) as SigningResponse
|
package/types.d.ts
CHANGED
|
@@ -35,14 +35,14 @@ export interface PortalMobileMpc {
|
|
|
35
35
|
generate: (
|
|
36
36
|
clientApiKey: string,
|
|
37
37
|
mpcApiUrl: string,
|
|
38
|
-
metadata: string
|
|
38
|
+
metadata: string
|
|
39
39
|
) => Promise<string>
|
|
40
40
|
rotate: (
|
|
41
41
|
clientApiKey: string,
|
|
42
42
|
mpcApiUrl: string,
|
|
43
43
|
isSim: boolean,
|
|
44
44
|
dkgResult?: string,
|
|
45
|
-
metadata: string
|
|
45
|
+
metadata: string
|
|
46
46
|
) => Promise<string>
|
|
47
47
|
sign: (
|
|
48
48
|
clientApiKey: string,
|
|
@@ -52,7 +52,7 @@ export interface PortalMobileMpc {
|
|
|
52
52
|
requestId: string,
|
|
53
53
|
mpcUrl: string,
|
|
54
54
|
chainId: string,
|
|
55
|
-
metadata: string
|
|
55
|
+
metadata: string
|
|
56
56
|
) => Promise<string>
|
|
57
57
|
}
|
|
58
58
|
|