@rhinestone/sdk 2.0.0-beta.4 → 2.0.0-beta.41

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 +23 -10
  8. package/dist/src/accounts/index.d.ts.map +1 -1
  9. package/dist/src/accounts/index.js +170 -79
  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 +10 -4
  20. package/dist/src/accounts/signing/common.d.ts.map +1 -1
  21. package/dist/src/accounts/signing/common.js +48 -46
  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 +42 -11
  40. package/dist/src/execution/error.d.ts.map +1 -1
  41. package/dist/src/execution/error.js +53 -15
  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 +55 -14
  46. package/dist/src/execution/utils.d.ts.map +1 -1
  47. package/dist/src/execution/utils.js +629 -82
  48. package/dist/src/index.d.ts +270 -38
  49. package/dist/src/index.d.ts.map +1 -1
  50. package/dist/src/index.js +89 -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
- import { concat, createPublicClient, createWalletClient, encodeAbiParameters, encodePacked, hashDomain, hashMessage, hashStruct, hashTypedData, isAddress, keccak256, publicActions, toHex, } from 'viem';
1
+ import { concat, createPublicClient, createWalletClient, encodeAbiParameters, encodePacked, hashDomain, hashMessage, hashStruct, hashTypedData, isAddress, keccak256, pad, 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';
5
- import { convertOwnerSetToSignerSet } from '../accounts/signing/common.js';
4
+ import { EoaAccountMustHaveAccountError, EoaSigningMethodNotConfiguredError, FactoryArgsNotAvailableError, getAccountProvider, getAddress, getEip712Domain, getEip1271Signature, getEip7702InitCall, getEmissarySignature, getInitCode, getOwnerEcdsaSignature, getOwnerPasskeySignature, getSmartAccount, getTypedDataPackedSignature, is7702, packAccountSignature, toErc6492Signature, } from '../accounts/index.js';
5
+ import { convertOwnerSetToSignerSet, packMultiFactorOwnerSignatures, packPasskeyOwnerSignatures, } 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, getValidator as getValidatorModule, 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, IndependentSigningNotSupportedError, InsufficientOwnerSignaturesError, InvalidOwnerSigningOptionsError, InvalidSourceCallsError, MismatchedOwnerSignaturesError, QuoteNotInPreparedTransactionError, UnknownOwnerError, } 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,
@@ -96,6 +153,9 @@ function getTransactionMessages(_config, preparedTransaction, options) {
96
153
  return getIntentMessages(quote.signData);
97
154
  }
98
155
  async function signTransaction(config, preparedTransaction, options) {
156
+ if (options && 'owner' in options) {
157
+ return signTransactionAsOwner(config, preparedTransaction, options);
158
+ }
99
159
  const { signers } = getTransactionParams(preparedTransaction.transaction);
100
160
  const quote = resolveQuote(preparedTransaction.quotes, options);
101
161
  const targetChain = 'targetChain' in preparedTransaction.transaction
@@ -113,6 +173,349 @@ async function signTransaction(config, preparedTransaction, options) {
113
173
  targetExecutionSignature,
114
174
  };
115
175
  }
176
+ function assertIndependentSigningSupported(config, preparedTransaction) {
177
+ if (config.account?.type === 'eoa') {
178
+ throw new IndependentSigningNotSupportedError({
179
+ context: { reason: 'eoa-account' },
180
+ });
181
+ }
182
+ const { signers } = getTransactionParams(preparedTransaction.transaction);
183
+ if (signers?.type === 'experimental_session') {
184
+ throw new IndependentSigningNotSupportedError({
185
+ context: { reason: 'smart-session' },
186
+ });
187
+ }
188
+ const validator = getOwnerValidator(config);
189
+ const selectedValidator = getValidator(config, signers);
190
+ if (!selectedValidator ||
191
+ selectedValidator.address.toLowerCase() !== validator.address.toLowerCase()) {
192
+ throw new IndependentSigningNotSupportedError({
193
+ context: { reason: 'non-owner-validator' },
194
+ });
195
+ }
196
+ if (validator.address.toLowerCase() ===
197
+ K1_DEFAULT_VALIDATOR_ADDRESS.toLowerCase()) {
198
+ throw new IndependentSigningNotSupportedError({
199
+ context: { reason: 'erc7739-validator' },
200
+ });
201
+ }
202
+ if (!config.owners) {
203
+ throw new IndependentSigningNotSupportedError({
204
+ context: { reason: 'missing-owner-set' },
205
+ });
206
+ }
207
+ return { owners: config.owners, signers, validator };
208
+ }
209
+ function getValidatorIdKey(id) {
210
+ if (typeof id === 'number' && (!Number.isSafeInteger(id) || id < 0)) {
211
+ return undefined;
212
+ }
213
+ try {
214
+ return pad(toHex(id), { size: 12 }).toLowerCase();
215
+ }
216
+ catch {
217
+ return undefined;
218
+ }
219
+ }
220
+ function getMultiFactorOwnerFactors(owners, signers) {
221
+ if (signers?.type === 'owner' && signers.kind === 'multi-factor') {
222
+ return signers.validators.map((factor) => {
223
+ switch (factor.type) {
224
+ case 'ecdsa':
225
+ return {
226
+ id: factor.id,
227
+ owners: {
228
+ type: 'ecdsa',
229
+ accounts: factor.accounts,
230
+ threshold: factor.accounts.length,
231
+ },
232
+ };
233
+ case 'passkey':
234
+ return {
235
+ id: factor.id,
236
+ owners: {
237
+ type: 'passkey',
238
+ accounts: factor.accounts,
239
+ threshold: factor.accounts.length,
240
+ },
241
+ };
242
+ }
243
+ });
244
+ }
245
+ return owners.validators.map((factor, id) => ({ id, owners: factor }));
246
+ }
247
+ function resolveAtomicOwnerSet(owners, validatorId, signers) {
248
+ if (owners.type !== 'multi-factor') {
249
+ return validatorId === undefined ? { id: 0, owners } : undefined;
250
+ }
251
+ if (validatorId === undefined)
252
+ return undefined;
253
+ const key = getValidatorIdKey(validatorId);
254
+ if (!key)
255
+ return undefined;
256
+ return getMultiFactorOwnerFactors(owners, signers).find((factor) => getValidatorIdKey(factor.id) === key);
257
+ }
258
+ function getAtomicOwnerAccounts(owners) {
259
+ switch (owners.type) {
260
+ case 'ecdsa':
261
+ case 'passkey':
262
+ return owners.accounts;
263
+ case 'ens':
264
+ return owners.owners.map(({ account }) => account);
265
+ }
266
+ }
267
+ function getAtomicOwnerThreshold(owners) {
268
+ return owners.threshold ?? 1;
269
+ }
270
+ function isWebAuthnAccount(account) {
271
+ return account.type === 'webAuthn';
272
+ }
273
+ function getAccountIdentity(account) {
274
+ return isWebAuthnAccount(account)
275
+ ? account.publicKey.toLowerCase()
276
+ : account.address.toLowerCase();
277
+ }
278
+ function getAtomicSignatureIdentity(signature) {
279
+ return signature.kind === 'passkey'
280
+ ? signature.publicKey.toLowerCase()
281
+ : signature.signer.toLowerCase();
282
+ }
283
+ function isOwnerMember(owners, account) {
284
+ if ((owners.type === 'passkey') !== isWebAuthnAccount(account))
285
+ return false;
286
+ const identity = getAccountIdentity(account);
287
+ return getAtomicOwnerAccounts(owners).some((configured) => getAccountIdentity(configured) === identity);
288
+ }
289
+ async function signTransactionAsOwner(config, preparedTransaction, options) {
290
+ const { owners, signers } = assertIndependentSigningSupported(config, preparedTransaction);
291
+ const factor = resolveAtomicOwnerSet(owners, options.validatorId, signers);
292
+ if (!factor) {
293
+ throw new InvalidOwnerSigningOptionsError({
294
+ context: { validatorId: options.validatorId },
295
+ });
296
+ }
297
+ const atomicOwners = factor.owners;
298
+ if (!isOwnerMember(atomicOwners, options.owner)) {
299
+ throw new UnknownOwnerError({
300
+ context: {
301
+ ...(isWebAuthnAccount(options.owner)
302
+ ? { publicKey: options.owner.publicKey }
303
+ : { signer: options.owner.address }),
304
+ validatorId: options.validatorId,
305
+ },
306
+ });
307
+ }
308
+ const quote = resolveQuote(preparedTransaction.quotes, options.intentId === undefined ? undefined : { intentId: options.intentId });
309
+ const { origin } = getIntentMessages(quote.signData);
310
+ const atomicSigners = convertOwnerSetToSignerSet(atomicOwners);
311
+ if (atomicSigners.type !== 'owner' || atomicSigners.kind === 'multi-factor') {
312
+ throw new IndependentSigningNotSupportedError();
313
+ }
314
+ const validatorSupportsEip712 = supportsEip712(getValidatorModule(atomicOwners));
315
+ let signature;
316
+ if (atomicSigners.kind === 'ecdsa' && !isWebAuthnAccount(options.owner)) {
317
+ const signatures = [];
318
+ for (const typedData of origin) {
319
+ signatures.push(await getOwnerEcdsaSignature(config, getChainById(typedData.domain?.chainId), typedData, options.owner, atomicSigners.module, validatorSupportsEip712));
320
+ }
321
+ signature = {
322
+ kind: 'ecdsa',
323
+ signer: options.owner.address,
324
+ origin: signatures,
325
+ };
326
+ }
327
+ else if (atomicSigners.kind === 'passkey' &&
328
+ isWebAuthnAccount(options.owner)) {
329
+ const signatures = [];
330
+ for (const typedData of origin) {
331
+ signatures.push(await getOwnerPasskeySignature(config, typedData, options.owner, validatorSupportsEip712));
332
+ }
333
+ signature = {
334
+ kind: 'passkey',
335
+ publicKey: options.owner.publicKey,
336
+ origin: signatures,
337
+ };
338
+ }
339
+ else {
340
+ throw new UnknownOwnerError({
341
+ context: { validatorId: options.validatorId },
342
+ });
343
+ }
344
+ return owners.type === 'multi-factor'
345
+ ? {
346
+ intentId: quote.intentId,
347
+ kind: 'multi-factor',
348
+ validatorId: factor.id,
349
+ signature,
350
+ }
351
+ : { intentId: quote.intentId, ...signature };
352
+ }
353
+ function orderAtomicOwnerSignatures(owners, signatures, originCount, validatorId) {
354
+ const expectedKind = owners.type === 'passkey' ? 'passkey' : 'ecdsa';
355
+ const byIdentity = new Map();
356
+ const configuredIdentities = new Set(getAtomicOwnerAccounts(owners).map(getAccountIdentity));
357
+ for (const signature of signatures) {
358
+ if (signature.kind !== expectedKind ||
359
+ signature.origin.length !== originCount) {
360
+ throw new MismatchedOwnerSignaturesError({
361
+ context: {
362
+ expectedKind,
363
+ expectedOriginCount: originCount,
364
+ validatorId,
365
+ },
366
+ });
367
+ }
368
+ const identity = getAtomicSignatureIdentity(signature);
369
+ if (!configuredIdentities.has(identity)) {
370
+ throw new UnknownOwnerError({
371
+ context: {
372
+ ...(signature.kind === 'passkey'
373
+ ? { publicKey: signature.publicKey }
374
+ : { signer: signature.signer }),
375
+ validatorId,
376
+ },
377
+ });
378
+ }
379
+ if (!byIdentity.has(identity))
380
+ byIdentity.set(identity, signature);
381
+ }
382
+ const ordered = [...configuredIdentities].flatMap((identity) => {
383
+ const signature = byIdentity.get(identity);
384
+ return signature ? [signature] : [];
385
+ });
386
+ const required = getAtomicOwnerThreshold(owners);
387
+ if (ordered.length < required) {
388
+ throw new InsufficientOwnerSignaturesError({
389
+ required,
390
+ provided: ordered.length,
391
+ validatorId,
392
+ });
393
+ }
394
+ return ordered;
395
+ }
396
+ function packAtomicOwnerSignatures(owners, signatures, originIndex, chain, accountAddress) {
397
+ const signers = convertOwnerSetToSignerSet(owners);
398
+ if (owners.type === 'passkey' &&
399
+ signers.type === 'owner' &&
400
+ signers.kind === 'passkey') {
401
+ const passkeySignatures = signatures.map((signature) => {
402
+ if (signature.kind !== 'passkey') {
403
+ throw new MismatchedOwnerSignaturesError();
404
+ }
405
+ return {
406
+ publicKey: signature.publicKey,
407
+ signature: signature.origin[originIndex],
408
+ };
409
+ });
410
+ return packPasskeyOwnerSignatures(chain, accountAddress, passkeySignatures.map(({ publicKey }) => publicKey), passkeySignatures.map(({ signature }) => signature), signers.module);
411
+ }
412
+ return concat(signatures.map((signature) => {
413
+ if (signature.kind !== 'ecdsa') {
414
+ throw new MismatchedOwnerSignaturesError();
415
+ }
416
+ return signature.origin[originIndex];
417
+ }));
418
+ }
419
+ async function assembleTransaction(config, preparedTransaction, signatures) {
420
+ const { owners, signers, validator } = assertIndependentSigningSupported(config, preparedTransaction);
421
+ if (signatures.length === 0) {
422
+ throw new InsufficientOwnerSignaturesError({
423
+ required: owners.threshold ?? 1,
424
+ provided: 0,
425
+ });
426
+ }
427
+ const intentIds = [...new Set(signatures.map(({ intentId }) => intentId))];
428
+ if (intentIds.length !== 1) {
429
+ throw new MismatchedOwnerSignaturesError({ context: { intentIds } });
430
+ }
431
+ const quote = resolveQuote(preparedTransaction.quotes, {
432
+ intentId: intentIds[0],
433
+ });
434
+ const { origin } = getIntentMessages(quote.signData);
435
+ const accountAddress = getAddress(config);
436
+ const validatorConfig = {
437
+ address: validator.address,
438
+ isRoot: true,
439
+ };
440
+ let directSignatures;
441
+ let factorSignatures;
442
+ if (owners.type === 'multi-factor') {
443
+ const factors = getMultiFactorOwnerFactors(owners, signers);
444
+ const factorsById = new Map(factors.flatMap((factor) => {
445
+ const key = getValidatorIdKey(factor.id);
446
+ return key ? [[key, factor]] : [];
447
+ }));
448
+ const grouped = new Map();
449
+ for (const signature of signatures) {
450
+ if (signature.kind !== 'multi-factor') {
451
+ throw new MismatchedOwnerSignaturesError({
452
+ context: { expectedKind: 'multi-factor' },
453
+ });
454
+ }
455
+ const key = getValidatorIdKey(signature.validatorId);
456
+ if (!key || !factorsById.has(key)) {
457
+ throw new MismatchedOwnerSignaturesError({
458
+ context: { validatorId: signature.validatorId },
459
+ });
460
+ }
461
+ const current = grouped.get(key) ?? [];
462
+ current.push(signature.signature);
463
+ grouped.set(key, current);
464
+ }
465
+ factorSignatures = factors.flatMap((factor) => {
466
+ const key = getValidatorIdKey(factor.id);
467
+ const groupedSignatures = key ? grouped.get(key) : undefined;
468
+ if (!groupedSignatures)
469
+ return [];
470
+ return [
471
+ {
472
+ id: factor.id,
473
+ owners: factor.owners,
474
+ signatures: orderAtomicOwnerSignatures(factor.owners, groupedSignatures, origin.length, factor.id),
475
+ },
476
+ ];
477
+ });
478
+ const required = owners.threshold ?? 1;
479
+ if (factorSignatures.length < required) {
480
+ throw new InsufficientOwnerSignaturesError({
481
+ required,
482
+ provided: factorSignatures.length,
483
+ });
484
+ }
485
+ }
486
+ else {
487
+ directSignatures = orderAtomicOwnerSignatures(owners, signatures.map((signature) => {
488
+ if (signature.kind === 'multi-factor') {
489
+ throw new MismatchedOwnerSignaturesError({
490
+ context: { expectedKind: owners.type },
491
+ });
492
+ }
493
+ const { intentId: _, ...atomicSignature } = signature;
494
+ return atomicSignature;
495
+ }), origin.length);
496
+ }
497
+ const originSignatures = [];
498
+ for (const [originIndex, typedData] of origin.entries()) {
499
+ const chain = getChainById(typedData.domain?.chainId);
500
+ const validatorSignature = factorSignatures
501
+ ? packMultiFactorOwnerSignatures(factorSignatures.map((factor) => ({
502
+ id: factor.id,
503
+ validatorAddress: getValidatorModule(factor.owners).address,
504
+ signature: packAtomicOwnerSignatures(factor.owners, factor.signatures, originIndex, chain, accountAddress),
505
+ })))
506
+ : packAtomicOwnerSignatures(owners, directSignatures, originIndex, chain, accountAddress);
507
+ originSignatures.push(await packAccountSignature(config, validatorSignature, validatorConfig));
508
+ }
509
+ return {
510
+ quote,
511
+ quotes: preparedTransaction.quotes,
512
+ intentInput: preparedTransaction.intentInput,
513
+ transaction: preparedTransaction.transaction,
514
+ originSignatures,
515
+ destinationSignature: originSignatures.at(-1) ?? '0x',
516
+ targetExecutionSignature: undefined,
517
+ };
518
+ }
116
519
  function resolveQuote(quotes, options) {
117
520
  if (!options)
118
521
  return quotes.best;
@@ -131,6 +534,11 @@ async function getTargetExecutionSignature(config, signData, targetChain, signer
131
534
  if (!signData.targetExecution) {
132
535
  return undefined;
133
536
  }
537
+ // Target executions are EVM-only (smart-session validator on destination).
538
+ // Non-EVM destinations don't have a validator there to verify the sig.
539
+ if (isNonEvmChain(targetChain)) {
540
+ return undefined;
541
+ }
134
542
  const resolvedSigners = await resolveSignersForChain(config, signers, targetChain.id);
135
543
  if (!isResolvedSessionSignerSet(resolvedSigners) ||
136
544
  !resolvedSigners.verifyExecutions) {
@@ -266,10 +674,16 @@ async function signAuthorizationsInternal(config, context) {
266
674
  }
267
675
  const accountAddress = getAddress(config);
268
676
  const { contract: eip7702Contract } = getEip7702InitCall(config, eip7702InitSignature);
677
+ // EIP-7702 authorization is EVM-only — there's no contract to delegate
678
+ // to on Solana / Tron. Skip the destination chain entirely when it's
679
+ // non-EVM; source chains are always EVM by construction.
269
680
  const chains = new Map();
270
- for (const chain of [...(context.sourceChains ?? []), context.targetChain]) {
681
+ for (const chain of context.sourceChains ?? []) {
271
682
  chains.set(chain.id, chain);
272
683
  }
684
+ if (!isNonEvmChain(context.targetChain)) {
685
+ chains.set(context.targetChain.id, context.targetChain);
686
+ }
273
687
  const authorizations = [];
274
688
  for (const chain of chains.values()) {
275
689
  const walletClient = createWalletClient({
@@ -314,10 +728,11 @@ function getTransactionParams(transaction) {
314
728
  const gasLimit = transaction.gasLimit;
315
729
  const settlementLayers = transaction.settlementLayers;
316
730
  const sourceAssets = transaction.sourceAssets;
317
- const feeAsset = transaction.feeAsset;
318
731
  const auxiliaryFunds = transaction.auxiliaryFunds;
732
+ const appFees = transaction.appFees;
319
733
  const account = transaction.experimental_accountOverride;
320
734
  const recipient = transaction.recipient;
735
+ const sourceCalls = transaction.sourceCalls;
321
736
  const tokenRequests = getTokenRequests(targetChain, initialTokenRequests);
322
737
  return {
323
738
  sourceChains,
@@ -329,15 +744,23 @@ function getTransactionParams(transaction) {
329
744
  gasLimit,
330
745
  settlementLayers,
331
746
  sourceAssets,
332
- feeAsset,
333
747
  auxiliaryFunds,
748
+ appFees,
334
749
  account,
335
750
  recipient,
751
+ sourceCalls,
336
752
  };
337
753
  }
338
754
  function getTokenRequests(targetChain, initialTokenRequests) {
339
- if (initialTokenRequests) {
340
- validateTokenSymbols(targetChain, initialTokenRequests.map((tokenRequest) => tokenRequest.address));
755
+ // Non-EVM destinations carry SPL mint / Tron T-prefixed addresses that
756
+ // aren't valid 0x-hex; skip symbol/EVM-address validation here and let
757
+ // the orchestrator validate per its own schema. EVM destinations keep
758
+ // the existing strict check so a typo on Optimism still fails fast.
759
+ if (initialTokenRequests && !isNonEvmChain(targetChain)) {
760
+ // Inside this branch targetChain is a viem `Chain`, which excludes the
761
+ // non-EVM transaction variant — token requests are EVM-typed here.
762
+ const evmRequests = initialTokenRequests;
763
+ validateTokenSymbols(targetChain, evmRequests.map((tokenRequest) => tokenRequest.address));
341
764
  }
342
765
  return initialTokenRequests ?? [];
343
766
  }
@@ -386,12 +809,46 @@ function getIntentAccount(config, eip7702InitSignature, account) {
386
809
  delegations,
387
810
  };
388
811
  }
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);
812
+ function cloneAuxiliaryFunds(auxiliaryFunds) {
813
+ if (!auxiliaryFunds)
814
+ return undefined;
815
+ return Object.fromEntries(Object.entries(auxiliaryFunds).map(([chainId, funds]) => [
816
+ Number(chainId),
817
+ { ...funds },
818
+ ]));
819
+ }
820
+ function toCallInput(sourceCall) {
821
+ const { provides: _provides, ...call } = sourceCall;
822
+ return call;
823
+ }
824
+ function addProvidedFunds(auxiliaryFunds, chainId, calls) {
825
+ let next = auxiliaryFunds;
826
+ for (const call of calls) {
827
+ for (const provided of call.provides ?? []) {
828
+ next ??= {};
829
+ next[chainId] ??= {};
830
+ const token = provided.token;
831
+ next[chainId][token] = (next[chainId][token] ?? 0n) + provided.amount;
832
+ }
833
+ }
834
+ return next;
835
+ }
836
+ async function prepareTransactionAsIntent(config, sourceChains, targetChain, callInputs, gasLimit, tokenRequests, recipientInput, sponsored, eip7702InitSignature, settlementLayers, sourceAssets, auxiliaryFunds, account, signers, sourceCalls, appFees) {
837
+ const targetChainId = getChainId(targetChain);
838
+ const calls = parseCalls(callInputs, targetChainId);
391
839
  const accountAccessList = createAccountAccessList(sourceChains, sourceAssets);
392
840
  function getRecipient(recipient) {
393
841
  if (typeof recipient === 'string') {
394
- // Passed as an address, assume it's an EOA
842
+ // Non-EVM-addressed recipients (Solana base58 / Tron T-prefix) carry no
843
+ // EVM smart-account semantics; the orchestrator schema requires
844
+ // accountType / setupOps to be unset. Emit just the address. HyperCore
845
+ // is EVM-addressed (eip155:1337) so it falls through to the EOA
846
+ // passthrough below — the orchestrator's HyperCore gate requires
847
+ // accountType: 'EOA'.
848
+ if (isNonEvmChainId(targetChainId)) {
849
+ return { address: recipient };
850
+ }
851
+ // EVM (and HyperCore) passthrough — assume EOA.
395
852
  return {
396
853
  address: recipient,
397
854
  accountType: 'EOA',
@@ -404,25 +861,65 @@ async function prepareTransactionAsIntent(config, sourceChains, targetChain, cal
404
861
  }
405
862
  return getIntentAccount(recipient, eip7702InitSignature, account);
406
863
  }
864
+ // Resolve per-chain signer state once (each resolveSignersForChain does an
865
+ // isSessionEnabled RPC) and reuse it for mock signatures, the signature mode,
866
+ // and preClaim ops. Exclude a non-EVM destination — it has no session
867
+ // validator, so resolving it would waste an RPC (or throw for per-chain
868
+ // session signers). resolveSignatureMode derives its chain set from this map's
869
+ // keys, so the excluded non-EVM target is never resolved there either.
870
+ const sessionChainIds = [
871
+ ...new Set([
872
+ ...(sourceChains ?? []).map((c) => c.id),
873
+ ...(isNonEvmChain(targetChain) ? [] : [targetChainId]),
874
+ ]),
875
+ ];
876
+ const resolvedByChain = signers?.type === 'experimental_session'
877
+ ? new Map(await Promise.all(sessionChainIds.map(async (chainId) => [
878
+ chainId,
879
+ await resolveSignersForChain(config, signers, chainId),
880
+ ])))
881
+ : undefined;
882
+ // Per-chain mock signatures: enables accurate per-chain session validation gas
883
+ // simulation. Non-EVM destinations are excluded — they have no destination-side
884
+ // session validator. Each chain's mock sig carries that chain's own resolved
885
+ // shape (ENABLE / USE / ERC-1271). Note these are per-chain and may differ in
886
+ // shape, whereas `signatureMode` (below) is a single global value resolved
887
+ // conservatively (anyVerifyExecutions across chains → mode 5) — so in mixed
888
+ // states a chain's mock shape need not match the global signatureMode.
889
+ let mockSignatures;
890
+ if (resolvedByChain) {
891
+ const entries = [...resolvedByChain.entries()].flatMap(([chainId, resolved]) => {
892
+ // resolvedByChain is keyed by sessionChainIds, which already excludes a
893
+ // non-EVM target — so no per-entry target guard is needed here.
894
+ if (!isResolvedSessionSignerSet(resolved))
895
+ return [];
896
+ // Match the mock shape to what the real sig will be: ERC-1271 when not
897
+ // verifying executions; otherwise ENABLE if the session still needs
898
+ // installing (enableData present), else USE (already enabled, e.g.
899
+ // explicit permissions — its real sig is MODE_USE with no enableData).
900
+ const shape = !resolved.verifyExecutions
901
+ ? 'erc1271'
902
+ : resolved.enableData !== undefined
903
+ ? 'enable'
904
+ : 'use';
905
+ return [
906
+ [
907
+ String(chainId),
908
+ buildMockSignature(resolved.session, config.useDevContracts, sourceChains?.length ?? 1, chainId, shape),
909
+ ],
910
+ ];
911
+ });
912
+ // Leave mockSignatures undefined (not {}) when there are no eligible chains,
913
+ // so downstream consumers can treat presence as "per-chain sigs provided".
914
+ if (entries.length > 0)
915
+ mockSignatures = Object.fromEntries(entries);
916
+ }
407
917
  const intentAccount = {
408
918
  ...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
- }),
919
+ ...(mockSignatures && { mockSignatures }),
421
920
  };
422
921
  const recipient = getRecipient(recipientInput);
423
- const signatureMode = signers?.type === 'experimental_session'
424
- ? SIG_MODE_EMISSARY_EXECUTION_ERC1271
425
- : SIG_MODE_ERC1271_EMISSARY;
922
+ const signatureMode = await resolveSignatureMode(config, signers, sourceChains, targetChainId, resolvedByChain);
426
923
  // For session signers that need enabling, pass a dummy preclaimop per source chain
427
924
  // so the orchestrator bakes it into the bundle before computing its HMAC. The filler
428
925
  // executes the op via verifyExecution in ENABLE mode, enabling the session on-chain
@@ -430,11 +927,11 @@ async function prepareTransactionAsIntent(config, sourceChains, targetChain, cal
430
927
  // post-facto — because the orchestrator HMAC covers preClaimOps.
431
928
  const preClaimExecutions = {};
432
929
  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) {
930
+ // Reuse the shared per-chain resolution (source chains are a subset of
931
+ // sessionChainIds) instead of resolving — and re-doing isSessionEnabled — again.
932
+ for (const chain of sourceChains) {
933
+ const chainId = chain.id;
934
+ const resolved = resolvedByChain?.get(chainId);
438
935
  if (!isResolvedSessionSignerSet(resolved))
439
936
  continue;
440
937
  const { enableData, verifyExecutions } = resolved;
@@ -449,10 +946,40 @@ async function prepareTransactionAsIntent(config, sourceChains, targetChain, cal
449
946
  ];
450
947
  }
451
948
  }
949
+ let combinedAuxiliaryFunds = cloneAuxiliaryFunds(auxiliaryFunds);
950
+ if (sourceCalls) {
951
+ const accountAddress = getAddress(config);
952
+ const allowedChainIds = new Set([
953
+ ...(sourceChains ?? []).map((c) => c.id),
954
+ ...(!isNonEvmChain(targetChain) ? [targetChainId] : []),
955
+ ]);
956
+ for (const [chainIdStr, calls] of Object.entries(sourceCalls)) {
957
+ const chainId = Number(chainIdStr);
958
+ if (!allowedChainIds.has(chainId)) {
959
+ throw new InvalidSourceCallsError({ chainId });
960
+ }
961
+ const chain = sourceChains?.find((c) => c.id === chainId) ??
962
+ (!isNonEvmChain(targetChain) && targetChainId === chainId
963
+ ? targetChain
964
+ : undefined);
965
+ if (!chain) {
966
+ throw new InvalidSourceCallsError({ chainId });
967
+ }
968
+ combinedAuxiliaryFunds = addProvidedFunds(combinedAuxiliaryFunds, chainId, calls);
969
+ const resolved = await resolveCallInputs(calls.map(toCallInput), config, chain, accountAddress);
970
+ const userExecutions = parseCalls(resolved, chainId);
971
+ if (userExecutions.length === 0)
972
+ continue;
973
+ preClaimExecutions[chainId] = [
974
+ ...(preClaimExecutions[chainId] ?? []),
975
+ ...userExecutions,
976
+ ];
977
+ }
978
+ }
452
979
  const metaIntent = {
453
- destinationChainId: targetChain.id,
980
+ destinationChainId: targetChainId,
454
981
  tokenRequests: tokenRequests.map((tokenRequest) => ({
455
- tokenAddress: resolveTokenAddress(tokenRequest.address, targetChain.id),
982
+ tokenAddress: resolveTokenAddress(tokenRequest.address, targetChainId),
456
983
  amount: tokenRequest.amount,
457
984
  })),
458
985
  recipient,
@@ -461,7 +988,6 @@ async function prepareTransactionAsIntent(config, sourceChains, targetChain, cal
461
988
  destinationGasUnits: gasLimit,
462
989
  accountAccessList,
463
990
  options: {
464
- feeToken: feeAsset,
465
991
  sponsorSettings: sponsored
466
992
  ? typeof sponsored === 'object'
467
993
  ? {
@@ -477,19 +1003,20 @@ async function prepareTransactionAsIntent(config, sourceChains, targetChain, cal
477
1003
  : undefined,
478
1004
  settlementLayers,
479
1005
  signatureMode,
480
- auxiliaryFunds,
1006
+ auxiliaryFunds: combinedAuxiliaryFunds,
1007
+ appFees,
481
1008
  },
482
1009
  ...(Object.keys(preClaimExecutions).length > 0 && { preClaimExecutions }),
483
1010
  };
484
1011
  const serializedIntent = convertBigIntFields(metaIntent);
485
1012
  const orchestrator = getOrchestrator(config._authProvider ?? createAuthProvider(config), config.endpointUrl, config.headers);
486
- const { routes } = await orchestrator.createQuote(metaIntent);
1013
+ const { routes, traceId } = await orchestrator.createQuote(metaIntent);
487
1014
  const best = routes[0];
488
1015
  if (!best) {
489
1016
  throw new Error('Orchestrator returned no quote');
490
1017
  }
491
1018
  return {
492
- quotes: { best, all: routes },
1019
+ quotes: { traceId, best, all: routes },
493
1020
  intentInput: serializedIntent,
494
1021
  };
495
1022
  }
@@ -529,7 +1056,14 @@ async function signIntent(config, signData, targetChain, signers, targetExecutio
529
1056
  const signature = await signIntentTypedData(config, originSigners, validator, isRoot, typedData, chain, targetExecution ?? false);
530
1057
  originSignatures.push(signature);
531
1058
  }
532
- const destinationSigners = await resolveSignersForChain(config, signers, targetChain.id);
1059
+ // Non-EVM destinations have no destination-side validator, so there's no
1060
+ // session to resolve and no signer to derive. Skipping here matters for
1061
+ // per-chain experimental sessions: `resolveSessionForChain` would throw
1062
+ // `No session configured for chain {synthetic-id}` since users never
1063
+ // configure a session keyed by the synthetic Solana/Tron chain id.
1064
+ const destinationSigners = isNonEvmChain(targetChain)
1065
+ ? undefined
1066
+ : await resolveSignersForChain(config, signers, targetChain.id);
533
1067
  const destinationSignature = await getDestinationSignature(config, destinationSigners, validator, isRoot, targetChain, destination, originSignatures, targetExecution ?? false);
534
1068
  return {
535
1069
  originSignatures,
@@ -537,18 +1071,25 @@ async function signIntent(config, signData, targetChain, signers, targetExecutio
537
1071
  };
538
1072
  }
539
1073
  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);
1074
+ // Non-EVM destinations have no destination-side validator, no
1075
+ // eip712Domain(), no smart session enable data. Settlement is solver-
1076
+ // mediated on the orchestrator side and the origin signatures alone
1077
+ // authorize the bundle. Fall through to the "reuse last origin sig"
1078
+ // branch instead of trying to sign on Solana / Tron.
1079
+ if (!isNonEvmChain(targetChain)) {
1080
+ // Smart sessions require a separate destination signature because the
1081
+ // session enable data differs per chain
1082
+ if (signers?.type === 'experimental_session') {
1083
+ return await signDestinationSeparately(config, signers, validator, isRoot, targetChain, destination, targetExecution);
1084
+ }
1085
+ // ERC-7739 with K1 validator requires a separate destination signature because
1086
+ // the account's eip712Domain() returns the target chain's chainId, which differs
1087
+ // from the origin chain used for the last origin signature
1088
+ const isK1Validator = validator.address.toLowerCase() ===
1089
+ K1_DEFAULT_VALIDATOR_ADDRESS.toLowerCase();
1090
+ if (isK1Validator && supportsEip712(validator)) {
1091
+ return await signDestinationSeparately(config, signers, validator, isRoot, targetChain, destination, targetExecution);
1092
+ }
552
1093
  }
553
1094
  const lastOriginSignature = originSignatures.at(-1);
554
1095
  return typeof lastOriginSignature === 'object'
@@ -628,7 +1169,17 @@ function resolveClaimPolicyData(signers, parameters) {
628
1169
  typeof msg.deadline !== 'bigint') {
629
1170
  return undefined;
630
1171
  }
631
- return buildPermit2ClaimPolicyCalldata(resolvePermit2ClaimPolicy(signers.session.claimPolicies[0]), parameters.message);
1172
+ const message = parameters.message;
1173
+ // A session may carry several claim policies (a user policy plus one or
1174
+ // more synthesized cross-chain permits). The on-chain emissary validates
1175
+ // against the policy that matches this Permit2 message, and the calldata
1176
+ // layout is policy-specific — so we must build it from the matching policy,
1177
+ // not blindly `claimPolicies[0]`.
1178
+ const claimPolicy = selectPermit2ClaimPolicyForMessage(signers.session.claimPolicies, message);
1179
+ if (!claimPolicy) {
1180
+ return undefined;
1181
+ }
1182
+ return buildPermit2ClaimPolicyCalldata(resolvePermit2ClaimPolicy(claimPolicy), message);
632
1183
  }
633
1184
  async function signIntentTypedData(config, signers, validator, isRoot, parameters, chain, targetExecution) {
634
1185
  if (supportsEip712(validator)) {
@@ -757,7 +1308,7 @@ async function submitIntentInternal(config, sourceChains, targetChain, quote, or
757
1308
  ...(authorizations.length > 0 && {
758
1309
  authorizations: {
759
1310
  sponsor: authorizations.map((authorization) => ({
760
- chainId: authorization.chainId,
1311
+ chainId: toCaip2(authorization.chainId),
761
1312
  address: authorization.address,
762
1313
  nonce: authorization.nonce,
763
1314
  yParity: authorization.yParity ?? 0,
@@ -774,8 +1325,9 @@ async function submitIntentInternal(config, sourceChains, targetChain, quote, or
774
1325
  return {
775
1326
  type: 'intent',
776
1327
  id: response.intentId,
1328
+ traceId: response.traceId,
777
1329
  sourceChains: sourceChains?.map((chain) => chain.id),
778
- targetChain: targetChain.id,
1330
+ targetChain: getChainId(targetChain),
779
1331
  };
780
1332
  }
781
1333
  async function getValidatorAccount(config, signers, publicClient, chain) {
@@ -787,13 +1339,7 @@ async function getValidatorAccount(config, signers, publicClient, chain) {
787
1339
  if (withOwner) {
788
1340
  return getSmartAccount(config, publicClient, chain);
789
1341
  }
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;
1342
+ return null;
797
1343
  }
798
1344
  function getValidator(config, signers) {
799
1345
  if (!signers) {
@@ -812,11 +1358,11 @@ function getValidator(config, signers) {
812
1358
  return getWebAuthnValidator(1, withOwner.accounts.map((account) => ({
813
1359
  pubKey: account.publicKey,
814
1360
  authenticatorId: account.id,
815
- })));
1361
+ })), withOwner.module);
816
1362
  }
817
1363
  // Multi-factor
818
1364
  if (withOwner.kind === 'multi-factor') {
819
- return getMultiFactorValidator(1, withOwner.validators);
1365
+ return getMultiFactorValidator(1, withOwner.validators, withOwner.module);
820
1366
  }
821
1367
  }
822
1368
  // Smart sessions
@@ -824,15 +1370,12 @@ function getValidator(config, signers) {
824
1370
  if (withSession) {
825
1371
  return getSmartSessionValidator(config);
826
1372
  }
827
- // Guardians (social recovery)
828
- const withGuardians = signers.type === 'guardians' ? signers : null;
829
- if (withGuardians) {
830
- return getSocialRecoveryValidator(withGuardians.guardians);
831
- }
832
1373
  // Fallback
833
1374
  return undefined;
834
1375
  }
835
1376
  function parseCalls(calls, chainId) {
1377
+ // Destination calls only run on EVM chains (non-EVM destinations reject
1378
+ // calls upstream), so the resolved `to` is always a viem `Address` here.
836
1379
  return calls.map((call) => ({
837
1380
  data: call.data ?? '0x',
838
1381
  value: call.value ?? 0n,
@@ -852,6 +1395,8 @@ function createAccountAccessList(sourceChains, sourceAssets) {
852
1395
  const chainTokenAmounts = {};
853
1396
  for (const config of sourceAssets) {
854
1397
  const chainId = config.chain.id;
1398
+ // Source assets live on viem `Chain`s, which are always EVM, so the
1399
+ // resolved value is a viem `Address`.
855
1400
  const tokenAddress = resolveTokenAddress(config.address, config.chain.id);
856
1401
  if (config.amount !== undefined) {
857
1402
  if (!chainTokenAmounts[chainId])
@@ -999,7 +1544,9 @@ function hashErc7739TypedDataForSolady({ domain, types, primaryType, message, ve
999
1544
  deps.delete(primary);
1000
1545
  const sorted = [primary, ...Array.from(deps).sort()];
1001
1546
  return sorted
1002
- .map((t) => `${t}(${allTypes[t].map((f) => `${f.type} ${f.name}`).join(',')})`)
1547
+ .map((t) => `${t}(${allTypes[t]
1548
+ .map((f) => `${f.type} ${f.name}`)
1549
+ .join(',')})`)
1003
1550
  .join('');
1004
1551
  }
1005
1552
  const contentsType = encodeTypeString(primaryType, types);
@@ -1051,4 +1598,4 @@ function hashErc7739TypedDataForSolady({ domain, types, primaryType, message, ve
1051
1598
  // Final hash: keccak256("\x19\x01" || appDomainSep || structHash)
1052
1599
  return keccak256(concat(['0x1901', appDomainSeparator, structHash]));
1053
1600
  }
1054
- export { prepareTransaction, getTransactionMessages, signTransaction, signAuthorizations, signAuthorizationsInternal, signMessage, signTypedData, submitTransaction, prepareUserOperation, signUserOperation, submitUserOperation, signIntent, prepareTransactionAsIntent, submitIntentInternal, getValidatorAccount, parseCalls, getTokenRequests, resolveCallInputs, getIntentAccount, getTargetExecutionSignature, hashErc7739TypedDataForSolady, resolveSessionForChain, };
1601
+ export { prepareTransaction, getTransactionMessages, signTransaction, assembleTransaction, signAuthorizations, signAuthorizationsInternal, signMessage, signTypedData, submitTransaction, prepareUserOperation, signUserOperation, submitUserOperation, signIntent, prepareTransactionAsIntent, submitIntentInternal, getValidatorAccount, parseCalls, getTokenRequests, resolveCallInputs, getIntentAccount, getTargetExecutionSignature, hashErc7739TypedDataForSolady, resolveSessionForChain, resolveSignatureMode, };