@rhinestone/sdk 2.0.0-beta.0 → 2.0.0-beta.10

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 (92) hide show
  1. package/README.md +43 -2
  2. package/dist/src/accounts/index.d.ts.map +1 -1
  3. package/dist/src/accounts/index.js +6 -34
  4. package/dist/src/accounts/json-rpc/providers.d.ts.map +1 -1
  5. package/dist/src/accounts/json-rpc/providers.js +3 -2
  6. package/dist/src/actions/smart-sessions.d.ts.map +1 -1
  7. package/dist/src/actions/smart-sessions.js +3 -3
  8. package/dist/src/errors/index.d.ts +3 -3
  9. package/dist/src/errors/index.d.ts.map +1 -1
  10. package/dist/src/errors/index.js +6 -4
  11. package/dist/src/execution/compact.d.ts +1 -144
  12. package/dist/src/execution/compact.d.ts.map +1 -1
  13. package/dist/src/execution/compact.js +1 -109
  14. package/dist/src/execution/error.d.ts +11 -2
  15. package/dist/src/execution/error.d.ts.map +1 -1
  16. package/dist/src/execution/error.js +11 -3
  17. package/dist/src/execution/index.d.ts +10 -11
  18. package/dist/src/execution/index.d.ts.map +1 -1
  19. package/dist/src/execution/index.js +37 -47
  20. package/dist/src/execution/utils.d.ts +34 -16
  21. package/dist/src/execution/utils.d.ts.map +1 -1
  22. package/dist/src/execution/utils.js +259 -144
  23. package/dist/src/index.d.ts +22 -16
  24. package/dist/src/index.d.ts.map +1 -1
  25. package/dist/src/index.js +18 -45
  26. package/dist/src/modules/index.d.ts +2 -2
  27. package/dist/src/modules/index.d.ts.map +1 -1
  28. package/dist/src/modules/index.js +2 -2
  29. package/dist/src/modules/read.d.ts.map +1 -1
  30. package/dist/src/modules/read.js +2 -4
  31. package/dist/src/modules/validators/index.d.ts +2 -2
  32. package/dist/src/modules/validators/index.d.ts.map +1 -1
  33. package/dist/src/modules/validators/index.js +2 -2
  34. package/dist/src/modules/validators/permissions.d.ts +5 -0
  35. package/dist/src/modules/validators/permissions.d.ts.map +1 -0
  36. package/dist/src/modules/validators/permissions.js +111 -0
  37. package/dist/src/modules/validators/policies/claim/permit2.d.ts +29 -3
  38. package/dist/src/modules/validators/policies/claim/permit2.d.ts.map +1 -1
  39. package/dist/src/modules/validators/smart-sessions.d.ts +14 -27
  40. package/dist/src/modules/validators/smart-sessions.d.ts.map +1 -1
  41. package/dist/src/modules/validators/smart-sessions.js +74 -22
  42. package/dist/src/orchestrator/caip2.d.ts +13 -0
  43. package/dist/src/orchestrator/caip2.d.ts.map +1 -0
  44. package/dist/src/orchestrator/caip2.js +52 -0
  45. package/dist/src/orchestrator/client.d.ts +12 -11
  46. package/dist/src/orchestrator/client.d.ts.map +1 -1
  47. package/dist/src/orchestrator/client.js +217 -296
  48. package/dist/src/orchestrator/consts.d.ts +2 -2
  49. package/dist/src/orchestrator/consts.d.ts.map +1 -1
  50. package/dist/src/orchestrator/consts.js +2 -2
  51. package/dist/src/orchestrator/destinations.d.ts +23 -0
  52. package/dist/src/orchestrator/destinations.d.ts.map +1 -0
  53. package/dist/src/orchestrator/destinations.js +36 -0
  54. package/dist/src/orchestrator/error.d.ts +72 -217
  55. package/dist/src/orchestrator/error.d.ts.map +1 -1
  56. package/dist/src/orchestrator/error.js +117 -195
  57. package/dist/src/orchestrator/index.d.ts +6 -5
  58. package/dist/src/orchestrator/index.d.ts.map +1 -1
  59. package/dist/src/orchestrator/index.js +4 -3
  60. package/dist/src/orchestrator/registry.d.ts +3 -9
  61. package/dist/src/orchestrator/registry.d.ts.map +1 -1
  62. package/dist/src/orchestrator/registry.js +11 -26
  63. package/dist/src/orchestrator/types.d.ts +136 -239
  64. package/dist/src/orchestrator/types.d.ts.map +1 -1
  65. package/dist/src/types.d.ts +126 -37
  66. package/dist/src/types.d.ts.map +1 -1
  67. package/dist/src/utils/index.d.ts +2 -1
  68. package/dist/src/utils/index.d.ts.map +1 -1
  69. package/dist/src/utils/index.js +2 -1
  70. package/dist/src/utils/walletClient.d.ts.map +1 -0
  71. package/dist/src/{accounts → utils}/walletClient.js +1 -1
  72. package/package.json +2 -6
  73. package/dist/src/accounts/passport.d.ts +0 -9
  74. package/dist/src/accounts/passport.d.ts.map +0 -1
  75. package/dist/src/accounts/passport.js +0 -78
  76. package/dist/src/accounts/walletClient.d.ts.map +0 -1
  77. package/dist/src/actions/compact.d.ts +0 -15
  78. package/dist/src/actions/compact.d.ts.map +0 -1
  79. package/dist/src/actions/compact.js +0 -200
  80. package/dist/src/actions/deployment.d.ts +0 -19
  81. package/dist/src/actions/deployment.d.ts.map +0 -1
  82. package/dist/src/actions/deployment.js +0 -76
  83. package/dist/src/execution/permit2.d.ts +0 -143
  84. package/dist/src/execution/permit2.d.ts.map +0 -1
  85. package/dist/src/execution/permit2.js +0 -280
  86. package/dist/src/execution/singleChainOps.d.ts +0 -41
  87. package/dist/src/execution/singleChainOps.d.ts.map +0 -1
  88. package/dist/src/execution/singleChainOps.js +0 -42
  89. package/dist/src/execution/types.d.ts +0 -36
  90. package/dist/src/execution/types.d.ts.map +0 -1
  91. package/dist/src/execution/types.js +0 -1
  92. /package/dist/src/{accounts → utils}/walletClient.d.ts +0 -0
@@ -6,18 +6,16 @@ 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
- import { getIntentExecutor } from '../modules/index.js';
10
9
  import { buildMockSignature, DUMMY_PRECLAIMOP_SELECTOR, DUMMY_PRECLAIMOP_TARGET, getOwnerValidator, getPermissionId, getSmartSessionValidator, isSessionEnabled, } from '../modules/validators/index.js';
11
10
  import { getMultiFactorValidator, getSocialRecoveryValidator, getWebAuthnValidator, supportsEip712, } from '../modules/validators/core.js';
12
- import { buildPermit2ClaimPolicyCalldata } from '../modules/validators/policies/claim/permit2.js';
11
+ import { buildPermit2ClaimPolicyCalldata, } from '../modules/validators/policies/claim/permit2.js';
12
+ import { resolvePermit2ClaimPolicy, } from '../modules/validators/smart-sessions.js';
13
13
  import { getOrchestrator, } from '../orchestrator/index.js';
14
+ import { getChainId, isNonEvmChain, } from '../orchestrator/destinations.js';
14
15
  import { getChainById, getTokenAddress, resolveTokenAddress, } from '../orchestrator/registry.js';
15
16
  import { SIG_MODE_EMISSARY_EXECUTION_ERC1271, SIG_MODE_ERC1271_EMISSARY, } from '../orchestrator/types.js';
16
17
  import { convertBigIntFields } from '../orchestrator/utils.js';
17
- import { getCompactTypedData } from './compact.js';
18
- import { Eip7702InitSignatureRequiredError, SignerNotSupportedError, } from './error.js';
19
- import { getTypedData as getPermit2TypedData } from './permit2.js';
20
- import { getTypedData as getSingleChainOpsTypedData } from './singleChainOps.js';
18
+ import { Eip7702InitSignatureRequiredError, QuoteNotInPreparedTransactionError, SignerNotSupportedError, } from './error.js';
21
19
  function isResolvedSessionSignerSet(signers) {
22
20
  return (signers?.type === 'experimental_session' && 'verifyExecutions' in signers);
23
21
  }
@@ -28,8 +26,9 @@ async function resolveSignersForChain(config, signers, chainId) {
28
26
  const resolved = resolveSessionForChain(signers, chainId);
29
27
  const enabled = await isSessionEnabled(getAddress(config), config.provider, resolved.session, config.useDevContracts);
30
28
  const enableData = enabled ? undefined : resolved.enableData;
31
- const hasExplicitActions = !!resolved.session.actions?.length;
32
- const verifyExecutions = resolved.verifyExecutions ?? signers.verifyExecutions ?? hasExplicitActions;
29
+ const verifyExecutions = resolved.verifyExecutions ??
30
+ signers.verifyExecutions ??
31
+ resolved.session.hasExplicitPermissions;
33
32
  return {
34
33
  type: 'experimental_session',
35
34
  session: resolved.session,
@@ -48,15 +47,29 @@ function resolveSessionForChain(signers, chainId) {
48
47
  return { session: signers.session, enableData: signers.enableData };
49
48
  }
50
49
  async function prepareTransaction(config, transaction) {
51
- const { sourceChains, targetChain, tokenRequests, signers, sponsored, eip7702InitSignature, settlementLayers, sourceAssets, feeAsset, lockFunds, auxiliaryFunds, account, recipient, } = getTransactionParams(transaction);
50
+ const { sourceChains, targetChain, tokenRequests, signers, sponsored, eip7702InitSignature, settlementLayers, sourceAssets, feeAsset, auxiliaryFunds, account, recipient, } = getTransactionParams(transaction);
52
51
  const accountAddress = getAddress(config);
53
52
  const isUserOpSigner = signers?.type === 'guardians';
54
53
  if (isUserOpSigner) {
55
54
  throw new SignerNotSupportedError();
56
55
  }
57
- const prepared = await prepareTransactionAsIntent(config, sourceChains, targetChain, await resolveCallInputs(transaction.calls, config, targetChain, accountAddress), transaction.gasLimit, tokenRequests, recipient, sponsored, eip7702InitSignature, settlementLayers, sourceAssets, feeAsset, lockFunds, auxiliaryFunds, account, signers);
56
+ // Destination calls (transaction.calls on a cross-chain transaction) are
57
+ // executed on the destination chain by the solver/account. For non-EVM
58
+ // destinations we can't resolve arbitrary EVM calls; assert there are
59
+ // none and route an empty list through.
60
+ let resolvedCalls;
61
+ if (isNonEvmChain(targetChain)) {
62
+ if (transaction.calls && transaction.calls.length > 0) {
63
+ throw new Error(`Destination calls are not supported for non-EVM target chain ${targetChain.name} (${targetChain.caip2})`);
64
+ }
65
+ resolvedCalls = [];
66
+ }
67
+ else {
68
+ resolvedCalls = await resolveCallInputs(transaction.calls, config, targetChain, accountAddress);
69
+ }
70
+ const prepared = await prepareTransactionAsIntent(config, sourceChains, targetChain, resolvedCalls, transaction.gasLimit, tokenRequests, recipient, sponsored, eip7702InitSignature, settlementLayers, sourceAssets, feeAsset, auxiliaryFunds, account, signers);
58
71
  return {
59
- intentRoute: prepared.intentRoute,
72
+ quotes: prepared.quotes,
60
73
  intentInput: prepared.intentInput,
61
74
  transaction,
62
75
  };
@@ -93,19 +106,21 @@ async function resolveCallInputs(inputs, config, chain, accountAddress) {
93
106
  }
94
107
  return resolved;
95
108
  }
96
- function getTransactionMessages(config, preparedTransaction) {
97
- return getIntentMessages(config, preparedTransaction.intentRoute.intentOp);
109
+ function getTransactionMessages(_config, preparedTransaction, options) {
110
+ const quote = resolveQuote(preparedTransaction.quotes, options);
111
+ return getIntentMessages(quote.signData);
98
112
  }
99
- async function signTransaction(config, preparedTransaction) {
113
+ async function signTransaction(config, preparedTransaction, options) {
100
114
  const { signers } = getTransactionParams(preparedTransaction.transaction);
101
- const intentRoute = preparedTransaction.intentRoute;
115
+ const quote = resolveQuote(preparedTransaction.quotes, options);
102
116
  const targetChain = 'targetChain' in preparedTransaction.transaction
103
117
  ? preparedTransaction.transaction.targetChain
104
118
  : preparedTransaction.transaction.chain;
105
- const { originSignatures, destinationSignature } = await signIntent(config, intentRoute.intentOp, targetChain, signers, false);
106
- const targetExecutionSignature = await getTargetExecutionSignature(config, intentRoute.intentOp, targetChain, signers);
119
+ const { originSignatures, destinationSignature } = await signIntent(config, quote.signData, targetChain, signers, false);
120
+ const targetExecutionSignature = await getTargetExecutionSignature(config, quote.signData, targetChain, signers);
107
121
  return {
108
- intentRoute,
122
+ quote,
123
+ quotes: preparedTransaction.quotes,
109
124
  intentInput: preparedTransaction.intentInput,
110
125
  transaction: preparedTransaction.transaction,
111
126
  originSignatures,
@@ -113,13 +128,27 @@ async function signTransaction(config, preparedTransaction) {
113
128
  targetExecutionSignature,
114
129
  };
115
130
  }
116
- async function getTargetExecutionSignature(config, intentOp, targetChain, signers) {
131
+ function resolveQuote(quotes, options) {
132
+ if (!options)
133
+ return quotes.best;
134
+ const match = quotes.all.find((q) => q.intentId === options.intentId);
135
+ if (!match) {
136
+ throw new QuoteNotInPreparedTransactionError({
137
+ context: { intentId: options.intentId },
138
+ });
139
+ }
140
+ return match;
141
+ }
142
+ async function getTargetExecutionSignature(config, signData, targetChain, signers) {
117
143
  if (signers?.type !== 'experimental_session') {
118
144
  return undefined;
119
145
  }
120
- const settlementLayers = intentOp.elements.map((e) => e.mandate.qualifier.settlementContext.settlementLayer);
121
- const hasIntentExecutorOps = settlementLayers.some((l) => l === 'INTENT_EXECUTOR' || l === 'SAME_CHAIN');
122
- if (!hasIntentExecutorOps) {
146
+ if (!signData.targetExecution) {
147
+ return undefined;
148
+ }
149
+ // Target executions are EVM-only (smart-session validator on destination).
150
+ // Non-EVM destinations don't have a validator there to verify the sig.
151
+ if (isNonEvmChain(targetChain)) {
123
152
  return undefined;
124
153
  }
125
154
  const resolvedSigners = await resolveSignersForChain(config, signers, targetChain.id);
@@ -127,13 +156,13 @@ async function getTargetExecutionSignature(config, intentOp, targetChain, signer
127
156
  !resolvedSigners.verifyExecutions) {
128
157
  return undefined;
129
158
  }
130
- const destination = getTargetExecutionMessage(config, intentOp);
131
159
  const validator = getValidator(config, signers);
132
160
  if (!validator) {
133
161
  throw new Error('Validator not available');
134
162
  }
135
163
  const ownerValidator = getOwnerValidator(config);
136
164
  const isRoot = validator.address === ownerValidator.address;
165
+ const destination = prepareTypedData(signData.targetExecution);
137
166
  const signature = await getDestinationSignature(config, resolvedSigners, validator, isRoot, targetChain, destination, [], true);
138
167
  return signature;
139
168
  }
@@ -151,7 +180,14 @@ async function signUserOperation(config, preparedUserOperation) {
151
180
  };
152
181
  }
153
182
  async function signAuthorizations(config, preparedTransaction) {
154
- return await signAuthorizationsInternal(config, preparedTransaction.intentRoute);
183
+ const transaction = preparedTransaction.transaction;
184
+ const sourceChains = 'chain' in transaction ? [transaction.chain] : transaction.sourceChains;
185
+ const targetChain = 'chain' in transaction ? transaction.chain : transaction.targetChain;
186
+ return await signAuthorizationsInternal(config, {
187
+ sourceChains,
188
+ targetChain,
189
+ eip7702InitSignature: transaction.eip7702InitSignature,
190
+ });
155
191
  }
156
192
  async function signMessage(config, message, chain, signers) {
157
193
  const validator = getValidator(config, signers);
@@ -239,19 +275,29 @@ async function signTypedDataWithSession(config, chain, validator, session, param
239
275
  });
240
276
  return await toErc6492Signature(config, signature, chain);
241
277
  }
242
- async function signAuthorizationsInternal(config, data) {
278
+ async function signAuthorizationsInternal(config, context) {
243
279
  const eoa = config.eoa;
244
280
  if (!eoa) {
245
281
  throw new Error('EIP-7702 initialization is required for EOA accounts');
246
282
  }
283
+ const eip7702InitSignature = context.eip7702InitSignature;
284
+ if (!eip7702InitSignature) {
285
+ return [];
286
+ }
247
287
  const accountAddress = getAddress(config);
248
- const requiredDelegations = 'intentOp' in data
249
- ? data.intentOp.signedMetadata.account.requiredDelegations || {}
250
- : {};
288
+ const { contract: eip7702Contract } = getEip7702InitCall(config, eip7702InitSignature);
289
+ // EIP-7702 authorization is EVM-only — there's no contract to delegate
290
+ // to on Solana / Tron. Skip the destination chain entirely when it's
291
+ // non-EVM; source chains are always EVM by construction.
292
+ const chains = new Map();
293
+ for (const chain of context.sourceChains ?? []) {
294
+ chains.set(chain.id, chain);
295
+ }
296
+ if (!isNonEvmChain(context.targetChain)) {
297
+ chains.set(context.targetChain.id, context.targetChain);
298
+ }
251
299
  const authorizations = [];
252
- for (const chainId in requiredDelegations) {
253
- const delegation = requiredDelegations[chainId];
254
- const chain = getChainById(Number(chainId));
300
+ for (const chain of chains.values()) {
255
301
  const walletClient = createWalletClient({
256
302
  chain,
257
303
  account: eoa,
@@ -260,23 +306,22 @@ async function signAuthorizationsInternal(config, data) {
260
306
  const code = await walletClient.getCode({
261
307
  address: accountAddress,
262
308
  });
263
- const isDelegated = code === concat(['0xef0100', delegation.contract.toLowerCase()]);
309
+ const isDelegated = code === concat(['0xef0100', eip7702Contract.toLowerCase()]);
264
310
  if (isDelegated) {
265
311
  continue;
266
312
  }
267
313
  const authorization = await walletClient.signAuthorization({
268
- contractAddress: delegation.contract,
269
- chainId: Number(chainId),
314
+ contractAddress: eip7702Contract,
315
+ chainId: chain.id,
270
316
  });
271
317
  authorizations.push(authorization);
272
318
  }
273
319
  return authorizations;
274
320
  }
275
321
  async function submitTransaction(config, signedTransaction, authorizations, dryRun = false) {
276
- const { intentRoute, intentInput, transaction, originSignatures, destinationSignature, targetExecutionSignature, } = signedTransaction;
322
+ const { quote, intentInput, transaction, originSignatures, destinationSignature, targetExecutionSignature, } = signedTransaction;
277
323
  const { sourceChains, targetChain } = getTransactionParams(transaction);
278
- const intentOp = intentRoute.intentOp;
279
- return await submitIntent(config, sourceChains, targetChain, intentOp, originSignatures, destinationSignature, targetExecutionSignature, authorizations, dryRun, intentInput);
324
+ return await submitIntentInternal(config, sourceChains, targetChain, quote, originSignatures, destinationSignature, targetExecutionSignature, authorizations, dryRun, intentInput);
280
325
  }
281
326
  async function submitUserOperation(config, signedUserOperation) {
282
327
  const chain = signedUserOperation.transaction.chain;
@@ -296,7 +341,6 @@ function getTransactionParams(transaction) {
296
341
  const settlementLayers = transaction.settlementLayers;
297
342
  const sourceAssets = transaction.sourceAssets;
298
343
  const feeAsset = transaction.feeAsset;
299
- const lockFunds = transaction.lockFunds;
300
344
  const auxiliaryFunds = transaction.auxiliaryFunds;
301
345
  const account = transaction.experimental_accountOverride;
302
346
  const recipient = transaction.recipient;
@@ -312,15 +356,21 @@ function getTransactionParams(transaction) {
312
356
  settlementLayers,
313
357
  sourceAssets,
314
358
  feeAsset,
315
- lockFunds,
316
359
  auxiliaryFunds,
317
360
  account,
318
361
  recipient,
319
362
  };
320
363
  }
321
364
  function getTokenRequests(targetChain, initialTokenRequests) {
322
- if (initialTokenRequests) {
323
- validateTokenSymbols(targetChain, initialTokenRequests.map((tokenRequest) => tokenRequest.address));
365
+ // Non-EVM destinations carry SPL mint / Tron T-prefixed addresses that
366
+ // aren't valid 0x-hex; skip symbol/EVM-address validation here and let
367
+ // the orchestrator validate per its own schema. EVM destinations keep
368
+ // the existing strict check so a typo on Optimism still fails fast.
369
+ if (initialTokenRequests && !isNonEvmChain(targetChain)) {
370
+ // Inside this branch targetChain is a viem `Chain`, which excludes the
371
+ // non-EVM transaction variant — token requests are EVM-typed here.
372
+ const evmRequests = initialTokenRequests;
373
+ validateTokenSymbols(targetChain, evmRequests.map((tokenRequest) => tokenRequest.address));
324
374
  }
325
375
  return initialTokenRequests ?? [];
326
376
  }
@@ -369,12 +419,19 @@ function getIntentAccount(config, eip7702InitSignature, account) {
369
419
  delegations,
370
420
  };
371
421
  }
372
- async function prepareTransactionAsIntent(config, sourceChains, targetChain, callInputs, gasLimit, tokenRequests, recipientInput, sponsored, eip7702InitSignature, settlementLayers, sourceAssets, feeAsset, lockFunds, auxiliaryFunds, account, signers) {
373
- const calls = parseCalls(callInputs, targetChain.id);
422
+ async function prepareTransactionAsIntent(config, sourceChains, targetChain, callInputs, gasLimit, tokenRequests, recipientInput, sponsored, eip7702InitSignature, settlementLayers, sourceAssets, feeAsset, auxiliaryFunds, account, signers) {
423
+ const targetChainId = getChainId(targetChain);
424
+ const calls = parseCalls(callInputs, targetChainId);
374
425
  const accountAccessList = createAccountAccessList(sourceChains, sourceAssets);
375
426
  function getRecipient(recipient) {
376
427
  if (typeof recipient === 'string') {
377
- // Passed as an address, assume it's an EOA
428
+ // Non-EVM recipients (Solana base58 / Tron T-prefix) carry no
429
+ // EVM smart-account semantics; orchestrator schema requires
430
+ // accountType / setupOps to be unset. Emit just the address.
431
+ if (isNonEvmChain(targetChain)) {
432
+ return { address: recipient };
433
+ }
434
+ // EVM passthrough — assume EOA.
378
435
  return {
379
436
  address: recipient,
380
437
  accountType: 'EOA',
@@ -390,13 +447,15 @@ async function prepareTransactionAsIntent(config, sourceChains, targetChain, cal
390
447
  const intentAccount = {
391
448
  ...getIntentAccount(config, eip7702InitSignature, account),
392
449
  ...(signers?.type === 'experimental_session' && {
393
- // Global fallback: target-chain sig for backward-compat with older orchestrators
394
- mockSignature: buildMockSignature(resolveSessionForChain(signers, targetChain.id).session, config.useDevContracts, sourceChains?.length ?? 1),
395
- // Per-chain map: enables accurate per-chain session validation gas simulation
450
+ // Per-chain map: enables accurate per-chain session validation gas
451
+ // simulation. Non-EVM destinations are excluded — they have no
452
+ // destination-side session validator, so adding the synthetic chain
453
+ // id would force users to configure a session that's never used and
454
+ // make `resolveSessionForChain` throw for per-chain session signers.
396
455
  mockSignatures: Object.fromEntries([
397
456
  ...new Set([
398
457
  ...(sourceChains ?? []).map((c) => c.id),
399
- targetChain.id,
458
+ ...(isNonEvmChain(targetChain) ? [] : [targetChainId]),
400
459
  ]),
401
460
  ].map((chainId) => [
402
461
  String(chainId),
@@ -435,9 +494,9 @@ async function prepareTransactionAsIntent(config, sourceChains, targetChain, cal
435
494
  }
436
495
  }
437
496
  const metaIntent = {
438
- destinationChainId: targetChain.id,
497
+ destinationChainId: targetChainId,
439
498
  tokenRequests: tokenRequests.map((tokenRequest) => ({
440
- tokenAddress: resolveTokenAddress(tokenRequest.address, targetChain.id),
499
+ tokenAddress: resolveTokenAddress(tokenRequest.address, targetChainId),
441
500
  amount: tokenRequest.amount,
442
501
  })),
443
502
  recipient,
@@ -446,19 +505,18 @@ async function prepareTransactionAsIntent(config, sourceChains, targetChain, cal
446
505
  destinationGasUnits: gasLimit,
447
506
  accountAccessList,
448
507
  options: {
449
- topupCompact: lockFunds ?? false,
450
508
  feeToken: feeAsset,
451
509
  sponsorSettings: sponsored
452
510
  ? typeof sponsored === 'object'
453
511
  ? {
454
- gasSponsored: sponsored.gas,
455
- bridgeFeesSponsored: sponsored.bridging,
456
- swapFeesSponsored: sponsored.swaps,
512
+ gas: sponsored.gas,
513
+ bridgeFees: sponsored.bridging,
514
+ swapFees: sponsored.swaps,
457
515
  }
458
516
  : {
459
- gasSponsored: sponsored,
460
- bridgeFeesSponsored: sponsored,
461
- swapFeesSponsored: sponsored,
517
+ gas: sponsored,
518
+ bridgeFees: sponsored,
519
+ swapFees: sponsored,
462
520
  }
463
521
  : undefined,
464
522
  settlementLayers,
@@ -469,11 +527,18 @@ async function prepareTransactionAsIntent(config, sourceChains, targetChain, cal
469
527
  };
470
528
  const serializedIntent = convertBigIntFields(metaIntent);
471
529
  const orchestrator = getOrchestrator(config._authProvider ?? createAuthProvider(config), config.endpointUrl, config.headers);
472
- const intentRoute = await orchestrator.getIntentRoute(metaIntent);
473
- return { intentRoute, intentInput: serializedIntent };
530
+ const { routes } = await orchestrator.createQuote(metaIntent);
531
+ const best = routes[0];
532
+ if (!best) {
533
+ throw new Error('Orchestrator returned no quote');
534
+ }
535
+ return {
536
+ quotes: { best, all: routes },
537
+ intentInput: serializedIntent,
538
+ };
474
539
  }
475
- async function signIntent(config, intentOp, targetChain, signers, targetExecution) {
476
- const { origin, destination } = getIntentMessages(config, intentOp);
540
+ async function signIntent(config, signData, targetChain, signers, targetExecution) {
541
+ const { origin, destination } = getIntentMessages(signData);
477
542
  if (config.account?.type === 'eoa') {
478
543
  const eoa = config.eoa;
479
544
  if (!eoa) {
@@ -508,7 +573,14 @@ async function signIntent(config, intentOp, targetChain, signers, targetExecutio
508
573
  const signature = await signIntentTypedData(config, originSigners, validator, isRoot, typedData, chain, targetExecution ?? false);
509
574
  originSignatures.push(signature);
510
575
  }
511
- const destinationSigners = await resolveSignersForChain(config, signers, targetChain.id);
576
+ // Non-EVM destinations have no destination-side validator, so there's no
577
+ // session to resolve and no signer to derive. Skipping here matters for
578
+ // per-chain experimental sessions: `resolveSessionForChain` would throw
579
+ // `No session configured for chain {synthetic-id}` since users never
580
+ // configure a session keyed by the synthetic Solana/Tron chain id.
581
+ const destinationSigners = isNonEvmChain(targetChain)
582
+ ? undefined
583
+ : await resolveSignersForChain(config, signers, targetChain.id);
512
584
  const destinationSignature = await getDestinationSignature(config, destinationSigners, validator, isRoot, targetChain, destination, originSignatures, targetExecution ?? false);
513
585
  return {
514
586
  originSignatures,
@@ -516,18 +588,25 @@ async function signIntent(config, intentOp, targetChain, signers, targetExecutio
516
588
  };
517
589
  }
518
590
  async function getDestinationSignature(config, signers, validator, isRoot, targetChain, destination, originSignatures, targetExecution) {
519
- // Smart sessions require a separate destination signature because the
520
- // session enable data differs per chain
521
- if (signers?.type === 'experimental_session') {
522
- return await signDestinationSeparately(config, signers, validator, isRoot, targetChain, destination, targetExecution);
523
- }
524
- // ERC-7739 with K1 validator requires a separate destination signature because
525
- // the account's eip712Domain() returns the target chain's chainId, which differs
526
- // from the origin chain used for the last origin signature
527
- const isK1Validator = validator.address.toLowerCase() ===
528
- K1_DEFAULT_VALIDATOR_ADDRESS.toLowerCase();
529
- if (isK1Validator && supportsEip712(validator)) {
530
- return await signDestinationSeparately(config, signers, validator, isRoot, targetChain, destination, targetExecution);
591
+ // Non-EVM destinations have no destination-side validator, no
592
+ // eip712Domain(), no smart session enable data. Settlement is solver-
593
+ // mediated on the orchestrator side and the origin signatures alone
594
+ // authorize the bundle. Fall through to the "reuse last origin sig"
595
+ // branch instead of trying to sign on Solana / Tron.
596
+ if (!isNonEvmChain(targetChain)) {
597
+ // Smart sessions require a separate destination signature because the
598
+ // session enable data differs per chain
599
+ if (signers?.type === 'experimental_session') {
600
+ return await signDestinationSeparately(config, signers, validator, isRoot, targetChain, destination, targetExecution);
601
+ }
602
+ // ERC-7739 with K1 validator requires a separate destination signature because
603
+ // the account's eip712Domain() returns the target chain's chainId, which differs
604
+ // from the origin chain used for the last origin signature
605
+ const isK1Validator = validator.address.toLowerCase() ===
606
+ K1_DEFAULT_VALIDATOR_ADDRESS.toLowerCase();
607
+ if (isK1Validator && supportsEip712(validator)) {
608
+ return await signDestinationSeparately(config, signers, validator, isRoot, targetChain, destination, targetExecution);
609
+ }
531
610
  }
532
611
  const lastOriginSignature = originSignatures.at(-1);
533
612
  return typeof lastOriginSignature === 'object'
@@ -541,49 +620,62 @@ async function signDestinationSeparately(config, signers, validator, isRoot, tar
541
620
  ? destinationSignatures.preClaimSig
542
621
  : (destinationSignatures ?? '0x');
543
622
  }
544
- function getIntentMessages(config, intentOp) {
545
- const address = getAddress(config);
546
- const intentExecutor = getIntentExecutor(config);
547
- const withPermit2 = intentOp.elements.some((element) => element.mandate.qualifier.settlementContext.fundingMethod === 'PERMIT2');
548
- const withIntentExecutorOps = intentOp.elements.some((element) => element.mandate.qualifier.settlementContext.settlementLayer ===
549
- 'INTENT_EXECUTOR');
550
- const origin = [];
551
- for (const element of intentOp.elements) {
552
- if (withIntentExecutorOps) {
553
- const typedData = getSingleChainOpsTypedData(address, intentExecutor.address, element, BigInt(intentOp.nonce));
554
- origin.push(typedData);
555
- }
556
- else if (withPermit2) {
557
- const typedData = getPermit2TypedData(element, BigInt(intentOp.nonce), BigInt(intentOp.expires));
558
- origin.push(typedData);
559
- }
560
- else {
561
- const typedData = getCompactTypedData(intentOp);
562
- origin.push(typedData);
563
- }
564
- }
565
- const destination = origin.at(-1);
623
+ function getIntentMessages(signData) {
566
624
  return {
567
- origin,
568
- destination,
625
+ origin: signData.origin.map(prepareTypedData),
626
+ destination: prepareTypedData(signData.destination),
627
+ targetExecution: signData.targetExecution
628
+ ? prepareTypedData(signData.targetExecution)
629
+ : undefined,
569
630
  };
570
631
  }
571
- function getTargetExecutionMessage(config, intentOp) {
572
- const address = getAddress(config);
573
- const intentExecutor = getIntentExecutor(config);
574
- const lastElement = intentOp.elements.at(-1);
575
- const typedData = getSingleChainOpsTypedData(address, intentExecutor.address, lastElement, BigInt(intentOp.targetExecutionNonce));
576
- typedData.message.gasRefund = typedData.message.gasRefund ?? {
577
- token: '0x0000000000000000000000000000000000000000',
578
- exchangeRate: 0n,
579
- overhead: 0n,
632
+ // Server emits uint*/int* values as decimal strings; viem's hashTypedData
633
+ // expects bigint. Walk the message tree against the type schema and coerce
634
+ // numeric fields back to bigint before signing.
635
+ function prepareTypedData(td) {
636
+ const types = td.types;
637
+ return {
638
+ ...td,
639
+ message: coerceTypedDataMessage(types, td.primaryType, td.message),
580
640
  };
581
- return typedData;
641
+ }
642
+ function coerceTypedDataMessage(types, primaryType, message) {
643
+ const fields = types[primaryType];
644
+ if (!fields)
645
+ return message;
646
+ const result = { ...message };
647
+ for (const { name, type } of fields) {
648
+ if (name in message) {
649
+ result[name] = coerceTypedDataValue(types, type, message[name]);
650
+ }
651
+ }
652
+ return result;
653
+ }
654
+ function coerceTypedDataValue(types, type, value) {
655
+ if (value === null || value === undefined)
656
+ return value;
657
+ const arrayMatch = type.match(/^(.+)\[\d*\]$/);
658
+ if (arrayMatch) {
659
+ const elementType = arrayMatch[1];
660
+ if (!Array.isArray(value))
661
+ return value;
662
+ return value.map((v) => coerceTypedDataValue(types, elementType, v));
663
+ }
664
+ if (/^u?int\d*$/.test(type)) {
665
+ if (typeof value === 'string' || typeof value === 'number') {
666
+ return BigInt(value);
667
+ }
668
+ return value;
669
+ }
670
+ if (types[type]) {
671
+ return coerceTypedDataMessage(types, type, value);
672
+ }
673
+ return value;
582
674
  }
583
675
  /** Computes claim policy calldata when parameters are Permit2 typed data with claim policies. */
584
676
  function resolveClaimPolicyData(signers, parameters) {
585
677
  if (parameters.primaryType !== 'PermitBatchWitnessTransferFrom' ||
586
- !signers.session.claimPolicies?.length) {
678
+ !signers.session.claimPolicies.length) {
587
679
  return undefined;
588
680
  }
589
681
  const msg = parameters.message;
@@ -594,7 +686,7 @@ function resolveClaimPolicyData(signers, parameters) {
594
686
  typeof msg.deadline !== 'bigint') {
595
687
  return undefined;
596
688
  }
597
- return buildPermit2ClaimPolicyCalldata(signers.session.claimPolicies[0], parameters.message);
689
+ return buildPermit2ClaimPolicyCalldata(resolvePermit2ClaimPolicy(signers.session.claimPolicies[0]), parameters.message);
598
690
  }
599
691
  async function signIntentTypedData(config, signers, validator, isRoot, parameters, chain, targetExecution) {
600
692
  if (supportsEip712(validator)) {
@@ -710,40 +802,39 @@ async function submitUserOp(config, chain, userOp, signature) {
710
802
  chain: chain.id,
711
803
  };
712
804
  }
713
- async function submitIntent(config, sourceChains, targetChain, intentOp, originSignatures, destinationSignature, targetExecutionSignature, authorizations, dryRun, intentInput) {
714
- return submitIntentInternal(config, sourceChains, targetChain, intentOp, originSignatures, destinationSignature, targetExecutionSignature, authorizations, dryRun, intentInput);
715
- }
716
- function createSignedIntentOp(intentOp, originSignatures, destinationSignature, targetExecutionSignature, authorizations) {
717
- return {
718
- ...intentOp,
719
- originSignatures,
720
- destinationSignature,
721
- targetExecutionSignature,
722
- signedAuthorizations: authorizations.length > 0
723
- ? authorizations.map((authorization) => ({
724
- chainId: authorization.chainId,
725
- address: authorization.address,
726
- nonce: authorization.nonce,
727
- yParity: authorization.yParity ?? 0,
728
- r: authorization.r,
729
- s: authorization.s,
730
- }))
731
- : undefined,
805
+ async function submitIntentInternal(config, sourceChains, targetChain, quote, originSignatures, destinationSignature, targetExecutionSignature, authorizations, dryRun, intentInput) {
806
+ const request = {
807
+ intentId: quote.intentId,
808
+ signatures: {
809
+ origin: originSignatures,
810
+ destination: destinationSignature,
811
+ ...(targetExecutionSignature !== undefined && {
812
+ targetExecution: targetExecutionSignature,
813
+ }),
814
+ },
815
+ ...(authorizations.length > 0 && {
816
+ authorizations: {
817
+ sponsor: authorizations.map((authorization) => ({
818
+ chainId: authorization.chainId,
819
+ address: authorization.address,
820
+ nonce: authorization.nonce,
821
+ yParity: authorization.yParity ?? 0,
822
+ r: authorization.r,
823
+ s: authorization.s,
824
+ })),
825
+ },
826
+ }),
827
+ ...(dryRun && { options: { dryRun: true } }),
732
828
  };
733
- }
734
- async function submitIntentInternal(config, sourceChains, targetChain, intentOp, originSignatures, destinationSignature, targetExecutionSignature, authorizations, dryRun, intentInput) {
735
- const signedIntentOp = createSignedIntentOp(intentOp, originSignatures, destinationSignature, targetExecutionSignature, authorizations);
736
829
  const isSponsored = !!intentInput?.options?.sponsorSettings;
737
830
  const orchestrator = getOrchestrator(config._authProvider ?? createAuthProvider(config), config.endpointUrl, config.headers);
738
- const intentResults = await orchestrator.submitIntent(signedIntentOp, dryRun, intentInput ? { intentInput, isSponsored } : undefined);
739
- // Some settlement paths (e.g. SAME_CHAIN) may not return a result.id — fall
740
- // back to the nonce which the orchestrator also accepts as an intent identifier.
741
- const intentId = intentResults.result.id ?? intentOp.nonce;
831
+ const response = await orchestrator.createIntent(request, intentInput ? { intentInput, isSponsored } : undefined);
742
832
  return {
743
833
  type: 'intent',
744
- id: BigInt(intentId),
834
+ id: response.intentId,
745
835
  sourceChains: sourceChains?.map((chain) => chain.id),
746
- targetChain: targetChain.id,
836
+ targetChain: getChainId(targetChain),
837
+ expiresAt: quote.expiresAt,
747
838
  };
748
839
  }
749
840
  async function getValidatorAccount(config, signers, publicClient, chain) {
@@ -801,6 +892,8 @@ function getValidator(config, signers) {
801
892
  return undefined;
802
893
  }
803
894
  function parseCalls(calls, chainId) {
895
+ // Destination calls only run on EVM chains (non-EVM destinations reject
896
+ // calls upstream), so the resolved `to` is always a viem `Address` here.
804
897
  return calls.map((call) => ({
805
898
  data: call.data ?? '0x',
806
899
  value: call.value ?? 0n,
@@ -816,12 +909,34 @@ function createAccountAccessList(sourceChains, sourceAssets) {
816
909
  if (Array.isArray(sourceAssets)) {
817
910
  const isExactConfig = sourceAssets.length > 0 && typeof sourceAssets[0] !== 'string';
818
911
  if (isExactConfig) {
819
- const resolvedConfigs = sourceAssets.map((config) => ({
820
- chainId: config.chain.id,
821
- tokenAddress: resolveTokenAddress(config.address, config.chain.id),
822
- amount: config.amount,
823
- }));
824
- return resolvedConfigs;
912
+ const chainTokens = {};
913
+ const chainTokenAmounts = {};
914
+ for (const config of sourceAssets) {
915
+ const chainId = config.chain.id;
916
+ // Source assets live on viem `Chain`s, which are always EVM, so the
917
+ // resolved value is a viem `Address`.
918
+ const tokenAddress = resolveTokenAddress(config.address, config.chain.id);
919
+ if (config.amount !== undefined) {
920
+ if (!chainTokenAmounts[chainId])
921
+ chainTokenAmounts[chainId] = {};
922
+ chainTokenAmounts[chainId][tokenAddress] = config.amount;
923
+ }
924
+ else {
925
+ if (!chainTokens[chainId])
926
+ chainTokens[chainId] = [];
927
+ chainTokens[chainId].push(tokenAddress);
928
+ }
929
+ }
930
+ const out = {};
931
+ if (Object.keys(chainTokens).length > 0) {
932
+ out.chainTokens =
933
+ chainTokens;
934
+ }
935
+ if (Object.keys(chainTokenAmounts).length > 0) {
936
+ out.chainTokenAmounts =
937
+ chainTokenAmounts;
938
+ }
939
+ return out;
825
940
  }
826
941
  return chainIds
827
942
  ? { chainIds, tokens: sourceAssets }