@rhinestone/sdk 2.0.0-beta.4 → 2.0.0-beta.40
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/dist/src/accounts/error.d.ts +2 -9
- package/dist/src/accounts/error.d.ts.map +1 -1
- package/dist/src/accounts/error.js +5 -11
- package/dist/src/accounts/hca.d.ts +25 -0
- package/dist/src/accounts/hca.d.ts.map +1 -0
- package/dist/src/accounts/hca.js +148 -0
- package/dist/src/accounts/index.d.ts +9 -9
- package/dist/src/accounts/index.d.ts.map +1 -1
- package/dist/src/accounts/index.js +119 -43
- package/dist/src/accounts/kernel.d.ts +1 -2
- package/dist/src/accounts/kernel.d.ts.map +1 -1
- package/dist/src/accounts/kernel.js +1 -8
- package/dist/src/accounts/nexus.d.ts +3 -2
- package/dist/src/accounts/nexus.d.ts.map +1 -1
- package/dist/src/accounts/nexus.js +33 -8
- package/dist/src/accounts/safe.d.ts +1 -2
- package/dist/src/accounts/safe.d.ts.map +1 -1
- package/dist/src/accounts/safe.js +3 -9
- package/dist/src/accounts/signing/common.d.ts +1 -4
- package/dist/src/accounts/signing/common.d.ts.map +1 -1
- package/dist/src/accounts/signing/common.js +8 -11
- package/dist/src/accounts/signing/message.d.ts.map +1 -1
- package/dist/src/accounts/signing/message.js +1 -4
- package/dist/src/accounts/signing/typedData.d.ts.map +1 -1
- package/dist/src/accounts/signing/typedData.js +1 -4
- package/dist/src/accounts/startale.d.ts +1 -2
- package/dist/src/accounts/startale.d.ts.map +1 -1
- package/dist/src/accounts/startale.js +6 -9
- package/dist/src/actions/ecdsa.js +5 -5
- package/dist/src/actions/index.js +2 -2
- package/dist/src/actions/mfa.js +2 -2
- package/dist/src/actions/passkeys.js +2 -2
- package/dist/src/actions/smart-sessions.d.ts +29 -5
- package/dist/src/actions/smart-sessions.d.ts.map +1 -1
- package/dist/src/actions/smart-sessions.js +38 -10
- package/dist/src/errors/index.d.ts +6 -4
- package/dist/src/errors/index.d.ts.map +1 -1
- package/dist/src/errors/index.js +6 -6
- package/dist/src/execution/error.d.ts +8 -21
- package/dist/src/execution/error.d.ts.map +1 -1
- package/dist/src/execution/error.js +7 -21
- package/dist/src/execution/index.d.ts +18 -18
- package/dist/src/execution/index.d.ts.map +1 -1
- package/dist/src/execution/index.js +27 -42
- package/dist/src/execution/utils.d.ts +15 -11
- package/dist/src/execution/utils.d.ts.map +1 -1
- package/dist/src/execution/utils.js +281 -80
- package/dist/src/index.d.ts +246 -37
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +82 -116
- package/dist/src/jwt-server/jcs.d.ts +1 -1
- package/dist/src/jwt-server/jcs.js +4 -2
- package/dist/src/modules/index.d.ts.map +1 -1
- package/dist/src/modules/index.js +0 -5
- package/dist/src/modules/read.d.ts +3 -2
- package/dist/src/modules/read.d.ts.map +1 -1
- package/dist/src/modules/read.js +52 -4
- package/dist/src/modules/validators/core.d.ts +6 -6
- package/dist/src/modules/validators/core.d.ts.map +1 -1
- package/dist/src/modules/validators/core.js +42 -39
- package/dist/src/modules/validators/cross-chain-permits.d.ts +21 -0
- package/dist/src/modules/validators/cross-chain-permits.d.ts.map +1 -0
- package/dist/src/modules/validators/cross-chain-permits.js +111 -0
- package/dist/src/modules/validators/permissions.d.ts +1 -0
- package/dist/src/modules/validators/permissions.d.ts.map +1 -1
- package/dist/src/modules/validators/permissions.js +192 -18
- package/dist/src/modules/validators/policies/claim/arbiters.d.ts +22 -0
- package/dist/src/modules/validators/policies/claim/arbiters.d.ts.map +1 -0
- package/dist/src/modules/validators/policies/claim/arbiters.js +57 -0
- package/dist/src/modules/validators/smart-sessions.d.ts +38 -9
- package/dist/src/modules/validators/smart-sessions.d.ts.map +1 -1
- package/dist/src/modules/validators/smart-sessions.js +509 -92
- package/dist/src/orchestrator/caip2.d.ts +16 -3
- package/dist/src/orchestrator/caip2.d.ts.map +1 -1
- package/dist/src/orchestrator/caip2.js +38 -6
- package/dist/src/orchestrator/client.d.ts +2 -1
- package/dist/src/orchestrator/client.d.ts.map +1 -1
- package/dist/src/orchestrator/client.js +50 -24
- package/dist/src/orchestrator/consts.d.ts +1 -1
- package/dist/src/orchestrator/consts.d.ts.map +1 -1
- package/dist/src/orchestrator/consts.js +1 -1
- package/dist/src/orchestrator/destinations.d.ts +24 -0
- package/dist/src/orchestrator/destinations.d.ts.map +1 -0
- package/dist/src/orchestrator/destinations.js +59 -0
- package/dist/src/orchestrator/error.d.ts +95 -5
- package/dist/src/orchestrator/error.d.ts.map +1 -1
- package/dist/src/orchestrator/error.js +260 -4
- package/dist/src/orchestrator/index.d.ts +7 -5
- package/dist/src/orchestrator/index.d.ts.map +1 -1
- package/dist/src/orchestrator/index.js +4 -3
- package/dist/src/orchestrator/registry.d.ts +2 -1
- package/dist/src/orchestrator/registry.d.ts.map +1 -1
- package/dist/src/orchestrator/registry.js +13 -0
- package/dist/src/orchestrator/types.d.ts +92 -29
- package/dist/src/orchestrator/types.d.ts.map +1 -1
- package/dist/src/orchestrator/types.js +1 -5
- package/dist/src/orchestrator/wire.d.ts +30 -0
- package/dist/src/orchestrator/wire.d.ts.map +1 -0
- package/dist/src/orchestrator/wire.gen.d.ts +4290 -0
- package/dist/src/orchestrator/wire.gen.d.ts.map +1 -0
- package/dist/src/orchestrator/wire.gen.js +1 -0
- package/dist/src/orchestrator/wire.js +1 -0
- package/dist/src/smart-sessions/index.d.ts +6 -0
- package/dist/src/smart-sessions/index.d.ts.map +1 -0
- package/dist/src/smart-sessions/index.js +7 -0
- package/dist/src/types.d.ts +299 -31
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/index.d.ts +59 -0
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/index.js +59 -0
- package/package.json +5 -9
- package/dist/src/actions/recovery.d.ts +0 -33
- package/dist/src/actions/recovery.d.ts.map +0 -1
- package/dist/src/actions/recovery.js +0 -189
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import { concat, createPublicClient, createWalletClient, encodeAbiParameters, encodePacked, hashDomain, hashMessage, hashStruct, hashTypedData, isAddress, keccak256, publicActions, toHex, } from 'viem';
|
|
2
2
|
import { entryPoint07Address, getUserOperationHash, } from 'viem/account-abstraction';
|
|
3
3
|
import { wrapTypedDataSignature } from 'viem/experimental/erc7739';
|
|
4
|
-
import { EoaAccountMustHaveAccountError, EoaSigningMethodNotConfiguredError, FactoryArgsNotAvailableError, getAccountProvider, getAddress, getEip712Domain, getEip1271Signature, getEip7702InitCall, getEmissarySignature,
|
|
4
|
+
import { EoaAccountMustHaveAccountError, EoaSigningMethodNotConfiguredError, FactoryArgsNotAvailableError, getAccountProvider, getAddress, getEip712Domain, getEip1271Signature, getEip7702InitCall, getEmissarySignature, getInitCode, getSmartAccount, getTypedDataPackedSignature, is7702, toErc6492Signature, } from '../accounts/index.js';
|
|
5
5
|
import { convertOwnerSetToSignerSet } from '../accounts/signing/common.js';
|
|
6
6
|
import { K1_DEFAULT_VALIDATOR_ADDRESS } from '../accounts/startale.js';
|
|
7
7
|
import { createTransport, getBundlerClient, } from '../accounts/utils.js';
|
|
8
8
|
import { createAuthProvider } from '../auth/provider.js';
|
|
9
9
|
import { buildMockSignature, DUMMY_PRECLAIMOP_SELECTOR, DUMMY_PRECLAIMOP_TARGET, getOwnerValidator, getPermissionId, getSmartSessionValidator, isSessionEnabled, } from '../modules/validators/index.js';
|
|
10
|
-
import { getMultiFactorValidator,
|
|
10
|
+
import { getMultiFactorValidator, getWebAuthnValidator, supportsEip712, } from '../modules/validators/core.js';
|
|
11
11
|
import { buildPermit2ClaimPolicyCalldata, } from '../modules/validators/policies/claim/permit2.js';
|
|
12
|
-
import { resolvePermit2ClaimPolicy, } from '../modules/validators/smart-sessions.js';
|
|
12
|
+
import { resolvePermit2ClaimPolicy, selectPermit2ClaimPolicyForMessage, } from '../modules/validators/smart-sessions.js';
|
|
13
13
|
import { getOrchestrator, } from '../orchestrator/index.js';
|
|
14
|
+
import { isNonEvmChainId, toCaip2 } from '../orchestrator/caip2.js';
|
|
15
|
+
import { getChainId, isNonEvmChain, } from '../orchestrator/destinations.js';
|
|
14
16
|
import { getChainById, getTokenAddress, resolveTokenAddress, } from '../orchestrator/registry.js';
|
|
15
|
-
import { SIG_MODE_EMISSARY_EXECUTION_ERC1271,
|
|
17
|
+
import { SIG_MODE_EMISSARY_EXECUTION_ERC1271, SIG_MODE_ERC1271, } from '../orchestrator/types.js';
|
|
16
18
|
import { convertBigIntFields } from '../orchestrator/utils.js';
|
|
17
|
-
import { Eip7702InitSignatureRequiredError,
|
|
19
|
+
import { Eip7702InitSignatureRequiredError, InvalidSourceCallsError, QuoteNotInPreparedTransactionError, } from './error.js';
|
|
18
20
|
function isResolvedSessionSignerSet(signers) {
|
|
19
21
|
return (signers?.type === 'experimental_session' && 'verifyExecutions' in signers);
|
|
20
22
|
}
|
|
@@ -25,16 +27,61 @@ async function resolveSignersForChain(config, signers, chainId) {
|
|
|
25
27
|
const resolved = resolveSessionForChain(signers, chainId);
|
|
26
28
|
const enabled = await isSessionEnabled(getAddress(config), config.provider, resolved.session, config.useDevContracts);
|
|
27
29
|
const enableData = enabled ? undefined : resolved.enableData;
|
|
28
|
-
const verifyExecutions = resolved.verifyExecutions ??
|
|
29
|
-
signers.verifyExecutions ??
|
|
30
|
-
resolved.session.hasExplicitPermissions;
|
|
31
30
|
return {
|
|
32
31
|
type: 'experimental_session',
|
|
33
32
|
session: resolved.session,
|
|
34
33
|
enableData,
|
|
35
|
-
|
|
34
|
+
// First use of any session must go through the emissary's verifyExecution
|
|
35
|
+
// path: that's the only mechanism that consumes enableData + calls setConfig
|
|
36
|
+
// to install the session on-chain. Once installed, steady-state signing can
|
|
37
|
+
// drop to mode 1 unless the session has explicit permissions to enforce.
|
|
38
|
+
verifyExecutions: !enabled || resolved.session.hasExplicitPermissions,
|
|
36
39
|
};
|
|
37
40
|
}
|
|
41
|
+
// Picks the single signature mode that matches the bytes shape the SDK will
|
|
42
|
+
// actually sign, so the on-chain dispatcher hits the right validator on the
|
|
43
|
+
// first try instead of falling through a hybrid.
|
|
44
|
+
async function resolveSignatureMode(config, signers, sourceChains, targetChainId,
|
|
45
|
+
// Optional pre-resolved per-chain signer sets. When supplied, reuse them
|
|
46
|
+
// instead of resolving again — each resolveSignersForChain does an
|
|
47
|
+
// isSessionEnabled RPC, so sharing one map across mockSignatures, sigMode, and
|
|
48
|
+
// preClaim avoids duplicate calls per intent. The map also defines *which*
|
|
49
|
+
// chains carry a session: the caller omits a non-EVM target (it has no session
|
|
50
|
+
// validator), so deriving the chain set from the map's keys keeps us from
|
|
51
|
+
// resolving — and throwing on — a target with no configured session.
|
|
52
|
+
preResolved) {
|
|
53
|
+
if (config.account?.type === 'eoa') {
|
|
54
|
+
return SIG_MODE_ERC1271;
|
|
55
|
+
}
|
|
56
|
+
if (signers?.type !== 'experimental_session') {
|
|
57
|
+
return SIG_MODE_ERC1271;
|
|
58
|
+
}
|
|
59
|
+
const chainIds = preResolved
|
|
60
|
+
? [...preResolved.keys()]
|
|
61
|
+
: [...new Set([...(sourceChains ?? []).map((c) => c.id), targetChainId])];
|
|
62
|
+
const resolvedSet = await Promise.all(chainIds.map((chainId) =>
|
|
63
|
+
// Use has() not `?? resolve` so a cached `undefined` entry is still reused
|
|
64
|
+
// (get() can't distinguish "missing key" from "present but undefined").
|
|
65
|
+
preResolved?.has(chainId)
|
|
66
|
+
? preResolved.get(chainId)
|
|
67
|
+
: resolveSignersForChain(config, signers, chainId)));
|
|
68
|
+
let anyVerifyExecutions = false;
|
|
69
|
+
for (const resolved of resolvedSet) {
|
|
70
|
+
if (!isResolvedSessionSignerSet(resolved)) {
|
|
71
|
+
return SIG_MODE_ERC1271;
|
|
72
|
+
}
|
|
73
|
+
// Conservative: one chain with verifyExecutions=true forces mode 5 across
|
|
74
|
+
// all origin signatures — a single mode field can't describe divergence.
|
|
75
|
+
if (resolved.verifyExecutions)
|
|
76
|
+
anyVerifyExecutions = true;
|
|
77
|
+
}
|
|
78
|
+
// Mode 4 (pure emissary-execution) is unused: signIntentTypedData always
|
|
79
|
+
// emits a dual sig for the intent's origin/destination signatures when
|
|
80
|
+
// verifyExecutions=true, so mode 5 is the right hybrid.
|
|
81
|
+
return anyVerifyExecutions
|
|
82
|
+
? SIG_MODE_EMISSARY_EXECUTION_ERC1271
|
|
83
|
+
: SIG_MODE_ERC1271;
|
|
84
|
+
}
|
|
38
85
|
function resolveSessionForChain(signers, chainId) {
|
|
39
86
|
if ('sessions' in signers) {
|
|
40
87
|
const config = signers.sessions[chainId];
|
|
@@ -46,13 +93,23 @@ function resolveSessionForChain(signers, chainId) {
|
|
|
46
93
|
return { session: signers.session, enableData: signers.enableData };
|
|
47
94
|
}
|
|
48
95
|
async function prepareTransaction(config, transaction) {
|
|
49
|
-
const { sourceChains, targetChain, tokenRequests, signers, sponsored, eip7702InitSignature, settlementLayers, sourceAssets,
|
|
96
|
+
const { sourceChains, targetChain, tokenRequests, signers, sponsored, eip7702InitSignature, settlementLayers, sourceAssets, auxiliaryFunds, appFees, account, recipient, sourceCalls, } = getTransactionParams(transaction);
|
|
50
97
|
const accountAddress = getAddress(config);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
98
|
+
// Destination calls (transaction.calls on a cross-chain transaction) are
|
|
99
|
+
// executed on the destination chain by the solver/account. For non-EVM
|
|
100
|
+
// destinations we can't resolve arbitrary EVM calls; assert there are
|
|
101
|
+
// none and route an empty list through.
|
|
102
|
+
let resolvedCalls;
|
|
103
|
+
if (isNonEvmChain(targetChain)) {
|
|
104
|
+
if (transaction.calls && transaction.calls.length > 0) {
|
|
105
|
+
throw new Error(`Destination calls are not supported for non-EVM target chain ${targetChain.name} (${targetChain.caip2})`);
|
|
106
|
+
}
|
|
107
|
+
resolvedCalls = [];
|
|
54
108
|
}
|
|
55
|
-
|
|
109
|
+
else {
|
|
110
|
+
resolvedCalls = await resolveCallInputs(transaction.calls, config, targetChain, accountAddress);
|
|
111
|
+
}
|
|
112
|
+
const prepared = await prepareTransactionAsIntent(config, sourceChains, targetChain, resolvedCalls, transaction.gasLimit, tokenRequests, recipient, sponsored, eip7702InitSignature, settlementLayers, sourceAssets, auxiliaryFunds, account, signers, sourceCalls, appFees);
|
|
56
113
|
return {
|
|
57
114
|
quotes: prepared.quotes,
|
|
58
115
|
intentInput: prepared.intentInput,
|
|
@@ -131,6 +188,11 @@ async function getTargetExecutionSignature(config, signData, targetChain, signer
|
|
|
131
188
|
if (!signData.targetExecution) {
|
|
132
189
|
return undefined;
|
|
133
190
|
}
|
|
191
|
+
// Target executions are EVM-only (smart-session validator on destination).
|
|
192
|
+
// Non-EVM destinations don't have a validator there to verify the sig.
|
|
193
|
+
if (isNonEvmChain(targetChain)) {
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
134
196
|
const resolvedSigners = await resolveSignersForChain(config, signers, targetChain.id);
|
|
135
197
|
if (!isResolvedSessionSignerSet(resolvedSigners) ||
|
|
136
198
|
!resolvedSigners.verifyExecutions) {
|
|
@@ -266,10 +328,16 @@ async function signAuthorizationsInternal(config, context) {
|
|
|
266
328
|
}
|
|
267
329
|
const accountAddress = getAddress(config);
|
|
268
330
|
const { contract: eip7702Contract } = getEip7702InitCall(config, eip7702InitSignature);
|
|
331
|
+
// EIP-7702 authorization is EVM-only — there's no contract to delegate
|
|
332
|
+
// to on Solana / Tron. Skip the destination chain entirely when it's
|
|
333
|
+
// non-EVM; source chains are always EVM by construction.
|
|
269
334
|
const chains = new Map();
|
|
270
|
-
for (const chain of
|
|
335
|
+
for (const chain of context.sourceChains ?? []) {
|
|
271
336
|
chains.set(chain.id, chain);
|
|
272
337
|
}
|
|
338
|
+
if (!isNonEvmChain(context.targetChain)) {
|
|
339
|
+
chains.set(context.targetChain.id, context.targetChain);
|
|
340
|
+
}
|
|
273
341
|
const authorizations = [];
|
|
274
342
|
for (const chain of chains.values()) {
|
|
275
343
|
const walletClient = createWalletClient({
|
|
@@ -314,10 +382,11 @@ function getTransactionParams(transaction) {
|
|
|
314
382
|
const gasLimit = transaction.gasLimit;
|
|
315
383
|
const settlementLayers = transaction.settlementLayers;
|
|
316
384
|
const sourceAssets = transaction.sourceAssets;
|
|
317
|
-
const feeAsset = transaction.feeAsset;
|
|
318
385
|
const auxiliaryFunds = transaction.auxiliaryFunds;
|
|
386
|
+
const appFees = transaction.appFees;
|
|
319
387
|
const account = transaction.experimental_accountOverride;
|
|
320
388
|
const recipient = transaction.recipient;
|
|
389
|
+
const sourceCalls = transaction.sourceCalls;
|
|
321
390
|
const tokenRequests = getTokenRequests(targetChain, initialTokenRequests);
|
|
322
391
|
return {
|
|
323
392
|
sourceChains,
|
|
@@ -329,15 +398,23 @@ function getTransactionParams(transaction) {
|
|
|
329
398
|
gasLimit,
|
|
330
399
|
settlementLayers,
|
|
331
400
|
sourceAssets,
|
|
332
|
-
feeAsset,
|
|
333
401
|
auxiliaryFunds,
|
|
402
|
+
appFees,
|
|
334
403
|
account,
|
|
335
404
|
recipient,
|
|
405
|
+
sourceCalls,
|
|
336
406
|
};
|
|
337
407
|
}
|
|
338
408
|
function getTokenRequests(targetChain, initialTokenRequests) {
|
|
339
|
-
|
|
340
|
-
|
|
409
|
+
// Non-EVM destinations carry SPL mint / Tron T-prefixed addresses that
|
|
410
|
+
// aren't valid 0x-hex; skip symbol/EVM-address validation here and let
|
|
411
|
+
// the orchestrator validate per its own schema. EVM destinations keep
|
|
412
|
+
// the existing strict check so a typo on Optimism still fails fast.
|
|
413
|
+
if (initialTokenRequests && !isNonEvmChain(targetChain)) {
|
|
414
|
+
// Inside this branch targetChain is a viem `Chain`, which excludes the
|
|
415
|
+
// non-EVM transaction variant — token requests are EVM-typed here.
|
|
416
|
+
const evmRequests = initialTokenRequests;
|
|
417
|
+
validateTokenSymbols(targetChain, evmRequests.map((tokenRequest) => tokenRequest.address));
|
|
341
418
|
}
|
|
342
419
|
return initialTokenRequests ?? [];
|
|
343
420
|
}
|
|
@@ -386,12 +463,46 @@ function getIntentAccount(config, eip7702InitSignature, account) {
|
|
|
386
463
|
delegations,
|
|
387
464
|
};
|
|
388
465
|
}
|
|
389
|
-
|
|
390
|
-
|
|
466
|
+
function cloneAuxiliaryFunds(auxiliaryFunds) {
|
|
467
|
+
if (!auxiliaryFunds)
|
|
468
|
+
return undefined;
|
|
469
|
+
return Object.fromEntries(Object.entries(auxiliaryFunds).map(([chainId, funds]) => [
|
|
470
|
+
Number(chainId),
|
|
471
|
+
{ ...funds },
|
|
472
|
+
]));
|
|
473
|
+
}
|
|
474
|
+
function toCallInput(sourceCall) {
|
|
475
|
+
const { provides: _provides, ...call } = sourceCall;
|
|
476
|
+
return call;
|
|
477
|
+
}
|
|
478
|
+
function addProvidedFunds(auxiliaryFunds, chainId, calls) {
|
|
479
|
+
let next = auxiliaryFunds;
|
|
480
|
+
for (const call of calls) {
|
|
481
|
+
for (const provided of call.provides ?? []) {
|
|
482
|
+
next ??= {};
|
|
483
|
+
next[chainId] ??= {};
|
|
484
|
+
const token = provided.token;
|
|
485
|
+
next[chainId][token] = (next[chainId][token] ?? 0n) + provided.amount;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return next;
|
|
489
|
+
}
|
|
490
|
+
async function prepareTransactionAsIntent(config, sourceChains, targetChain, callInputs, gasLimit, tokenRequests, recipientInput, sponsored, eip7702InitSignature, settlementLayers, sourceAssets, auxiliaryFunds, account, signers, sourceCalls, appFees) {
|
|
491
|
+
const targetChainId = getChainId(targetChain);
|
|
492
|
+
const calls = parseCalls(callInputs, targetChainId);
|
|
391
493
|
const accountAccessList = createAccountAccessList(sourceChains, sourceAssets);
|
|
392
494
|
function getRecipient(recipient) {
|
|
393
495
|
if (typeof recipient === 'string') {
|
|
394
|
-
//
|
|
496
|
+
// Non-EVM-addressed recipients (Solana base58 / Tron T-prefix) carry no
|
|
497
|
+
// EVM smart-account semantics; the orchestrator schema requires
|
|
498
|
+
// accountType / setupOps to be unset. Emit just the address. HyperCore
|
|
499
|
+
// is EVM-addressed (eip155:1337) so it falls through to the EOA
|
|
500
|
+
// passthrough below — the orchestrator's HyperCore gate requires
|
|
501
|
+
// accountType: 'EOA'.
|
|
502
|
+
if (isNonEvmChainId(targetChainId)) {
|
|
503
|
+
return { address: recipient };
|
|
504
|
+
}
|
|
505
|
+
// EVM (and HyperCore) passthrough — assume EOA.
|
|
395
506
|
return {
|
|
396
507
|
address: recipient,
|
|
397
508
|
accountType: 'EOA',
|
|
@@ -404,25 +515,65 @@ async function prepareTransactionAsIntent(config, sourceChains, targetChain, cal
|
|
|
404
515
|
}
|
|
405
516
|
return getIntentAccount(recipient, eip7702InitSignature, account);
|
|
406
517
|
}
|
|
518
|
+
// Resolve per-chain signer state once (each resolveSignersForChain does an
|
|
519
|
+
// isSessionEnabled RPC) and reuse it for mock signatures, the signature mode,
|
|
520
|
+
// and preClaim ops. Exclude a non-EVM destination — it has no session
|
|
521
|
+
// validator, so resolving it would waste an RPC (or throw for per-chain
|
|
522
|
+
// session signers). resolveSignatureMode derives its chain set from this map's
|
|
523
|
+
// keys, so the excluded non-EVM target is never resolved there either.
|
|
524
|
+
const sessionChainIds = [
|
|
525
|
+
...new Set([
|
|
526
|
+
...(sourceChains ?? []).map((c) => c.id),
|
|
527
|
+
...(isNonEvmChain(targetChain) ? [] : [targetChainId]),
|
|
528
|
+
]),
|
|
529
|
+
];
|
|
530
|
+
const resolvedByChain = signers?.type === 'experimental_session'
|
|
531
|
+
? new Map(await Promise.all(sessionChainIds.map(async (chainId) => [
|
|
532
|
+
chainId,
|
|
533
|
+
await resolveSignersForChain(config, signers, chainId),
|
|
534
|
+
])))
|
|
535
|
+
: undefined;
|
|
536
|
+
// Per-chain mock signatures: enables accurate per-chain session validation gas
|
|
537
|
+
// simulation. Non-EVM destinations are excluded — they have no destination-side
|
|
538
|
+
// session validator. Each chain's mock sig carries that chain's own resolved
|
|
539
|
+
// shape (ENABLE / USE / ERC-1271). Note these are per-chain and may differ in
|
|
540
|
+
// shape, whereas `signatureMode` (below) is a single global value resolved
|
|
541
|
+
// conservatively (anyVerifyExecutions across chains → mode 5) — so in mixed
|
|
542
|
+
// states a chain's mock shape need not match the global signatureMode.
|
|
543
|
+
let mockSignatures;
|
|
544
|
+
if (resolvedByChain) {
|
|
545
|
+
const entries = [...resolvedByChain.entries()].flatMap(([chainId, resolved]) => {
|
|
546
|
+
// resolvedByChain is keyed by sessionChainIds, which already excludes a
|
|
547
|
+
// non-EVM target — so no per-entry target guard is needed here.
|
|
548
|
+
if (!isResolvedSessionSignerSet(resolved))
|
|
549
|
+
return [];
|
|
550
|
+
// Match the mock shape to what the real sig will be: ERC-1271 when not
|
|
551
|
+
// verifying executions; otherwise ENABLE if the session still needs
|
|
552
|
+
// installing (enableData present), else USE (already enabled, e.g.
|
|
553
|
+
// explicit permissions — its real sig is MODE_USE with no enableData).
|
|
554
|
+
const shape = !resolved.verifyExecutions
|
|
555
|
+
? 'erc1271'
|
|
556
|
+
: resolved.enableData !== undefined
|
|
557
|
+
? 'enable'
|
|
558
|
+
: 'use';
|
|
559
|
+
return [
|
|
560
|
+
[
|
|
561
|
+
String(chainId),
|
|
562
|
+
buildMockSignature(resolved.session, config.useDevContracts, sourceChains?.length ?? 1, chainId, shape),
|
|
563
|
+
],
|
|
564
|
+
];
|
|
565
|
+
});
|
|
566
|
+
// Leave mockSignatures undefined (not {}) when there are no eligible chains,
|
|
567
|
+
// so downstream consumers can treat presence as "per-chain sigs provided".
|
|
568
|
+
if (entries.length > 0)
|
|
569
|
+
mockSignatures = Object.fromEntries(entries);
|
|
570
|
+
}
|
|
407
571
|
const intentAccount = {
|
|
408
572
|
...getIntentAccount(config, eip7702InitSignature, account),
|
|
409
|
-
...(
|
|
410
|
-
// Per-chain map: enables accurate per-chain session validation gas simulation
|
|
411
|
-
mockSignatures: Object.fromEntries([
|
|
412
|
-
...new Set([
|
|
413
|
-
...(sourceChains ?? []).map((c) => c.id),
|
|
414
|
-
targetChain.id,
|
|
415
|
-
]),
|
|
416
|
-
].map((chainId) => [
|
|
417
|
-
String(chainId),
|
|
418
|
-
buildMockSignature(resolveSessionForChain(signers, chainId).session, config.useDevContracts, sourceChains?.length ?? 1, chainId),
|
|
419
|
-
])),
|
|
420
|
-
}),
|
|
573
|
+
...(mockSignatures && { mockSignatures }),
|
|
421
574
|
};
|
|
422
575
|
const recipient = getRecipient(recipientInput);
|
|
423
|
-
const signatureMode = signers
|
|
424
|
-
? SIG_MODE_EMISSARY_EXECUTION_ERC1271
|
|
425
|
-
: SIG_MODE_ERC1271_EMISSARY;
|
|
576
|
+
const signatureMode = await resolveSignatureMode(config, signers, sourceChains, targetChainId, resolvedByChain);
|
|
426
577
|
// For session signers that need enabling, pass a dummy preclaimop per source chain
|
|
427
578
|
// so the orchestrator bakes it into the bundle before computing its HMAC. The filler
|
|
428
579
|
// executes the op via verifyExecution in ENABLE mode, enabling the session on-chain
|
|
@@ -430,11 +581,11 @@ async function prepareTransactionAsIntent(config, sourceChains, targetChain, cal
|
|
|
430
581
|
// post-facto — because the orchestrator HMAC covers preClaimOps.
|
|
431
582
|
const preClaimExecutions = {};
|
|
432
583
|
if (signers?.type === 'experimental_session' && sourceChains) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
584
|
+
// Reuse the shared per-chain resolution (source chains are a subset of
|
|
585
|
+
// sessionChainIds) instead of resolving — and re-doing isSessionEnabled — again.
|
|
586
|
+
for (const chain of sourceChains) {
|
|
587
|
+
const chainId = chain.id;
|
|
588
|
+
const resolved = resolvedByChain?.get(chainId);
|
|
438
589
|
if (!isResolvedSessionSignerSet(resolved))
|
|
439
590
|
continue;
|
|
440
591
|
const { enableData, verifyExecutions } = resolved;
|
|
@@ -449,10 +600,40 @@ async function prepareTransactionAsIntent(config, sourceChains, targetChain, cal
|
|
|
449
600
|
];
|
|
450
601
|
}
|
|
451
602
|
}
|
|
603
|
+
let combinedAuxiliaryFunds = cloneAuxiliaryFunds(auxiliaryFunds);
|
|
604
|
+
if (sourceCalls) {
|
|
605
|
+
const accountAddress = getAddress(config);
|
|
606
|
+
const allowedChainIds = new Set([
|
|
607
|
+
...(sourceChains ?? []).map((c) => c.id),
|
|
608
|
+
...(!isNonEvmChain(targetChain) ? [targetChainId] : []),
|
|
609
|
+
]);
|
|
610
|
+
for (const [chainIdStr, calls] of Object.entries(sourceCalls)) {
|
|
611
|
+
const chainId = Number(chainIdStr);
|
|
612
|
+
if (!allowedChainIds.has(chainId)) {
|
|
613
|
+
throw new InvalidSourceCallsError({ chainId });
|
|
614
|
+
}
|
|
615
|
+
const chain = sourceChains?.find((c) => c.id === chainId) ??
|
|
616
|
+
(!isNonEvmChain(targetChain) && targetChainId === chainId
|
|
617
|
+
? targetChain
|
|
618
|
+
: undefined);
|
|
619
|
+
if (!chain) {
|
|
620
|
+
throw new InvalidSourceCallsError({ chainId });
|
|
621
|
+
}
|
|
622
|
+
combinedAuxiliaryFunds = addProvidedFunds(combinedAuxiliaryFunds, chainId, calls);
|
|
623
|
+
const resolved = await resolveCallInputs(calls.map(toCallInput), config, chain, accountAddress);
|
|
624
|
+
const userExecutions = parseCalls(resolved, chainId);
|
|
625
|
+
if (userExecutions.length === 0)
|
|
626
|
+
continue;
|
|
627
|
+
preClaimExecutions[chainId] = [
|
|
628
|
+
...(preClaimExecutions[chainId] ?? []),
|
|
629
|
+
...userExecutions,
|
|
630
|
+
];
|
|
631
|
+
}
|
|
632
|
+
}
|
|
452
633
|
const metaIntent = {
|
|
453
|
-
destinationChainId:
|
|
634
|
+
destinationChainId: targetChainId,
|
|
454
635
|
tokenRequests: tokenRequests.map((tokenRequest) => ({
|
|
455
|
-
tokenAddress: resolveTokenAddress(tokenRequest.address,
|
|
636
|
+
tokenAddress: resolveTokenAddress(tokenRequest.address, targetChainId),
|
|
456
637
|
amount: tokenRequest.amount,
|
|
457
638
|
})),
|
|
458
639
|
recipient,
|
|
@@ -461,7 +642,6 @@ async function prepareTransactionAsIntent(config, sourceChains, targetChain, cal
|
|
|
461
642
|
destinationGasUnits: gasLimit,
|
|
462
643
|
accountAccessList,
|
|
463
644
|
options: {
|
|
464
|
-
feeToken: feeAsset,
|
|
465
645
|
sponsorSettings: sponsored
|
|
466
646
|
? typeof sponsored === 'object'
|
|
467
647
|
? {
|
|
@@ -477,19 +657,20 @@ async function prepareTransactionAsIntent(config, sourceChains, targetChain, cal
|
|
|
477
657
|
: undefined,
|
|
478
658
|
settlementLayers,
|
|
479
659
|
signatureMode,
|
|
480
|
-
auxiliaryFunds,
|
|
660
|
+
auxiliaryFunds: combinedAuxiliaryFunds,
|
|
661
|
+
appFees,
|
|
481
662
|
},
|
|
482
663
|
...(Object.keys(preClaimExecutions).length > 0 && { preClaimExecutions }),
|
|
483
664
|
};
|
|
484
665
|
const serializedIntent = convertBigIntFields(metaIntent);
|
|
485
666
|
const orchestrator = getOrchestrator(config._authProvider ?? createAuthProvider(config), config.endpointUrl, config.headers);
|
|
486
|
-
const { routes } = await orchestrator.createQuote(metaIntent);
|
|
667
|
+
const { routes, traceId } = await orchestrator.createQuote(metaIntent);
|
|
487
668
|
const best = routes[0];
|
|
488
669
|
if (!best) {
|
|
489
670
|
throw new Error('Orchestrator returned no quote');
|
|
490
671
|
}
|
|
491
672
|
return {
|
|
492
|
-
quotes: { best, all: routes },
|
|
673
|
+
quotes: { traceId, best, all: routes },
|
|
493
674
|
intentInput: serializedIntent,
|
|
494
675
|
};
|
|
495
676
|
}
|
|
@@ -529,7 +710,14 @@ async function signIntent(config, signData, targetChain, signers, targetExecutio
|
|
|
529
710
|
const signature = await signIntentTypedData(config, originSigners, validator, isRoot, typedData, chain, targetExecution ?? false);
|
|
530
711
|
originSignatures.push(signature);
|
|
531
712
|
}
|
|
532
|
-
|
|
713
|
+
// Non-EVM destinations have no destination-side validator, so there's no
|
|
714
|
+
// session to resolve and no signer to derive. Skipping here matters for
|
|
715
|
+
// per-chain experimental sessions: `resolveSessionForChain` would throw
|
|
716
|
+
// `No session configured for chain {synthetic-id}` since users never
|
|
717
|
+
// configure a session keyed by the synthetic Solana/Tron chain id.
|
|
718
|
+
const destinationSigners = isNonEvmChain(targetChain)
|
|
719
|
+
? undefined
|
|
720
|
+
: await resolveSignersForChain(config, signers, targetChain.id);
|
|
533
721
|
const destinationSignature = await getDestinationSignature(config, destinationSigners, validator, isRoot, targetChain, destination, originSignatures, targetExecution ?? false);
|
|
534
722
|
return {
|
|
535
723
|
originSignatures,
|
|
@@ -537,18 +725,25 @@ async function signIntent(config, signData, targetChain, signers, targetExecutio
|
|
|
537
725
|
};
|
|
538
726
|
}
|
|
539
727
|
async function getDestinationSignature(config, signers, validator, isRoot, targetChain, destination, originSignatures, targetExecution) {
|
|
540
|
-
//
|
|
541
|
-
// session enable data
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
728
|
+
// Non-EVM destinations have no destination-side validator, no
|
|
729
|
+
// eip712Domain(), no smart session enable data. Settlement is solver-
|
|
730
|
+
// mediated on the orchestrator side and the origin signatures alone
|
|
731
|
+
// authorize the bundle. Fall through to the "reuse last origin sig"
|
|
732
|
+
// branch instead of trying to sign on Solana / Tron.
|
|
733
|
+
if (!isNonEvmChain(targetChain)) {
|
|
734
|
+
// Smart sessions require a separate destination signature because the
|
|
735
|
+
// session enable data differs per chain
|
|
736
|
+
if (signers?.type === 'experimental_session') {
|
|
737
|
+
return await signDestinationSeparately(config, signers, validator, isRoot, targetChain, destination, targetExecution);
|
|
738
|
+
}
|
|
739
|
+
// ERC-7739 with K1 validator requires a separate destination signature because
|
|
740
|
+
// the account's eip712Domain() returns the target chain's chainId, which differs
|
|
741
|
+
// from the origin chain used for the last origin signature
|
|
742
|
+
const isK1Validator = validator.address.toLowerCase() ===
|
|
743
|
+
K1_DEFAULT_VALIDATOR_ADDRESS.toLowerCase();
|
|
744
|
+
if (isK1Validator && supportsEip712(validator)) {
|
|
745
|
+
return await signDestinationSeparately(config, signers, validator, isRoot, targetChain, destination, targetExecution);
|
|
746
|
+
}
|
|
552
747
|
}
|
|
553
748
|
const lastOriginSignature = originSignatures.at(-1);
|
|
554
749
|
return typeof lastOriginSignature === 'object'
|
|
@@ -628,7 +823,17 @@ function resolveClaimPolicyData(signers, parameters) {
|
|
|
628
823
|
typeof msg.deadline !== 'bigint') {
|
|
629
824
|
return undefined;
|
|
630
825
|
}
|
|
631
|
-
|
|
826
|
+
const message = parameters.message;
|
|
827
|
+
// A session may carry several claim policies (a user policy plus one or
|
|
828
|
+
// more synthesized cross-chain permits). The on-chain emissary validates
|
|
829
|
+
// against the policy that matches this Permit2 message, and the calldata
|
|
830
|
+
// layout is policy-specific — so we must build it from the matching policy,
|
|
831
|
+
// not blindly `claimPolicies[0]`.
|
|
832
|
+
const claimPolicy = selectPermit2ClaimPolicyForMessage(signers.session.claimPolicies, message);
|
|
833
|
+
if (!claimPolicy) {
|
|
834
|
+
return undefined;
|
|
835
|
+
}
|
|
836
|
+
return buildPermit2ClaimPolicyCalldata(resolvePermit2ClaimPolicy(claimPolicy), message);
|
|
632
837
|
}
|
|
633
838
|
async function signIntentTypedData(config, signers, validator, isRoot, parameters, chain, targetExecution) {
|
|
634
839
|
if (supportsEip712(validator)) {
|
|
@@ -757,7 +962,7 @@ async function submitIntentInternal(config, sourceChains, targetChain, quote, or
|
|
|
757
962
|
...(authorizations.length > 0 && {
|
|
758
963
|
authorizations: {
|
|
759
964
|
sponsor: authorizations.map((authorization) => ({
|
|
760
|
-
chainId: authorization.chainId,
|
|
965
|
+
chainId: toCaip2(authorization.chainId),
|
|
761
966
|
address: authorization.address,
|
|
762
967
|
nonce: authorization.nonce,
|
|
763
968
|
yParity: authorization.yParity ?? 0,
|
|
@@ -774,8 +979,9 @@ async function submitIntentInternal(config, sourceChains, targetChain, quote, or
|
|
|
774
979
|
return {
|
|
775
980
|
type: 'intent',
|
|
776
981
|
id: response.intentId,
|
|
982
|
+
traceId: response.traceId,
|
|
777
983
|
sourceChains: sourceChains?.map((chain) => chain.id),
|
|
778
|
-
targetChain: targetChain
|
|
984
|
+
targetChain: getChainId(targetChain),
|
|
779
985
|
};
|
|
780
986
|
}
|
|
781
987
|
async function getValidatorAccount(config, signers, publicClient, chain) {
|
|
@@ -787,13 +993,7 @@ async function getValidatorAccount(config, signers, publicClient, chain) {
|
|
|
787
993
|
if (withOwner) {
|
|
788
994
|
return getSmartAccount(config, publicClient, chain);
|
|
789
995
|
}
|
|
790
|
-
|
|
791
|
-
return withGuardians
|
|
792
|
-
? await getGuardianSmartAccount(config, publicClient, chain, {
|
|
793
|
-
type: 'ecdsa',
|
|
794
|
-
accounts: withGuardians.guardians,
|
|
795
|
-
})
|
|
796
|
-
: null;
|
|
996
|
+
return null;
|
|
797
997
|
}
|
|
798
998
|
function getValidator(config, signers) {
|
|
799
999
|
if (!signers) {
|
|
@@ -812,11 +1012,11 @@ function getValidator(config, signers) {
|
|
|
812
1012
|
return getWebAuthnValidator(1, withOwner.accounts.map((account) => ({
|
|
813
1013
|
pubKey: account.publicKey,
|
|
814
1014
|
authenticatorId: account.id,
|
|
815
|
-
})));
|
|
1015
|
+
})), withOwner.module);
|
|
816
1016
|
}
|
|
817
1017
|
// Multi-factor
|
|
818
1018
|
if (withOwner.kind === 'multi-factor') {
|
|
819
|
-
return getMultiFactorValidator(1, withOwner.validators);
|
|
1019
|
+
return getMultiFactorValidator(1, withOwner.validators, withOwner.module);
|
|
820
1020
|
}
|
|
821
1021
|
}
|
|
822
1022
|
// Smart sessions
|
|
@@ -824,15 +1024,12 @@ function getValidator(config, signers) {
|
|
|
824
1024
|
if (withSession) {
|
|
825
1025
|
return getSmartSessionValidator(config);
|
|
826
1026
|
}
|
|
827
|
-
// Guardians (social recovery)
|
|
828
|
-
const withGuardians = signers.type === 'guardians' ? signers : null;
|
|
829
|
-
if (withGuardians) {
|
|
830
|
-
return getSocialRecoveryValidator(withGuardians.guardians);
|
|
831
|
-
}
|
|
832
1027
|
// Fallback
|
|
833
1028
|
return undefined;
|
|
834
1029
|
}
|
|
835
1030
|
function parseCalls(calls, chainId) {
|
|
1031
|
+
// Destination calls only run on EVM chains (non-EVM destinations reject
|
|
1032
|
+
// calls upstream), so the resolved `to` is always a viem `Address` here.
|
|
836
1033
|
return calls.map((call) => ({
|
|
837
1034
|
data: call.data ?? '0x',
|
|
838
1035
|
value: call.value ?? 0n,
|
|
@@ -852,6 +1049,8 @@ function createAccountAccessList(sourceChains, sourceAssets) {
|
|
|
852
1049
|
const chainTokenAmounts = {};
|
|
853
1050
|
for (const config of sourceAssets) {
|
|
854
1051
|
const chainId = config.chain.id;
|
|
1052
|
+
// Source assets live on viem `Chain`s, which are always EVM, so the
|
|
1053
|
+
// resolved value is a viem `Address`.
|
|
855
1054
|
const tokenAddress = resolveTokenAddress(config.address, config.chain.id);
|
|
856
1055
|
if (config.amount !== undefined) {
|
|
857
1056
|
if (!chainTokenAmounts[chainId])
|
|
@@ -999,7 +1198,9 @@ function hashErc7739TypedDataForSolady({ domain, types, primaryType, message, ve
|
|
|
999
1198
|
deps.delete(primary);
|
|
1000
1199
|
const sorted = [primary, ...Array.from(deps).sort()];
|
|
1001
1200
|
return sorted
|
|
1002
|
-
.map((t) => `${t}(${allTypes[t]
|
|
1201
|
+
.map((t) => `${t}(${allTypes[t]
|
|
1202
|
+
.map((f) => `${f.type} ${f.name}`)
|
|
1203
|
+
.join(',')})`)
|
|
1003
1204
|
.join('');
|
|
1004
1205
|
}
|
|
1005
1206
|
const contentsType = encodeTypeString(primaryType, types);
|
|
@@ -1051,4 +1252,4 @@ function hashErc7739TypedDataForSolady({ domain, types, primaryType, message, ve
|
|
|
1051
1252
|
// Final hash: keccak256("\x19\x01" || appDomainSep || structHash)
|
|
1052
1253
|
return keccak256(concat(['0x1901', appDomainSeparator, structHash]));
|
|
1053
1254
|
}
|
|
1054
|
-
export { prepareTransaction, getTransactionMessages, signTransaction, signAuthorizations, signAuthorizationsInternal, signMessage, signTypedData, submitTransaction, prepareUserOperation, signUserOperation, submitUserOperation, signIntent, prepareTransactionAsIntent, submitIntentInternal, getValidatorAccount, parseCalls, getTokenRequests, resolveCallInputs, getIntentAccount, getTargetExecutionSignature, hashErc7739TypedDataForSolady, resolveSessionForChain, };
|
|
1255
|
+
export { prepareTransaction, getTransactionMessages, signTransaction, signAuthorizations, signAuthorizationsInternal, signMessage, signTypedData, submitTransaction, prepareUserOperation, signUserOperation, submitUserOperation, signIntent, prepareTransactionAsIntent, submitIntentInternal, getValidatorAccount, parseCalls, getTokenRequests, resolveCallInputs, getIntentAccount, getTargetExecutionSignature, hashErc7739TypedDataForSolady, resolveSessionForChain, resolveSignatureMode, };
|