@portal-hq/web 3.13.1 → 3.13.2-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 +127 -9
- package/lib/commonjs/index.test.js +13 -0
- package/lib/commonjs/integrations/delegations/index.js +109 -2
- package/lib/commonjs/integrations/delegations/index.test.js +171 -0
- package/lib/commonjs/integrations/ramps/noah/index.test.js +18 -5
- package/lib/commonjs/integrations/trading/index.js +16 -5
- package/lib/commonjs/integrations/trading/lifi/index.js +297 -25
- package/lib/commonjs/integrations/trading/lifi/lifi.tradeAsset.test.js +360 -0
- package/lib/commonjs/integrations/trading/lifi/lifiStatusPoll.js +118 -0
- package/lib/commonjs/integrations/trading/lifi/lifiStatusPoll.test.js +66 -0
- package/lib/commonjs/integrations/trading/zero-x/index.js +129 -26
- package/lib/commonjs/integrations/trading/zero-x/index.test.js +163 -1
- package/lib/commonjs/integrations/yield/index.js +18 -4
- package/lib/commonjs/integrations/yield/yieldxyz.getValidators.test.js +71 -0
- package/lib/commonjs/integrations/yield/yieldxyz.highLevel.test.js +438 -0
- package/lib/commonjs/integrations/yield/yieldxyz.js +541 -1
- package/lib/commonjs/internal/pollLoop.js +64 -0
- package/lib/commonjs/internal/pollLoop.test.js +100 -0
- package/lib/commonjs/internal/stripStalePlanningNonce.js +65 -0
- package/lib/commonjs/internal/stripStalePlanningNonce.test.js +35 -0
- package/lib/commonjs/internal/waitForEvmOrUserOpConfirmation.js +155 -0
- package/lib/commonjs/internal/waitForEvmOrUserOpConfirmation.test.js +33 -0
- package/lib/commonjs/internal/waitForEvmTxConfirmation.js +104 -0
- package/lib/commonjs/internal/waitForSolanaTxConfirmation.js +106 -0
- package/lib/commonjs/internal/yieldEvmNetwork.js +60 -0
- package/lib/commonjs/mpc/index.js +116 -1
- package/lib/commonjs/provider/index.js +17 -0
- package/lib/commonjs/shared/trace/index.js +0 -1
- package/lib/esm/index.js +127 -9
- package/lib/esm/index.test.js +13 -0
- package/lib/esm/integrations/delegations/index.js +109 -2
- package/lib/esm/integrations/delegations/index.test.js +171 -0
- package/lib/esm/integrations/ramps/noah/index.test.js +18 -5
- package/lib/esm/integrations/trading/index.js +16 -5
- package/lib/esm/integrations/trading/lifi/index.js +292 -25
- package/lib/esm/integrations/trading/lifi/lifi.tradeAsset.test.js +332 -0
- package/lib/esm/integrations/trading/lifi/lifiStatusPoll.js +113 -0
- package/lib/esm/integrations/trading/lifi/lifiStatusPoll.test.js +64 -0
- package/lib/esm/integrations/trading/zero-x/index.js +129 -26
- package/lib/esm/integrations/trading/zero-x/index.test.js +141 -2
- package/lib/esm/integrations/yield/index.js +18 -4
- package/lib/esm/integrations/yield/yieldxyz.getValidators.test.js +66 -0
- package/lib/esm/integrations/yield/yieldxyz.highLevel.test.js +433 -0
- package/lib/esm/integrations/yield/yieldxyz.js +541 -1
- package/lib/esm/internal/pollLoop.js +59 -0
- package/lib/esm/internal/pollLoop.test.js +98 -0
- package/lib/esm/internal/stripStalePlanningNonce.js +61 -0
- package/lib/esm/internal/stripStalePlanningNonce.test.js +33 -0
- package/lib/esm/internal/waitForEvmOrUserOpConfirmation.js +151 -0
- package/lib/esm/internal/waitForEvmOrUserOpConfirmation.test.js +31 -0
- package/lib/esm/internal/waitForEvmTxConfirmation.js +100 -0
- package/lib/esm/internal/waitForSolanaTxConfirmation.js +102 -0
- package/lib/esm/internal/yieldEvmNetwork.js +55 -0
- package/lib/esm/mpc/index.js +116 -1
- package/lib/esm/provider/index.js +17 -0
- package/lib/esm/shared/trace/index.js +0 -1
- package/noah-types.d.ts +16 -2
- package/package.json +3 -2
- package/src/index.test.ts +15 -0
- package/src/index.ts +203 -14
- package/src/integrations/delegations/index.test.ts +251 -0
- package/src/integrations/delegations/index.ts +202 -4
- package/src/integrations/ramps/noah/index.test.ts +18 -5
- package/src/integrations/trading/index.ts +10 -7
- package/src/integrations/trading/lifi/index.ts +388 -28
- package/src/integrations/trading/lifi/lifi.tradeAsset.test.ts +436 -0
- package/src/integrations/trading/lifi/lifiStatusPoll.test.ts +74 -0
- package/src/integrations/trading/lifi/lifiStatusPoll.ts +158 -0
- package/src/integrations/trading/zero-x/index.test.ts +297 -1
- package/src/integrations/trading/zero-x/index.ts +181 -27
- package/src/integrations/yield/index.ts +24 -4
- package/src/integrations/yield/yieldxyz.getValidators.test.ts +70 -0
- package/src/integrations/yield/yieldxyz.highLevel.test.ts +536 -0
- package/src/integrations/yield/yieldxyz.ts +762 -8
- package/src/internal/pollLoop.test.ts +109 -0
- package/src/internal/pollLoop.ts +87 -0
- package/src/internal/stripStalePlanningNonce.test.ts +38 -0
- package/src/internal/stripStalePlanningNonce.ts +66 -0
- package/src/internal/waitForEvmOrUserOpConfirmation.test.ts +31 -0
- package/src/internal/waitForEvmOrUserOpConfirmation.ts +194 -0
- package/src/internal/waitForEvmTxConfirmation.ts +155 -0
- package/src/internal/waitForSolanaTxConfirmation.ts +135 -0
- package/src/internal/yieldEvmNetwork.ts +57 -0
- package/src/mpc/index.ts +142 -1
- package/src/provider/index.ts +25 -0
- package/src/shared/trace/index.ts +0 -1
- package/src/shared/types/README.md +6 -0
- package/src/shared/types/api.ts +12 -1
- package/src/shared/types/common.ts +332 -20
- package/src/shared/types/delegations.ts +10 -0
- package/src/shared/types/index.ts +1 -0
- package/src/shared/types/lifi.ts +82 -0
- package/src/shared/types/noah.ts +124 -33
- package/src/shared/types/yieldxyz.ts +193 -0
- package/src/shared/types/zero-x.ts +66 -0
- package/types.d.ts +6 -0
|
@@ -14,7 +14,7 @@ const errors_1 = require("./errors");
|
|
|
14
14
|
const logger_1 = require("../logger");
|
|
15
15
|
const index_1 = require("../index");
|
|
16
16
|
const trace_1 = require("../shared/trace");
|
|
17
|
-
const WEB_SDK_VERSION = '3.13.
|
|
17
|
+
const WEB_SDK_VERSION = '3.13.2-0';
|
|
18
18
|
class Mpc {
|
|
19
19
|
get ready() {
|
|
20
20
|
return this._ready;
|
|
@@ -38,6 +38,8 @@ class Mpc {
|
|
|
38
38
|
mpcVersion: this.portal.mpcVersion,
|
|
39
39
|
featureFlags: this.portal.featureFlags,
|
|
40
40
|
logLevel: this.portal.getLogLevel(),
|
|
41
|
+
rpcConfig: this.portal.rpcConfig,
|
|
42
|
+
iframeRpcConfig: this.portal.iframeRpcConfig,
|
|
41
43
|
};
|
|
42
44
|
const message = {
|
|
43
45
|
type: 'portal:configure',
|
|
@@ -311,8 +313,18 @@ class Mpc {
|
|
|
311
313
|
});
|
|
312
314
|
});
|
|
313
315
|
}
|
|
316
|
+
/**
|
|
317
|
+
* @deprecated This method is deprecated and will be removed in a future version.
|
|
318
|
+
* Please use `getTransactionHistory()` instead, which uses the new Portal v3 API
|
|
319
|
+
* endpoint and returns the unified transaction format across all chains.
|
|
320
|
+
*/
|
|
314
321
|
getTransactions(chainId, limit, offset, order) {
|
|
315
322
|
return __awaiter(this, void 0, void 0, function* () {
|
|
323
|
+
// Log deprecation warning
|
|
324
|
+
logger_1.sdkLogger.warn('[DEPRECATED] getTransactions() is deprecated and will be removed in a future version. ' +
|
|
325
|
+
'Please use getTransactionHistory() instead, which provides improved type safety with ' +
|
|
326
|
+
'discriminated unions for regular transactions and UserOperations, and proper polymorphic ' +
|
|
327
|
+
'response types for Solana vs unified formats.');
|
|
316
328
|
return this.handleRequestToIframeAndPost({
|
|
317
329
|
methodMessage: 'portal:getTransactions',
|
|
318
330
|
errorMessage: 'portal:getTransactionsError',
|
|
@@ -326,6 +338,31 @@ class Mpc {
|
|
|
326
338
|
});
|
|
327
339
|
});
|
|
328
340
|
}
|
|
341
|
+
/**
|
|
342
|
+
* Retrieves transaction history for the client's wallet on the specified chain.
|
|
343
|
+
*
|
|
344
|
+
* This method uses the new Portal v3 API endpoint and returns the unified
|
|
345
|
+
* transaction format. Supports EVM (EIP-155), Solana, Bitcoin, Tron, and Stellar chains.
|
|
346
|
+
*
|
|
347
|
+
* @param params - Request parameters
|
|
348
|
+
* @param params.chainId - Chain ID in CAIP-2 format (e.g., 'eip155:1', 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp')
|
|
349
|
+
* @param params.limit - Maximum number of transactions to return (default: 50)
|
|
350
|
+
* @param params.offset - Number of transactions to skip (default: 0)
|
|
351
|
+
* @param params.order - Sort order ('asc' or 'desc')
|
|
352
|
+
* @param params.address - Override wallet address (EVM only)
|
|
353
|
+
* @param params.userOperations - Filter for ERC-4337 UserOperations (EVM only)
|
|
354
|
+
* @returns Promise resolving to transaction history response
|
|
355
|
+
*/
|
|
356
|
+
getTransactionHistory(params) {
|
|
357
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
358
|
+
return this.handleRequestToIframeAndPost({
|
|
359
|
+
methodMessage: 'portal:getTransactionHistory',
|
|
360
|
+
errorMessage: 'portal:getTransactionHistoryError',
|
|
361
|
+
resultMessage: 'portal:getTransactionHistoryResult',
|
|
362
|
+
data: params,
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
}
|
|
329
366
|
setBackupStatus(status, backupIds) {
|
|
330
367
|
return __awaiter(this, void 0, void 0, function* () {
|
|
331
368
|
return this.handleRequestToIframeAndPost({
|
|
@@ -478,6 +515,26 @@ class Mpc {
|
|
|
478
515
|
});
|
|
479
516
|
});
|
|
480
517
|
}
|
|
518
|
+
getYieldXyzDefaults(data) {
|
|
519
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
520
|
+
return this.handleRequestToIframeAndPost({
|
|
521
|
+
methodMessage: 'portal:yieldxyz:getDefaults',
|
|
522
|
+
errorMessage: 'portal:yieldxyz:getDefaultsError',
|
|
523
|
+
resultMessage: 'portal:yieldxyz:getDefaultsResult',
|
|
524
|
+
data: data !== null && data !== void 0 ? data : {},
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
getYieldXyzValidators(yieldId) {
|
|
529
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
530
|
+
return this.handleRequestToIframeAndPost({
|
|
531
|
+
methodMessage: 'portal:yieldxyz:getValidators',
|
|
532
|
+
errorMessage: 'portal:yieldxyz:getValidatorsError',
|
|
533
|
+
resultMessage: 'portal:yieldxyz:getValidatorsResult',
|
|
534
|
+
data: yieldId,
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
}
|
|
481
538
|
getLifiRoutes(data) {
|
|
482
539
|
return __awaiter(this, void 0, void 0, function* () {
|
|
483
540
|
return this.handleRequestToIframeAndPost({
|
|
@@ -953,6 +1010,64 @@ class Mpc {
|
|
|
953
1010
|
});
|
|
954
1011
|
});
|
|
955
1012
|
}
|
|
1013
|
+
rpcRequest(data, options) {
|
|
1014
|
+
var _a, _b;
|
|
1015
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1016
|
+
const { timeoutMs = 30000, traceId } = options !== null && options !== void 0 ? options : {};
|
|
1017
|
+
const requestId = (_b = (_a = crypto.randomUUID) === null || _a === void 0 ? void 0 : _a.call(crypto)) !== null && _b !== void 0 ? _b : `${Date.now()}-${Math.random()}`;
|
|
1018
|
+
const resolvedTraceId = traceId !== null && traceId !== void 0 ? traceId : (0, trace_1.generateTraceId)();
|
|
1019
|
+
logger_1.sdkLogger.debug('[Portal] rpcRequest', {
|
|
1020
|
+
requestId,
|
|
1021
|
+
method: data.method,
|
|
1022
|
+
chainId: data.chainId,
|
|
1023
|
+
traceId: resolvedTraceId,
|
|
1024
|
+
timeoutMs,
|
|
1025
|
+
});
|
|
1026
|
+
return new Promise((resolve, reject) => {
|
|
1027
|
+
let timeoutId;
|
|
1028
|
+
const cleanup = () => {
|
|
1029
|
+
window.removeEventListener('message', handleResponse);
|
|
1030
|
+
if (timeoutId !== undefined) {
|
|
1031
|
+
clearTimeout(timeoutId);
|
|
1032
|
+
}
|
|
1033
|
+
};
|
|
1034
|
+
const handleResponse = (event) => {
|
|
1035
|
+
var _a;
|
|
1036
|
+
const { origin } = event;
|
|
1037
|
+
if (origin !== this.getOrigin())
|
|
1038
|
+
return;
|
|
1039
|
+
const { type, data: result } = event.data;
|
|
1040
|
+
if (type === 'portal:rpc:requestResult' &&
|
|
1041
|
+
(result === null || result === void 0 ? void 0 : result.requestId) === requestId) {
|
|
1042
|
+
cleanup();
|
|
1043
|
+
resolve(result);
|
|
1044
|
+
}
|
|
1045
|
+
else if (type === 'portal:rpc:requestError' &&
|
|
1046
|
+
(result === null || result === void 0 ? void 0 : result.requestId) === requestId) {
|
|
1047
|
+
cleanup();
|
|
1048
|
+
reject(new Error((_a = result.message) !== null && _a !== void 0 ? _a : 'RPC proxy error'));
|
|
1049
|
+
}
|
|
1050
|
+
};
|
|
1051
|
+
timeoutId = setTimeout(() => {
|
|
1052
|
+
cleanup();
|
|
1053
|
+
const msg = `RPC request ${requestId} (${data.method}) timed out after ${timeoutMs}ms`;
|
|
1054
|
+
logger_1.sdkLogger.error('[Portal] rpcRequest timeout', {
|
|
1055
|
+
requestId,
|
|
1056
|
+
method: data.method,
|
|
1057
|
+
chainId: data.chainId,
|
|
1058
|
+
timeoutMs,
|
|
1059
|
+
});
|
|
1060
|
+
reject(new Error(msg));
|
|
1061
|
+
}, timeoutMs);
|
|
1062
|
+
window.addEventListener('message', handleResponse);
|
|
1063
|
+
this.postMessage({
|
|
1064
|
+
type: 'portal:rpc:request',
|
|
1065
|
+
data: Object.assign(Object.assign({}, data), { requestId }),
|
|
1066
|
+
traceId: resolvedTraceId,
|
|
1067
|
+
});
|
|
1068
|
+
});
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
956
1071
|
postMessage(event) {
|
|
957
1072
|
var _a, _b;
|
|
958
1073
|
(_b = (_a = this.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow) === null || _b === void 0 ? void 0 : _b.postMessage(event, this.getOrigin());
|
|
@@ -152,6 +152,11 @@ const signerMethods = [
|
|
|
152
152
|
RequestMethod.sol_signMessage,
|
|
153
153
|
RequestMethod.sol_signTransaction,
|
|
154
154
|
];
|
|
155
|
+
const iframeProxiedMethodStrings = [
|
|
156
|
+
'eth_getTransactionReceipt',
|
|
157
|
+
'eth_getUserOperationReceipt',
|
|
158
|
+
'getSignatureStatuses',
|
|
159
|
+
];
|
|
155
160
|
class Provider {
|
|
156
161
|
constructor({ portal, chainId }) {
|
|
157
162
|
this.enforceEip155ChainId = (chainId) => {
|
|
@@ -387,6 +392,18 @@ class Provider {
|
|
|
387
392
|
*/
|
|
388
393
|
handleGatewayRequest({ chainId, method, params, traceId, }) {
|
|
389
394
|
return __awaiter(this, void 0, void 0, function* () {
|
|
395
|
+
if (iframeProxiedMethodStrings.includes(method)) {
|
|
396
|
+
logger_1.sdkLogger.info(`[PortalProvider] routing ${method} through iframe (chainId=${String(chainId)})`, { traceId });
|
|
397
|
+
return this.portal.mpc.rpcRequest({
|
|
398
|
+
method,
|
|
399
|
+
params: Array.isArray(params)
|
|
400
|
+
? params
|
|
401
|
+
: params != null
|
|
402
|
+
? [params]
|
|
403
|
+
: [],
|
|
404
|
+
chainId: chainId,
|
|
405
|
+
}, { traceId });
|
|
406
|
+
}
|
|
390
407
|
const requestBody = {
|
|
391
408
|
body: JSON.stringify({
|
|
392
409
|
jsonrpc: '2.0',
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
3
|
* Request tracing for Portal API calls.
|
|
4
|
-
* Aligns with portal-react-native X-Portal-Trace-Id / traceId behavior.
|
|
5
4
|
*
|
|
6
5
|
* Propagation in the Web SDK:
|
|
7
6
|
* - Browser: High-level methods (backup, recover, sendAsset, provider.request) accept optional
|
package/lib/esm/index.js
CHANGED
|
@@ -19,15 +19,23 @@ import PasskeyService from './passkeys';
|
|
|
19
19
|
import { EvmAccountType } from './namespaces/evmAccountType';
|
|
20
20
|
import { sdkLogger } from './logger';
|
|
21
21
|
import { generateTraceId } from './shared/trace';
|
|
22
|
+
import { waitForEvmOrUserOpConfirmation } from './internal/waitForEvmOrUserOpConfirmation';
|
|
23
|
+
import { waitForSolanaTxConfirmation } from './internal/waitForSolanaTxConfirmation';
|
|
22
24
|
class Portal {
|
|
23
25
|
get ready() {
|
|
24
26
|
return this.mpc.ready;
|
|
25
27
|
}
|
|
28
|
+
get rpcConfig() {
|
|
29
|
+
return this._rpcConfig;
|
|
30
|
+
}
|
|
31
|
+
get iframeRpcConfig() {
|
|
32
|
+
return this._iframeRpcConfig;
|
|
33
|
+
}
|
|
26
34
|
constructor({
|
|
27
35
|
// Required
|
|
28
36
|
rpcConfig,
|
|
29
37
|
// Optional
|
|
30
|
-
apiKey, authToken, authUrl, autoApprove = false, gdrive, passkey, host = 'web.portalhq.io', mpcVersion = 'v6', mpcHost = 'mpc-client.portalhq.io', featureFlags = {}, chainId, logLevel = 'none', logger = console, }) {
|
|
38
|
+
iframeRpcConfig, apiKey, authToken, authUrl, autoApprove = false, gdrive, passkey, host = 'web.portalhq.io', mpcVersion = 'v6', mpcHost = 'mpc-client.portalhq.io', featureFlags = {}, chainId, logLevel = 'none', logger = console, }) {
|
|
31
39
|
this.errorCallbacks = [];
|
|
32
40
|
this.readyCallbacks = [];
|
|
33
41
|
this.logger = console;
|
|
@@ -48,7 +56,8 @@ class Portal {
|
|
|
48
56
|
this.authToken = authToken;
|
|
49
57
|
this.authUrl = authUrl;
|
|
50
58
|
this.autoApprove = autoApprove;
|
|
51
|
-
this.
|
|
59
|
+
this._rpcConfig = rpcConfig;
|
|
60
|
+
this._iframeRpcConfig = iframeRpcConfig;
|
|
52
61
|
this.host = host;
|
|
53
62
|
this.mpcHost = mpcHost;
|
|
54
63
|
this.mpcVersion = mpcVersion;
|
|
@@ -66,15 +75,43 @@ class Portal {
|
|
|
66
75
|
this.mpc = new Mpc({
|
|
67
76
|
portal: this,
|
|
68
77
|
});
|
|
69
|
-
this.yield = new Yield({ mpc: this.mpc });
|
|
70
78
|
this.ramps = new Ramps({ mpc: this.mpc });
|
|
71
|
-
this.trading = new Trading({ mpc: this.mpc });
|
|
72
79
|
this.security = new Security({ mpc: this.mpc });
|
|
73
|
-
this.delegations = new Delegations({ mpc: this.mpc });
|
|
74
80
|
this.provider = new Provider({
|
|
75
81
|
portal: this,
|
|
76
82
|
chainId: chainId ? Number(chainId) : undefined,
|
|
77
83
|
});
|
|
84
|
+
const signAndSendTransaction = (transaction, network) => __awaiter(this, void 0, void 0, function* () {
|
|
85
|
+
const method = network.startsWith('solana')
|
|
86
|
+
? RequestMethod.sol_signAndSendTransaction
|
|
87
|
+
: RequestMethod.eth_sendTransaction;
|
|
88
|
+
const hash = yield this.provider.request({
|
|
89
|
+
chainId: network,
|
|
90
|
+
method,
|
|
91
|
+
params: [transaction],
|
|
92
|
+
});
|
|
93
|
+
if (typeof hash !== 'string' || hash.length === 0) {
|
|
94
|
+
throw new Error('[Portal] Signing request did not return a transaction hash. The user may have rejected the request, or the provider did not complete signing.');
|
|
95
|
+
}
|
|
96
|
+
return hash;
|
|
97
|
+
});
|
|
98
|
+
const evmRequestFn = (method, params, network) => this.provider.request({ chainId: network, method, params });
|
|
99
|
+
this.yield = new Yield({
|
|
100
|
+
mpc: this.mpc,
|
|
101
|
+
waitForConfirmation: this.waitForConfirmation.bind(this),
|
|
102
|
+
evmRequestFn,
|
|
103
|
+
});
|
|
104
|
+
this.trading = new Trading({
|
|
105
|
+
mpc: this.mpc,
|
|
106
|
+
signAndSendTransaction,
|
|
107
|
+
waitForConfirmation: this.waitForConfirmation.bind(this),
|
|
108
|
+
evmRequestFn,
|
|
109
|
+
});
|
|
110
|
+
this.yield.yieldXyz.setSignAndSendTransaction(signAndSendTransaction);
|
|
111
|
+
this.delegations = new Delegations({
|
|
112
|
+
mpc: this.mpc,
|
|
113
|
+
signAndSendTransaction,
|
|
114
|
+
});
|
|
78
115
|
this.evmAccountType = new EvmAccountType({ mpc: this.mpc });
|
|
79
116
|
}
|
|
80
117
|
/***********************************
|
|
@@ -493,6 +530,44 @@ class Portal {
|
|
|
493
530
|
}
|
|
494
531
|
});
|
|
495
532
|
}
|
|
533
|
+
/**
|
|
534
|
+
* Wait until a transaction is confirmed on-chain, or until timeout.
|
|
535
|
+
*
|
|
536
|
+
* - **EVM (`eip155:*`):** Polls both `eth_getTransactionReceipt` and
|
|
537
|
+
* `eth_getUserOperationReceipt` (auto-detect, locks after first hit).
|
|
538
|
+
* - **Solana (`solana:*`):** Polls `getSignatureStatuses` until the
|
|
539
|
+
* commitment level from `options.commitment`
|
|
540
|
+
* is met (default `confirmed`).
|
|
541
|
+
* - **Other networks:** Returns `false` (unsupported for polling).
|
|
542
|
+
*
|
|
543
|
+
* Optional `options` tune poll/timeout for all polled chains; EVM also accepts
|
|
544
|
+
* `onTimeout` (default `resolve_false`) and `lockModeAfterDetection` (default `true`) for dual-receipt polling and timeout handling.
|
|
545
|
+
*
|
|
546
|
+
* All RPC calls are routed through the iframe proxy to avoid CORS issues.
|
|
547
|
+
*/
|
|
548
|
+
waitForConfirmation(txHash, network, options) {
|
|
549
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
550
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
551
|
+
const requestFn = (method, params, chainId) => this.provider.request({ chainId, method, params });
|
|
552
|
+
if (network.startsWith('eip155:')) {
|
|
553
|
+
return waitForEvmOrUserOpConfirmation(txHash, network, requestFn, {
|
|
554
|
+
pollIntervalMs: (_a = options === null || options === void 0 ? void 0 : options.pollIntervalMs) !== null && _a !== void 0 ? _a : 4000,
|
|
555
|
+
timeoutMs: (_b = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _b !== void 0 ? _b : 900000,
|
|
556
|
+
onTimeout: (_c = options === null || options === void 0 ? void 0 : options.onTimeout) !== null && _c !== void 0 ? _c : 'resolve_false',
|
|
557
|
+
lockModeAfterDetection: (_d = options === null || options === void 0 ? void 0 : options.lockModeAfterDetection) !== null && _d !== void 0 ? _d : true,
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
if (network.toLowerCase().startsWith('solana:')) {
|
|
561
|
+
return waitForSolanaTxConfirmation(txHash, network, requestFn, {
|
|
562
|
+
pollIntervalMs: (_e = options === null || options === void 0 ? void 0 : options.pollIntervalMs) !== null && _e !== void 0 ? _e : 4000,
|
|
563
|
+
timeoutMs: (_f = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _f !== void 0 ? _f : 900000,
|
|
564
|
+
commitment: (_g = options === null || options === void 0 ? void 0 : options.commitment) !== null && _g !== void 0 ? _g : 'confirmed',
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
sdkLogger.warn(`[Portal.waitForConfirmation] Unsupported network: "${network}". Returning false (cannot verify confirmation).`, { txHash, network });
|
|
568
|
+
return false;
|
|
569
|
+
});
|
|
570
|
+
}
|
|
496
571
|
/****************************
|
|
497
572
|
* Provider Methods
|
|
498
573
|
****************************/
|
|
@@ -782,12 +857,57 @@ class Portal {
|
|
|
782
857
|
return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getNFTs(chainId);
|
|
783
858
|
});
|
|
784
859
|
}
|
|
860
|
+
/**
|
|
861
|
+
* @deprecated This method is deprecated and will be removed in a future version.
|
|
862
|
+
* Please use `getTransactionHistory()` instead, which uses the new Portal v3 API
|
|
863
|
+
* endpoint and returns the unified transaction format across all chains.
|
|
864
|
+
*
|
|
865
|
+
* Legacy endpoint: /api/v3/clients/me/transactions?chainId={chainId}
|
|
866
|
+
* New endpoint: /api/v3/clients/me/chains/{chain}/transactions
|
|
867
|
+
*/
|
|
785
868
|
getTransactions(chainId, limit, offset, order) {
|
|
786
869
|
var _a;
|
|
787
870
|
return __awaiter(this, void 0, void 0, function* () {
|
|
788
871
|
return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getTransactions(chainId, limit, offset, order);
|
|
789
872
|
});
|
|
790
873
|
}
|
|
874
|
+
/**
|
|
875
|
+
* Retrieves transaction history for the client's wallet on the specified chain.
|
|
876
|
+
*
|
|
877
|
+
* This method uses the new Portal v3 API endpoint and returns the unified
|
|
878
|
+
* transaction format. Supports EVM (EIP-155), Solana, Bitcoin, Tron, and Stellar chains.
|
|
879
|
+
*
|
|
880
|
+
* Response format varies by chain:
|
|
881
|
+
* - Solana returns the legacy format (will be migrated in a future release)
|
|
882
|
+
* - All other chains return the unified TransactionHistoryItem format
|
|
883
|
+
*
|
|
884
|
+
* @param params - Request parameters
|
|
885
|
+
* @param params.chainId - Chain ID in CAIP-2 format (e.g., 'eip155:1', 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp')
|
|
886
|
+
* @param params.limit - Maximum number of transactions to return (default: 50, max: 1000 for EVM, 15 for Solana)
|
|
887
|
+
* @param params.offset - Number of transactions to skip (default: 0)
|
|
888
|
+
* @param params.order - Sort order ('asc' or 'desc')
|
|
889
|
+
* @param params.address - Override wallet address (EVM only, must match client's known addresses)
|
|
890
|
+
* @param params.userOperations - Filter for ERC-4337 UserOperations (EVM only): 'include', 'only', or 'exclude'
|
|
891
|
+
* @returns Promise resolving to transaction history response
|
|
892
|
+
*
|
|
893
|
+
* @example
|
|
894
|
+
* ```typescript
|
|
895
|
+
* // Fetch latest 100 transactions for Ethereum mainnet
|
|
896
|
+
* const response = await portal.getTransactionHistory({
|
|
897
|
+
* chainId: 'eip155:1',
|
|
898
|
+
* limit: 100,
|
|
899
|
+
* order: 'desc'
|
|
900
|
+
* });
|
|
901
|
+
*
|
|
902
|
+
* console.log(response.data.transactions); // Array of TransactionHistoryItem
|
|
903
|
+
* ```
|
|
904
|
+
*/
|
|
905
|
+
getTransactionHistory(params) {
|
|
906
|
+
var _a;
|
|
907
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
908
|
+
return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getTransactionHistory(params);
|
|
909
|
+
});
|
|
910
|
+
}
|
|
791
911
|
/**
|
|
792
912
|
* @deprecated This method is deprecated. Use `portal.evaluateTransaction` instead.
|
|
793
913
|
*/
|
|
@@ -859,13 +979,11 @@ class Portal {
|
|
|
859
979
|
if (!chainId) {
|
|
860
980
|
throw new Error('[Portal] No chainId provided. Please provide a chainId to get the RPC endpoint');
|
|
861
981
|
}
|
|
862
|
-
// Ensure the chainId is configured in the rpcConfig.
|
|
863
982
|
// eslint-disable-next-line no-prototype-builtins
|
|
864
|
-
if (!this.
|
|
983
|
+
if (!this._rpcConfig.hasOwnProperty(chainId)) {
|
|
865
984
|
throw new Error(`[Portal] No RPC endpoint configured for chainId: ${chainId}`);
|
|
866
985
|
}
|
|
867
|
-
|
|
868
|
-
const gatewayUrl = this.rpcConfig[chainId];
|
|
986
|
+
const gatewayUrl = this._rpcConfig[chainId];
|
|
869
987
|
// If the RPC endpoint is a string, return it as-is.
|
|
870
988
|
if (typeof gatewayUrl === 'string') {
|
|
871
989
|
return gatewayUrl;
|
package/lib/esm/index.test.js
CHANGED
|
@@ -703,5 +703,18 @@ describe('Portal', () => {
|
|
|
703
703
|
it('should throw an error if the chainId is not present in the rpc config', () => {
|
|
704
704
|
expect(() => portal.getRpcUrl('incorrect-config')).toThrow(new Error('[Portal] Could not find a valid rpcConfig entry for chainId: incorrect-config'));
|
|
705
705
|
});
|
|
706
|
+
it('should use rpcConfig for getRpcUrl when iframeRpcConfig is also set', () => {
|
|
707
|
+
const iframeRpcConfig = {
|
|
708
|
+
'eip155:1': 'http://localhost:9999/rpc/v1/eip155/1',
|
|
709
|
+
};
|
|
710
|
+
portal = new Portal({
|
|
711
|
+
rpcConfig: mockRpcConfig,
|
|
712
|
+
iframeRpcConfig,
|
|
713
|
+
});
|
|
714
|
+
portal.mpc = mpcMock;
|
|
715
|
+
portal.provider = providerMock;
|
|
716
|
+
expect(portal.getRpcUrl('eip155:1')).toEqual(mockEthRpcUrl);
|
|
717
|
+
expect(portal.iframeRpcConfig).toEqual(iframeRpcConfig);
|
|
718
|
+
});
|
|
706
719
|
});
|
|
707
720
|
});
|
|
@@ -7,9 +7,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
+
const DELEGATIONS_SUBMIT_CONFIG_ERROR = '[Delegations] No signer configured. Call setSignAndSendTransaction() on the instance or pass signAndSendTransaction in options.';
|
|
10
11
|
export default class Delegations {
|
|
11
|
-
constructor(
|
|
12
|
-
this.mpc = mpc;
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.mpc = options.mpc;
|
|
14
|
+
this.signAndSendTransaction = options.signAndSendTransaction;
|
|
15
|
+
}
|
|
16
|
+
setSignAndSendTransaction(fn) {
|
|
17
|
+
this.signAndSendTransaction = fn;
|
|
13
18
|
}
|
|
14
19
|
/**
|
|
15
20
|
* Approves a delegation for a specified token on a given chain.
|
|
@@ -59,4 +64,106 @@ export default class Delegations {
|
|
|
59
64
|
return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.delegationsTransferFrom(params);
|
|
60
65
|
});
|
|
61
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Approves a delegation, then signs and broadcasts each returned transaction via
|
|
69
|
+
* {@link DelegationsOptions.signAndSendTransaction}.
|
|
70
|
+
*
|
|
71
|
+
* Requires `signAndSendTransaction` (provided by default on `Portal.delegations`).
|
|
72
|
+
* Confirming transactions on-chain remains the application's responsibility.
|
|
73
|
+
*
|
|
74
|
+
* @param params - Same as {@link Delegations.approve}
|
|
75
|
+
* @param options - Optional progress callbacks
|
|
76
|
+
* @returns Transaction hashes in submission order
|
|
77
|
+
*/
|
|
78
|
+
approveAndSubmit(params, options) {
|
|
79
|
+
var _a;
|
|
80
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
81
|
+
const signAndSend = (_a = options === null || options === void 0 ? void 0 : options.signAndSendTransaction) !== null && _a !== void 0 ? _a : this.signAndSendTransaction;
|
|
82
|
+
if (!signAndSend) {
|
|
83
|
+
throw new Error(DELEGATIONS_SUBMIT_CONFIG_ERROR);
|
|
84
|
+
}
|
|
85
|
+
const response = yield this.approve(params);
|
|
86
|
+
return this.executeAndTrack(response, params.chain, signAndSend, options === null || options === void 0 ? void 0 : options.onProgress);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Revokes a delegation, then signs and broadcasts each returned transaction.
|
|
91
|
+
*
|
|
92
|
+
* Requires `signAndSendTransaction` (provided by default on `Portal.delegations`).
|
|
93
|
+
*
|
|
94
|
+
* @param params - Same as {@link Delegations.revoke}
|
|
95
|
+
* @param options - Optional progress callbacks
|
|
96
|
+
* @returns Transaction hashes in submission order
|
|
97
|
+
*/
|
|
98
|
+
revokeAndSubmit(params, options) {
|
|
99
|
+
var _a;
|
|
100
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
101
|
+
const signAndSend = (_a = options === null || options === void 0 ? void 0 : options.signAndSendTransaction) !== null && _a !== void 0 ? _a : this.signAndSendTransaction;
|
|
102
|
+
if (!signAndSend) {
|
|
103
|
+
throw new Error(DELEGATIONS_SUBMIT_CONFIG_ERROR);
|
|
104
|
+
}
|
|
105
|
+
const response = yield this.revoke(params);
|
|
106
|
+
return this.executeAndTrack(response, params.chain, signAndSend, options === null || options === void 0 ? void 0 : options.onProgress);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Executes a delegated transfer, then signs and broadcasts each returned transaction.
|
|
111
|
+
*
|
|
112
|
+
* Requires `signAndSendTransaction` (provided by default on `Portal.delegations`).
|
|
113
|
+
*
|
|
114
|
+
* @param params - Same as {@link Delegations.transferFrom}
|
|
115
|
+
* @param options - Optional progress callbacks
|
|
116
|
+
* @returns Transaction hashes in submission order
|
|
117
|
+
*/
|
|
118
|
+
transferAndSubmit(params, options) {
|
|
119
|
+
var _a;
|
|
120
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
121
|
+
const signAndSend = (_a = options === null || options === void 0 ? void 0 : options.signAndSendTransaction) !== null && _a !== void 0 ? _a : this.signAndSendTransaction;
|
|
122
|
+
if (!signAndSend) {
|
|
123
|
+
throw new Error(DELEGATIONS_SUBMIT_CONFIG_ERROR);
|
|
124
|
+
}
|
|
125
|
+
const response = yield this.transferFrom(params);
|
|
126
|
+
return this.executeAndTrack(response, params.chain, signAndSend, options === null || options === void 0 ? void 0 : options.onProgress);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
normalizeToTransactionList(response) {
|
|
130
|
+
const transactions = Array.isArray(response.transactions)
|
|
131
|
+
? response.transactions
|
|
132
|
+
: [];
|
|
133
|
+
const encodedTransactions = Array.isArray(response.encodedTransactions)
|
|
134
|
+
? response.encodedTransactions
|
|
135
|
+
: [];
|
|
136
|
+
if (transactions.length > 0) {
|
|
137
|
+
return transactions;
|
|
138
|
+
}
|
|
139
|
+
if (encodedTransactions.length > 0) {
|
|
140
|
+
return encodedTransactions;
|
|
141
|
+
}
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
executeAndTrack(response, chainId, signAndSend, onProgress) {
|
|
145
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
146
|
+
const transactions = this.normalizeToTransactionList(response);
|
|
147
|
+
if (transactions.length === 0) {
|
|
148
|
+
throw new Error('No transactions in delegation response.');
|
|
149
|
+
}
|
|
150
|
+
const total = transactions.length;
|
|
151
|
+
const hashes = [];
|
|
152
|
+
for (let index = 0; index < transactions.length; index++) {
|
|
153
|
+
const tx = transactions[index];
|
|
154
|
+
// Validate transaction exists (defensive check for sparse arrays)
|
|
155
|
+
if (!tx) {
|
|
156
|
+
throw new Error(`Transaction at index ${index} is undefined or null. This indicates a malformed API response.`);
|
|
157
|
+
}
|
|
158
|
+
onProgress === null || onProgress === void 0 ? void 0 : onProgress({ step: 'signing', index, total });
|
|
159
|
+
const hash = yield signAndSend(tx, chainId);
|
|
160
|
+
if (typeof hash !== 'string' || hash.trim().length === 0) {
|
|
161
|
+
throw new Error(`Invalid transaction hash returned from signAndSendTransaction at index ${index} for chain ${chainId}.`);
|
|
162
|
+
}
|
|
163
|
+
hashes.push(hash);
|
|
164
|
+
onProgress === null || onProgress === void 0 ? void 0 : onProgress({ step: 'submitted', index, total, hash });
|
|
165
|
+
}
|
|
166
|
+
return { hashes };
|
|
167
|
+
});
|
|
168
|
+
}
|
|
62
169
|
}
|