Skip to content

Commit cec55b2

Browse files
committed
feat: added EnsoCCIPReceiver tests
1 parent 8068820 commit cec55b2

File tree

15 files changed

+857
-82
lines changed

15 files changed

+857
-82
lines changed

src/bridge/EnsoCCIPReceiver.sol

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pragma solidity ^0.8.24;
33

44
import { IEnsoCCIPReceiver } from "../interfaces/IEnsoCCIPReceiver.sol";
55
import { IEnsoRouter, Token, TokenType } from "../interfaces/IEnsoRouter.sol";
6+
import { ITypeAndVersion } from "../interfaces/ITypeAndVersion.sol";
67
import { CCIPMessageDecoder } from "../libraries/CCIPMessageDecoder.sol";
78
import { CCIPReceiver, Client } from "chainlink-ccip/applications/CCIPReceiver.sol";
89
import { Ownable, Ownable2Step } from "openzeppelin-contracts/access/Ownable2Step.sol";
@@ -23,10 +24,10 @@ import { Pausable } from "openzeppelin-contracts/utils/Pausable.sol";
2324
/// - For malformed messages (no/too many tokens, zero amount, bad payload, zero address receiver), quarantines
2425
/// funds in this contract.
2526
/// - Executes Shortcuts using a self-call (`try this.execute(...)`) to catch and handle reverts.
26-
contract EnsoCCIPReceiver is IEnsoCCIPReceiver, CCIPReceiver, Ownable2Step, Pausable {
27+
contract EnsoCCIPReceiver is IEnsoCCIPReceiver, CCIPReceiver, Ownable2Step, Pausable, ITypeAndVersion {
2728
using SafeERC20 for IERC20;
2829

29-
uint256 private constant VERSION = 1;
30+
string public constant override typeAndVersion = "EnsoCCIPReceiver 1.0.0";
3031

3132
/// @dev Immutable Enso Router used to dispatch tokens + call Shortcuts.
3233
/// forge-lint: disable-next-item(screaming-snake-case-immutable)
@@ -133,11 +134,6 @@ contract EnsoCCIPReceiver is IEnsoCCIPReceiver, CCIPReceiver, Ownable2Step, Paus
133134
return address(i_ensoRouter);
134135
}
135136

136-
/// @inheritdoc IEnsoCCIPReceiver
137-
function version() external pure returns (uint256) {
138-
return VERSION;
139-
}
140-
141137
/// @inheritdoc IEnsoCCIPReceiver
142138
function wasMessageExecuted(bytes32 _messageId) external view returns (bool) {
143139
return s_executedMessage[_messageId];

src/interfaces/IEnsoCCIPReceiver.sol

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ interface IEnsoCCIPReceiver {
4747
/// @dev errorData encodings:
4848
/// - ALREADY_EXECUTED: (bytes32 messageId)
4949
/// - Others: empty bytes unless specified by the implementation.
50-
event MessageValidationFailed(bytes32 indexed messageId, ErrorCode errorCode, bytes errorData);
50+
event MessageValidationFailed(bytes32 indexed messageId, ErrorCode indexed errorCode, bytes errorData);
5151

5252
/// @notice Funds were quarantined in the receiver instead of delivered to the payload receiver.
5353
/// @param messageId The CCIP message id.
@@ -56,7 +56,7 @@ interface IEnsoCCIPReceiver {
5656
/// @param amount Token amount retained.
5757
/// @param receiver Original payload receiver (informational; may be zero if not decoded).
5858
event MessageQuarantined(
59-
bytes32 indexed messageId, ErrorCode code, address token, uint256 amount, address receiver
59+
bytes32 indexed messageId, ErrorCode indexed code, address token, uint256 amount, address receiver
6060
);
6161

6262
/// @notice Emitted when Enso Shortcuts execution succeeds for a CCIP message.
@@ -69,7 +69,7 @@ interface IEnsoCCIPReceiver {
6969
event ShortcutExecutionFailed(bytes32 indexed messageId, bytes err);
7070

7171
/// @notice Emitted when the owner recovers tokens from the receiver.
72-
event TokensRecovered(address token, address to, uint256 amount);
72+
event TokensRecovered(address indexed token, address indexed to, uint256 amount);
7373

7474
// -------------------------------------------------------------------------
7575
// Errors
@@ -116,10 +116,6 @@ interface IEnsoCCIPReceiver {
116116
/// @return router Address of the Enso Router.
117117
function getEnsoRouter() external view returns (address router);
118118

119-
/// @notice Returns a human-readable version/format indicator for off-chain tooling and tests.
120-
/// @return version The version number of this receiver implementation.
121-
function version() external view returns (uint256 version);
122-
123119
/// @notice Returns whether a CCIP message was already handled (executed/refunded/quarantined).
124120
/// @param messageId CCIP message identifier.
125121
/// @return executed True if the messageId is marked as executed/handled.

src/interfaces/ITypeAndVersion.sol

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// SPDX-License-Identifier: GPL-3.0-only
2+
pragma solidity ^0.8.0;
3+
4+
/// @title ITypeAndVersion
5+
/// @author Enso
6+
/// @notice Provides a human-readable identifier for the contract type and its version.
7+
interface ITypeAndVersion {
8+
/// @return A string containing the contract type and semantic version.
9+
function typeAndVersion() external pure returns (string memory);
10+
}

test/mocks/MockEnsoRouter.sol

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ contract MockEnsoRouter {
3737
}
3838
}
3939
if (isNativeAsset) {
40-
shortcuts.call{ value: msg.value }("");
40+
(bool success, bytes memory result) = shortcuts.call{ value: msg.value }("");
41+
(success);
42+
(result);
4143
}
4244
}
4345

test/shortcuts/ShortcutsEthereum.sol

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,9 @@ library ShortcutsEthereum {
144144

145145
shortcut.txGas = 92_661;
146146
shortcut.txData = abi.encodePacked(
147-
hex"95352c9fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a51b21602de47c41deb22fa12edf3f9188303132333435363738394142434445460000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000042e1a7d4d0100ffffffffffffc02aaa39b223fe8d0a0e5c4f27ead9083c756cc219198595a30081ffffffffff",
147+
hex"95352c9fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a523e16585efc24d639f861691ad38481130313233343536373839414243444546000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000005a9059cbb010001ffffffffffc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22e1a7d4d0102ffffffffffffc02aaa39b223fe8d0a0e5c4f27ead9083c756cc219198595a30283ffffffffff",
148148
receiver,
149-
hex"6e7a43a3010002ffffffff027e7d64d987cab6eed08a191c4c2459daf2f8ed0b241c59120102ffffffffffff7e7d64d987cab6eed08a191c4c2459daf2f8ed0b0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000dcef33a6f838000"
149+
hex"6e7a43a3010204ffffffff047e7d64d987cab6eed08a191c4c2459daf2f8ed0b241c59120104ffffffffffff7e7d64d987cab6eed08a191c4c2459daf2f8ed0b000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000200000000000000000000000006aa68c46ed86161eb318b1396f7b79e386e886760000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000dbd2fc137a30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001"
150150
);
151151
shortcut.referralCode = "0123456789ABCDEF";
152152
}
@@ -158,7 +158,8 @@ library ShortcutsEthereum {
158158
function getShortcut2(
159159
address weth,
160160
address ensoShortcutsHelpers,
161-
address receiver
161+
address receiver,
162+
address feeReceiver
162163
)
163164
public
164165
pure
@@ -182,19 +183,23 @@ library ShortcutsEthereum {
182183
shortcut.tokensOut = tokensOut;
183184

184185
shortcut.fee = 0.01 ether;
185-
shortcut.feeReceiver = 0x6AA68C46eD86161eB318b1396F7b79E386e88676;
186+
shortcut.feeReceiver = feeReceiver;
186187

187188
shortcut.txGas = 92_661;
188189
shortcut.txData = abi.encodePacked(
189-
hex"95352c9fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a51b21602de47c41deb22fa12edf3f9188303132333435363738394142434445460000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000042e1a7d4d0100ffffffffffff",
190+
hex"95352c9fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a523e16585efc24d639f861691ad38481130313233343536373839414243444546000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000005a9059cbb010001ffffffffff",
191+
weth,
192+
hex"2e1a7d4d0102ffffffffffff",
190193
weth,
191-
hex"19198595a30081ffffffffff",
194+
hex"19198595a30283ffffffffff",
192195
receiver,
193-
hex"6e7a43a3010002ffffffff02",
196+
hex"6e7a43a3010204ffffffff04",
194197
ensoShortcutsHelpers,
195-
hex"241c59120102ffffffffffff",
198+
hex"241c59120104ffffffffffff",
196199
ensoShortcutsHelpers,
197-
hex"0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000dcef33a6f838000"
200+
hex"000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000",
201+
feeReceiver,
202+
hex"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000dbd2fc137a30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001"
198203
);
199204
shortcut.referralCode = "0123456789ABCDEF";
200205
}

test/unit/concrete/bridge/ensoCCIPReceiver/EnsoCCIPReceiver.t.sol

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
// SPDX-License-Identifier: GPL-3.0-only
22
pragma solidity ^0.8.28;
33

4+
import { EnsoShortcuts } from "../../../../../src/EnsoShortcuts.sol";
45
import { EnsoCCIPReceiver } from "../../../../../src/bridge/EnsoCCIPReceiver.sol";
56
import { EnsoShortcutsHelpers } from "../../../../../src/helpers/EnsoShortcutsHelpers.sol";
67
import { EnsoRouter } from "../../../../../src/router/EnsoRouter.sol";
8+
import { MockERC20 } from "../../../../mocks/MockERC20.sol";
79
import { WETH9 } from "../../../../mocks/WETH9.sol";
810
import { MockCCIPRouter } from "chainlink-ccip/test/mocks/MockRouter.sol";
911
import { Test } from "forge-std-1.9.7/Test.sol";
@@ -14,10 +16,13 @@ abstract contract EnsoCCIPReceiver_Unit_Concrete_Test is Test {
1416
address payable internal s_account1;
1517
address payable internal s_account2;
1618
EnsoRouter internal s_ensoRouter;
19+
EnsoShortcuts internal s_ensoShortcuts;
1720
EnsoShortcutsHelpers internal s_ensoShortcutsHelpers;
1821
MockCCIPRouter internal s_ccipRouter;
1922
EnsoCCIPReceiver internal s_ensoCcipReceiver;
2023
WETH9 internal s_weth;
24+
MockERC20 internal s_tokenA;
25+
MockERC20 internal s_tokenB;
2126

2227
function setUp() public virtual {
2328
s_deployer = payable(vm.addr(1));
@@ -40,6 +45,9 @@ abstract contract EnsoCCIPReceiver_Unit_Concrete_Test is Test {
4045
s_ensoRouter = new EnsoRouter();
4146
vm.label(address(s_ensoRouter), "EnsoRouter");
4247

48+
s_ensoShortcuts = EnsoShortcuts(payable(s_ensoRouter.shortcuts()));
49+
vm.label(address(s_ensoShortcuts), "EnsoShortcuts");
50+
4351
s_ensoShortcutsHelpers = new EnsoShortcutsHelpers();
4452
vm.label(address(s_ensoShortcutsHelpers), "EnsoShortcutsHelpers");
4553

@@ -51,6 +59,15 @@ abstract contract EnsoCCIPReceiver_Unit_Concrete_Test is Test {
5159

5260
s_weth = new WETH9();
5361
vm.label(address(s_weth), "WETH9");
62+
63+
s_tokenA = new MockERC20("Token A", "TKNA");
64+
vm.label(address(s_tokenA), "TKNA");
65+
s_tokenA.mint(s_deployer, 1000 ether);
66+
67+
s_tokenB = new MockERC20("Token B", "TKNB");
68+
vm.label(address(s_tokenB), "TKNB");
69+
s_tokenB.mint(s_deployer, 1000 ether);
70+
5471
vm.stopPrank();
5572
}
5673
}

0 commit comments

Comments
 (0)