@portal-hq/web 3.13.2 → 3.14.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 +318 -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 +117 -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 +313 -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 +117 -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 +1 -1
- 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 +421 -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 +144 -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 +83 -1
- package/types.d.ts +6 -0
package/lib/esm/mpc/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { PortalMpcError } from './errors';
|
|
|
11
11
|
import { sdkLogger } from '../logger';
|
|
12
12
|
import { BackupMethods, } from '../index';
|
|
13
13
|
import { generateTraceId } from '../shared/trace';
|
|
14
|
-
const WEB_SDK_VERSION = '3.
|
|
14
|
+
const WEB_SDK_VERSION = '3.14.0';
|
|
15
15
|
class Mpc {
|
|
16
16
|
get ready() {
|
|
17
17
|
return this._ready;
|
|
@@ -35,6 +35,8 @@ class Mpc {
|
|
|
35
35
|
mpcVersion: this.portal.mpcVersion,
|
|
36
36
|
featureFlags: this.portal.featureFlags,
|
|
37
37
|
logLevel: this.portal.getLogLevel(),
|
|
38
|
+
rpcConfig: this.portal.rpcConfig,
|
|
39
|
+
iframeRpcConfig: this.portal.iframeRpcConfig,
|
|
38
40
|
};
|
|
39
41
|
const message = {
|
|
40
42
|
type: 'portal:configure',
|
|
@@ -308,8 +310,18 @@ class Mpc {
|
|
|
308
310
|
});
|
|
309
311
|
});
|
|
310
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* @deprecated This method is deprecated and will be removed in a future version.
|
|
315
|
+
* Please use `getTransactionHistory()` instead, which uses the new Portal v3 API
|
|
316
|
+
* endpoint and returns the unified transaction format across all chains.
|
|
317
|
+
*/
|
|
311
318
|
getTransactions(chainId, limit, offset, order) {
|
|
312
319
|
return __awaiter(this, void 0, void 0, function* () {
|
|
320
|
+
// Log deprecation warning
|
|
321
|
+
sdkLogger.warn('[DEPRECATED] getTransactions() is deprecated and will be removed in a future version. ' +
|
|
322
|
+
'Please use getTransactionHistory() instead, which provides improved type safety with ' +
|
|
323
|
+
'discriminated unions for regular transactions and UserOperations, and proper polymorphic ' +
|
|
324
|
+
'response types for Solana vs unified formats.');
|
|
313
325
|
return this.handleRequestToIframeAndPost({
|
|
314
326
|
methodMessage: 'portal:getTransactions',
|
|
315
327
|
errorMessage: 'portal:getTransactionsError',
|
|
@@ -323,6 +335,31 @@ class Mpc {
|
|
|
323
335
|
});
|
|
324
336
|
});
|
|
325
337
|
}
|
|
338
|
+
/**
|
|
339
|
+
* Retrieves transaction history for the client's wallet on the specified chain.
|
|
340
|
+
*
|
|
341
|
+
* This method uses the new Portal v3 API endpoint and returns the unified
|
|
342
|
+
* transaction format. Supports EVM (EIP-155), Solana, Bitcoin, Tron, and Stellar chains.
|
|
343
|
+
*
|
|
344
|
+
* @param params - Request parameters
|
|
345
|
+
* @param params.chainId - Chain ID in CAIP-2 format (e.g., 'eip155:1', 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp')
|
|
346
|
+
* @param params.limit - Maximum number of transactions to return (default: 50)
|
|
347
|
+
* @param params.offset - Number of transactions to skip (default: 0)
|
|
348
|
+
* @param params.order - Sort order ('asc' or 'desc')
|
|
349
|
+
* @param params.address - Override wallet address (EVM only)
|
|
350
|
+
* @param params.userOperations - Filter for ERC-4337 UserOperations (EVM only)
|
|
351
|
+
* @returns Promise resolving to transaction history response
|
|
352
|
+
*/
|
|
353
|
+
getTransactionHistory(params) {
|
|
354
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
355
|
+
return this.handleRequestToIframeAndPost({
|
|
356
|
+
methodMessage: 'portal:getTransactionHistory',
|
|
357
|
+
errorMessage: 'portal:getTransactionHistoryError',
|
|
358
|
+
resultMessage: 'portal:getTransactionHistoryResult',
|
|
359
|
+
data: params,
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
}
|
|
326
363
|
setBackupStatus(status, backupIds) {
|
|
327
364
|
return __awaiter(this, void 0, void 0, function* () {
|
|
328
365
|
return this.handleRequestToIframeAndPost({
|
|
@@ -475,6 +512,26 @@ class Mpc {
|
|
|
475
512
|
});
|
|
476
513
|
});
|
|
477
514
|
}
|
|
515
|
+
getYieldXyzDefaults(data) {
|
|
516
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
517
|
+
return this.handleRequestToIframeAndPost({
|
|
518
|
+
methodMessage: 'portal:yieldxyz:getDefaults',
|
|
519
|
+
errorMessage: 'portal:yieldxyz:getDefaultsError',
|
|
520
|
+
resultMessage: 'portal:yieldxyz:getDefaultsResult',
|
|
521
|
+
data: data !== null && data !== void 0 ? data : {},
|
|
522
|
+
});
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
getYieldXyzValidators(yieldId) {
|
|
526
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
527
|
+
return this.handleRequestToIframeAndPost({
|
|
528
|
+
methodMessage: 'portal:yieldxyz:getValidators',
|
|
529
|
+
errorMessage: 'portal:yieldxyz:getValidatorsError',
|
|
530
|
+
resultMessage: 'portal:yieldxyz:getValidatorsResult',
|
|
531
|
+
data: yieldId,
|
|
532
|
+
});
|
|
533
|
+
});
|
|
534
|
+
}
|
|
478
535
|
getLifiRoutes(data) {
|
|
479
536
|
return __awaiter(this, void 0, void 0, function* () {
|
|
480
537
|
return this.handleRequestToIframeAndPost({
|
|
@@ -950,6 +1007,65 @@ class Mpc {
|
|
|
950
1007
|
});
|
|
951
1008
|
});
|
|
952
1009
|
}
|
|
1010
|
+
rpcRequest(data, options) {
|
|
1011
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1012
|
+
const { timeoutMs = 30000, traceId } = options !== null && options !== void 0 ? options : {};
|
|
1013
|
+
const requestId = typeof crypto !== 'undefined' && crypto.randomUUID
|
|
1014
|
+
? crypto.randomUUID()
|
|
1015
|
+
: `${Date.now()}-${Math.random()}`;
|
|
1016
|
+
const resolvedTraceId = traceId !== null && traceId !== void 0 ? traceId : generateTraceId();
|
|
1017
|
+
sdkLogger.debug('[Portal] rpcRequest', {
|
|
1018
|
+
requestId,
|
|
1019
|
+
method: data.method,
|
|
1020
|
+
chainId: data.chainId,
|
|
1021
|
+
traceId: resolvedTraceId,
|
|
1022
|
+
timeoutMs,
|
|
1023
|
+
});
|
|
1024
|
+
return new Promise((resolve, reject) => {
|
|
1025
|
+
let timeoutId;
|
|
1026
|
+
const cleanup = () => {
|
|
1027
|
+
window.removeEventListener('message', handleResponse);
|
|
1028
|
+
if (timeoutId !== undefined) {
|
|
1029
|
+
clearTimeout(timeoutId);
|
|
1030
|
+
}
|
|
1031
|
+
};
|
|
1032
|
+
const handleResponse = (event) => {
|
|
1033
|
+
var _a;
|
|
1034
|
+
const { origin } = event;
|
|
1035
|
+
if (origin !== this.getOrigin())
|
|
1036
|
+
return;
|
|
1037
|
+
const { type, data: result } = event.data;
|
|
1038
|
+
if (type === 'portal:rpc:requestResult' &&
|
|
1039
|
+
(result === null || result === void 0 ? void 0 : result.requestId) === requestId) {
|
|
1040
|
+
cleanup();
|
|
1041
|
+
resolve(result);
|
|
1042
|
+
}
|
|
1043
|
+
else if (type === 'portal:rpc:requestError' &&
|
|
1044
|
+
(result === null || result === void 0 ? void 0 : result.requestId) === requestId) {
|
|
1045
|
+
cleanup();
|
|
1046
|
+
reject(new Error((_a = result.message) !== null && _a !== void 0 ? _a : 'RPC proxy error'));
|
|
1047
|
+
}
|
|
1048
|
+
};
|
|
1049
|
+
timeoutId = setTimeout(() => {
|
|
1050
|
+
cleanup();
|
|
1051
|
+
const msg = `RPC request ${requestId} (${data.method}) timed out after ${timeoutMs}ms`;
|
|
1052
|
+
sdkLogger.error('[Portal] rpcRequest timeout', {
|
|
1053
|
+
requestId,
|
|
1054
|
+
method: data.method,
|
|
1055
|
+
chainId: data.chainId,
|
|
1056
|
+
timeoutMs,
|
|
1057
|
+
});
|
|
1058
|
+
reject(new Error(msg));
|
|
1059
|
+
}, timeoutMs);
|
|
1060
|
+
window.addEventListener('message', handleResponse);
|
|
1061
|
+
this.postMessage({
|
|
1062
|
+
type: 'portal:rpc:request',
|
|
1063
|
+
data: Object.assign(Object.assign({}, data), { requestId }),
|
|
1064
|
+
traceId: resolvedTraceId,
|
|
1065
|
+
});
|
|
1066
|
+
});
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
953
1069
|
postMessage(event) {
|
|
954
1070
|
var _a, _b;
|
|
955
1071
|
(_b = (_a = this.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow) === null || _b === void 0 ? void 0 : _b.postMessage(event, this.getOrigin());
|
|
@@ -149,6 +149,11 @@ const signerMethods = [
|
|
|
149
149
|
RequestMethod.sol_signMessage,
|
|
150
150
|
RequestMethod.sol_signTransaction,
|
|
151
151
|
];
|
|
152
|
+
const iframeProxiedMethodStrings = [
|
|
153
|
+
'eth_getTransactionReceipt',
|
|
154
|
+
'eth_getUserOperationReceipt',
|
|
155
|
+
'getSignatureStatuses',
|
|
156
|
+
];
|
|
152
157
|
class Provider {
|
|
153
158
|
constructor({ portal, chainId }) {
|
|
154
159
|
this.enforceEip155ChainId = (chainId) => {
|
|
@@ -384,6 +389,18 @@ class Provider {
|
|
|
384
389
|
*/
|
|
385
390
|
handleGatewayRequest({ chainId, method, params, traceId, }) {
|
|
386
391
|
return __awaiter(this, void 0, void 0, function* () {
|
|
392
|
+
if (iframeProxiedMethodStrings.includes(method)) {
|
|
393
|
+
sdkLogger.info(`[PortalProvider] routing ${method} through iframe (chainId=${String(chainId)})`, { traceId });
|
|
394
|
+
return this.portal.mpc.rpcRequest({
|
|
395
|
+
method,
|
|
396
|
+
params: Array.isArray(params)
|
|
397
|
+
? params
|
|
398
|
+
: params != null
|
|
399
|
+
? [params]
|
|
400
|
+
: [],
|
|
401
|
+
chainId: chainId,
|
|
402
|
+
}, { traceId });
|
|
403
|
+
}
|
|
387
404
|
const requestBody = {
|
|
388
405
|
body: JSON.stringify({
|
|
389
406
|
jsonrpc: '2.0',
|
package/noah-types.d.ts
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
export type {
|
|
2
|
-
|
|
2
|
+
AccountHolderDetails,
|
|
3
|
+
AmountCondition,
|
|
4
|
+
BankDetails,
|
|
5
|
+
BankToAddressRelatedPaymentMethod,
|
|
6
|
+
Channel,
|
|
7
|
+
ChannelCalculated,
|
|
8
|
+
ChannelLimits,
|
|
9
|
+
DepositSourceTriggerCondition,
|
|
10
|
+
FormNextStep,
|
|
11
|
+
IssuerDetails,
|
|
3
12
|
NoahGetPaymentMethodsResponse,
|
|
4
13
|
NoahGetPaymentMethodsResponseData,
|
|
5
14
|
NoahGetPayoutChannelFormResponse,
|
|
15
|
+
NoahGetPayoutChannelFormResponseData,
|
|
6
16
|
NoahGetPayoutChannelsRequest,
|
|
7
17
|
NoahGetPayoutChannelsResponse,
|
|
18
|
+
NoahGetPayoutChannelsResponseData,
|
|
8
19
|
NoahGetPayoutCountriesResponse,
|
|
20
|
+
NoahGetPayoutCountriesResponseData,
|
|
9
21
|
NoahGetPayoutQuoteRequest,
|
|
10
22
|
NoahGetPayoutQuoteResponse,
|
|
11
23
|
NoahGetPayoutQuoteResponseData,
|
|
@@ -18,11 +30,13 @@ export type {
|
|
|
18
30
|
NoahInitiatePayoutRequest,
|
|
19
31
|
NoahInitiatePayoutResponse,
|
|
20
32
|
NoahInitiatePayoutResponseData,
|
|
21
|
-
NoahPayoutConditionBlock,
|
|
22
33
|
NoahSingleOnchainDepositSourceTriggerInput,
|
|
23
34
|
NoahSimulatePayinRequest,
|
|
24
35
|
NoahSimulatePayinResponse,
|
|
25
36
|
NoahSimulatePayinResponseData,
|
|
26
37
|
NoahSolanaCaipId,
|
|
38
|
+
PaymentMethod,
|
|
39
|
+
PaymentMethodDetails,
|
|
27
40
|
PortalApiSuccessEnvelope,
|
|
41
|
+
StreetAddress,
|
|
28
42
|
} from './src/shared/types/noah'
|
package/package.json
CHANGED
package/src/index.test.ts
CHANGED
|
@@ -1138,5 +1138,20 @@ describe('Portal', () => {
|
|
|
1138
1138
|
),
|
|
1139
1139
|
)
|
|
1140
1140
|
})
|
|
1141
|
+
|
|
1142
|
+
it('should use rpcConfig for getRpcUrl when iframeRpcConfig is also set', () => {
|
|
1143
|
+
const iframeRpcConfig = {
|
|
1144
|
+
'eip155:1': 'http://localhost:9999/rpc/v1/eip155/1',
|
|
1145
|
+
}
|
|
1146
|
+
portal = new Portal({
|
|
1147
|
+
rpcConfig: mockRpcConfig,
|
|
1148
|
+
iframeRpcConfig,
|
|
1149
|
+
})
|
|
1150
|
+
portal.mpc = mpcMock
|
|
1151
|
+
portal.provider = providerMock
|
|
1152
|
+
|
|
1153
|
+
expect(portal.getRpcUrl('eip155:1')).toEqual(mockEthRpcUrl)
|
|
1154
|
+
expect(portal.iframeRpcConfig).toEqual(iframeRpcConfig)
|
|
1155
|
+
})
|
|
1141
1156
|
})
|
|
1142
1157
|
})
|
package/src/index.ts
CHANGED
|
@@ -16,6 +16,8 @@ import {
|
|
|
16
16
|
NFTAsset,
|
|
17
17
|
OrgBackupShares,
|
|
18
18
|
SendAssetParams,
|
|
19
|
+
GetTransactionHistoryParams,
|
|
20
|
+
GetTransactionHistoryResponse,
|
|
19
21
|
type BackupConfigs,
|
|
20
22
|
type BackupResponse,
|
|
21
23
|
type Balance,
|
|
@@ -58,6 +60,8 @@ import PasskeyService from './passkeys'
|
|
|
58
60
|
import { EvmAccountType } from './namespaces/evmAccountType'
|
|
59
61
|
import { sdkLogger } from './logger'
|
|
60
62
|
import { generateTraceId } from './shared/trace'
|
|
63
|
+
import { waitForEvmOrUserOpConfirmation } from './internal/waitForEvmOrUserOpConfirmation'
|
|
64
|
+
import { waitForSolanaTxConfirmation } from './internal/waitForSolanaTxConfirmation'
|
|
61
65
|
import type { LogLevel, ILogger } from '../types'
|
|
62
66
|
|
|
63
67
|
class Portal {
|
|
@@ -82,7 +86,8 @@ class Portal {
|
|
|
82
86
|
public featureFlags: FeatureFlags
|
|
83
87
|
|
|
84
88
|
private errorCallbacks: ((reason: string) => any | Promise<any>)[] = []
|
|
85
|
-
private
|
|
89
|
+
private _rpcConfig: RpcConfig
|
|
90
|
+
private _iframeRpcConfig?: RpcConfig
|
|
86
91
|
private readyCallbacks: (() => any | Promise<any>)[] = []
|
|
87
92
|
private passkeyService?: PasskeyService
|
|
88
93
|
private passkeyServiceDefaultDomain?: string
|
|
@@ -92,11 +97,20 @@ class Portal {
|
|
|
92
97
|
return this.mpc.ready
|
|
93
98
|
}
|
|
94
99
|
|
|
100
|
+
public get rpcConfig(): RpcConfig {
|
|
101
|
+
return this._rpcConfig
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public get iframeRpcConfig(): RpcConfig | undefined {
|
|
105
|
+
return this._iframeRpcConfig
|
|
106
|
+
}
|
|
107
|
+
|
|
95
108
|
constructor({
|
|
96
109
|
// Required
|
|
97
110
|
rpcConfig,
|
|
98
111
|
|
|
99
112
|
// Optional
|
|
113
|
+
iframeRpcConfig,
|
|
100
114
|
apiKey,
|
|
101
115
|
authToken,
|
|
102
116
|
authUrl,
|
|
@@ -115,7 +129,8 @@ class Portal {
|
|
|
115
129
|
this.authToken = authToken
|
|
116
130
|
this.authUrl = authUrl
|
|
117
131
|
this.autoApprove = autoApprove
|
|
118
|
-
this.
|
|
132
|
+
this._rpcConfig = rpcConfig
|
|
133
|
+
this._iframeRpcConfig = iframeRpcConfig
|
|
119
134
|
this.host = host
|
|
120
135
|
this.mpcHost = mpcHost
|
|
121
136
|
this.mpcVersion = mpcVersion
|
|
@@ -136,21 +151,58 @@ class Portal {
|
|
|
136
151
|
portal: this,
|
|
137
152
|
})
|
|
138
153
|
|
|
139
|
-
this.yield = new Yield({ mpc: this.mpc })
|
|
140
|
-
|
|
141
154
|
this.ramps = new Ramps({ mpc: this.mpc })
|
|
142
155
|
|
|
143
|
-
this.trading = new Trading({ mpc: this.mpc })
|
|
144
|
-
|
|
145
156
|
this.security = new Security({ mpc: this.mpc })
|
|
146
157
|
|
|
147
|
-
this.delegations = new Delegations({ mpc: this.mpc })
|
|
148
|
-
|
|
149
158
|
this.provider = new Provider({
|
|
150
159
|
portal: this,
|
|
151
160
|
chainId: chainId ? Number(chainId) : undefined,
|
|
152
161
|
})
|
|
153
162
|
|
|
163
|
+
const signAndSendTransaction = async (
|
|
164
|
+
transaction: unknown,
|
|
165
|
+
network: string,
|
|
166
|
+
): Promise<string> => {
|
|
167
|
+
const method = network.startsWith('solana')
|
|
168
|
+
? RequestMethod.sol_signAndSendTransaction
|
|
169
|
+
: RequestMethod.eth_sendTransaction
|
|
170
|
+
const hash = await this.provider.request({
|
|
171
|
+
chainId: network,
|
|
172
|
+
method,
|
|
173
|
+
params: [transaction],
|
|
174
|
+
})
|
|
175
|
+
if (typeof hash !== 'string' || hash.length === 0) {
|
|
176
|
+
throw new Error(
|
|
177
|
+
'[Portal] Signing request did not return a transaction hash. The user may have rejected the request, or the provider did not complete signing.',
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
return hash
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const evmRequestFn = (method: string, params: unknown[], network: string) =>
|
|
184
|
+
this.provider.request({ chainId: network, method, params })
|
|
185
|
+
|
|
186
|
+
this.yield = new Yield({
|
|
187
|
+
mpc: this.mpc,
|
|
188
|
+
waitForConfirmation: this.waitForConfirmation.bind(this),
|
|
189
|
+
evmRequestFn,
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
this.trading = new Trading({
|
|
193
|
+
mpc: this.mpc,
|
|
194
|
+
signAndSendTransaction,
|
|
195
|
+
waitForConfirmation: this.waitForConfirmation.bind(this),
|
|
196
|
+
evmRequestFn,
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
this.yield.yieldXyz.setSignAndSendTransaction(signAndSendTransaction)
|
|
200
|
+
|
|
201
|
+
this.delegations = new Delegations({
|
|
202
|
+
mpc: this.mpc,
|
|
203
|
+
signAndSendTransaction,
|
|
204
|
+
})
|
|
205
|
+
|
|
154
206
|
this.evmAccountType = new EvmAccountType({ mpc: this.mpc })
|
|
155
207
|
}
|
|
156
208
|
|
|
@@ -690,6 +742,62 @@ class Portal {
|
|
|
690
742
|
}
|
|
691
743
|
}
|
|
692
744
|
|
|
745
|
+
/**
|
|
746
|
+
* Wait until a transaction is confirmed on-chain, or until timeout.
|
|
747
|
+
*
|
|
748
|
+
* - **EVM (`eip155:*`):** Polls both `eth_getTransactionReceipt` and
|
|
749
|
+
* `eth_getUserOperationReceipt` (auto-detect, locks after first hit).
|
|
750
|
+
* - **Solana (`solana:*`):** Polls `getSignatureStatuses` until the
|
|
751
|
+
* commitment level from `options.commitment`
|
|
752
|
+
* is met (default `confirmed`).
|
|
753
|
+
* - **Other networks:** Returns `false` (unsupported for polling).
|
|
754
|
+
*
|
|
755
|
+
* Optional `options` tune poll/timeout for all polled chains; EVM also accepts
|
|
756
|
+
* `onTimeout` (default `resolve_false`) and `lockModeAfterDetection` (default `true`) for dual-receipt polling and timeout handling.
|
|
757
|
+
*
|
|
758
|
+
* All RPC calls are routed through the iframe proxy to avoid CORS issues.
|
|
759
|
+
*/
|
|
760
|
+
public async waitForConfirmation(
|
|
761
|
+
txHash: string,
|
|
762
|
+
network: string,
|
|
763
|
+
options?: {
|
|
764
|
+
pollIntervalMs?: number
|
|
765
|
+
timeoutMs?: number
|
|
766
|
+
/** EVM / dual-mode only. @default 'resolve_false' */
|
|
767
|
+
onTimeout?: 'resolve_false' | 'throw'
|
|
768
|
+
/** EVM / dual-mode only. @default true */
|
|
769
|
+
lockModeAfterDetection?: boolean
|
|
770
|
+
/** Solana only. @default 'confirmed' */
|
|
771
|
+
commitment?: 'processed' | 'confirmed' | 'finalized'
|
|
772
|
+
},
|
|
773
|
+
): Promise<boolean> {
|
|
774
|
+
const requestFn = (method: string, params: unknown[], chainId: string) =>
|
|
775
|
+
this.provider.request({ chainId, method, params })
|
|
776
|
+
|
|
777
|
+
if (network.startsWith('eip155:')) {
|
|
778
|
+
return waitForEvmOrUserOpConfirmation(txHash, network, requestFn, {
|
|
779
|
+
pollIntervalMs: options?.pollIntervalMs ?? 4_000,
|
|
780
|
+
timeoutMs: options?.timeoutMs ?? 900_000,
|
|
781
|
+
onTimeout: options?.onTimeout ?? 'resolve_false',
|
|
782
|
+
lockModeAfterDetection: options?.lockModeAfterDetection ?? true,
|
|
783
|
+
})
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
if (network.toLowerCase().startsWith('solana:')) {
|
|
787
|
+
return waitForSolanaTxConfirmation(txHash, network, requestFn, {
|
|
788
|
+
pollIntervalMs: options?.pollIntervalMs ?? 4_000,
|
|
789
|
+
timeoutMs: options?.timeoutMs ?? 900_000,
|
|
790
|
+
commitment: options?.commitment ?? 'confirmed',
|
|
791
|
+
})
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
sdkLogger.warn(
|
|
795
|
+
`[Portal.waitForConfirmation] Unsupported network: "${network}". Returning false (cannot verify confirmation).`,
|
|
796
|
+
{ txHash, network },
|
|
797
|
+
)
|
|
798
|
+
return false
|
|
799
|
+
}
|
|
800
|
+
|
|
693
801
|
/****************************
|
|
694
802
|
* Provider Methods
|
|
695
803
|
****************************/
|
|
@@ -1054,6 +1162,14 @@ class Portal {
|
|
|
1054
1162
|
return this.mpc?.getNFTs(chainId)
|
|
1055
1163
|
}
|
|
1056
1164
|
|
|
1165
|
+
/**
|
|
1166
|
+
* @deprecated This method is deprecated and will be removed in a future version.
|
|
1167
|
+
* Please use `getTransactionHistory()` instead, which uses the new Portal v3 API
|
|
1168
|
+
* endpoint and returns the unified transaction format across all chains.
|
|
1169
|
+
*
|
|
1170
|
+
* Legacy endpoint: /api/v3/clients/me/transactions?chainId={chainId}
|
|
1171
|
+
* New endpoint: /api/v3/clients/me/chains/{chain}/transactions
|
|
1172
|
+
*/
|
|
1057
1173
|
public async getTransactions(
|
|
1058
1174
|
chainId: string,
|
|
1059
1175
|
limit?: number,
|
|
@@ -1063,6 +1179,43 @@ class Portal {
|
|
|
1063
1179
|
return this.mpc?.getTransactions(chainId, limit, offset, order)
|
|
1064
1180
|
}
|
|
1065
1181
|
|
|
1182
|
+
/**
|
|
1183
|
+
* Retrieves transaction history for the client's wallet on the specified chain.
|
|
1184
|
+
*
|
|
1185
|
+
* This method uses the new Portal v3 API endpoint and returns the unified
|
|
1186
|
+
* transaction format. Supports EVM (EIP-155), Solana, Bitcoin, Tron, and Stellar chains.
|
|
1187
|
+
*
|
|
1188
|
+
* Response format varies by chain:
|
|
1189
|
+
* - Solana returns the legacy format (will be migrated in a future release)
|
|
1190
|
+
* - All other chains return the unified TransactionHistoryItem format
|
|
1191
|
+
*
|
|
1192
|
+
* @param params - Request parameters
|
|
1193
|
+
* @param params.chainId - Chain ID in CAIP-2 format (e.g., 'eip155:1', 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp')
|
|
1194
|
+
* @param params.limit - Maximum number of transactions to return (default: 50, max: 1000 for EVM, 15 for Solana)
|
|
1195
|
+
* @param params.offset - Number of transactions to skip (default: 0)
|
|
1196
|
+
* @param params.order - Sort order ('asc' or 'desc')
|
|
1197
|
+
* @param params.address - Override wallet address (EVM only, must match client's known addresses)
|
|
1198
|
+
* @param params.userOperations - Filter for ERC-4337 UserOperations (EVM only): 'include', 'only', or 'exclude'
|
|
1199
|
+
* @returns Promise resolving to transaction history response
|
|
1200
|
+
*
|
|
1201
|
+
* @example
|
|
1202
|
+
* ```typescript
|
|
1203
|
+
* // Fetch latest 100 transactions for Ethereum mainnet
|
|
1204
|
+
* const response = await portal.getTransactionHistory({
|
|
1205
|
+
* chainId: 'eip155:1',
|
|
1206
|
+
* limit: 100,
|
|
1207
|
+
* order: 'desc'
|
|
1208
|
+
* });
|
|
1209
|
+
*
|
|
1210
|
+
* console.log(response.data.transactions); // Array of TransactionHistoryItem
|
|
1211
|
+
* ```
|
|
1212
|
+
*/
|
|
1213
|
+
public async getTransactionHistory(
|
|
1214
|
+
params: GetTransactionHistoryParams,
|
|
1215
|
+
): Promise<GetTransactionHistoryResponse> {
|
|
1216
|
+
return this.mpc?.getTransactionHistory(params)
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1066
1219
|
/**
|
|
1067
1220
|
* @deprecated This method is deprecated. Use `portal.evaluateTransaction` instead.
|
|
1068
1221
|
*/
|
|
@@ -1150,16 +1303,14 @@ class Portal {
|
|
|
1150
1303
|
)
|
|
1151
1304
|
}
|
|
1152
1305
|
|
|
1153
|
-
// Ensure the chainId is configured in the rpcConfig.
|
|
1154
1306
|
// eslint-disable-next-line no-prototype-builtins
|
|
1155
|
-
if (!this.
|
|
1307
|
+
if (!this._rpcConfig.hasOwnProperty(chainId)) {
|
|
1156
1308
|
throw new Error(
|
|
1157
1309
|
`[Portal] No RPC endpoint configured for chainId: ${chainId}`,
|
|
1158
1310
|
)
|
|
1159
1311
|
}
|
|
1160
1312
|
|
|
1161
|
-
|
|
1162
|
-
const gatewayUrl = this.rpcConfig[chainId]
|
|
1313
|
+
const gatewayUrl = this._rpcConfig[chainId]
|
|
1163
1314
|
|
|
1164
1315
|
// If the RPC endpoint is a string, return it as-is.
|
|
1165
1316
|
if (typeof gatewayUrl === 'string') {
|
|
@@ -1307,6 +1458,13 @@ class Portal {
|
|
|
1307
1458
|
}
|
|
1308
1459
|
}
|
|
1309
1460
|
|
|
1461
|
+
export type {
|
|
1462
|
+
IDelegations,
|
|
1463
|
+
IPortalDelegationsApi,
|
|
1464
|
+
DelegationsOptions,
|
|
1465
|
+
DelegationSubmitOptions,
|
|
1466
|
+
} from './integrations/delegations'
|
|
1467
|
+
|
|
1310
1468
|
export {
|
|
1311
1469
|
type YieldXyzEnterRequest,
|
|
1312
1470
|
type YieldXyzEnterYieldResponse,
|
|
@@ -1324,6 +1482,22 @@ export {
|
|
|
1324
1482
|
type YieldXyzManageYieldResponse,
|
|
1325
1483
|
type YieldXyzTrackTransactionRequest,
|
|
1326
1484
|
type YieldXyzTrackTransactionResponse,
|
|
1485
|
+
type YieldXyzGetYieldDefaultsRequest,
|
|
1486
|
+
type YieldXyzGetYieldDefaultsResponse,
|
|
1487
|
+
type YieldXyzGetYieldValidatorsResponse,
|
|
1488
|
+
type YieldDepositParams,
|
|
1489
|
+
type YieldDepositResult,
|
|
1490
|
+
type YieldSubmitOptions,
|
|
1491
|
+
type YieldSubmitProgress,
|
|
1492
|
+
type YieldWithdrawParams,
|
|
1493
|
+
type YieldWithdrawResult,
|
|
1494
|
+
type LifiTradeAssetParams,
|
|
1495
|
+
type LifiTradeAssetOptions,
|
|
1496
|
+
type LifiTradeAssetResult,
|
|
1497
|
+
type LifiPollStatusOptions,
|
|
1498
|
+
type ZeroXTradeAssetParams,
|
|
1499
|
+
type ZeroXTradeAssetOptions,
|
|
1500
|
+
type ZeroXTradeAssetResult,
|
|
1327
1501
|
type ApproveDelegationRequest,
|
|
1328
1502
|
type ApproveDelegationResponse,
|
|
1329
1503
|
type RevokeDelegationRequest,
|
|
@@ -1332,6 +1506,7 @@ export {
|
|
|
1332
1506
|
type DelegationStatusResponse,
|
|
1333
1507
|
type TransferFromRequest,
|
|
1334
1508
|
type TransferFromResponse,
|
|
1509
|
+
type DelegationSubmitProgress,
|
|
1335
1510
|
type EvmAccountTypeGetStatusRequest,
|
|
1336
1511
|
type EvmAccountTypeGetStatusResponse,
|
|
1337
1512
|
type BuildAuthorizationListRequest,
|
|
@@ -1341,16 +1516,23 @@ export {
|
|
|
1341
1516
|
type UpgradeTo7702Request,
|
|
1342
1517
|
type UpgradeTo7702Response,
|
|
1343
1518
|
type GetAddressesResponse,
|
|
1519
|
+
type GetTransactionHistoryParams,
|
|
1520
|
+
type GetTransactionHistoryResponse,
|
|
1521
|
+
type TransactionHistoryItem,
|
|
1522
|
+
type SolanaTransactionDetails,
|
|
1523
|
+
type Transaction,
|
|
1344
1524
|
} from './shared/types'
|
|
1345
1525
|
|
|
1346
1526
|
export type {
|
|
1347
|
-
NoahAmountConditionRow,
|
|
1348
1527
|
NoahGetPaymentMethodsResponse,
|
|
1349
1528
|
NoahGetPaymentMethodsResponseData,
|
|
1350
1529
|
NoahGetPayoutChannelFormResponse,
|
|
1530
|
+
NoahGetPayoutChannelFormResponseData,
|
|
1351
1531
|
NoahGetPayoutChannelsRequest,
|
|
1352
1532
|
NoahGetPayoutChannelsResponse,
|
|
1533
|
+
NoahGetPayoutChannelsResponseData,
|
|
1353
1534
|
NoahGetPayoutCountriesResponse,
|
|
1535
|
+
NoahGetPayoutCountriesResponseData,
|
|
1354
1536
|
NoahGetPayoutQuoteRequest,
|
|
1355
1537
|
NoahGetPayoutQuoteResponse,
|
|
1356
1538
|
NoahGetPayoutQuoteResponseData,
|
|
@@ -1363,7 +1545,6 @@ export type {
|
|
|
1363
1545
|
NoahInitiatePayoutRequest,
|
|
1364
1546
|
NoahInitiatePayoutResponse,
|
|
1365
1547
|
NoahInitiatePayoutResponseData,
|
|
1366
|
-
NoahPayoutConditionBlock,
|
|
1367
1548
|
NoahSingleOnchainDepositSourceTriggerInput,
|
|
1368
1549
|
NoahSimulatePayinRequest,
|
|
1369
1550
|
NoahSimulatePayinResponse,
|
|
@@ -1372,6 +1553,14 @@ export type {
|
|
|
1372
1553
|
PortalApiSuccessEnvelope,
|
|
1373
1554
|
} from './shared/types'
|
|
1374
1555
|
|
|
1556
|
+
export type {
|
|
1557
|
+
TradingOptions,
|
|
1558
|
+
LifiOptions,
|
|
1559
|
+
ZeroXOptions,
|
|
1560
|
+
ILiFi,
|
|
1561
|
+
IZeroX,
|
|
1562
|
+
} from './integrations/trading'
|
|
1563
|
+
|
|
1375
1564
|
export { MpcError, MpcErrorCodes } from './mpc'
|
|
1376
1565
|
|
|
1377
1566
|
export { PortalMpcError } from './mpc/errors'
|