@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.
Files changed (114) hide show
  1. package/dist/src/accounts/error.d.ts +2 -9
  2. package/dist/src/accounts/error.d.ts.map +1 -1
  3. package/dist/src/accounts/error.js +5 -11
  4. package/dist/src/accounts/hca.d.ts +25 -0
  5. package/dist/src/accounts/hca.d.ts.map +1 -0
  6. package/dist/src/accounts/hca.js +148 -0
  7. package/dist/src/accounts/index.d.ts +9 -9
  8. package/dist/src/accounts/index.d.ts.map +1 -1
  9. package/dist/src/accounts/index.js +119 -43
  10. package/dist/src/accounts/kernel.d.ts +1 -2
  11. package/dist/src/accounts/kernel.d.ts.map +1 -1
  12. package/dist/src/accounts/kernel.js +1 -8
  13. package/dist/src/accounts/nexus.d.ts +3 -2
  14. package/dist/src/accounts/nexus.d.ts.map +1 -1
  15. package/dist/src/accounts/nexus.js +33 -8
  16. package/dist/src/accounts/safe.d.ts +1 -2
  17. package/dist/src/accounts/safe.d.ts.map +1 -1
  18. package/dist/src/accounts/safe.js +3 -9
  19. package/dist/src/accounts/signing/common.d.ts +1 -4
  20. package/dist/src/accounts/signing/common.d.ts.map +1 -1
  21. package/dist/src/accounts/signing/common.js +8 -11
  22. package/dist/src/accounts/signing/message.d.ts.map +1 -1
  23. package/dist/src/accounts/signing/message.js +1 -4
  24. package/dist/src/accounts/signing/typedData.d.ts.map +1 -1
  25. package/dist/src/accounts/signing/typedData.js +1 -4
  26. package/dist/src/accounts/startale.d.ts +1 -2
  27. package/dist/src/accounts/startale.d.ts.map +1 -1
  28. package/dist/src/accounts/startale.js +6 -9
  29. package/dist/src/actions/ecdsa.js +5 -5
  30. package/dist/src/actions/index.js +2 -2
  31. package/dist/src/actions/mfa.js +2 -2
  32. package/dist/src/actions/passkeys.js +2 -2
  33. package/dist/src/actions/smart-sessions.d.ts +29 -5
  34. package/dist/src/actions/smart-sessions.d.ts.map +1 -1
  35. package/dist/src/actions/smart-sessions.js +38 -10
  36. package/dist/src/errors/index.d.ts +6 -4
  37. package/dist/src/errors/index.d.ts.map +1 -1
  38. package/dist/src/errors/index.js +6 -6
  39. package/dist/src/execution/error.d.ts +8 -21
  40. package/dist/src/execution/error.d.ts.map +1 -1
  41. package/dist/src/execution/error.js +7 -21
  42. package/dist/src/execution/index.d.ts +18 -18
  43. package/dist/src/execution/index.d.ts.map +1 -1
  44. package/dist/src/execution/index.js +27 -42
  45. package/dist/src/execution/utils.d.ts +15 -11
  46. package/dist/src/execution/utils.d.ts.map +1 -1
  47. package/dist/src/execution/utils.js +281 -80
  48. package/dist/src/index.d.ts +246 -37
  49. package/dist/src/index.d.ts.map +1 -1
  50. package/dist/src/index.js +82 -116
  51. package/dist/src/jwt-server/jcs.d.ts +1 -1
  52. package/dist/src/jwt-server/jcs.js +4 -2
  53. package/dist/src/modules/index.d.ts.map +1 -1
  54. package/dist/src/modules/index.js +0 -5
  55. package/dist/src/modules/read.d.ts +3 -2
  56. package/dist/src/modules/read.d.ts.map +1 -1
  57. package/dist/src/modules/read.js +52 -4
  58. package/dist/src/modules/validators/core.d.ts +6 -6
  59. package/dist/src/modules/validators/core.d.ts.map +1 -1
  60. package/dist/src/modules/validators/core.js +42 -39
  61. package/dist/src/modules/validators/cross-chain-permits.d.ts +21 -0
  62. package/dist/src/modules/validators/cross-chain-permits.d.ts.map +1 -0
  63. package/dist/src/modules/validators/cross-chain-permits.js +111 -0
  64. package/dist/src/modules/validators/permissions.d.ts +1 -0
  65. package/dist/src/modules/validators/permissions.d.ts.map +1 -1
  66. package/dist/src/modules/validators/permissions.js +192 -18
  67. package/dist/src/modules/validators/policies/claim/arbiters.d.ts +22 -0
  68. package/dist/src/modules/validators/policies/claim/arbiters.d.ts.map +1 -0
  69. package/dist/src/modules/validators/policies/claim/arbiters.js +57 -0
  70. package/dist/src/modules/validators/smart-sessions.d.ts +38 -9
  71. package/dist/src/modules/validators/smart-sessions.d.ts.map +1 -1
  72. package/dist/src/modules/validators/smart-sessions.js +509 -92
  73. package/dist/src/orchestrator/caip2.d.ts +16 -3
  74. package/dist/src/orchestrator/caip2.d.ts.map +1 -1
  75. package/dist/src/orchestrator/caip2.js +38 -6
  76. package/dist/src/orchestrator/client.d.ts +2 -1
  77. package/dist/src/orchestrator/client.d.ts.map +1 -1
  78. package/dist/src/orchestrator/client.js +50 -24
  79. package/dist/src/orchestrator/consts.d.ts +1 -1
  80. package/dist/src/orchestrator/consts.d.ts.map +1 -1
  81. package/dist/src/orchestrator/consts.js +1 -1
  82. package/dist/src/orchestrator/destinations.d.ts +24 -0
  83. package/dist/src/orchestrator/destinations.d.ts.map +1 -0
  84. package/dist/src/orchestrator/destinations.js +59 -0
  85. package/dist/src/orchestrator/error.d.ts +95 -5
  86. package/dist/src/orchestrator/error.d.ts.map +1 -1
  87. package/dist/src/orchestrator/error.js +260 -4
  88. package/dist/src/orchestrator/index.d.ts +7 -5
  89. package/dist/src/orchestrator/index.d.ts.map +1 -1
  90. package/dist/src/orchestrator/index.js +4 -3
  91. package/dist/src/orchestrator/registry.d.ts +2 -1
  92. package/dist/src/orchestrator/registry.d.ts.map +1 -1
  93. package/dist/src/orchestrator/registry.js +13 -0
  94. package/dist/src/orchestrator/types.d.ts +92 -29
  95. package/dist/src/orchestrator/types.d.ts.map +1 -1
  96. package/dist/src/orchestrator/types.js +1 -5
  97. package/dist/src/orchestrator/wire.d.ts +30 -0
  98. package/dist/src/orchestrator/wire.d.ts.map +1 -0
  99. package/dist/src/orchestrator/wire.gen.d.ts +4290 -0
  100. package/dist/src/orchestrator/wire.gen.d.ts.map +1 -0
  101. package/dist/src/orchestrator/wire.gen.js +1 -0
  102. package/dist/src/orchestrator/wire.js +1 -0
  103. package/dist/src/smart-sessions/index.d.ts +6 -0
  104. package/dist/src/smart-sessions/index.d.ts.map +1 -0
  105. package/dist/src/smart-sessions/index.js +7 -0
  106. package/dist/src/types.d.ts +299 -31
  107. package/dist/src/types.d.ts.map +1 -1
  108. package/dist/src/utils/index.d.ts +59 -0
  109. package/dist/src/utils/index.d.ts.map +1 -1
  110. package/dist/src/utils/index.js +59 -0
  111. package/package.json +5 -9
  112. package/dist/src/actions/recovery.d.ts +0 -33
  113. package/dist/src/actions/recovery.d.ts.map +0 -1
  114. 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, getGuardianSmartAccount, getInitCode, getSmartAccount, getTypedDataPackedSignature, is7702, toErc6492Signature, } from '../accounts/index.js';
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, getSocialRecoveryValidator, getWebAuthnValidator, supportsEip712, } from '../modules/validators/core.js';
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, SIG_MODE_ERC1271_EMISSARY, } from '../orchestrator/types.js';
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, QuoteNotInPreparedTransactionError, SignerNotSupportedError, } from './error.js';
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
- verifyExecutions,
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, feeAsset, auxiliaryFunds, account, recipient, } = getTransactionParams(transaction);
96
+ const { sourceChains, targetChain, tokenRequests, signers, sponsored, eip7702InitSignature, settlementLayers, sourceAssets, auxiliaryFunds, appFees, account, recipient, sourceCalls, } = getTransactionParams(transaction);
50
97
  const accountAddress = getAddress(config);
51
- const isUserOpSigner = signers?.type === 'guardians';
52
- if (isUserOpSigner) {
53
- throw new SignerNotSupportedError();
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
- const prepared = await prepareTransactionAsIntent(config, sourceChains, targetChain, await resolveCallInputs(transaction.calls, config, targetChain, accountAddress), transaction.gasLimit, tokenRequests, recipient, sponsored, eip7702InitSignature, settlementLayers, sourceAssets, feeAsset, auxiliaryFunds, account, signers);
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 [...(context.sourceChains ?? []), context.targetChain]) {
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
- if (initialTokenRequests) {
340
- validateTokenSymbols(targetChain, initialTokenRequests.map((tokenRequest) => tokenRequest.address));
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
- async function prepareTransactionAsIntent(config, sourceChains, targetChain, callInputs, gasLimit, tokenRequests, recipientInput, sponsored, eip7702InitSignature, settlementLayers, sourceAssets, feeAsset, auxiliaryFunds, account, signers) {
390
- const calls = parseCalls(callInputs, targetChain.id);
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
- // Passed as an address, assume it's an EOA
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
- ...(signers?.type === 'experimental_session' && {
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?.type === 'experimental_session'
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
- const resolvedPerChain = await Promise.all(sourceChains.map(async (chain) => ({
434
- chainId: chain.id,
435
- resolved: await resolveSignersForChain(config, signers, chain.id),
436
- })));
437
- for (const { chainId, resolved } of resolvedPerChain) {
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: targetChain.id,
634
+ destinationChainId: targetChainId,
454
635
  tokenRequests: tokenRequests.map((tokenRequest) => ({
455
- tokenAddress: resolveTokenAddress(tokenRequest.address, targetChain.id),
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
- const destinationSigners = await resolveSignersForChain(config, signers, targetChain.id);
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
- // Smart sessions require a separate destination signature because the
541
- // session enable data differs per chain
542
- if (signers?.type === 'experimental_session') {
543
- return await signDestinationSeparately(config, signers, validator, isRoot, targetChain, destination, targetExecution);
544
- }
545
- // ERC-7739 with K1 validator requires a separate destination signature because
546
- // the account's eip712Domain() returns the target chain's chainId, which differs
547
- // from the origin chain used for the last origin signature
548
- const isK1Validator = validator.address.toLowerCase() ===
549
- K1_DEFAULT_VALIDATOR_ADDRESS.toLowerCase();
550
- if (isK1Validator && supportsEip712(validator)) {
551
- return await signDestinationSeparately(config, signers, validator, isRoot, targetChain, destination, targetExecution);
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
- return buildPermit2ClaimPolicyCalldata(resolvePermit2ClaimPolicy(signers.session.claimPolicies[0]), parameters.message);
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.id,
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
- const withGuardians = signers.type === 'guardians' ? signers : null;
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].map((f) => `${f.type} ${f.name}`).join(',')})`)
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, };