Skip to content

Commit 69323f4

Browse files
committed
extract verifier finality config
1 parent b233a70 commit 69323f4

26 files changed

+379
-143
lines changed

chains/evm/.gas-snapshot

Lines changed: 84 additions & 73 deletions
Large diffs are not rendered by default.

chains/evm/contracts/ccvs/CCTPVerifier.sol

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,14 @@ contract CCTPVerifier is Ownable2StepMsgSender, BaseVerifier {
446446
_applyAllowlistUpdates(allowlistConfigArgsItems);
447447
}
448448

449+
/// @notice Sets the finality config according to the FinalityCodec library encoding.
450+
/// @param allowedFinality The finality settings allowed by this verifier.
451+
function setAllowedFinalityConfig(
452+
bytes4 allowedFinality
453+
) external onlyOwner {
454+
_setAllowedFinalityConfig(allowedFinality);
455+
}
456+
449457
/// @notice Updates the storage location identifiers.
450458
/// @param newLocations The new storage location identifiers.
451459
function updateStorageLocations(

chains/evm/contracts/ccvs/CommitteeVerifier.sol

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,14 @@ contract CommitteeVerifier is Ownable2StepMsgSender, ICrossChainVerifierV1, Sign
163163
_applyAllowlistUpdates(allowlistConfigArgsItems);
164164
}
165165

166+
/// @notice Sets the finality config according to the FinalityCodec library encoding.
167+
/// @param allowedFinality The finality settings allowed by this verifier.
168+
function setAllowedFinalityConfig(
169+
bytes4 allowedFinality
170+
) external onlyOwner {
171+
_setAllowedFinalityConfig(allowedFinality);
172+
}
173+
166174
/// @notice Returns the account currently authorized to manage the storage location.
167175
/// @return storageLocationsAdmin The active storage locations admin.
168176
function getStorageLocationsAdmin() external view returns (address storageLocationsAdmin) {

chains/evm/contracts/ccvs/LombardVerifier.sol

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,14 @@ contract LombardVerifier is BaseVerifier, Ownable2StepMsgSender {
510510
_applyAllowlistUpdates(allowlistConfigArgsItems);
511511
}
512512

513+
/// @notice Sets the finality config according to the FinalityCodec library encoding.
514+
/// @param allowedFinality The finality settings allowed by this verifier.
515+
function setAllowedFinalityConfig(
516+
bytes4 allowedFinality
517+
) external onlyOwner {
518+
_setAllowedFinalityConfig(allowedFinality);
519+
}
520+
513521
/// @notice Updates the storage location identifiers.
514522
/// @param newLocations The new storage location identifiers.
515523
function updateStorageLocations(

chains/evm/contracts/ccvs/components/BaseVerifier.sol

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import {IRouter} from "../../interfaces/IRouter.sol";
77
import {ITypeAndVersion} from "@chainlink/contracts/src/v0.8/shared/interfaces/ITypeAndVersion.sol";
88

99
import {Client} from "../../libraries/Client.sol";
10-
1110
import {FinalityCodec} from "../../libraries/FinalityCodec.sol";
11+
1212
import {IERC165} from "@openzeppelin/contracts@5.3.0/utils/introspection/IERC165.sol";
1313
import {EnumerableSet} from "@openzeppelin/contracts@5.3.0/utils/structs/EnumerableSet.sol";
1414

@@ -29,14 +29,14 @@ abstract contract BaseVerifier is ICrossChainVerifierV1, ITypeAndVersion {
2929
event AllowListSendersRemoved(uint64 indexed destChainSelector, address senders);
3030
event AllowListStateChanged(uint64 indexed destChainSelector, bool allowlistEnabled);
3131
event StorageLocationsUpdated(string[] oldLocations, string[] newLocations);
32+
event FinalityConfigSet(bytes4 allowedFinality);
3233

3334
// solhint-disable-next-line gas-struct-packing
3435
struct RemoteChainConfig {
3536
IRouter router; // ─────────────╮ Local router to use for messages to/from this chain.
3637
uint16 feeUSDCents; // │ The fee in US dollar cents for messages to this remote chain. [0, $655.35]
3738
uint32 gasForVerification; // │ The gas to reserve for verification of messages on the remote chain.
3839
uint16 payloadSizeBytes; // │ The size of the verification payload on the remote chain.
39-
bytes4 allowedFinalityConfig; //│ The finality configuration for the local chain for messages to the remote chain.
4040
bool allowlistEnabled; // ──────╯ True if the allowlist is enabled.
4141
EnumerableSet.AddressSet allowedSendersList; // The list of addresses allowed to send messages.
4242
}
@@ -46,9 +46,8 @@ abstract contract BaseVerifier is ICrossChainVerifierV1, ITypeAndVersion {
4646
uint64 remoteChainSelector; // │ Remote chain selector.
4747
bool allowlistEnabled; // │ True if the allowlist is enabled.
4848
uint16 feeUSDCents; // ────────╯ The fee in US dollar cents for messages to this remote chain.
49-
uint32 gasForVerification; // ────╮ The gas to reserve for verification of messages on the remote chain.
50-
uint16 payloadSizeBytes; // │ The size of the verification payload on the remote chain.
51-
bytes4 allowedFinalityConfig; // ─╯ The finality configuration for the local chain for messages to the remote chain.
49+
uint32 gasForVerification; // ─╮ The gas to reserve for verification of messages on the remote chain.
50+
uint16 payloadSizeBytes; // ───╯ The size of the verification payload on the remote chain.
5251
}
5352

5453
/// @dev Struct to hold the allowlist configuration args per dest chain.
@@ -69,6 +68,10 @@ abstract contract BaseVerifier is ICrossChainVerifierV1, ITypeAndVersion {
6968
/// implement a way to update this value if needed.
7069
string[] internal s_storageLocations;
7170

71+
/// @dev Allowed finality config for fast finality transfers (see `FinalityCodec`).
72+
/// FinalityCodec.WAIT_FOR_FINALITY_FLAG means wait for finality.
73+
bytes4 internal s_allowedFinalityConfig;
74+
7275
constructor(
7376
string[] memory storageLocations,
7477
address rmnAddress
@@ -110,6 +113,25 @@ abstract contract BaseVerifier is ICrossChainVerifierV1, ITypeAndVersion {
110113
return s_storageLocations;
111114
}
112115

116+
/// @notice Gets the finality config as defined in the FinalityCodec library. This value does NOT 1:1 translate to
117+
/// a block depth. The finality config contains special flags and should only be encoded/decoded using the
118+
/// FinalityCodec library. Checks must happen by calling `FinalityCodec._ensureRequestedFinalityAllowed`.
119+
function getAllowedFinalityConfig() public view virtual returns (bytes4 allowedFinality) {
120+
return s_allowedFinalityConfig;
121+
}
122+
123+
/// @notice Sets the finality config according to the FinalityCodec library encoding.
124+
/// @param allowedFinality The finality settings allowed in this verifier, according to the FinalityCodec encoding.
125+
function _setAllowedFinalityConfig(
126+
bytes4 allowedFinality
127+
) internal virtual {
128+
// Any bytes4 value is accepted as allowedFinality; the FinalityCodec semantics are enforced when requests are
129+
// checked against this value via FinalityCodec._ensureRequestedFinalityAllowed.
130+
s_allowedFinalityConfig = allowedFinality;
131+
132+
emit FinalityConfigSet(allowedFinality);
133+
}
134+
113135
/// @notice get ChainConfig configured for the remoteChainSelector.
114136
/// @param remoteChainSelector The remote chain selector.
115137
/// @return remoteChainConfig The struct containing the remote chain settings.
@@ -130,8 +152,7 @@ abstract contract BaseVerifier is ICrossChainVerifierV1, ITypeAndVersion {
130152
allowlistEnabled: config.allowlistEnabled,
131153
feeUSDCents: config.feeUSDCents,
132154
gasForVerification: config.gasForVerification,
133-
payloadSizeBytes: config.payloadSizeBytes,
134-
allowedFinalityConfig: config.allowedFinalityConfig
155+
payloadSizeBytes: config.payloadSizeBytes
135156
}),
136157
config.allowedSendersList.values()
137158
);
@@ -168,7 +189,6 @@ abstract contract BaseVerifier is ICrossChainVerifierV1, ITypeAndVersion {
168189
remoteChainConfig.gasForVerification = remoteChainConfigArg.gasForVerification;
169190
// The payload could be zero bytes if no offchain data is required.
170191
remoteChainConfig.payloadSizeBytes = remoteChainConfigArg.payloadSizeBytes;
171-
remoteChainConfig.allowedFinalityConfig = remoteChainConfigArg.allowedFinalityConfig;
172192

173193
emit RemoteChainConfigSet(
174194
remoteChainSelector, address(remoteChainConfigArg.router), remoteChainConfig.allowlistEnabled
@@ -265,7 +285,7 @@ abstract contract BaseVerifier is ICrossChainVerifierV1, ITypeAndVersion {
265285
if (config.router == IRouter(address(0))) {
266286
revert RemoteChainNotSupported(destChainSelector);
267287
}
268-
FinalityCodec._ensureRequestedFinalityAllowed(requestedFinality, config.allowedFinalityConfig);
288+
FinalityCodec._ensureRequestedFinalityAllowed(requestedFinality, getAllowedFinalityConfig());
269289

270290
return (config.feeUSDCents, config.gasForVerification, config.payloadSizeBytes);
271291
}

chains/evm/contracts/interfaces/IPoolV2.sol

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ import {IERC165} from "@openzeppelin/contracts@5.3.0/utils/introspection/IERC165
99
/// Each pool type handles a different child token model e.g. lock/release, mint/burn.
1010
interface IPoolV2 is IERC165 {
1111
struct TokenTransferFeeConfig {
12-
uint32 destGasOverhead; // ───────────────────────╮ Gas charged to execute the token transfer on the destination chain.
13-
uint32 destBytesOverhead; // │ Data availability bytes.
14-
uint32 finalityFeeUSDCents; // │ Fee to charge for token transfer with default (wait-for-finality) finality, multiples of 0.01 USD.
15-
uint32 fastFinalityFeeUSDCents; // │ Fee to charge for token transfer with fast finality (FTF), multiples of 0.01 USD.
16-
// │ The following two fee is deducted from the transferred asset, not added on top.
17-
uint16 finalityTransferFeeBps; //│ Fee in basis points for default finality transfers [0-10_000].
18-
uint16 fastFinalityTransferFeeBps; // │ Fee in basis points for custom finality transfers [0-10_000].
19-
bool isEnabled; // ───────────────────────────────╯ Whether this config is enabled.
12+
uint32 destGasOverhead; // ──────────╮ Gas charged to execute the token transfer on the destination chain.
13+
uint32 destBytesOverhead; // │ Data availability bytes.
14+
uint32 finalityFeeUSDCents; // │ Fee to charge for token transfer with default (wait-for-finality) finality, multiples of 0.01 USD.
15+
uint32 fastFinalityFeeUSDCents; // │ Fee to charge for token transfer with fast finality (FTF), multiples of 0.01 USD.
16+
// │ The following two fee is deducted from the transferred asset, not added on top.
17+
uint16 finalityTransferFeeBps; // │ Fee in basis points for default finality transfers [0-10_000].
18+
uint16 fastFinalityTransferFeeBps; //│ Fee in basis points for custom finality transfers [0-10_000].
19+
bool isEnabled; // ──────────────────╯ Whether this config is enabled.
2020
}
2121

2222
enum MessageDirection {

chains/evm/contracts/pools/TokenPool.sol

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,6 @@ abstract contract TokenPool is IPoolV1V2, Ownable2StepMsgSender {
465465
/// @param releaseOrMintIn The input to validate.
466466
/// @param localAmount The local amount to be released or minted.
467467
/// @param requestedFinalityConfig The requested finality encoding (see `FinalityCodec`).
468-
/// FinalityCodec.WAIT_FOR_FINALITY_FLAG means wait for finality.
469468
/// @dev This function should always be called before executing a release or mint. Not doing so would allow
470469
/// for various exploits.
471470
function _validateReleaseOrMint(
@@ -484,10 +483,6 @@ abstract contract TokenPool is IPoolV1V2, Ownable2StepMsgSender {
484483
revert InvalidSourcePoolAddress(releaseOrMintIn.sourcePoolAddress);
485484
}
486485
if (requestedFinalityConfig != FinalityCodec.WAIT_FOR_FINALITY_FLAG) {
487-
// Validate that the finality carried in the inbound message is permitted by this pool's config. This mirrors
488-
// the outbound check in _validateLockOrBurn and ensures the FTF inbound rate-limit bucket is only consumed for
489-
// modes the pool has explicitly enabled, even if a future OffRamp skips this check.
490-
FinalityCodec._ensureRequestedFinalityAllowed(requestedFinalityConfig, s_allowedFinalityConfig);
491486
_consumeFastFinalityInboundRateLimit(releaseOrMintIn.localToken, releaseOrMintIn.remoteChainSelector, localAmount);
492487
} else {
493488
_consumeInboundRateLimit(releaseOrMintIn.localToken, releaseOrMintIn.remoteChainSelector, localAmount);

chains/evm/contracts/test/ccvs/CCTPVerifier/CCTPVerifier.applyDestChainConfigUpdates.t.sol

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ pragma solidity ^0.8.24;
44
import {IRouter} from "../../../interfaces/IRouter.sol";
55

66
import {BaseVerifier} from "../../../ccvs/components/BaseVerifier.sol";
7-
import {FinalityCodec} from "../../../libraries/FinalityCodec.sol";
87
import {CCTPVerifierSetup} from "./CCTPVerifierSetup.t.sol";
98
import {Ownable2Step} from "@chainlink/contracts/src/v0.8/shared/access/Ownable2Step.sol";
109

@@ -20,8 +19,7 @@ contract CCTPVerifier_applyRemoteChainConfigUpdates is CCTPVerifierSetup {
2019
allowlistEnabled: true,
2120
feeUSDCents: DEFAULT_CCV_FEE_USD_CENTS,
2221
gasForVerification: DEFAULT_CCV_GAS_LIMIT,
23-
payloadSizeBytes: DEFAULT_CCV_PAYLOAD_SIZE,
24-
allowedFinalityConfig: FinalityCodec.WAIT_FOR_FINALITY_FLAG
22+
payloadSizeBytes: DEFAULT_CCV_PAYLOAD_SIZE
2523
});
2624

2725
vm.expectEmit();
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.24;
3+
4+
import {BaseVerifier} from "../../../ccvs/components/BaseVerifier.sol";
5+
import {FinalityCodec} from "../../../libraries/FinalityCodec.sol";
6+
import {CCTPVerifierSetup} from "./CCTPVerifierSetup.t.sol";
7+
import {Ownable2Step} from "@chainlink/contracts/src/v0.8/shared/access/Ownable2Step.sol";
8+
9+
contract CCTPVerifier_setAllowedFinalityConfig is CCTPVerifierSetup {
10+
function test_setAllowedFinalityConfig() public {
11+
bytes4 newFinality = FinalityCodec._encodeBlockDepth(42);
12+
13+
vm.expectEmit();
14+
emit BaseVerifier.FinalityConfigSet(newFinality);
15+
16+
s_cctpVerifier.setAllowedFinalityConfig(newFinality);
17+
assertEq(s_cctpVerifier.getAllowedFinalityConfig(), newFinality);
18+
}
19+
20+
function test_setAllowedFinalityConfig_RevertWhen_OnlyCallableByOwner() public {
21+
vm.startPrank(STRANGER);
22+
23+
vm.expectRevert(Ownable2Step.OnlyCallableByOwner.selector);
24+
s_cctpVerifier.setAllowedFinalityConfig(FinalityCodec._encodeBlockDepth(1));
25+
}
26+
}

chains/evm/contracts/test/ccvs/CCTPVerifier/CCTPVerifierSetup.t.sol

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,7 @@ contract CCTPVerifierSetup is BaseVerifierSetup {
8585
allowlistEnabled: false,
8686
feeUSDCents: DEFAULT_CCV_FEE_USD_CENTS,
8787
gasForVerification: DEFAULT_CCV_GAS_LIMIT,
88-
payloadSizeBytes: DEFAULT_CCV_PAYLOAD_SIZE,
89-
allowedFinalityConfig: FinalityCodec.WAIT_FOR_FINALITY_FLAG
88+
payloadSizeBytes: DEFAULT_CCV_PAYLOAD_SIZE
9089
});
9190
s_cctpVerifier.applyRemoteChainConfigUpdates(remoteChainConfigArgs);
9291

0 commit comments

Comments
 (0)