@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.
- package/README.md +43 -2
- package/dist/src/accounts/index.d.ts.map +1 -1
- package/dist/src/accounts/index.js +6 -34
- package/dist/src/accounts/json-rpc/providers.d.ts.map +1 -1
- package/dist/src/accounts/json-rpc/providers.js +3 -2
- package/dist/src/actions/smart-sessions.d.ts.map +1 -1
- package/dist/src/actions/smart-sessions.js +3 -3
- package/dist/src/errors/index.d.ts +3 -3
- package/dist/src/errors/index.d.ts.map +1 -1
- package/dist/src/errors/index.js +6 -4
- package/dist/src/execution/compact.d.ts +1 -144
- package/dist/src/execution/compact.d.ts.map +1 -1
- package/dist/src/execution/compact.js +1 -109
- package/dist/src/execution/error.d.ts +11 -2
- package/dist/src/execution/error.d.ts.map +1 -1
- package/dist/src/execution/error.js +11 -3
- package/dist/src/execution/index.d.ts +10 -11
- package/dist/src/execution/index.d.ts.map +1 -1
- package/dist/src/execution/index.js +37 -47
- package/dist/src/execution/utils.d.ts +34 -16
- package/dist/src/execution/utils.d.ts.map +1 -1
- package/dist/src/execution/utils.js +259 -144
- package/dist/src/index.d.ts +22 -16
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +18 -45
- package/dist/src/modules/index.d.ts +2 -2
- package/dist/src/modules/index.d.ts.map +1 -1
- package/dist/src/modules/index.js +2 -2
- package/dist/src/modules/read.d.ts.map +1 -1
- package/dist/src/modules/read.js +2 -4
- package/dist/src/modules/validators/index.d.ts +2 -2
- package/dist/src/modules/validators/index.d.ts.map +1 -1
- package/dist/src/modules/validators/index.js +2 -2
- package/dist/src/modules/validators/permissions.d.ts +5 -0
- package/dist/src/modules/validators/permissions.d.ts.map +1 -0
- package/dist/src/modules/validators/permissions.js +111 -0
- package/dist/src/modules/validators/policies/claim/permit2.d.ts +29 -3
- package/dist/src/modules/validators/policies/claim/permit2.d.ts.map +1 -1
- package/dist/src/modules/validators/smart-sessions.d.ts +14 -27
- package/dist/src/modules/validators/smart-sessions.d.ts.map +1 -1
- package/dist/src/modules/validators/smart-sessions.js +74 -22
- package/dist/src/orchestrator/caip2.d.ts +13 -0
- package/dist/src/orchestrator/caip2.d.ts.map +1 -0
- package/dist/src/orchestrator/caip2.js +52 -0
- package/dist/src/orchestrator/client.d.ts +12 -11
- package/dist/src/orchestrator/client.d.ts.map +1 -1
- package/dist/src/orchestrator/client.js +217 -296
- package/dist/src/orchestrator/consts.d.ts +2 -2
- package/dist/src/orchestrator/consts.d.ts.map +1 -1
- package/dist/src/orchestrator/consts.js +2 -2
- package/dist/src/orchestrator/destinations.d.ts +23 -0
- package/dist/src/orchestrator/destinations.d.ts.map +1 -0
- package/dist/src/orchestrator/destinations.js +36 -0
- package/dist/src/orchestrator/error.d.ts +72 -217
- package/dist/src/orchestrator/error.d.ts.map +1 -1
- package/dist/src/orchestrator/error.js +117 -195
- package/dist/src/orchestrator/index.d.ts +6 -5
- package/dist/src/orchestrator/index.d.ts.map +1 -1
- package/dist/src/orchestrator/index.js +4 -3
- package/dist/src/orchestrator/registry.d.ts +3 -9
- package/dist/src/orchestrator/registry.d.ts.map +1 -1
- package/dist/src/orchestrator/registry.js +11 -26
- package/dist/src/orchestrator/types.d.ts +136 -239
- package/dist/src/orchestrator/types.d.ts.map +1 -1
- package/dist/src/types.d.ts +126 -37
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/index.d.ts +2 -1
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/index.js +2 -1
- package/dist/src/utils/walletClient.d.ts.map +1 -0
- package/dist/src/{accounts → utils}/walletClient.js +1 -1
- package/package.json +2 -6
- package/dist/src/accounts/passport.d.ts +0 -9
- package/dist/src/accounts/passport.d.ts.map +0 -1
- package/dist/src/accounts/passport.js +0 -78
- package/dist/src/accounts/walletClient.d.ts.map +0 -1
- package/dist/src/actions/compact.d.ts +0 -15
- package/dist/src/actions/compact.d.ts.map +0 -1
- package/dist/src/actions/compact.js +0 -200
- package/dist/src/actions/deployment.d.ts +0 -19
- package/dist/src/actions/deployment.d.ts.map +0 -1
- package/dist/src/actions/deployment.js +0 -76
- package/dist/src/execution/permit2.d.ts +0 -143
- package/dist/src/execution/permit2.d.ts.map +0 -1
- package/dist/src/execution/permit2.js +0 -280
- package/dist/src/execution/singleChainOps.d.ts +0 -41
- package/dist/src/execution/singleChainOps.d.ts.map +0 -1
- package/dist/src/execution/singleChainOps.js +0 -42
- package/dist/src/execution/types.d.ts +0 -36
- package/dist/src/execution/types.d.ts.map +0 -1
- package/dist/src/execution/types.js +0 -1
- /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 {
|
|
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
|
|
32
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
97
|
-
|
|
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
|
|
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,
|
|
106
|
-
const targetExecutionSignature = await getTargetExecutionSignature(config,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
|
249
|
-
|
|
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
|
|
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',
|
|
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:
|
|
269
|
-
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 {
|
|
322
|
+
const { quote, intentInput, transaction, originSignatures, destinationSignature, targetExecutionSignature, } = signedTransaction;
|
|
277
323
|
const { sourceChains, targetChain } = getTransactionParams(transaction);
|
|
278
|
-
|
|
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
|
-
|
|
323
|
-
|
|
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,
|
|
373
|
-
const
|
|
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
|
-
//
|
|
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
|
-
//
|
|
394
|
-
|
|
395
|
-
//
|
|
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
|
|
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:
|
|
497
|
+
destinationChainId: targetChainId,
|
|
439
498
|
tokenRequests: tokenRequests.map((tokenRequest) => ({
|
|
440
|
-
tokenAddress: resolveTokenAddress(tokenRequest.address,
|
|
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
|
-
|
|
455
|
-
|
|
456
|
-
|
|
512
|
+
gas: sponsored.gas,
|
|
513
|
+
bridgeFees: sponsored.bridging,
|
|
514
|
+
swapFees: sponsored.swaps,
|
|
457
515
|
}
|
|
458
516
|
: {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
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
|
|
473
|
-
|
|
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,
|
|
476
|
-
const { origin, destination } = getIntentMessages(
|
|
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
|
-
|
|
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
|
-
//
|
|
520
|
-
// session enable data
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
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(
|
|
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
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
const
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
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
|
|
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:
|
|
834
|
+
id: response.intentId,
|
|
745
835
|
sourceChains: sourceChains?.map((chain) => chain.id),
|
|
746
|
-
targetChain: targetChain
|
|
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
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
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 }
|