@debridge-finance/borderless-validation-sdk 0.3.1 → 0.4.1
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 +120 -11
- package/dist/cjs/graylists/evm/token-permit-metadata.js +7 -1
- package/dist/cjs/graylists/evm/token-permit-metadata.js.map +1 -1
- package/dist/cjs/helpers/address.js +139 -63
- package/dist/cjs/helpers/address.js.map +1 -1
- package/dist/cjs/helpers/amount.js +8 -0
- package/dist/cjs/helpers/amount.js.map +1 -0
- package/dist/cjs/helpers/evm-dln-hook-pack.js +16 -4
- package/dist/cjs/helpers/evm-dln-hook-pack.js.map +1 -1
- package/dist/cjs/helpers/evm-gas-compensation-tx.js +11 -26
- package/dist/cjs/helpers/evm-gas-compensation-tx.js.map +1 -1
- package/dist/cjs/helpers/evm-intent-id-abi.js +8 -1
- package/dist/cjs/helpers/evm-intent-id-abi.js.map +1 -1
- package/dist/cjs/helpers/evm-trade-amounts.js +11 -3
- package/dist/cjs/helpers/evm-trade-amounts.js.map +1 -1
- package/dist/cjs/helpers/expected-delegate.js +2 -6
- package/dist/cjs/helpers/expected-delegate.js.map +1 -1
- package/dist/cjs/helpers/gas-compensation.js +8 -4
- package/dist/cjs/helpers/gas-compensation.js.map +1 -1
- package/dist/cjs/helpers/interactions.js +4 -20
- package/dist/cjs/helpers/interactions.js.map +1 -1
- package/dist/cjs/helpers/synthetic-native-wrap.js +3 -2
- package/dist/cjs/helpers/synthetic-native-wrap.js.map +1 -1
- package/dist/cjs/types/enums.js +1 -0
- package/dist/cjs/types/enums.js.map +1 -1
- package/dist/cjs/types/request.js +15 -2
- package/dist/cjs/types/request.js.map +1 -1
- package/dist/cjs/types/response.js +2 -1
- package/dist/cjs/types/response.js.map +1 -1
- package/dist/cjs/types/validation.js +21 -3
- package/dist/cjs/types/validation.js.map +1 -1
- package/dist/cjs/validations/compensation-hook.js +4 -5
- package/dist/cjs/validations/compensation-hook.js.map +1 -1
- package/dist/cjs/validations/cost-token.js +9 -1
- package/dist/cjs/validations/cost-token.js.map +1 -1
- package/dist/cjs/validations/echo-fields.js +18 -0
- package/dist/cjs/validations/echo-fields.js.map +1 -1
- package/dist/cjs/validations/evm-caveats.js +3 -0
- package/dist/cjs/validations/evm-caveats.js.map +1 -1
- package/dist/cjs/validations/evm-on-chain-intent.js +150 -0
- package/dist/cjs/validations/evm-on-chain-intent.js.map +1 -0
- package/dist/cjs/validations/evm-op-budget.js +23 -3
- package/dist/cjs/validations/evm-op-budget.js.map +1 -1
- package/dist/cjs/validations/evm-op-hook.js +6 -6
- package/dist/cjs/validations/evm-op-hook.js.map +1 -1
- package/dist/cjs/validations/evm-permit.js +17 -6
- package/dist/cjs/validations/evm-permit.js.map +1 -1
- package/dist/cjs/validations/evm-permit2.js +14 -6
- package/dist/cjs/validations/evm-permit2.js.map +1 -1
- package/dist/cjs/validations/evm-required-actions.js +26 -7
- package/dist/cjs/validations/evm-required-actions.js.map +1 -1
- package/dist/cjs/validations/evm-sign712-metamask.js +3 -126
- package/dist/cjs/validations/evm-sign712-metamask.js.map +1 -1
- package/dist/cjs/validations/evm-sign712-shared.js +127 -0
- package/dist/cjs/validations/evm-sign712-shared.js.map +1 -1
- package/dist/cjs/validations/evm-sign712.js +18 -2
- package/dist/cjs/validations/evm-sign712.js.map +1 -1
- package/dist/cjs/validations/evm-sign7702.js +2 -0
- package/dist/cjs/validations/evm-sign7702.js.map +1 -1
- package/dist/cjs/validations/evm-transaction.js +7 -1
- package/dist/cjs/validations/evm-transaction.js.map +1 -1
- package/dist/cjs/validations/external-call.js +9 -20
- package/dist/cjs/validations/external-call.js.map +1 -1
- package/dist/cjs/validations/hook-version.js +35 -0
- package/dist/cjs/validations/hook-version.js.map +1 -0
- package/dist/cjs/validations/hooks-common.js +74 -199
- package/dist/cjs/validations/hooks-common.js.map +1 -1
- package/dist/cjs/validations/intent-destinations.js +52 -50
- package/dist/cjs/validations/intent-destinations.js.map +1 -1
- package/dist/cjs/validations/intent-tokens.js +319 -79
- package/dist/cjs/validations/intent-tokens.js.map +1 -1
- package/dist/cjs/validations/intent.js +34 -26
- package/dist/cjs/validations/intent.js.map +1 -1
- package/dist/cjs/validations/max-reserved.js +54 -0
- package/dist/cjs/validations/max-reserved.js.map +1 -0
- package/dist/cjs/validations/on-chain-intent-submission.js +70 -0
- package/dist/cjs/validations/on-chain-intent-submission.js.map +1 -0
- package/dist/cjs/validations/ptp.js +9 -6
- package/dist/cjs/validations/ptp.js.map +1 -1
- package/dist/cjs/validations/refill.js +11 -5
- package/dist/cjs/validations/refill.js.map +1 -1
- package/dist/cjs/validations/solana-hook.js +12 -64
- package/dist/cjs/validations/solana-hook.js.map +1 -1
- package/dist/cjs/validations/solana-op-budget.js +1 -1
- package/dist/cjs/validations/solana-op-budget.js.map +1 -1
- package/dist/cjs/validations/solana-op-wrap.js +29 -47
- package/dist/cjs/validations/solana-op-wrap.js.map +1 -1
- package/dist/cjs/validations/solana-required-actions.js +2 -2
- package/dist/cjs/validations/solana-required-actions.js.map +1 -1
- package/dist/cjs/validations/solana-transaction.js +4 -53
- package/dist/cjs/validations/solana-transaction.js.map +1 -1
- package/dist/cjs/validations/total-dst-amount.js +19 -3
- package/dist/cjs/validations/total-dst-amount.js.map +1 -1
- package/dist/cjs/validations/trade-grouping.js +35 -9
- package/dist/cjs/validations/trade-grouping.js.map +1 -1
- package/dist/cjs/validations/trade-matching.js +1 -1
- package/dist/cjs/validations/trade-matching.js.map +1 -1
- package/dist/cjs/validations/trades.js +29 -9
- package/dist/cjs/validations/trades.js.map +1 -1
- package/dist/cjs/validator.js +28 -17
- package/dist/cjs/validator.js.map +1 -1
- package/dist/cjs/whitelists/environment-config.js +9 -22
- package/dist/cjs/whitelists/environment-config.js.map +1 -1
- package/dist/cjs/whitelists/types.js +2 -5
- package/dist/cjs/whitelists/types.js.map +1 -1
- package/dist/esm/graylists/evm/token-permit-metadata.js +7 -1
- package/dist/esm/graylists/evm/token-permit-metadata.js.map +1 -1
- package/dist/esm/helpers/address.js +133 -61
- package/dist/esm/helpers/address.js.map +1 -1
- package/dist/esm/helpers/amount.js +5 -0
- package/dist/esm/helpers/amount.js.map +1 -0
- package/dist/esm/helpers/evm-dln-hook-pack.js +15 -4
- package/dist/esm/helpers/evm-dln-hook-pack.js.map +1 -1
- package/dist/esm/helpers/evm-gas-compensation-tx.js +12 -27
- package/dist/esm/helpers/evm-gas-compensation-tx.js.map +1 -1
- package/dist/esm/helpers/evm-intent-id-abi.js +7 -0
- package/dist/esm/helpers/evm-intent-id-abi.js.map +1 -1
- package/dist/esm/helpers/evm-trade-amounts.js +12 -4
- package/dist/esm/helpers/evm-trade-amounts.js.map +1 -1
- package/dist/esm/helpers/expected-delegate.js +2 -6
- package/dist/esm/helpers/expected-delegate.js.map +1 -1
- package/dist/esm/helpers/gas-compensation.js +9 -5
- package/dist/esm/helpers/gas-compensation.js.map +1 -1
- package/dist/esm/helpers/interactions.js +5 -21
- package/dist/esm/helpers/interactions.js.map +1 -1
- package/dist/esm/helpers/synthetic-native-wrap.js +4 -3
- package/dist/esm/helpers/synthetic-native-wrap.js.map +1 -1
- package/dist/esm/types/enums.js +1 -0
- package/dist/esm/types/enums.js.map +1 -1
- package/dist/esm/types/request.js +15 -2
- package/dist/esm/types/request.js.map +1 -1
- package/dist/esm/types/response.js +3 -2
- package/dist/esm/types/response.js.map +1 -1
- package/dist/esm/types/validation.js +21 -3
- package/dist/esm/types/validation.js.map +1 -1
- package/dist/esm/validations/compensation-hook.js +4 -5
- package/dist/esm/validations/compensation-hook.js.map +1 -1
- package/dist/esm/validations/cost-token.js +9 -1
- package/dist/esm/validations/cost-token.js.map +1 -1
- package/dist/esm/validations/echo-fields.js +18 -0
- package/dist/esm/validations/echo-fields.js.map +1 -1
- package/dist/esm/validations/evm-caveats.js +3 -0
- package/dist/esm/validations/evm-caveats.js.map +1 -1
- package/dist/esm/validations/evm-on-chain-intent.js +147 -0
- package/dist/esm/validations/evm-on-chain-intent.js.map +1 -0
- package/dist/esm/validations/evm-op-budget.js +25 -5
- package/dist/esm/validations/evm-op-budget.js.map +1 -1
- package/dist/esm/validations/evm-op-hook.js +8 -8
- package/dist/esm/validations/evm-op-hook.js.map +1 -1
- package/dist/esm/validations/evm-permit.js +18 -7
- package/dist/esm/validations/evm-permit.js.map +1 -1
- package/dist/esm/validations/evm-permit2.js +15 -7
- package/dist/esm/validations/evm-permit2.js.map +1 -1
- package/dist/esm/validations/evm-required-actions.js +28 -9
- package/dist/esm/validations/evm-required-actions.js.map +1 -1
- package/dist/esm/validations/evm-sign712-metamask.js +4 -126
- package/dist/esm/validations/evm-sign712-metamask.js.map +1 -1
- package/dist/esm/validations/evm-sign712-shared.js +126 -1
- package/dist/esm/validations/evm-sign712-shared.js.map +1 -1
- package/dist/esm/validations/evm-sign712.js +17 -2
- package/dist/esm/validations/evm-sign712.js.map +1 -1
- package/dist/esm/validations/evm-sign7702.js +2 -0
- package/dist/esm/validations/evm-sign7702.js.map +1 -1
- package/dist/esm/validations/evm-transaction.js +7 -1
- package/dist/esm/validations/evm-transaction.js.map +1 -1
- package/dist/esm/validations/external-call.js +10 -21
- package/dist/esm/validations/external-call.js.map +1 -1
- package/dist/esm/validations/hook-version.js +31 -0
- package/dist/esm/validations/hook-version.js.map +1 -0
- package/dist/esm/validations/hooks-common.js +75 -200
- package/dist/esm/validations/hooks-common.js.map +1 -1
- package/dist/esm/validations/intent-destinations.js +53 -51
- package/dist/esm/validations/intent-destinations.js.map +1 -1
- package/dist/esm/validations/intent-tokens.js +320 -80
- package/dist/esm/validations/intent-tokens.js.map +1 -1
- package/dist/esm/validations/intent.js +34 -26
- package/dist/esm/validations/intent.js.map +1 -1
- package/dist/esm/validations/max-reserved.js +51 -0
- package/dist/esm/validations/max-reserved.js.map +1 -0
- package/dist/esm/validations/on-chain-intent-submission.js +67 -0
- package/dist/esm/validations/on-chain-intent-submission.js.map +1 -0
- package/dist/esm/validations/ptp.js +9 -6
- package/dist/esm/validations/ptp.js.map +1 -1
- package/dist/esm/validations/refill.js +11 -5
- package/dist/esm/validations/refill.js.map +1 -1
- package/dist/esm/validations/solana-hook.js +12 -64
- package/dist/esm/validations/solana-hook.js.map +1 -1
- package/dist/esm/validations/solana-op-budget.js +1 -1
- package/dist/esm/validations/solana-op-budget.js.map +1 -1
- package/dist/esm/validations/solana-op-wrap.js +30 -48
- package/dist/esm/validations/solana-op-wrap.js.map +1 -1
- package/dist/esm/validations/solana-required-actions.js +2 -2
- package/dist/esm/validations/solana-required-actions.js.map +1 -1
- package/dist/esm/validations/solana-transaction.js +4 -53
- package/dist/esm/validations/solana-transaction.js.map +1 -1
- package/dist/esm/validations/total-dst-amount.js +20 -4
- package/dist/esm/validations/total-dst-amount.js.map +1 -1
- package/dist/esm/validations/trade-grouping.js +35 -10
- package/dist/esm/validations/trade-grouping.js.map +1 -1
- package/dist/esm/validations/trade-matching.js +1 -1
- package/dist/esm/validations/trade-matching.js.map +1 -1
- package/dist/esm/validations/trades.js +29 -9
- package/dist/esm/validations/trades.js.map +1 -1
- package/dist/esm/validator.js +28 -17
- package/dist/esm/validator.js.map +1 -1
- package/dist/esm/whitelists/environment-config.js +8 -21
- package/dist/esm/whitelists/environment-config.js.map +1 -1
- package/dist/esm/whitelists/types.js +3 -6
- package/dist/esm/whitelists/types.js.map +1 -1
- package/dist/types/graylists/evm/token-permit-metadata.d.ts.map +1 -1
- package/dist/types/helpers/address.d.ts +9 -5
- package/dist/types/helpers/address.d.ts.map +1 -1
- package/dist/types/helpers/amount.d.ts +2 -0
- package/dist/types/helpers/amount.d.ts.map +1 -0
- package/dist/types/helpers/evm-dln-hook-pack.d.ts +1 -0
- package/dist/types/helpers/evm-dln-hook-pack.d.ts.map +1 -1
- package/dist/types/helpers/evm-gas-compensation-tx.d.ts +1 -3
- package/dist/types/helpers/evm-gas-compensation-tx.d.ts.map +1 -1
- package/dist/types/helpers/evm-intent-id-abi.d.ts +111 -0
- package/dist/types/helpers/evm-intent-id-abi.d.ts.map +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/interactions.d.ts.map +1 -1
- package/dist/types/helpers/synthetic-native-wrap.d.ts.map +1 -1
- package/dist/types/types/enums.d.ts +1 -0
- package/dist/types/types/enums.d.ts.map +1 -1
- package/dist/types/types/request.d.ts +32 -23
- package/dist/types/types/request.d.ts.map +1 -1
- package/dist/types/types/response.d.ts +10 -42
- package/dist/types/types/response.d.ts.map +1 -1
- package/dist/types/types/validation.d.ts +19 -4
- package/dist/types/types/validation.d.ts.map +1 -1
- package/dist/types/validations/compensation-hook.d.ts +1 -2
- package/dist/types/validations/compensation-hook.d.ts.map +1 -1
- package/dist/types/validations/cost-token.d.ts.map +1 -1
- package/dist/types/validations/echo-fields.d.ts.map +1 -1
- package/dist/types/validations/evm-caveats.d.ts.map +1 -1
- package/dist/types/validations/evm-on-chain-intent.d.ts +4 -0
- package/dist/types/validations/evm-on-chain-intent.d.ts.map +1 -0
- package/dist/types/validations/evm-op-budget.d.ts.map +1 -1
- package/dist/types/validations/evm-op-hook.d.ts.map +1 -1
- package/dist/types/validations/evm-permit.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.map +1 -1
- package/dist/types/validations/evm-sign712-metamask.d.ts +0 -11
- package/dist/types/validations/evm-sign712-metamask.d.ts.map +1 -1
- package/dist/types/validations/evm-sign712-shared.d.ts +12 -0
- package/dist/types/validations/evm-sign712-shared.d.ts.map +1 -1
- package/dist/types/validations/evm-sign712.d.ts +1 -0
- package/dist/types/validations/evm-sign712.d.ts.map +1 -1
- package/dist/types/validations/evm-sign7702.d.ts.map +1 -1
- package/dist/types/validations/evm-transaction.d.ts +1 -1
- package/dist/types/validations/evm-transaction.d.ts.map +1 -1
- package/dist/types/validations/external-call.d.ts.map +1 -1
- package/dist/types/validations/hook-version.d.ts +7 -0
- package/dist/types/validations/hook-version.d.ts.map +1 -0
- package/dist/types/validations/hooks-common.d.ts +1 -4
- package/dist/types/validations/hooks-common.d.ts.map +1 -1
- package/dist/types/validations/intent-destinations.d.ts.map +1 -1
- package/dist/types/validations/intent-tokens.d.ts.map +1 -1
- package/dist/types/validations/max-reserved.d.ts +3 -0
- package/dist/types/validations/max-reserved.d.ts.map +1 -0
- package/dist/types/validations/on-chain-intent-submission.d.ts +3 -0
- package/dist/types/validations/on-chain-intent-submission.d.ts.map +1 -0
- package/dist/types/validations/ptp.d.ts.map +1 -1
- package/dist/types/validations/refill.d.ts.map +1 -1
- package/dist/types/validations/solana-hook.d.ts +1 -2
- package/dist/types/validations/solana-hook.d.ts.map +1 -1
- package/dist/types/validations/solana-op-wrap.d.ts +2 -2
- package/dist/types/validations/solana-op-wrap.d.ts.map +1 -1
- package/dist/types/validations/solana-required-actions.d.ts.map +1 -1
- package/dist/types/validations/solana-transaction.d.ts +3 -3
- package/dist/types/validations/solana-transaction.d.ts.map +1 -1
- package/dist/types/validations/total-dst-amount.d.ts.map +1 -1
- package/dist/types/validations/trade-grouping.d.ts +1 -0
- package/dist/types/validations/trade-grouping.d.ts.map +1 -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 +0 -1
- package/dist/types/whitelists/environment-config.d.ts.map +1 -1
- package/dist/types/whitelists/types.d.ts +0 -1
- package/dist/types/whitelists/types.d.ts.map +1 -1
- package/package.json +5 -2
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.validateIntentTokens = validateIntentTokens;
|
|
4
4
|
const types_1 = require("../types");
|
|
5
|
+
const trade_grouping_1 = require("./trade-grouping");
|
|
5
6
|
const address_1 = require("../helpers/address");
|
|
6
7
|
const evm_token_1 = require("../helpers/evm-token");
|
|
7
8
|
const subscription_to_chain_id_1 = require("../whitelists/subscription-to-chain-id");
|
|
@@ -14,6 +15,7 @@ function validateIntentTokens(ctx, basePath) {
|
|
|
14
15
|
...resolution.violations,
|
|
15
16
|
...validateInputTokens(intent.inputToken, ctx, resolution.expected, `${basePath}.inputToken`),
|
|
16
17
|
...validateGiveTokens(ctx, `${basePath}.giveToken`),
|
|
18
|
+
...validateTakeTokenZeroMode(ctx, `${basePath}.takeToken`),
|
|
17
19
|
...validateTakeTokens(ctx, `${basePath}.takeToken`),
|
|
18
20
|
];
|
|
19
21
|
}
|
|
@@ -24,7 +26,7 @@ function validateIntentTokens(ctx, basePath) {
|
|
|
24
26
|
// so the caller knows which trade is unverifiable.
|
|
25
27
|
function resolveIntentInputTokens(ctx) {
|
|
26
28
|
const group = ctx.tradeGroup;
|
|
27
|
-
const expected = new
|
|
29
|
+
const expected = new Map();
|
|
28
30
|
const violations = [];
|
|
29
31
|
for (let i = 0; i < ctx.intentTrades.length; i++) {
|
|
30
32
|
const trade = ctx.intentTrades[i];
|
|
@@ -34,12 +36,27 @@ function resolveIntentInputTokens(ctx) {
|
|
|
34
36
|
code: types_1.ViolationCode.IntentInputTokenWrappedAddressUnknown,
|
|
35
37
|
message: "cannot resolve wrapped token address: native token on a"
|
|
36
38
|
+ " chain with no WETH mapping in the whitelist",
|
|
37
|
-
path: `request.trades[${
|
|
39
|
+
path: `request.trades[${(0, trade_grouping_1.getRequestTradeIndex)(ctx, i)}].srcChainTokenIn`,
|
|
38
40
|
actual: trade.srcChainTokenIn,
|
|
39
41
|
});
|
|
40
42
|
continue;
|
|
41
43
|
}
|
|
42
|
-
|
|
44
|
+
const tokenKey = (0, address_1.getAddressIdentityKey)(group.realChainId, resolved);
|
|
45
|
+
if (tokenKey === undefined) {
|
|
46
|
+
violations.push({
|
|
47
|
+
code: types_1.ViolationCode.RequestTradeAddressInvalid,
|
|
48
|
+
message: "request.trades[].srcChainTokenIn is not a valid address"
|
|
49
|
+
+ " for srcChainId",
|
|
50
|
+
path: `request.trades[${(0, trade_grouping_1.getRequestTradeIndex)(ctx, i)}].srcChainTokenIn`,
|
|
51
|
+
expected: {
|
|
52
|
+
srcChainId: trade.srcChainId,
|
|
53
|
+
realChainId: group.realChainId,
|
|
54
|
+
},
|
|
55
|
+
actual: trade.srcChainTokenIn,
|
|
56
|
+
});
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
expected.set(tokenKey, resolved);
|
|
43
60
|
}
|
|
44
61
|
return { expected, violations };
|
|
45
62
|
}
|
|
@@ -51,11 +68,21 @@ function validateInputTokens(inputTokens, ctx, expectedTokens, basePath) {
|
|
|
51
68
|
const group = ctx.tradeGroup;
|
|
52
69
|
const actual = inputTokens ?? [];
|
|
53
70
|
const violations = [];
|
|
54
|
-
const actualAddresses = actual.map(t => (0, address_1.normalizeAddress)(group.realChainId, t.address));
|
|
55
71
|
const firstOccurrence = new Map();
|
|
56
|
-
for (let i = 0; i <
|
|
57
|
-
const
|
|
58
|
-
|
|
72
|
+
for (let i = 0; i < actual.length; i++) {
|
|
73
|
+
const addressKey = (0, address_1.getAddressIdentityKey)(group.realChainId, actual[i].address);
|
|
74
|
+
if (addressKey === undefined) {
|
|
75
|
+
violations.push({
|
|
76
|
+
code: types_1.ViolationCode.IntentInputTokenAddressMismatch,
|
|
77
|
+
message: "intent.inputToken[].address is not a valid address for"
|
|
78
|
+
+ " the intent source chain",
|
|
79
|
+
path: `${basePath}[${i}].address`,
|
|
80
|
+
expected: Array.from(expectedTokens.values()),
|
|
81
|
+
actual: actual[i].address,
|
|
82
|
+
});
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const earlier = firstOccurrence.get(addressKey);
|
|
59
86
|
if (earlier !== undefined) {
|
|
60
87
|
violations.push({
|
|
61
88
|
code: types_1.ViolationCode.IntentInputTokenDuplicate,
|
|
@@ -63,38 +90,38 @@ function validateInputTokens(inputTokens, ctx, expectedTokens, basePath) {
|
|
|
63
90
|
+ `${earlier} — each srcChainTokenIn (or its wrapped `
|
|
64
91
|
+ `equivalent) must appear once`,
|
|
65
92
|
path: `${basePath}[${i}].address`,
|
|
66
|
-
actual: address,
|
|
93
|
+
actual: actual[i].address,
|
|
67
94
|
});
|
|
68
95
|
}
|
|
69
96
|
else {
|
|
70
|
-
firstOccurrence.set(
|
|
97
|
+
firstOccurrence.set(addressKey, i);
|
|
71
98
|
}
|
|
72
99
|
}
|
|
73
|
-
for (const
|
|
74
|
-
if (!firstOccurrence.has(
|
|
100
|
+
for (const [expectedKey, expectedAddress] of expectedTokens) {
|
|
101
|
+
if (!firstOccurrence.has(expectedKey)) {
|
|
75
102
|
violations.push({
|
|
76
103
|
code: types_1.ViolationCode.IntentInputTokenMissing,
|
|
77
104
|
message: "an expected srcChainTokenIn address (or its wrapped "
|
|
78
105
|
+ "equivalent) is missing from intent.inputToken[]",
|
|
79
106
|
path: basePath,
|
|
80
|
-
expected:
|
|
107
|
+
expected: expectedAddress,
|
|
81
108
|
});
|
|
82
109
|
}
|
|
83
110
|
}
|
|
84
111
|
// Validate each unique entry (duplicates were already reported above)
|
|
85
|
-
for (const [
|
|
86
|
-
if (!expectedTokens.has(
|
|
112
|
+
for (const [addressKey, i] of firstOccurrence) {
|
|
113
|
+
if (!expectedTokens.has(addressKey)) {
|
|
87
114
|
violations.push({
|
|
88
115
|
code: types_1.ViolationCode.IntentInputTokenAddressMismatch,
|
|
89
116
|
message: "intent.inputToken[].address does not match any request"
|
|
90
117
|
+ " srcChainTokenIn (including native-to-wrapped resolution)",
|
|
91
118
|
path: `${basePath}[${i}].address`,
|
|
92
|
-
expected: Array.from(expectedTokens),
|
|
93
|
-
actual: address,
|
|
119
|
+
expected: Array.from(expectedTokens.values()),
|
|
120
|
+
actual: actual[i].address,
|
|
94
121
|
});
|
|
95
122
|
continue;
|
|
96
123
|
}
|
|
97
|
-
violations.push(...validateConstraintBudget(actual[i], ctx,
|
|
124
|
+
violations.push(...validateConstraintBudget(actual[i], ctx, addressKey, `${basePath}[${i}]`));
|
|
98
125
|
}
|
|
99
126
|
return violations;
|
|
100
127
|
}
|
|
@@ -108,7 +135,7 @@ function validateInputTokens(inputTokens, ctx, expectedTokens, basePath) {
|
|
|
108
135
|
//
|
|
109
136
|
// Sanity bounds on `response.srcChainTokenIn.amount` itself live in
|
|
110
137
|
// `validateTrades`.
|
|
111
|
-
function validateConstraintBudget(inputToken, ctx,
|
|
138
|
+
function validateConstraintBudget(inputToken, ctx, addressKey, basePath) {
|
|
112
139
|
// MEDIUM: exact per-intent trade subset is unverifiable for partial quote
|
|
113
140
|
// groups because the public response strips the hidden grouping keys.
|
|
114
141
|
if (ctx.quoteTradeSubsetUnverifiable)
|
|
@@ -119,10 +146,11 @@ function validateConstraintBudget(inputToken, ctx, normalizedAddress, basePath)
|
|
|
119
146
|
.filter(({ trade }) => {
|
|
120
147
|
const resolved = (0, evm_token_1.resolveWrappedTokenAddress)(trade.srcChainTokenIn, realChainId);
|
|
121
148
|
// Safe skip: unresolved input tokens are already reported by
|
|
122
|
-
// `
|
|
149
|
+
// `resolveIntentInputTokens`.
|
|
123
150
|
if (resolved === undefined)
|
|
124
151
|
return false;
|
|
125
|
-
|
|
152
|
+
const tradeTokenKey = (0, address_1.getAddressIdentityKey)(realChainId, resolved);
|
|
153
|
+
return tradeTokenKey !== undefined && tradeTokenKey === addressKey;
|
|
126
154
|
});
|
|
127
155
|
// Safe skip: missing response trade at a contributing index is reported
|
|
128
156
|
// by `validateTrades` as `TradeCountMismatch`; computing a partial sum here
|
|
@@ -192,32 +220,29 @@ function validateGiveTokens(ctx, basePath) {
|
|
|
192
220
|
return [];
|
|
193
221
|
}
|
|
194
222
|
const violations = [];
|
|
195
|
-
const
|
|
223
|
+
const expectedEngine = (0, address_1.getChainEngine)(group.realChainId);
|
|
196
224
|
for (let i = 0; i < giveTokens.length; i++) {
|
|
197
|
-
const
|
|
198
|
-
if (!allowed.has(
|
|
225
|
+
const addressKey = (0, address_1.getAddressIdentityKey)(group.realChainId, giveTokens[i].inputTokenAddress);
|
|
226
|
+
if (addressKey === undefined || !allowed.has(addressKey)) {
|
|
199
227
|
violations.push({
|
|
200
228
|
code: types_1.ViolationCode.IntentGiveTokenInputAddressMismatch,
|
|
201
229
|
message: "intent.giveToken[].inputTokenAddress must equal one of"
|
|
202
230
|
+ " intent.inputToken[].address used by a cross-chain"
|
|
203
231
|
+ " trade in the group",
|
|
204
232
|
path: `${basePath}[${i}].inputTokenAddress`,
|
|
205
|
-
expected: Array.from(allowed),
|
|
233
|
+
expected: Array.from(allowed.values()),
|
|
206
234
|
actual: giveTokens[i].inputTokenAddress,
|
|
207
235
|
});
|
|
208
236
|
}
|
|
209
237
|
// CRITICAL: giveTokenAddress is a bridge token in src chain — its value
|
|
210
238
|
// is API-determined and unpredictable, but its format must match the
|
|
211
239
|
// intent chain's engine.
|
|
212
|
-
|
|
213
|
-
if (actualFormat !== expectedFormat) {
|
|
240
|
+
if (!(0, address_1.isAddressRepresentationValidForChain)(group.realChainId, giveTokens[i].giveTokenAddress)) {
|
|
214
241
|
violations.push({
|
|
215
242
|
code: types_1.ViolationCode.IntentGiveTokenAddressFormatMismatch,
|
|
216
|
-
message:
|
|
217
|
-
+ `
|
|
218
|
-
+ ` (${types_1.ChainEngine[expectedFormat]})`,
|
|
243
|
+
message: "intent.giveToken[].giveTokenAddress does not use a supported"
|
|
244
|
+
+ ` format for the intent chain engine (${types_1.ChainEngine[expectedEngine]})`,
|
|
219
245
|
path: `${basePath}[${i}].giveTokenAddress`,
|
|
220
|
-
expected: types_1.ChainEngine[expectedFormat],
|
|
221
246
|
actual: giveTokens[i].giveTokenAddress,
|
|
222
247
|
});
|
|
223
248
|
}
|
|
@@ -229,43 +254,168 @@ function validateGiveTokens(ctx, basePath) {
|
|
|
229
254
|
function collectInputAddressesForCrossChainTrades(ctx) {
|
|
230
255
|
const intent = ctx.intentPayload.intent;
|
|
231
256
|
const group = ctx.tradeGroup;
|
|
232
|
-
const inputAddresses = new
|
|
233
|
-
const
|
|
257
|
+
const inputAddresses = new Map();
|
|
258
|
+
for (const inputToken of intent.inputToken ?? []) {
|
|
259
|
+
const inputTokenKey = (0, address_1.getAddressIdentityKey)(group.realChainId, inputToken.address);
|
|
260
|
+
if (inputTokenKey !== undefined) {
|
|
261
|
+
inputAddresses.set(inputTokenKey, inputToken.address);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const result = new Map();
|
|
234
265
|
for (const trade of ctx.intentTrades) {
|
|
235
266
|
if (!isCrossChain(trade))
|
|
236
267
|
continue;
|
|
237
268
|
const resolved = (0, evm_token_1.resolveWrappedTokenAddress)(trade.srcChainTokenIn, group.realChainId);
|
|
238
269
|
// Safe skip: unresolved input tokens are already reported by
|
|
239
|
-
//
|
|
270
|
+
// `resolveIntentInputTokens`.
|
|
240
271
|
if (resolved === undefined)
|
|
241
272
|
continue;
|
|
242
|
-
const
|
|
243
|
-
if (
|
|
244
|
-
|
|
245
|
-
|
|
273
|
+
const addressKey = (0, address_1.getAddressIdentityKey)(group.realChainId, resolved);
|
|
274
|
+
if (addressKey === undefined)
|
|
275
|
+
continue;
|
|
276
|
+
const inputAddress = inputAddresses.get(addressKey);
|
|
277
|
+
if (inputAddress !== undefined)
|
|
278
|
+
result.set(addressKey, inputAddress);
|
|
246
279
|
}
|
|
247
280
|
return result;
|
|
248
281
|
}
|
|
249
282
|
function isCrossChain(trade) {
|
|
250
283
|
return trade.srcChainId !== trade.dstChainId;
|
|
251
284
|
}
|
|
252
|
-
// CRITICAL: intent
|
|
253
|
-
//
|
|
254
|
-
//
|
|
255
|
-
//
|
|
256
|
-
|
|
285
|
+
// CRITICAL: trades folded into one intent must not mix zero and non-zero
|
|
286
|
+
// destination amounts for the same source/destination token pair. The intent
|
|
287
|
+
// stores one exchange ratio per pair, so mixing modes would collapse the
|
|
288
|
+
// signed ratio to zero for every trade in that pair.
|
|
289
|
+
function validateTakeTokenZeroMode(ctx, basePath) {
|
|
290
|
+
const modes = new Map();
|
|
291
|
+
const reportedPairs = new Set();
|
|
292
|
+
const violations = [];
|
|
293
|
+
for (let i = 0; i < ctx.intentResponseTrades.length; i++) {
|
|
294
|
+
const requestTrade = ctx.intentTrades[i];
|
|
295
|
+
const responseTrade = ctx.intentResponseTrades[i];
|
|
296
|
+
if (requestTrade === undefined || responseTrade === undefined) {
|
|
297
|
+
// Safe skip: missing trade pairs are reported by trade count and matching checks.
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
const entry = getTakeTokenZeroModeEntry(requestTrade, responseTrade);
|
|
301
|
+
if (entry === undefined)
|
|
302
|
+
continue;
|
|
303
|
+
const existing = modes.get(entry.key);
|
|
304
|
+
if (existing === undefined) {
|
|
305
|
+
modes.set(entry.key, {
|
|
306
|
+
fromChainId: entry.fromChainId,
|
|
307
|
+
fromTokenAddress: entry.fromTokenAddress,
|
|
308
|
+
takeChainId: entry.takeChainId,
|
|
309
|
+
takeTokenAddress: entry.takeTokenAddress,
|
|
310
|
+
isDestinationAmountZero: entry.isDestinationAmountZero,
|
|
311
|
+
amounts: [entry.amount],
|
|
312
|
+
});
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
existing.amounts.push(entry.amount);
|
|
316
|
+
if (existing.isDestinationAmountZero === entry.isDestinationAmountZero)
|
|
317
|
+
continue;
|
|
318
|
+
if (reportedPairs.has(entry.key))
|
|
319
|
+
continue;
|
|
320
|
+
reportedPairs.add(entry.key);
|
|
321
|
+
violations.push(createTakeTokenZeroModeViolation(existing, basePath));
|
|
322
|
+
}
|
|
323
|
+
return violations;
|
|
324
|
+
}
|
|
325
|
+
function getTakeTokenZeroModeEntry(requestTrade, responseTrade) {
|
|
326
|
+
let amount;
|
|
327
|
+
try {
|
|
328
|
+
amount = (0, integer_1.parseIntegerString)(responseTrade.dstChainTokenOut.amount);
|
|
329
|
+
}
|
|
330
|
+
catch {
|
|
331
|
+
// Safe skip: malformed destination amounts are reported by the trade-level checks.
|
|
332
|
+
return undefined;
|
|
333
|
+
}
|
|
334
|
+
if (amount < 0n) {
|
|
335
|
+
// Safe skip: legacy Solana negative outputs are validated separately.
|
|
336
|
+
return undefined;
|
|
337
|
+
}
|
|
338
|
+
const pair = resolveTakeTokenPairIdentity(requestTrade, responseTrade);
|
|
339
|
+
if (pair === undefined) {
|
|
340
|
+
// Safe skip: unknown chains, malformed token addresses, and native
|
|
341
|
+
// mapping gaps are reported by the dedicated trade/intent validators.
|
|
342
|
+
return undefined;
|
|
343
|
+
}
|
|
344
|
+
return {
|
|
345
|
+
...pair,
|
|
346
|
+
amount: responseTrade.dstChainTokenOut.amount,
|
|
347
|
+
isDestinationAmountZero: amount === 0n,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
function createTakeTokenZeroModeViolation(mode, basePath) {
|
|
351
|
+
return {
|
|
352
|
+
code: types_1.ViolationCode.IntentTakeTokenZeroModeMismatch,
|
|
353
|
+
message: "trades represented by one intent must not mix zero and non-zero"
|
|
354
|
+
+ " destination amounts for the same token pair",
|
|
355
|
+
path: basePath,
|
|
356
|
+
actual: {
|
|
357
|
+
fromChainId: mode.fromChainId,
|
|
358
|
+
fromTokenAddress: mode.fromTokenAddress,
|
|
359
|
+
takeChainId: mode.takeChainId,
|
|
360
|
+
takeTokenAddress: mode.takeTokenAddress,
|
|
361
|
+
destinationAmounts: [...mode.amounts],
|
|
362
|
+
},
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
function resolveTakeTokenPairIdentity(requestTrade, responseTrade) {
|
|
366
|
+
const fromRealChainId = (0, subscription_to_chain_id_1.resolveChainId)(requestTrade.srcChainId);
|
|
367
|
+
const takeRealChainId = (0, subscription_to_chain_id_1.resolveChainId)(requestTrade.dstChainId);
|
|
368
|
+
if (fromRealChainId === undefined || takeRealChainId === undefined)
|
|
369
|
+
return undefined;
|
|
370
|
+
const fromToken = responseTrade.srcChainTokenOut ?? responseTrade.srcChainTokenIn;
|
|
371
|
+
const canonicalFromTokenAddress = fromRealChainId === takeRealChainId
|
|
372
|
+
? (0, evm_token_1.resolveWrappedTokenAddress)(fromToken.address, fromRealChainId)
|
|
373
|
+
: fromToken.address;
|
|
374
|
+
if (canonicalFromTokenAddress === undefined)
|
|
375
|
+
return undefined;
|
|
376
|
+
const takeTokenAddress = responseTrade.dstChainTokenOut.address;
|
|
377
|
+
const fromTokenKey = (0, address_1.getAddressIdentityKey)(fromRealChainId, canonicalFromTokenAddress);
|
|
378
|
+
const takeTokenKey = (0, address_1.getAddressIdentityKey)(takeRealChainId, takeTokenAddress);
|
|
379
|
+
if (fromTokenKey === undefined || takeTokenKey === undefined)
|
|
380
|
+
return undefined;
|
|
381
|
+
return {
|
|
382
|
+
key: [
|
|
383
|
+
fromRealChainId,
|
|
384
|
+
fromTokenKey,
|
|
385
|
+
takeRealChainId,
|
|
386
|
+
takeTokenKey,
|
|
387
|
+
].join(":"),
|
|
388
|
+
fromChainId: fromRealChainId,
|
|
389
|
+
fromTokenAddress: canonicalFromTokenAddress,
|
|
390
|
+
takeChainId: takeRealChainId,
|
|
391
|
+
takeTokenAddress,
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
// CRITICAL: intent.takeToken[] must cover every unique
|
|
395
|
+
// (fromTokenAddress, takeTokenChainId, takeTokenAddress) identity represented
|
|
396
|
+
// by this concrete intent's trades. Missing and duplicate checks use the same
|
|
397
|
+
// full identity so one source token cannot borrow another source token's output
|
|
398
|
+
// constraint merely because both trades share a destination token.
|
|
257
399
|
// CRITICAL: fromTokenAddress must be in inputToken[] (same-chain) or giveToken[]
|
|
258
400
|
// (cross-chain).
|
|
259
401
|
function validateTakeTokens(ctx, basePath) {
|
|
260
402
|
const intent = ctx.intentPayload.intent;
|
|
261
403
|
const group = ctx.tradeGroup;
|
|
262
404
|
const violations = [];
|
|
263
|
-
const
|
|
405
|
+
const expectedResult = buildExpectedTakeTokens(ctx);
|
|
406
|
+
const expectedIdentities = expectedResult.identities;
|
|
407
|
+
const expectedDestinations = expectedResult.destinations;
|
|
408
|
+
violations.push(...expectedResult.violations);
|
|
264
409
|
const actualKeys = intent.takeToken.map(takeToken => buildTakeTokenIdentityKey(takeToken, group.realChainId));
|
|
265
|
-
const
|
|
410
|
+
const actualIdentityKeys = new Set(actualKeys.flatMap(key => key === undefined ? [] : [key]));
|
|
266
411
|
const firstOccurrence = new Map();
|
|
412
|
+
const uniqueIndices = [];
|
|
267
413
|
for (let i = 0; i < actualKeys.length; i++) {
|
|
268
414
|
const key = actualKeys[i];
|
|
415
|
+
if (key === undefined) {
|
|
416
|
+
uniqueIndices.push(i);
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
269
419
|
const earlier = firstOccurrence.get(key);
|
|
270
420
|
if (earlier !== undefined) {
|
|
271
421
|
violations.push({
|
|
@@ -274,57 +424,110 @@ function validateTakeTokens(ctx, basePath) {
|
|
|
274
424
|
+ ` index ${earlier} — each (fromTokenAddress,`
|
|
275
425
|
+ ` takeTokenChainId, takeTokenAddress) tuple must appear once`,
|
|
276
426
|
path: `${basePath}[${i}]`,
|
|
277
|
-
actual:
|
|
427
|
+
actual: {
|
|
428
|
+
fromTokenAddress: intent.takeToken[i].fromTokenAddress,
|
|
429
|
+
takeTokenChainId: intent.takeToken[i].takeTokenChainId,
|
|
430
|
+
takeTokenAddress: intent.takeToken[i].takeTokenAddress,
|
|
431
|
+
},
|
|
278
432
|
});
|
|
279
433
|
}
|
|
280
434
|
else {
|
|
281
435
|
firstOccurrence.set(key, i);
|
|
436
|
+
uniqueIndices.push(i);
|
|
282
437
|
}
|
|
283
438
|
}
|
|
284
|
-
for (const expectedTakeToken of
|
|
285
|
-
if (!
|
|
439
|
+
for (const [expectedKey, expectedTakeToken] of expectedIdentities) {
|
|
440
|
+
if (!actualIdentityKeys.has(expectedKey)) {
|
|
286
441
|
violations.push({
|
|
287
442
|
code: types_1.ViolationCode.IntentTakeTokenMissing,
|
|
288
|
-
message: "an expected (
|
|
289
|
-
+ " missing from
|
|
443
|
+
message: "an expected (fromTokenAddress, takeTokenChainId,"
|
|
444
|
+
+ " takeTokenAddress) identity is missing from"
|
|
445
|
+
+ " intent.takeToken[]",
|
|
290
446
|
path: basePath,
|
|
291
447
|
expected: expectedTakeToken,
|
|
292
448
|
});
|
|
293
449
|
}
|
|
294
450
|
}
|
|
295
451
|
// Validate each unique entry (duplicates are already reported above)
|
|
296
|
-
for (const
|
|
452
|
+
for (const i of uniqueIndices) {
|
|
297
453
|
violations.push(...validateSingleTakeToken(intent, intent.takeToken[i], group, expectedDestinations, `${basePath}[${i}]`));
|
|
298
454
|
}
|
|
299
455
|
return violations;
|
|
300
456
|
}
|
|
301
|
-
// Single source of truth for the "chainId:
|
|
302
|
-
// to compare takeToken entries as a set.
|
|
303
|
-
//
|
|
304
|
-
// duplicate detection; the chainId mismatch is flagged separately.
|
|
457
|
+
// Single source of truth for the "chainId:canonicalAddress" key format used
|
|
458
|
+
// to compare takeToken entries as a set. Unknown chains and malformed
|
|
459
|
+
// addresses have no comparable identity.
|
|
305
460
|
function buildChainTokenKey(chainId, realChainId, address) {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
461
|
+
if (realChainId === undefined)
|
|
462
|
+
return undefined;
|
|
463
|
+
const addressKey = (0, address_1.getAddressIdentityKey)(realChainId, address);
|
|
464
|
+
if (addressKey === undefined)
|
|
465
|
+
return undefined;
|
|
466
|
+
return `${chainId}:${addressKey}`;
|
|
310
467
|
}
|
|
311
468
|
function buildTakeTokenDestinationKey(takeToken) {
|
|
312
469
|
return buildChainTokenKey(takeToken.takeTokenChainId, (0, subscription_to_chain_id_1.resolveChainId)(takeToken.takeTokenChainId), takeToken.takeTokenAddress);
|
|
313
470
|
}
|
|
314
471
|
function buildTakeTokenIdentityKey(takeToken, sourceRealChainId) {
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
472
|
+
const destinationRealChainId = (0, subscription_to_chain_id_1.resolveChainId)(takeToken.takeTokenChainId);
|
|
473
|
+
if (destinationRealChainId === undefined)
|
|
474
|
+
return undefined;
|
|
475
|
+
return buildResolvedTakeTokenIdentityKey(sourceRealChainId, takeToken.fromTokenAddress, destinationRealChainId, takeToken.takeTokenAddress);
|
|
318
476
|
}
|
|
319
|
-
function
|
|
320
|
-
const
|
|
321
|
-
|
|
477
|
+
function buildResolvedTakeTokenIdentityKey(sourceRealChainId, fromTokenAddress, destinationRealChainId, takeTokenAddress) {
|
|
478
|
+
const fromKey = (0, address_1.getAddressIdentityKey)(sourceRealChainId, fromTokenAddress);
|
|
479
|
+
const takeKey = (0, address_1.getAddressIdentityKey)(destinationRealChainId, takeTokenAddress);
|
|
480
|
+
if (fromKey === undefined || takeKey === undefined)
|
|
481
|
+
return undefined;
|
|
482
|
+
return [
|
|
483
|
+
sourceRealChainId,
|
|
484
|
+
fromKey,
|
|
485
|
+
destinationRealChainId,
|
|
486
|
+
takeKey,
|
|
487
|
+
].join(":");
|
|
488
|
+
}
|
|
489
|
+
function buildExpectedTakeTokens(ctx) {
|
|
490
|
+
const identities = new Map();
|
|
491
|
+
const destinations = new Map();
|
|
492
|
+
const violations = [];
|
|
493
|
+
for (let i = 0; i < ctx.intentTrades.length; i++) {
|
|
494
|
+
const trade = ctx.intentTrades[i];
|
|
495
|
+
const responseTrade = ctx.intentResponseTrades[i];
|
|
322
496
|
const dstRealChainId = (0, subscription_to_chain_id_1.resolveChainId)(trade.dstChainId);
|
|
323
497
|
// Safe skip: unknown subscriptionId for dstChainId is reported elsewhere
|
|
324
498
|
// (validateTrades reports UnknownSubscriptionId for dstChainId)
|
|
325
499
|
if (dstRealChainId === undefined)
|
|
326
500
|
continue;
|
|
327
|
-
|
|
501
|
+
const destinationKey = buildChainTokenKey(trade.dstChainId, dstRealChainId, trade.dstChainTokenOut);
|
|
502
|
+
if (destinationKey === undefined) {
|
|
503
|
+
violations.push({
|
|
504
|
+
code: types_1.ViolationCode.RequestTradeAddressInvalid,
|
|
505
|
+
message: "request.trades[].dstChainTokenOut is not a valid address"
|
|
506
|
+
+ " for dstChainId",
|
|
507
|
+
path: `request.trades[${(0, trade_grouping_1.getRequestTradeIndex)(ctx, i)}].dstChainTokenOut`,
|
|
508
|
+
expected: {
|
|
509
|
+
dstChainId: trade.dstChainId,
|
|
510
|
+
realChainId: dstRealChainId,
|
|
511
|
+
},
|
|
512
|
+
actual: trade.dstChainTokenOut,
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
destinations.set(destinationKey, {
|
|
517
|
+
takeTokenChainId: trade.dstChainId,
|
|
518
|
+
takeTokenAddress: trade.dstChainTokenOut,
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
const pair = responseTrade === undefined
|
|
522
|
+
? undefined
|
|
523
|
+
: resolveTakeTokenPairIdentity(trade, responseTrade);
|
|
524
|
+
if (pair !== undefined) {
|
|
525
|
+
identities.set(pair.key, {
|
|
526
|
+
fromTokenAddress: pair.fromTokenAddress,
|
|
527
|
+
takeTokenChainId: trade.dstChainId,
|
|
528
|
+
takeTokenAddress: pair.takeTokenAddress,
|
|
529
|
+
});
|
|
530
|
+
}
|
|
328
531
|
// CRITICAL: same-chain Solana with native dst — API also emits a wSOL
|
|
329
532
|
// takeToken[] entry alongside the native one because Solana DLN
|
|
330
533
|
// settlement operates on SPL tokens. Both entries are legitimate and
|
|
@@ -332,27 +535,57 @@ function buildExpectedTakeTokenDestinations(ctx) {
|
|
|
332
535
|
if (trade.srcChainId === trade.dstChainId
|
|
333
536
|
&& (0, address_1.getChainEngine)(dstRealChainId) === types_1.ChainEngine.Solana
|
|
334
537
|
&& (0, address_1.isNativeToken)(trade.dstChainTokenOut, dstRealChainId)) {
|
|
335
|
-
|
|
538
|
+
const wrappedDestinationKey = buildChainTokenKey(trade.dstChainId, dstRealChainId, programs_1.SPL_NATIVE_MINT);
|
|
539
|
+
if (wrappedDestinationKey !== undefined) {
|
|
540
|
+
destinations.set(wrappedDestinationKey, {
|
|
541
|
+
takeTokenChainId: trade.dstChainId,
|
|
542
|
+
takeTokenAddress: programs_1.SPL_NATIVE_MINT,
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
if (pair !== undefined) {
|
|
546
|
+
const wrappedIdentityKey = buildResolvedTakeTokenIdentityKey(pair.fromChainId, pair.fromTokenAddress, pair.takeChainId, programs_1.SPL_NATIVE_MINT);
|
|
547
|
+
if (wrappedIdentityKey !== undefined) {
|
|
548
|
+
identities.set(wrappedIdentityKey, {
|
|
549
|
+
fromTokenAddress: pair.fromTokenAddress,
|
|
550
|
+
takeTokenChainId: trade.dstChainId,
|
|
551
|
+
takeTokenAddress: programs_1.SPL_NATIVE_MINT,
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
}
|
|
336
555
|
}
|
|
337
556
|
}
|
|
338
|
-
return
|
|
557
|
+
return { identities, destinations, violations };
|
|
339
558
|
}
|
|
340
559
|
function validateSingleTakeToken(intent, takeToken, group, expected, basePath) {
|
|
341
560
|
const violations = [];
|
|
342
561
|
const dstRealChainId = (0, subscription_to_chain_id_1.resolveChainId)(takeToken.takeTokenChainId);
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
562
|
+
if (dstRealChainId === undefined) {
|
|
563
|
+
violations.push({
|
|
564
|
+
code: types_1.ViolationCode.IntentTakeTokenAddressMismatch,
|
|
565
|
+
message: "intent.takeToken[].takeTokenChainId is not a known"
|
|
566
|
+
+ " destination subscriptionId",
|
|
567
|
+
path: `${basePath}.takeTokenChainId`,
|
|
568
|
+
expected: Array.from(expected.values()),
|
|
569
|
+
actual: {
|
|
570
|
+
takeTokenChainId: takeToken.takeTokenChainId,
|
|
571
|
+
takeTokenAddress: takeToken.takeTokenAddress,
|
|
572
|
+
},
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
346
576
|
const key = buildChainTokenKey(takeToken.takeTokenChainId, dstRealChainId, takeToken.takeTokenAddress);
|
|
347
|
-
if (!expected.has(key)) {
|
|
577
|
+
if (key === undefined || !expected.has(key)) {
|
|
348
578
|
violations.push({
|
|
349
579
|
code: types_1.ViolationCode.IntentTakeTokenAddressMismatch,
|
|
350
580
|
message: "intent.takeToken[] (takeTokenChainId, takeTokenAddress)"
|
|
351
581
|
+ " pair does not match any request (dstChainId,"
|
|
352
582
|
+ " dstChainTokenOut) pair in the trade group",
|
|
353
583
|
path: basePath,
|
|
354
|
-
expected: Array.from(expected),
|
|
355
|
-
actual:
|
|
584
|
+
expected: Array.from(expected.values()),
|
|
585
|
+
actual: {
|
|
586
|
+
takeTokenChainId: takeToken.takeTokenChainId,
|
|
587
|
+
takeTokenAddress: takeToken.takeTokenAddress,
|
|
588
|
+
},
|
|
356
589
|
});
|
|
357
590
|
}
|
|
358
591
|
}
|
|
@@ -361,11 +594,18 @@ function validateSingleTakeToken(intent, takeToken, group, expected, basePath) {
|
|
|
361
594
|
}
|
|
362
595
|
function validateTakeTokenFromAddress(intent, takeToken, group, basePath) {
|
|
363
596
|
const isSameChain = takeToken.takeTokenChainId === group.srcChainId;
|
|
364
|
-
const
|
|
365
|
-
const
|
|
366
|
-
?
|
|
367
|
-
:
|
|
368
|
-
|
|
597
|
+
const addressKey = (0, address_1.getAddressIdentityKey)(group.realChainId, takeToken.fromTokenAddress);
|
|
598
|
+
const allowedAddresses = isSameChain
|
|
599
|
+
? (intent.inputToken ?? []).map(t => t.address)
|
|
600
|
+
: (intent.giveToken ?? []).map(t => t.giveTokenAddress);
|
|
601
|
+
const allowedByIdentity = new Map();
|
|
602
|
+
for (const address of allowedAddresses) {
|
|
603
|
+
const allowedAddressKey = (0, address_1.getAddressIdentityKey)(group.realChainId, address);
|
|
604
|
+
if (allowedAddressKey !== undefined) {
|
|
605
|
+
allowedByIdentity.set(allowedAddressKey, address);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
if (addressKey === undefined || !allowedByIdentity.has(addressKey)) {
|
|
369
609
|
return [{
|
|
370
610
|
code: types_1.ViolationCode.IntentTakeTokenFromAddressInvalid,
|
|
371
611
|
message: isSameChain
|
|
@@ -374,7 +614,7 @@ function validateTakeTokenFromAddress(intent, takeToken, group, basePath) {
|
|
|
374
614
|
: "intent.takeToken[].fromTokenAddress must be present"
|
|
375
615
|
+ " in intent.giveToken[].giveTokenAddress for cross-chain trades",
|
|
376
616
|
path: `${basePath}.fromTokenAddress`,
|
|
377
|
-
expected: Array.from(
|
|
617
|
+
expected: Array.from(allowedByIdentity.values()),
|
|
378
618
|
actual: takeToken.fromTokenAddress,
|
|
379
619
|
}];
|
|
380
620
|
}
|