@debridge-finance/borderless-validation-sdk 0.0.5 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/helpers/evm-dln-hook-pack.js +8 -6
- package/dist/cjs/helpers/evm-dln-hook-pack.js.map +1 -1
- package/dist/cjs/helpers/evm-gas-compensation-tx.js +2 -1
- package/dist/cjs/helpers/evm-gas-compensation-tx.js.map +1 -1
- package/dist/cjs/helpers/evm-intent-id.js +6 -5
- package/dist/cjs/helpers/evm-intent-id.js.map +1 -1
- package/dist/cjs/helpers/evm-trade-amounts.js +25 -43
- package/dist/cjs/helpers/evm-trade-amounts.js.map +1 -1
- package/dist/cjs/helpers/expected-delegate.js +10 -11
- package/dist/cjs/helpers/expected-delegate.js.map +1 -1
- package/dist/cjs/helpers/gas-compensation.js +3 -0
- package/dist/cjs/helpers/gas-compensation.js.map +1 -1
- package/dist/cjs/helpers/hex.js +35 -0
- package/dist/cjs/helpers/hex.js.map +1 -1
- package/dist/cjs/helpers/integer.js +10 -0
- package/dist/cjs/helpers/integer.js.map +1 -0
- package/dist/cjs/helpers/placeholder.js +3 -2
- package/dist/cjs/helpers/placeholder.js.map +1 -1
- package/dist/cjs/helpers/solana-intent-id.js +6 -5
- package/dist/cjs/helpers/solana-intent-id.js.map +1 -1
- package/dist/cjs/helpers/synthetic-native-wrap.js +56 -0
- package/dist/cjs/helpers/synthetic-native-wrap.js.map +1 -0
- package/dist/cjs/types/enums.js +2 -0
- package/dist/cjs/types/enums.js.map +1 -1
- package/dist/cjs/types/request.js +27 -5
- package/dist/cjs/types/request.js.map +1 -1
- package/dist/cjs/types/response.js +11 -3
- package/dist/cjs/types/response.js.map +1 -1
- package/dist/cjs/types/validation.js +40 -1
- package/dist/cjs/types/validation.js.map +1 -1
- package/dist/cjs/validations/accumulative-token.js +272 -0
- package/dist/cjs/validations/accumulative-token.js.map +1 -0
- package/dist/cjs/validations/compensation-hook.js +9 -0
- package/dist/cjs/validations/compensation-hook.js.map +1 -1
- package/dist/cjs/validations/cost-token.js +56 -0
- package/dist/cjs/validations/cost-token.js.map +1 -0
- package/dist/cjs/validations/dln-metadata.js +63 -0
- package/dist/cjs/validations/dln-metadata.js.map +1 -0
- package/dist/cjs/validations/evm-caveats.js +5 -3
- package/dist/cjs/validations/evm-caveats.js.map +1 -1
- package/dist/cjs/validations/evm-op-budget.js +4 -4
- package/dist/cjs/validations/evm-op-budget.js.map +1 -1
- package/dist/cjs/validations/evm-op-hook.js +7 -1
- package/dist/cjs/validations/evm-op-hook.js.map +1 -1
- package/dist/cjs/validations/evm-op-wrap.js +6 -5
- package/dist/cjs/validations/evm-op-wrap.js.map +1 -1
- package/dist/cjs/validations/evm-permit2.js +7 -4
- package/dist/cjs/validations/evm-permit2.js.map +1 -1
- package/dist/cjs/validations/evm-required-actions.js +7 -4
- package/dist/cjs/validations/evm-required-actions.js.map +1 -1
- package/dist/cjs/validations/external-call.js +330 -0
- package/dist/cjs/validations/external-call.js.map +1 -0
- package/dist/cjs/validations/hooks-common.js +38 -2
- package/dist/cjs/validations/hooks-common.js.map +1 -1
- package/dist/cjs/validations/intent-tokens.js +54 -40
- package/dist/cjs/validations/intent-tokens.js.map +1 -1
- package/dist/cjs/validations/intent.js +192 -71
- package/dist/cjs/validations/intent.js.map +1 -1
- package/dist/cjs/validations/ptp.js +157 -0
- package/dist/cjs/validations/ptp.js.map +1 -0
- package/dist/cjs/validations/required-actions.js +2 -2
- package/dist/cjs/validations/required-actions.js.map +1 -1
- package/dist/cjs/validations/solana-hook.js +12 -0
- package/dist/cjs/validations/solana-hook.js.map +1 -1
- package/dist/cjs/validations/solana-op-budget.js +20 -40
- package/dist/cjs/validations/solana-op-budget.js.map +1 -1
- package/dist/cjs/validations/solana-op-wrap.js +27 -32
- package/dist/cjs/validations/solana-op-wrap.js.map +1 -1
- package/dist/cjs/validations/total-dst-amount.js +432 -0
- package/dist/cjs/validations/total-dst-amount.js.map +1 -0
- package/dist/cjs/validations/trade-grouping.js +67 -25
- package/dist/cjs/validations/trade-grouping.js.map +1 -1
- package/dist/cjs/validations/trade-matching.js +112 -0
- package/dist/cjs/validations/trade-matching.js.map +1 -0
- package/dist/cjs/validations/trades.js +365 -71
- package/dist/cjs/validations/trades.js.map +1 -1
- package/dist/cjs/validator.js +22 -4
- package/dist/cjs/validator.js.map +1 -1
- package/dist/cjs/whitelists/environment-config.js +5 -5
- package/dist/cjs/whitelists/environment-config.js.map +1 -1
- package/dist/esm/helpers/evm-dln-hook-pack.js +8 -6
- package/dist/esm/helpers/evm-dln-hook-pack.js.map +1 -1
- package/dist/esm/helpers/evm-gas-compensation-tx.js +2 -1
- package/dist/esm/helpers/evm-gas-compensation-tx.js.map +1 -1
- package/dist/esm/helpers/evm-intent-id.js +6 -5
- package/dist/esm/helpers/evm-intent-id.js.map +1 -1
- package/dist/esm/helpers/evm-trade-amounts.js +26 -44
- package/dist/esm/helpers/evm-trade-amounts.js.map +1 -1
- package/dist/esm/helpers/expected-delegate.js +10 -11
- package/dist/esm/helpers/expected-delegate.js.map +1 -1
- package/dist/esm/helpers/gas-compensation.js +3 -0
- package/dist/esm/helpers/gas-compensation.js.map +1 -1
- package/dist/esm/helpers/hex.js +29 -0
- package/dist/esm/helpers/hex.js.map +1 -1
- package/dist/esm/helpers/integer.js +7 -0
- package/dist/esm/helpers/integer.js.map +1 -0
- package/dist/esm/helpers/placeholder.js +3 -2
- package/dist/esm/helpers/placeholder.js.map +1 -1
- package/dist/esm/helpers/solana-intent-id.js +6 -5
- package/dist/esm/helpers/solana-intent-id.js.map +1 -1
- package/dist/esm/helpers/synthetic-native-wrap.js +52 -0
- package/dist/esm/helpers/synthetic-native-wrap.js.map +1 -0
- package/dist/esm/types/enums.js +2 -0
- package/dist/esm/types/enums.js.map +1 -1
- package/dist/esm/types/request.js +25 -4
- package/dist/esm/types/request.js.map +1 -1
- package/dist/esm/types/response.js +11 -3
- package/dist/esm/types/response.js.map +1 -1
- package/dist/esm/types/validation.js +40 -1
- package/dist/esm/types/validation.js.map +1 -1
- package/dist/esm/validations/accumulative-token.js +269 -0
- package/dist/esm/validations/accumulative-token.js.map +1 -0
- package/dist/esm/validations/compensation-hook.js +9 -0
- package/dist/esm/validations/compensation-hook.js.map +1 -1
- package/dist/esm/validations/cost-token.js +53 -0
- package/dist/esm/validations/cost-token.js.map +1 -0
- package/dist/esm/validations/dln-metadata.js +56 -0
- package/dist/esm/validations/dln-metadata.js.map +1 -0
- package/dist/esm/validations/evm-caveats.js +5 -3
- package/dist/esm/validations/evm-caveats.js.map +1 -1
- package/dist/esm/validations/evm-op-budget.js +4 -4
- package/dist/esm/validations/evm-op-budget.js.map +1 -1
- package/dist/esm/validations/evm-op-hook.js +7 -1
- package/dist/esm/validations/evm-op-hook.js.map +1 -1
- package/dist/esm/validations/evm-op-wrap.js +6 -5
- package/dist/esm/validations/evm-op-wrap.js.map +1 -1
- package/dist/esm/validations/evm-permit2.js +7 -4
- package/dist/esm/validations/evm-permit2.js.map +1 -1
- package/dist/esm/validations/evm-required-actions.js +7 -4
- package/dist/esm/validations/evm-required-actions.js.map +1 -1
- package/dist/esm/validations/external-call.js +325 -0
- package/dist/esm/validations/external-call.js.map +1 -0
- package/dist/esm/validations/hooks-common.js +38 -2
- package/dist/esm/validations/hooks-common.js.map +1 -1
- package/dist/esm/validations/intent-tokens.js +55 -41
- package/dist/esm/validations/intent-tokens.js.map +1 -1
- package/dist/esm/validations/intent.js +194 -73
- package/dist/esm/validations/intent.js.map +1 -1
- package/dist/esm/validations/ptp.js +154 -0
- package/dist/esm/validations/ptp.js.map +1 -0
- package/dist/esm/validations/required-actions.js +2 -2
- package/dist/esm/validations/required-actions.js.map +1 -1
- package/dist/esm/validations/solana-hook.js +13 -1
- package/dist/esm/validations/solana-hook.js.map +1 -1
- package/dist/esm/validations/solana-op-budget.js +21 -41
- package/dist/esm/validations/solana-op-budget.js.map +1 -1
- package/dist/esm/validations/solana-op-wrap.js +28 -33
- package/dist/esm/validations/solana-op-wrap.js.map +1 -1
- package/dist/esm/validations/total-dst-amount.js +429 -0
- package/dist/esm/validations/total-dst-amount.js.map +1 -0
- package/dist/esm/validations/trade-grouping.js +67 -25
- package/dist/esm/validations/trade-grouping.js.map +1 -1
- package/dist/esm/validations/trade-matching.js +109 -0
- package/dist/esm/validations/trade-matching.js.map +1 -0
- package/dist/esm/validations/trades.js +365 -71
- package/dist/esm/validations/trades.js.map +1 -1
- package/dist/esm/validator.js +22 -4
- package/dist/esm/validator.js.map +1 -1
- package/dist/esm/whitelists/environment-config.js +5 -5
- package/dist/esm/whitelists/environment-config.js.map +1 -1
- package/dist/types/helpers/evm-dln-hook-pack.d.ts.map +1 -1
- package/dist/types/helpers/evm-gas-compensation-tx.d.ts.map +1 -1
- package/dist/types/helpers/evm-intent-id.d.ts.map +1 -1
- package/dist/types/helpers/evm-trade-amounts.d.ts +1 -1
- package/dist/types/helpers/evm-trade-amounts.d.ts.map +1 -1
- package/dist/types/helpers/expected-delegate.d.ts.map +1 -1
- package/dist/types/helpers/gas-compensation.d.ts.map +1 -1
- package/dist/types/helpers/hex.d.ts +6 -0
- package/dist/types/helpers/hex.d.ts.map +1 -1
- package/dist/types/helpers/integer.d.ts +2 -0
- package/dist/types/helpers/integer.d.ts.map +1 -0
- package/dist/types/helpers/placeholder.d.ts.map +1 -1
- package/dist/types/helpers/solana-intent-id.d.ts.map +1 -1
- package/dist/types/helpers/synthetic-native-wrap.d.ts +4 -0
- package/dist/types/helpers/synthetic-native-wrap.d.ts.map +1 -0
- package/dist/types/types/enums.d.ts +4 -2
- package/dist/types/types/enums.d.ts.map +1 -1
- package/dist/types/types/request.d.ts +85 -6
- package/dist/types/types/request.d.ts.map +1 -1
- package/dist/types/types/response.d.ts +96 -12
- package/dist/types/types/response.d.ts.map +1 -1
- package/dist/types/types/validation.d.ts +36 -1
- package/dist/types/types/validation.d.ts.map +1 -1
- package/dist/types/validations/accumulative-token.d.ts +3 -0
- package/dist/types/validations/accumulative-token.d.ts.map +1 -0
- package/dist/types/validations/compensation-hook.d.ts.map +1 -1
- package/dist/types/validations/cost-token.d.ts +3 -0
- package/dist/types/validations/cost-token.d.ts.map +1 -0
- package/dist/types/validations/dln-metadata.d.ts +7 -0
- package/dist/types/validations/dln-metadata.d.ts.map +1 -0
- package/dist/types/validations/evm-caveats.d.ts.map +1 -1
- package/dist/types/validations/evm-op-hook.d.ts.map +1 -1
- package/dist/types/validations/evm-op-wrap.d.ts.map +1 -1
- package/dist/types/validations/evm-permit2.d.ts.map +1 -1
- package/dist/types/validations/evm-required-actions.d.ts +1 -1
- package/dist/types/validations/evm-required-actions.d.ts.map +1 -1
- package/dist/types/validations/external-call.d.ts +15 -0
- package/dist/types/validations/external-call.d.ts.map +1 -0
- package/dist/types/validations/intent-tokens.d.ts.map +1 -1
- package/dist/types/validations/intent.d.ts +1 -1
- package/dist/types/validations/intent.d.ts.map +1 -1
- package/dist/types/validations/ptp.d.ts +3 -0
- package/dist/types/validations/ptp.d.ts.map +1 -0
- package/dist/types/validations/required-actions.d.ts +1 -1
- package/dist/types/validations/required-actions.d.ts.map +1 -1
- package/dist/types/validations/solana-hook.d.ts.map +1 -1
- package/dist/types/validations/solana-op-budget.d.ts.map +1 -1
- package/dist/types/validations/solana-op-wrap.d.ts.map +1 -1
- package/dist/types/validations/total-dst-amount.d.ts +3 -0
- package/dist/types/validations/total-dst-amount.d.ts.map +1 -0
- package/dist/types/validations/trade-grouping.d.ts +2 -1
- package/dist/types/validations/trade-grouping.d.ts.map +1 -1
- package/dist/types/validations/trade-matching.d.ts +13 -0
- package/dist/types/validations/trade-matching.d.ts.map +1 -0
- package/dist/types/validations/trades.d.ts +2 -1
- package/dist/types/validations/trades.d.ts.map +1 -1
- package/dist/types/validator.d.ts.map +1 -1
- package/dist/types/whitelists/environment-config.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateTotalDstAmount = validateTotalDstAmount;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
const subscription_to_chain_id_1 = require("../whitelists/subscription-to-chain-id");
|
|
6
|
+
const address_1 = require("../helpers/address");
|
|
7
|
+
const integer_1 = require("../helpers/integer");
|
|
8
|
+
// Asset consolidation mode: when `request.totalDstAmount` is set, the API
|
|
9
|
+
// treats `srcChainTokenInAmount` of each trade as an upper bound, walks trades
|
|
10
|
+
// in order, and produces a balancing trade that closes the dst total to
|
|
11
|
+
// `totalDstAmount` exactly. Tail trades after the balancing trade may be
|
|
12
|
+
// dropped from `response.trades[]`. With `allowPartialFill=true` the pipeline
|
|
13
|
+
// may stop short and emit no balancing trade — every kept trade is then taken
|
|
14
|
+
// at the full upper bound. See the `enum TradeRole` invariant for how the
|
|
15
|
+
// balancing trade is identified in each pipeline branch.
|
|
16
|
+
function validateTotalDstAmount(request, response) {
|
|
17
|
+
const requestHasField = request.totalDstAmount !== undefined;
|
|
18
|
+
const responseHasField = response.estimatedTotalDstAmount !== undefined;
|
|
19
|
+
// Neither field is set — request runs in regular mode, nothing to validate.
|
|
20
|
+
if (!requestHasField && !responseHasField)
|
|
21
|
+
return [];
|
|
22
|
+
// CRITICAL: the two fields must appear together
|
|
23
|
+
if (requestHasField !== responseHasField) {
|
|
24
|
+
return [{
|
|
25
|
+
code: types_1.ViolationCode.TotalDstAmountModeMismatch,
|
|
26
|
+
message: "request.totalDstAmount and response.estimatedTotalDstAmount must appear together",
|
|
27
|
+
path: "response.estimatedTotalDstAmount",
|
|
28
|
+
expected: request.totalDstAmount,
|
|
29
|
+
actual: response.estimatedTotalDstAmount,
|
|
30
|
+
}];
|
|
31
|
+
}
|
|
32
|
+
// Both fields are defined here: the two early returns above handle the
|
|
33
|
+
// neither-set and one-sided cases.
|
|
34
|
+
const requestedTotal = request.totalDstAmount;
|
|
35
|
+
const estimatedTotal = response.estimatedTotalDstAmount;
|
|
36
|
+
const formatViolations = validateTotalAmountFormats(requestedTotal, estimatedTotal);
|
|
37
|
+
return [
|
|
38
|
+
...validateRequestLevelConstraints(request),
|
|
39
|
+
...formatViolations,
|
|
40
|
+
...(formatViolations.length === 0
|
|
41
|
+
? [
|
|
42
|
+
...validateEstimatedTotal(request, requestedTotal, estimatedTotal),
|
|
43
|
+
...validateEstimatedVsAccumulative(response, estimatedTotal),
|
|
44
|
+
...validateEstimatedVsSumOfTradeDstAmounts(response, estimatedTotal),
|
|
45
|
+
]
|
|
46
|
+
: []),
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
function validateTotalAmountFormats(requestedTotal, estimatedTotal) {
|
|
50
|
+
const violations = [];
|
|
51
|
+
// CRITICAL: request.totalDstAmount must parse as a positive integer.
|
|
52
|
+
try {
|
|
53
|
+
if ((0, integer_1.parseIntegerString)(requestedTotal) <= 0n) {
|
|
54
|
+
violations.push({
|
|
55
|
+
code: types_1.ViolationCode.TotalDstAmountInvalid,
|
|
56
|
+
message: "request.totalDstAmount must be a positive integer string",
|
|
57
|
+
path: "request.totalDstAmount",
|
|
58
|
+
actual: requestedTotal,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
violations.push({
|
|
64
|
+
code: types_1.ViolationCode.TotalDstAmountInvalid,
|
|
65
|
+
message: "request.totalDstAmount must be a positive integer string",
|
|
66
|
+
path: "request.totalDstAmount",
|
|
67
|
+
actual: requestedTotal,
|
|
68
|
+
details: error,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// CRITICAL: response.estimatedTotalDstAmount must parse as a positive integer.
|
|
72
|
+
try {
|
|
73
|
+
if ((0, integer_1.parseIntegerString)(estimatedTotal) <= 0n) {
|
|
74
|
+
violations.push({
|
|
75
|
+
code: types_1.ViolationCode.TotalDstAmountInvalid,
|
|
76
|
+
message: "response.estimatedTotalDstAmount must be a positive integer string",
|
|
77
|
+
path: "response.estimatedTotalDstAmount",
|
|
78
|
+
actual: estimatedTotal,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
violations.push({
|
|
84
|
+
code: types_1.ViolationCode.TotalDstAmountInvalid,
|
|
85
|
+
message: "response.estimatedTotalDstAmount must be a positive integer string",
|
|
86
|
+
path: "response.estimatedTotalDstAmount",
|
|
87
|
+
actual: estimatedTotal,
|
|
88
|
+
details: error,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return violations;
|
|
92
|
+
}
|
|
93
|
+
function validateRequestLevelConstraints(request) {
|
|
94
|
+
return [
|
|
95
|
+
...validateAccountAbstractionRequired(request),
|
|
96
|
+
...validateRecipientsRequired(request),
|
|
97
|
+
...validateSingleDestination(request),
|
|
98
|
+
...validateDstAmountIsAuto(request),
|
|
99
|
+
...validateAutoSrcIsLast(request),
|
|
100
|
+
...validateNoDuplicateSpecialSrcAssets(request),
|
|
101
|
+
];
|
|
102
|
+
}
|
|
103
|
+
function validateAccountAbstractionRequired(request) {
|
|
104
|
+
if (request.enableAccountAbstraction)
|
|
105
|
+
return [];
|
|
106
|
+
// CRITICAL: `enableAccountAbstraction` must be true in asset consolidation mode
|
|
107
|
+
return [{
|
|
108
|
+
code: types_1.ViolationCode.TotalDstAmountAccountAbstractionRequired,
|
|
109
|
+
message: "request.enableAccountAbstraction must be true when request.totalDstAmount is set",
|
|
110
|
+
path: "request.enableAccountAbstraction",
|
|
111
|
+
expected: true,
|
|
112
|
+
actual: request.enableAccountAbstraction,
|
|
113
|
+
}];
|
|
114
|
+
}
|
|
115
|
+
function validateRecipientsRequired(request) {
|
|
116
|
+
const violations = [];
|
|
117
|
+
for (let i = 0; i < request.trades.length; i++) {
|
|
118
|
+
const recipient = request.trades[i].dstChainTokenOutRecipient;
|
|
119
|
+
if (recipient === undefined) {
|
|
120
|
+
// CRITICAL: the API's totalDstAmount bundle validator requires a
|
|
121
|
+
// concrete destination recipient so it can compare destinations.
|
|
122
|
+
violations.push({
|
|
123
|
+
code: types_1.ViolationCode.TotalDstAmountRecipientRequired,
|
|
124
|
+
message: "request.trades[].dstChainTokenOutRecipient is required"
|
|
125
|
+
+ " in asset consolidation mode",
|
|
126
|
+
path: `request.trades[${i}].dstChainTokenOutRecipient`,
|
|
127
|
+
actual: recipient,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return violations;
|
|
132
|
+
}
|
|
133
|
+
function validateSingleDestination(request) {
|
|
134
|
+
if (request.trades.length === 0)
|
|
135
|
+
return [];
|
|
136
|
+
const violations = [];
|
|
137
|
+
const referenceTrade = request.trades[0];
|
|
138
|
+
const referenceRealChainId = (0, subscription_to_chain_id_1.resolveChainId)(referenceTrade.dstChainId);
|
|
139
|
+
for (let i = 1; i < request.trades.length; i++) {
|
|
140
|
+
const trade = request.trades[i];
|
|
141
|
+
violations.push(...checkDestinationMatchesReference(trade, i, referenceTrade, referenceRealChainId));
|
|
142
|
+
}
|
|
143
|
+
return violations;
|
|
144
|
+
}
|
|
145
|
+
function checkDestinationMatchesReference(trade, tradeIndex, referenceTrade, referenceRealChainId) {
|
|
146
|
+
const violations = [];
|
|
147
|
+
const basePath = `request.trades[${tradeIndex}]`;
|
|
148
|
+
// CRITICAL: all trades must share the same destination chain
|
|
149
|
+
if (trade.dstChainId !== referenceTrade.dstChainId) {
|
|
150
|
+
violations.push({
|
|
151
|
+
code: types_1.ViolationCode.TotalDstAmountSingleDestinationMismatch,
|
|
152
|
+
message: "all request.trades[].dstChainId must be equal in asset consolidation mode",
|
|
153
|
+
path: `${basePath}.dstChainId`,
|
|
154
|
+
expected: referenceTrade.dstChainId,
|
|
155
|
+
actual: trade.dstChainId,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
// Safe skip: when dstChainId differs from the `referenceTrade`, the address
|
|
159
|
+
// comparison below is meaningless — address formats and case sensitivity
|
|
160
|
+
// are chain-specific (EVM lowercase vs Solana/Tron case-sensitive), so
|
|
161
|
+
// comparing under the wrong chain would produce nonsense. The chainId
|
|
162
|
+
// mismatch is already reported above as its own Violation.
|
|
163
|
+
if (trade.dstChainId === referenceTrade.dstChainId && referenceRealChainId !== undefined) {
|
|
164
|
+
// CRITICAL: same dst token across trades
|
|
165
|
+
if (!(0, address_1.addressEquals)(referenceRealChainId, referenceTrade.dstChainTokenOut, trade.dstChainTokenOut)) {
|
|
166
|
+
violations.push({
|
|
167
|
+
code: types_1.ViolationCode.TotalDstAmountSingleDestinationMismatch,
|
|
168
|
+
message: "all request.trades[].dstChainTokenOut must be equal in asset consolidation mode",
|
|
169
|
+
path: `${basePath}.dstChainTokenOut`,
|
|
170
|
+
expected: referenceTrade.dstChainTokenOut,
|
|
171
|
+
actual: trade.dstChainTokenOut,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
// CRITICAL: same recipient across trades
|
|
175
|
+
violations.push(...checkRecipientMatches(trade, tradeIndex, referenceTrade, referenceRealChainId));
|
|
176
|
+
}
|
|
177
|
+
return violations;
|
|
178
|
+
}
|
|
179
|
+
function checkRecipientMatches(trade, tradeIndex, referenceTrade, referenceRealChainId) {
|
|
180
|
+
const refRecipient = referenceTrade.dstChainTokenOutRecipient;
|
|
181
|
+
const tradeRecipient = trade.dstChainTokenOutRecipient;
|
|
182
|
+
// Both undefined — simple match.
|
|
183
|
+
if (refRecipient === undefined && tradeRecipient === undefined)
|
|
184
|
+
return [];
|
|
185
|
+
const path = `request.trades[${tradeIndex}].dstChainTokenOutRecipient`;
|
|
186
|
+
const code = types_1.ViolationCode.TotalDstAmountSingleDestinationMismatch;
|
|
187
|
+
// One defined, the other not — Violation regardless of address comparison
|
|
188
|
+
if (refRecipient === undefined || tradeRecipient === undefined) {
|
|
189
|
+
return [{
|
|
190
|
+
code,
|
|
191
|
+
message: "all request.trades[].dstChainTokenOutRecipient must be equal in asset consolidation mode",
|
|
192
|
+
path,
|
|
193
|
+
expected: refRecipient,
|
|
194
|
+
actual: tradeRecipient,
|
|
195
|
+
}];
|
|
196
|
+
}
|
|
197
|
+
if (!(0, address_1.addressEquals)(referenceRealChainId, refRecipient, tradeRecipient)) {
|
|
198
|
+
return [{
|
|
199
|
+
code,
|
|
200
|
+
message: "all request.trades[].dstChainTokenOutRecipient must be equal in asset consolidation mode",
|
|
201
|
+
path,
|
|
202
|
+
expected: refRecipient,
|
|
203
|
+
actual: tradeRecipient,
|
|
204
|
+
}];
|
|
205
|
+
}
|
|
206
|
+
return [];
|
|
207
|
+
}
|
|
208
|
+
function validateDstAmountIsAuto(request) {
|
|
209
|
+
const violations = [];
|
|
210
|
+
for (let i = 0; i < request.trades.length; i++) {
|
|
211
|
+
const amount = request.trades[i].dstChainTokenOutAmount;
|
|
212
|
+
if (amount !== undefined && amount !== types_1.SpecialAmount.Auto) {
|
|
213
|
+
// CRITICAL: all trades must have dstChainTokenOutAmount='auto' in consolidation mode
|
|
214
|
+
violations.push({
|
|
215
|
+
code: types_1.ViolationCode.TotalDstAmountDstAmountMustBeAuto,
|
|
216
|
+
message: "request.trades[].dstChainTokenOutAmount must be 'auto' in asset consolidation mode",
|
|
217
|
+
path: `request.trades[${i}].dstChainTokenOutAmount`,
|
|
218
|
+
expected: types_1.SpecialAmount.Auto,
|
|
219
|
+
actual: amount,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return violations;
|
|
224
|
+
}
|
|
225
|
+
function validateAutoSrcIsLast(request) {
|
|
226
|
+
const violations = [];
|
|
227
|
+
const lastIndex = request.trades.length - 1;
|
|
228
|
+
for (let i = 0; i < request.trades.length; i++) {
|
|
229
|
+
const isAuto = request.trades[i].srcChainTokenInAmount === types_1.SpecialAmount.Auto;
|
|
230
|
+
if (isAuto && i !== lastIndex) {
|
|
231
|
+
// CRITICAL: 'auto' src amount may appear only on the last trade.
|
|
232
|
+
// No single "expected" concrete value (any non-'auto' value would
|
|
233
|
+
// satisfy the rule); the human-readable explanation is in `message`.
|
|
234
|
+
violations.push({
|
|
235
|
+
code: types_1.ViolationCode.TotalDstAmountAutoSrcMustBeLast,
|
|
236
|
+
message: "request.trades[].srcChainTokenInAmount='auto' is only"
|
|
237
|
+
+ " allowed on the last trade in asset consolidation mode",
|
|
238
|
+
path: `request.trades[${i}].srcChainTokenInAmount`,
|
|
239
|
+
actual: types_1.SpecialAmount.Auto,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return violations;
|
|
244
|
+
}
|
|
245
|
+
function validateNoDuplicateSpecialSrcAssets(request) {
|
|
246
|
+
const violations = [];
|
|
247
|
+
const seen = new Map();
|
|
248
|
+
for (let i = 0; i < request.trades.length; i++) {
|
|
249
|
+
const trade = request.trades[i];
|
|
250
|
+
const realSrcChainId = (0, subscription_to_chain_id_1.resolveChainId)(trade.srcChainId);
|
|
251
|
+
// Safe skip: an unknown `srcChainId` is already reported as
|
|
252
|
+
// UnknownSubscriptionId by `groupTrades` / `validateSingleTrade`.
|
|
253
|
+
if (realSrcChainId === undefined)
|
|
254
|
+
continue;
|
|
255
|
+
const isSpecial = trade.srcChainTokenInAmount === types_1.SpecialAmount.Max
|
|
256
|
+
|| trade.srcChainTokenInAmount === types_1.SpecialAmount.Auto;
|
|
257
|
+
const key = `${trade.srcChainId}:${(0, address_1.normalizeAddress)(realSrcChainId, trade.srcChainTokenIn)}`;
|
|
258
|
+
const existing = seen.get(key);
|
|
259
|
+
if (existing !== undefined && (isSpecial || existing.isSpecial)) {
|
|
260
|
+
const existingTrade = request.trades[existing.index];
|
|
261
|
+
// CRITICAL: only one trade per (`srcChainId`, `srcChainTokenIn`)
|
|
262
|
+
// when either uses 'max' or 'auto'.
|
|
263
|
+
violations.push({
|
|
264
|
+
code: types_1.ViolationCode.TotalDstAmountDuplicateSpecialSrcAsset,
|
|
265
|
+
message: "duplicate (srcChainId, srcChainTokenIn) is only allowed"
|
|
266
|
+
+ " when both trades use a fixed amount in asset"
|
|
267
|
+
+ " consolidation mode",
|
|
268
|
+
path: "request.trades",
|
|
269
|
+
actual: {
|
|
270
|
+
existing: {
|
|
271
|
+
index: existing.index,
|
|
272
|
+
srcChainId: existingTrade.srcChainId,
|
|
273
|
+
srcChainTokenIn: existingTrade.srcChainTokenIn,
|
|
274
|
+
srcChainTokenInAmount: existingTrade.srcChainTokenInAmount,
|
|
275
|
+
},
|
|
276
|
+
duplicate: {
|
|
277
|
+
index: i,
|
|
278
|
+
srcChainId: trade.srcChainId,
|
|
279
|
+
srcChainTokenIn: trade.srcChainTokenIn,
|
|
280
|
+
srcChainTokenInAmount: trade.srcChainTokenInAmount,
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
seen.set(key, { index: i, isSpecial });
|
|
286
|
+
}
|
|
287
|
+
return violations;
|
|
288
|
+
}
|
|
289
|
+
function validateEstimatedTotal(request, requestedTotal, estimatedTotal) {
|
|
290
|
+
let parsedEstimated;
|
|
291
|
+
let parsedRequested;
|
|
292
|
+
try {
|
|
293
|
+
parsedEstimated = (0, integer_1.parseIntegerString)(estimatedTotal);
|
|
294
|
+
parsedRequested = (0, integer_1.parseIntegerString)(requestedTotal);
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
return [{
|
|
298
|
+
code: types_1.ViolationCode.TotalDstAmountEstimatedExceedsRequested,
|
|
299
|
+
message: "failed to parse request.totalDstAmount / response.estimatedTotalDstAmount as BigInt",
|
|
300
|
+
path: "response.estimatedTotalDstAmount",
|
|
301
|
+
expected: undefined,
|
|
302
|
+
actual: {
|
|
303
|
+
"request.totalDstAmount": requestedTotal,
|
|
304
|
+
"response.estimatedTotalDstAmount": estimatedTotal,
|
|
305
|
+
},
|
|
306
|
+
details: error,
|
|
307
|
+
}];
|
|
308
|
+
}
|
|
309
|
+
// CRITICAL: estimated must be strictly positive
|
|
310
|
+
if (parsedEstimated <= 0n) {
|
|
311
|
+
return [{
|
|
312
|
+
code: types_1.ViolationCode.TotalDstAmountEstimatedNonPositive,
|
|
313
|
+
message: "response.estimatedTotalDstAmount must be strictly positive",
|
|
314
|
+
path: "response.estimatedTotalDstAmount",
|
|
315
|
+
actual: estimatedTotal,
|
|
316
|
+
}];
|
|
317
|
+
}
|
|
318
|
+
// CRITICAL: estimated must equal requested in strict mode (default), or
|
|
319
|
+
// be <= requested when `allowPartialFill=true`.
|
|
320
|
+
const allowPartial = request.allowPartialFill === true;
|
|
321
|
+
if (allowPartial) {
|
|
322
|
+
if (parsedEstimated > parsedRequested) {
|
|
323
|
+
return [{
|
|
324
|
+
code: types_1.ViolationCode.TotalDstAmountEstimatedExceedsRequested,
|
|
325
|
+
message: "response.estimatedTotalDstAmount must be <= request.totalDstAmount (allowPartialFill=true)",
|
|
326
|
+
path: "response.estimatedTotalDstAmount",
|
|
327
|
+
expected: { max: requestedTotal },
|
|
328
|
+
actual: estimatedTotal,
|
|
329
|
+
}];
|
|
330
|
+
}
|
|
331
|
+
return [];
|
|
332
|
+
}
|
|
333
|
+
// CRITICAL: in strict mode (`allowPartialFill=false` / default), the API
|
|
334
|
+
// must collect exactly `totalDstAmount` — otherwise it should return an
|
|
335
|
+
// error before producing a response.
|
|
336
|
+
if (parsedEstimated !== parsedRequested) {
|
|
337
|
+
return [{
|
|
338
|
+
code: types_1.ViolationCode.TotalDstAmountEstimatedExceedsRequested,
|
|
339
|
+
message: "response.estimatedTotalDstAmount must equal request.totalDstAmount (allowPartialFill=false)",
|
|
340
|
+
path: "response.estimatedTotalDstAmount",
|
|
341
|
+
expected: requestedTotal,
|
|
342
|
+
actual: estimatedTotal,
|
|
343
|
+
}];
|
|
344
|
+
}
|
|
345
|
+
return [];
|
|
346
|
+
}
|
|
347
|
+
function validateEstimatedVsAccumulative(response, estimatedTotal) {
|
|
348
|
+
// Safe skip: an empty / multi-element `accumulativeTokenOutput` is already
|
|
349
|
+
// reported by `validateAccumulativeTokens` (counts and group recomputation).
|
|
350
|
+
// We only run this sanity check when there is exactly one element, which
|
|
351
|
+
// is the expected shape for asset consolidation mode (all trades share the
|
|
352
|
+
// same dst token / chain / recipient — enforced by `validateSingleDestination`
|
|
353
|
+
// above for the request side, and by the accumulative-token grouping for
|
|
354
|
+
// the response side).
|
|
355
|
+
if (response.accumulativeTokenOutput.length !== 1)
|
|
356
|
+
return [];
|
|
357
|
+
const accumulativeAmount = response.accumulativeTokenOutput[0].amount;
|
|
358
|
+
let parsedEstimated;
|
|
359
|
+
let parsedAccumulative;
|
|
360
|
+
try {
|
|
361
|
+
parsedEstimated = (0, integer_1.parseIntegerString)(estimatedTotal);
|
|
362
|
+
parsedAccumulative = (0, integer_1.parseIntegerString)(accumulativeAmount);
|
|
363
|
+
}
|
|
364
|
+
catch (error) {
|
|
365
|
+
return [{
|
|
366
|
+
code: types_1.ViolationCode.TotalDstAmountVsAccumulativeMismatch,
|
|
367
|
+
message: "failed to parse response.estimatedTotalDstAmount / accumulativeTokenOutput[0].amount as BigInt",
|
|
368
|
+
path: "response.estimatedTotalDstAmount",
|
|
369
|
+
expected: undefined,
|
|
370
|
+
actual: {
|
|
371
|
+
"response.estimatedTotalDstAmount": estimatedTotal,
|
|
372
|
+
"response.accumulativeTokenOutput[0].amount": accumulativeAmount,
|
|
373
|
+
},
|
|
374
|
+
details: error,
|
|
375
|
+
}];
|
|
376
|
+
}
|
|
377
|
+
// CRITICAL: `estimatedTotalDstAmount` must equal `accumulativeTokenOutput[0].amount`
|
|
378
|
+
if (parsedEstimated !== parsedAccumulative) {
|
|
379
|
+
return [{
|
|
380
|
+
code: types_1.ViolationCode.TotalDstAmountVsAccumulativeMismatch,
|
|
381
|
+
message: "response.estimatedTotalDstAmount must equal response.accumulativeTokenOutput[0].amount",
|
|
382
|
+
path: "response.estimatedTotalDstAmount",
|
|
383
|
+
expected: accumulativeAmount,
|
|
384
|
+
actual: estimatedTotal,
|
|
385
|
+
}];
|
|
386
|
+
}
|
|
387
|
+
return [];
|
|
388
|
+
}
|
|
389
|
+
// CRITICAL: direct invariant of the consolidation mode — the destination
|
|
390
|
+
// total the user receives is the sum of per-trade dst amounts. Independent
|
|
391
|
+
// from the `accumulativeTokenOutput` sanity above: an attacker who reconciled
|
|
392
|
+
// `estimatedTotalDstAmount` with `accumulativeTokenOutput[0].amount` would
|
|
393
|
+
// still need to reconcile each per-trade `dstChainTokenOut.amount` to pass
|
|
394
|
+
// this check — and per-trade amounts are pinned by the API pipeline
|
|
395
|
+
// (remaining `dst` needed to reach `totalDstAmount` on balancing, `dst` computed
|
|
396
|
+
// from `src` on non-balancing).
|
|
397
|
+
function validateEstimatedVsSumOfTradeDstAmounts(response, estimatedTotal) {
|
|
398
|
+
let sum = 0n;
|
|
399
|
+
for (let i = 0; i < response.trades.length; i++) {
|
|
400
|
+
const tradeAmount = response.trades[i].dstChainTokenOut.amount;
|
|
401
|
+
try {
|
|
402
|
+
sum += (0, integer_1.parseIntegerString)(tradeAmount);
|
|
403
|
+
}
|
|
404
|
+
catch (error) {
|
|
405
|
+
// Safe skip: invalid per-trade `dst.amount` is already reported by
|
|
406
|
+
// `validateTrades` (`dst.amount` parse rules).
|
|
407
|
+
void error;
|
|
408
|
+
return [];
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
let parsedEstimated;
|
|
412
|
+
try {
|
|
413
|
+
parsedEstimated = (0, integer_1.parseIntegerString)(estimatedTotal);
|
|
414
|
+
}
|
|
415
|
+
catch {
|
|
416
|
+
// Safe skip: invalid `estimatedTotalDstAmount` is reported by
|
|
417
|
+
// `validateEstimatedTotal` above.
|
|
418
|
+
return [];
|
|
419
|
+
}
|
|
420
|
+
if (parsedEstimated !== sum) {
|
|
421
|
+
return [{
|
|
422
|
+
code: types_1.ViolationCode.TotalDstAmountSumDstMismatch,
|
|
423
|
+
message: "response.estimatedTotalDstAmount must equal the sum of"
|
|
424
|
+
+ " response.trades[].dstChainTokenOut.amount",
|
|
425
|
+
path: "response.estimatedTotalDstAmount",
|
|
426
|
+
expected: sum.toString(),
|
|
427
|
+
actual: estimatedTotal,
|
|
428
|
+
}];
|
|
429
|
+
}
|
|
430
|
+
return [];
|
|
431
|
+
}
|
|
432
|
+
//# sourceMappingURL=total-dst-amount.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"total-dst-amount.js","sourceRoot":"","sources":["../../../src/validations/total-dst-amount.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,45 +8,53 @@ const subscription_to_chain_id_1 = require("../whitelists/subscription-to-chain-
|
|
|
8
8
|
const address_1 = require("../helpers/address");
|
|
9
9
|
const evm_dln_hook_pack_1 = require("../helpers/evm-dln-hook-pack");
|
|
10
10
|
const hex_1 = require("../helpers/hex");
|
|
11
|
+
const dln_metadata_1 = require("./dln-metadata");
|
|
12
|
+
const external_call_1 = require("./external-call");
|
|
13
|
+
const trade_matching_1 = require("./trade-matching");
|
|
11
14
|
// Groups request trades to match them later with response intents.
|
|
12
15
|
//
|
|
13
16
|
// Quote mode: groups by srcChainId only (addresses are placeholders).
|
|
14
17
|
//
|
|
15
18
|
// Execution mode: groups by (srcChainId, srcChainAuthorityAddress).
|
|
16
19
|
//
|
|
20
|
+
// Consolidation mode: groups only the request trades that were matched to
|
|
21
|
+
// response trades. Skipped request trades must not affect per-intent budgets,
|
|
22
|
+
// partner costs, hooks, or metadata checks.
|
|
23
|
+
//
|
|
17
24
|
// NOTE: the API may further split a group into multiple intents based on
|
|
18
25
|
// fields like intent.executionMetadata, intent.dlnMetadata,
|
|
19
26
|
// intent.externalCallHash, etc. that are not present in the request, so one
|
|
20
27
|
// group can correspond to one or more response intents.
|
|
21
|
-
function groupTrades(trades, responseTrades, quoteMode) {
|
|
28
|
+
function groupTrades(trades, responseTrades, quoteMode, consolidationMode = false, tradePairs) {
|
|
22
29
|
const map = new Map();
|
|
23
30
|
const violations = [];
|
|
24
31
|
// Track already-reported unknown subscriptionIds to avoid duplicate violations
|
|
25
32
|
const reportedUnknown = new Set();
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
33
|
+
const entries = getGroupEntries(trades, responseTrades, quoteMode, consolidationMode, tradePairs);
|
|
34
|
+
violations.push(...entries.violations);
|
|
35
|
+
for (const entry of entries.items) {
|
|
36
|
+
const realChainId = (0, subscription_to_chain_id_1.resolveChainId)(entry.trade.srcChainId);
|
|
29
37
|
if (realChainId === undefined) {
|
|
30
|
-
if (!reportedUnknown.has(trade.srcChainId)) {
|
|
31
|
-
reportedUnknown.add(trade.srcChainId);
|
|
38
|
+
if (!reportedUnknown.has(entry.trade.srcChainId)) {
|
|
39
|
+
reportedUnknown.add(entry.trade.srcChainId);
|
|
32
40
|
// CRITICAL: unknown subscriptionId — cannot validate this trade
|
|
33
41
|
violations.push({
|
|
34
42
|
code: types_1.ViolationCode.UnknownSubscriptionId,
|
|
35
|
-
message: `srcChainId=${trade.srcChainId} is not a known subscriptionId`,
|
|
36
|
-
path: `request.trades[${
|
|
37
|
-
actual: trade.srcChainId,
|
|
43
|
+
message: `srcChainId=${entry.trade.srcChainId} is not a known subscriptionId`,
|
|
44
|
+
path: `request.trades[${entry.requestIndex}].srcChainId`,
|
|
45
|
+
actual: entry.trade.srcChainId,
|
|
38
46
|
});
|
|
39
47
|
}
|
|
40
48
|
continue;
|
|
41
49
|
}
|
|
42
50
|
const key = quoteMode
|
|
43
|
-
? String(trade.srcChainId)
|
|
44
|
-
: `${trade.srcChainId}:${trade.srcChainAuthorityAddress ?? ""}`;
|
|
51
|
+
? String(entry.trade.srcChainId)
|
|
52
|
+
: `${entry.trade.srcChainId}:${entry.trade.srcChainAuthorityAddress ?? ""}`;
|
|
45
53
|
let group = map.get(key);
|
|
46
54
|
if (!group) {
|
|
47
55
|
group = {
|
|
48
|
-
srcChainId: trade.srcChainId,
|
|
49
|
-
srcChainAuthorityAddress: quoteMode ? undefined : trade.srcChainAuthorityAddress,
|
|
56
|
+
srcChainId: entry.trade.srcChainId,
|
|
57
|
+
srcChainAuthorityAddress: quoteMode ? undefined : entry.trade.srcChainAuthorityAddress,
|
|
50
58
|
realChainId,
|
|
51
59
|
tradeIndices: [],
|
|
52
60
|
trades: [],
|
|
@@ -54,12 +62,37 @@ function groupTrades(trades, responseTrades, quoteMode) {
|
|
|
54
62
|
};
|
|
55
63
|
map.set(key, group);
|
|
56
64
|
}
|
|
57
|
-
group.tradeIndices.push(
|
|
58
|
-
group.trades.push(trade);
|
|
59
|
-
group.responseTrades.push(
|
|
65
|
+
group.tradeIndices.push(entry.requestIndex);
|
|
66
|
+
group.trades.push(entry.trade);
|
|
67
|
+
group.responseTrades.push(entry.responseTrade);
|
|
60
68
|
}
|
|
61
69
|
return { groups: Array.from(map.values()), violations };
|
|
62
70
|
}
|
|
71
|
+
function getGroupEntries(trades, responseTrades, quoteMode, consolidationMode, tradePairs) {
|
|
72
|
+
// Regular mode groups every request trade. Consolidation mode groups only
|
|
73
|
+
// matched pairs because the API may intentionally skip some request trades.
|
|
74
|
+
if (!consolidationMode) {
|
|
75
|
+
return {
|
|
76
|
+
items: trades.map((trade, requestIndex) => ({
|
|
77
|
+
requestIndex,
|
|
78
|
+
trade,
|
|
79
|
+
responseTrade: responseTrades[requestIndex],
|
|
80
|
+
})),
|
|
81
|
+
violations: [],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const matchResult = tradePairs === undefined
|
|
85
|
+
? (0, trade_matching_1.matchTrades)(trades, responseTrades, quoteMode, true)
|
|
86
|
+
: { pairs: tradePairs, violations: [] };
|
|
87
|
+
return {
|
|
88
|
+
items: matchResult.pairs.map(pair => ({
|
|
89
|
+
requestIndex: pair.requestIndex,
|
|
90
|
+
trade: pair.requestTrade,
|
|
91
|
+
responseTrade: pair.responseTrade,
|
|
92
|
+
})),
|
|
93
|
+
violations: matchResult.violations,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
63
96
|
// Matches each response intent to its trade group.
|
|
64
97
|
//
|
|
65
98
|
// Quote mode: matches by intentChainId == group.srcChainId.
|
|
@@ -167,7 +200,7 @@ function validateIntentDifferentiation(contexts) {
|
|
|
167
200
|
function intentDifferentiationKey(intent) {
|
|
168
201
|
return [
|
|
169
202
|
intent.externalCallHash ?? "",
|
|
170
|
-
intent.dlnMetadata
|
|
203
|
+
(0, dln_metadata_1.normalizeDlnMetadataKey)(intent.dlnMetadata),
|
|
171
204
|
intent.executionMetadata ?? "",
|
|
172
205
|
].join("|");
|
|
173
206
|
}
|
|
@@ -179,7 +212,7 @@ function intentDifferentiationKey(intent) {
|
|
|
179
212
|
function selectIntentTrades(group, intent) {
|
|
180
213
|
// Distinct keys for trades in the group; if every trade has the same key,
|
|
181
214
|
// they all belong to the single intent (no ambiguity).
|
|
182
|
-
const tradeKeys = group.trades.map(
|
|
215
|
+
const tradeKeys = group.trades.map((trade, i) => tradeDifferentiationKey(trade, group.responseTrades[i]));
|
|
183
216
|
const distinct = new Set(tradeKeys);
|
|
184
217
|
if (distinct.size <= 1) {
|
|
185
218
|
return {
|
|
@@ -193,7 +226,7 @@ function selectIntentTrades(group, intent) {
|
|
|
193
226
|
const responseTrades = [];
|
|
194
227
|
for (let i = 0; i < group.trades.length; i++) {
|
|
195
228
|
const trade = group.trades[i];
|
|
196
|
-
if (tradeMatchesIntent(trade, intent)) {
|
|
229
|
+
if (tradeMatchesIntent(trade, group.responseTrades[i], intent)) {
|
|
197
230
|
indices.push(i);
|
|
198
231
|
trades.push(trade);
|
|
199
232
|
responseTrades.push(group.responseTrades[i]);
|
|
@@ -213,12 +246,15 @@ function selectIntentTrades(group, intent) {
|
|
|
213
246
|
}
|
|
214
247
|
return { indices, trades, responseTrades };
|
|
215
248
|
}
|
|
216
|
-
function tradeDifferentiationKey(trade) {
|
|
217
|
-
return [
|
|
249
|
+
function tradeDifferentiationKey(trade, responseTrade) {
|
|
250
|
+
return [
|
|
251
|
+
computeTradeExternalCallHash(trade, responseTrade) ?? "",
|
|
252
|
+
(0, dln_metadata_1.normalizeDlnMetadataKey)(trade.dlnMetadata),
|
|
253
|
+
].join("|");
|
|
218
254
|
}
|
|
219
|
-
function tradeMatchesIntent(trade, intent) {
|
|
220
|
-
return ((0, hex_1.hexEquals)(intent.externalCallHash, computeTradeExternalCallHash(trade))
|
|
221
|
-
&& (0,
|
|
255
|
+
function tradeMatchesIntent(trade, responseTrade, intent) {
|
|
256
|
+
return ((0, hex_1.hexEquals)(intent.externalCallHash, computeTradeExternalCallHash(trade, responseTrade))
|
|
257
|
+
&& (0, dln_metadata_1.dlnMetadataEquals)(intent.dlnMetadata, trade.dlnMetadata)
|
|
222
258
|
&& (0, hex_1.isEmptyHex)(intent.executionMetadata));
|
|
223
259
|
}
|
|
224
260
|
// Returns the same hash the API stores in `intent.externalCallHash` for a
|
|
@@ -226,7 +262,13 @@ function tradeMatchesIntent(trade, intent) {
|
|
|
226
262
|
// serialization failure: `validateExternalCallHash` reports it on its own; here
|
|
227
263
|
// we just treat the trade as un-matchable so the fallback in
|
|
228
264
|
// `selectIntentTrades` keeps the broader group intact.
|
|
229
|
-
function computeTradeExternalCallHash(trade) {
|
|
265
|
+
function computeTradeExternalCallHash(trade, responseTrade) {
|
|
266
|
+
const responseHash = (0, external_call_1.getResponseExternalCallHash)(responseTrade);
|
|
267
|
+
if (responseHash.kind === external_call_1.ResponseExternalCallHashKind.Hash) {
|
|
268
|
+
return responseHash.hash;
|
|
269
|
+
}
|
|
270
|
+
// Safe skip: malformed `response.trades[].externalCallData` is reported by
|
|
271
|
+
// `validateExternalCalls`; fall back to request-side EVM serialization below.
|
|
230
272
|
try {
|
|
231
273
|
const packed = (0, evm_dln_hook_pack_1.serializeDlnHook)(trade);
|
|
232
274
|
return packed === undefined ? undefined : (0, viem_1.keccak256)(packed);
|