Skip to content

Commit 7b5d701

Browse files
committed
fix tests
1 parent d9638c6 commit 7b5d701

6 files changed

Lines changed: 1210 additions & 133 deletions

File tree

base/src/Bridge.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// SPDX-License-Identifier: MIT
22
pragma solidity 0.8.28;
33

4+
import {Initializable} from "solady/utils/Initializable.sol";
45
import {LibClone} from "solady/utils/LibClone.sol";
56
import {ReentrancyGuardTransient} from "solady/utils/ReentrancyGuardTransient.sol";
67
import {UpgradeableBeacon} from "solady/utils/UpgradeableBeacon.sol";
7-
import {Initializable} from "solady/utils/Initializable.sol";
88

99
import {Call} from "./libraries/CallLib.sol";
1010
import {MessageStorageLib} from "./libraries/MessageStorageLib.sol";

base/src/CrossChainERC20Factory.sol

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ contract CrossChainERC20Factory {
4444
///
4545
/// @dev Uses CREATE2 with a salt derived from token parameters to ensure deterministic addresses.
4646
/// The same parameters will always result in the same deployment address.
47+
/// Deploys the proxy and initializes it with the provided parameters.
4748
/// Emits CrossChainERC20Created event upon successful deployment.
4849
///
4950
/// @param remoteToken The 32-byte identifier of the corresponding token on the remote chain
@@ -59,6 +60,9 @@ contract CrossChainERC20Factory {
5960
bytes32 salt = keccak256(abi.encode(remoteToken, name, symbol, decimals));
6061
address localToken = LibClone.deployDeterministicERC1967BeaconProxy({beacon: BEACON, salt: salt});
6162

63+
// Initialize the deployed proxy with the token parameters
64+
CrossChainERC20(localToken).initialize(remoteToken, name, symbol, decimals);
65+
6266
emit CrossChainERC20Created({localToken: localToken, remoteToken: remoteToken, deployer: msg.sender});
6367

6468
return localToken;

base/test/Bridge.t.sol

Lines changed: 62 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,21 @@
22
pragma solidity 0.8.28;
33

44
import {Test} from "forge-std/Test.sol";
5-
import {console} from "forge-std/console.sol";
65

7-
import {Bridge} from "../src/Bridge.sol";
6+
import {ERC1967Factory} from "solady/utils/ERC1967Factory.sol";
7+
import {LibClone} from "solady/utils/LibClone.sol";
8+
import {UpgradeableBeacon} from "solady/utils/UpgradeableBeacon.sol";
89

10+
import {Bridge} from "../src/Bridge.sol";
911
import {CrossChainERC20} from "../src/CrossChainERC20.sol";
12+
import {CrossChainERC20Factory} from "../src/CrossChainERC20Factory.sol";
1013
import {Twin} from "../src/Twin.sol";
11-
1214
import {Call, CallType} from "../src/libraries/CallLib.sol";
1315
import {MessageStorageLib} from "../src/libraries/MessageStorageLib.sol";
1416
import {SVMBridgeLib} from "../src/libraries/SVMBridgeLib.sol";
1517
import {Ix, Pubkey} from "../src/libraries/SVMLib.sol";
1618
import {SolanaTokenType, TokenLib, Transfer} from "../src/libraries/TokenLib.sol";
1719

18-
import {LibClone} from "solady/utils/LibClone.sol";
19-
import {UpgradeableBeacon} from "solady/utils/UpgradeableBeacon.sol";
20-
2120
contract BridgeTest is Test {
2221
Bridge public bridge;
2322
address public trustedRelayer;
@@ -46,13 +45,29 @@ contract BridgeTest is Test {
4645
user = makeAddr("user");
4746
unauthorizedUser = makeAddr("unauthorizedUser");
4847

49-
// Deploy bridge
50-
bridge = new Bridge(REMOTE_BRIDGE, trustedRelayer, initialOwner);
48+
ERC1967Factory f = new ERC1967Factory();
49+
50+
Bridge bridgeImpl = new Bridge({remoteBridge: REMOTE_BRIDGE, trustedRelayer: trustedRelayer});
51+
bridge = Bridge(
52+
f.deployAndCall({
53+
implementation: address(bridgeImpl),
54+
admin: address(this),
55+
data: abi.encodeCall(Bridge.initialize, (initialOwner))
56+
})
57+
);
58+
59+
address tokenImpl = address(new CrossChainERC20(address(bridge)));
60+
address erc20Beacon =
61+
address(new UpgradeableBeacon({initialOwner: address(this), initialImplementation: tokenImpl}));
62+
CrossChainERC20Factory xChainERC20FactoryImpl = new CrossChainERC20Factory(erc20Beacon);
63+
CrossChainERC20Factory xChainERC20Factory =
64+
CrossChainERC20Factory(f.deploy({implementation: address(xChainERC20FactoryImpl), admin: address(this)}));
65+
crossChainToken =
66+
CrossChainERC20(xChainERC20Factory.deploy(Pubkey.unwrap(TEST_REMOTE_TOKEN), "Mock Token", "MOCK", 18));
5167

5268
// Deploy mock contracts
5369
mockToken = new MockERC20("Mock Token", "MOCK", 18);
5470
mockTarget = new MockTarget();
55-
crossChainToken = new CrossChainERC20(address(bridge));
5671

5772
// Set up balances
5873
vm.deal(address(bridge), 100 ether);
@@ -67,24 +82,23 @@ contract BridgeTest is Test {
6782
//////////////////////////////////////////////////////////////
6883

6984
function test_constructor_setsCorrectValues() public {
70-
Bridge testBridge = new Bridge(TEST_SENDER, trustedRelayer, initialOwner);
85+
Bridge testBridge = new Bridge(TEST_SENDER, trustedRelayer);
7186

7287
assertEq(Pubkey.unwrap(testBridge.REMOTE_BRIDGE()), Pubkey.unwrap(TEST_SENDER));
7388
assertEq(testBridge.TRUSTED_RELAYER(), trustedRelayer);
74-
assertTrue(testBridge.TWIN_BEACON() != address(0));
7589
assertEq(testBridge.nextIncomingNonce(), 0);
7690
}
7791

7892
function test_constructor_deploysTwinBeacon() public view {
79-
address twinBeacon = bridge.TWIN_BEACON();
93+
address twinBeacon = bridge.twinBeacon();
8094
assertTrue(twinBeacon != address(0));
8195

8296
UpgradeableBeacon beacon = UpgradeableBeacon(twinBeacon);
8397
assertTrue(beacon.implementation() != address(0));
8498
}
8599

86100
function test_constructor_withZeroAddresses() public {
87-
Bridge testBridge = new Bridge(Pubkey.wrap(0), address(0), address(0));
101+
Bridge testBridge = new Bridge(Pubkey.wrap(0), address(0));
88102

89103
assertEq(Pubkey.unwrap(testBridge.REMOTE_BRIDGE()), 0);
90104
assertEq(testBridge.TRUSTED_RELAYER(), address(0));
@@ -298,12 +312,12 @@ contract BridgeTest is Test {
298312
}
299313

300314
function test_relayMessages_revertsOnAlreadySuccessfulMessage() public {
301-
// First, create a message that will fail with trusted relayer due to low gas
315+
// First, create a message that will succeed with trusted relayer
302316
Bridge.IncomingMessage[] memory messages = new Bridge.IncomingMessage[](1);
303317
messages[0] = Bridge.IncomingMessage({
304318
nonce: 0,
305319
sender: TEST_SENDER,
306-
gasLimit: 1000000, // Low gas to cause failure
320+
gasLimit: 1000000,
307321
ty: Bridge.MessageType.Call,
308322
data: abi.encode(
309323
Call({
@@ -317,11 +331,11 @@ contract BridgeTest is Test {
317331

318332
bytes memory ismData = hex"";
319333

320-
// First attempt by trusted relayer should fail due to low gas
334+
// First attempt by trusted relayer should succeed
321335
vm.prank(trustedRelayer);
322336
bridge.relayMessages(messages, ismData);
323337

324-
// Now try the same message again with non-trusted relayer - should revert with
338+
// Now try the exact same message again with non-trusted relayer - should revert with
325339
// MessageAlreadySuccessfullyRelayed
326340
vm.expectRevert(Bridge.MessageAlreadySuccessfullyRelayed.selector);
327341
vm.prank(unauthorizedUser);
@@ -420,15 +434,9 @@ contract BridgeTest is Test {
420434
}
421435

422436
function test_relayMessage_transferType() public {
423-
// Deploy a test cross-chain token that can be initialized
424-
TestCrossChainERC20 testToken = new TestCrossChainERC20(address(bridge));
425-
426-
// Initialize it as the bridge
427-
vm.prank(address(bridge));
428-
testToken.initialize(Pubkey.unwrap(TEST_REMOTE_TOKEN), "Test Token", "TEST", 18);
429-
437+
// Use the crossChainToken already deployed in setUp
430438
Transfer memory transfer = Transfer({
431-
localToken: address(testToken),
439+
localToken: address(crossChainToken),
432440
remoteToken: TEST_REMOTE_TOKEN,
433441
to: bytes32(bytes20(user)), // Left-align the address in bytes32
434442
remoteAmount: 100e6
@@ -448,19 +456,13 @@ contract BridgeTest is Test {
448456
vm.prank(trustedRelayer);
449457
bridge.relayMessages(messages, ismData);
450458

451-
assertEq(testToken.balanceOf(user), 100e6);
459+
assertEq(crossChainToken.balanceOf(user), 100e6);
452460
}
453461

454462
function test_relayMessage_transferAndCallType() public {
455-
// Deploy a test cross-chain token for this test
456-
TestCrossChainERC20 testToken2 = new TestCrossChainERC20(address(bridge));
457-
458-
// Initialize it as the bridge
459-
vm.prank(address(bridge));
460-
testToken2.initialize(Pubkey.unwrap(TEST_REMOTE_TOKEN), "Test Token 2", "TEST2", 18);
461-
463+
// Use the crossChainToken already deployed in setUp
462464
Transfer memory transfer = Transfer({
463-
localToken: address(testToken2),
465+
localToken: address(crossChainToken),
464466
remoteToken: TEST_REMOTE_TOKEN,
465467
to: bytes32(bytes20(user)), // Left-align the address in bytes32
466468
remoteAmount: 100e6
@@ -487,7 +489,7 @@ contract BridgeTest is Test {
487489
vm.prank(trustedRelayer);
488490
bridge.relayMessages(messages, ismData);
489491

490-
assertEq(testToken2.balanceOf(user), 100e6);
492+
assertEq(crossChainToken.balanceOf(user), 100e6);
491493
assertEq(mockTarget.value(), 456);
492494
}
493495

@@ -532,7 +534,7 @@ contract BridgeTest is Test {
532534

533535
vm.expectRevert(Bridge.SenderIsNotEntrypoint.selector);
534536
vm.prank(user);
535-
bridge.__validateAndRelay(message, true, 0);
537+
bridge.__validateAndRelay(message, true);
536538
}
537539

538540
function test_relayMessage_revertsOnDirectCall() public {
@@ -718,11 +720,32 @@ contract BridgeTest is Test {
718720
}
719721

720722
function testFuzz_relayMessage_withDifferentNonces(uint64 nonce) public {
721-
vm.assume(nonce < 1000); // Limit to reasonable range to avoid overflow
723+
vm.assume(nonce < 100); // Limit to a smaller range to avoid excessive gas usage
722724

723-
// Set the next nonce to match
724-
_setNextNonce(nonce);
725+
// Increment the nonce naturally by sending messages
726+
for (uint64 i = 0; i < nonce; i++) {
727+
Bridge.IncomingMessage[] memory tempMessages = new Bridge.IncomingMessage[](1);
728+
tempMessages[0] = Bridge.IncomingMessage({
729+
nonce: i,
730+
sender: TEST_SENDER,
731+
gasLimit: 1000000,
732+
ty: Bridge.MessageType.Call,
733+
data: abi.encode(
734+
Call({
735+
ty: CallType.Call,
736+
to: address(mockTarget),
737+
value: 0,
738+
data: abi.encodeWithSelector(MockTarget.setValue.selector, i)
739+
})
740+
)
741+
});
725742

743+
bytes memory tempIsmData = hex"";
744+
vm.prank(trustedRelayer);
745+
bridge.relayMessages(tempMessages, tempIsmData);
746+
}
747+
748+
// Now send the actual test message
726749
Bridge.IncomingMessage[] memory messages = new Bridge.IncomingMessage[](1);
727750
messages[0] = Bridge.IncomingMessage({
728751
nonce: nonce,
@@ -770,11 +793,6 @@ contract BridgeTest is Test {
770793
vm.prank(trustedRelayer);
771794
bridge.relayMessages(messages, ismData);
772795
}
773-
774-
function _setNextNonce(uint64 nonce) internal {
775-
// Set the nextIncomingNonce storage slot (slot 3 in Bridge contract)
776-
vm.store(address(bridge), bytes32(uint256(3)), bytes32(uint256(nonce)));
777-
}
778796
}
779797

780798
//////////////////////////////////////////////////////////////
@@ -843,91 +861,3 @@ contract MockTarget {
843861
revert("This function always reverts");
844862
}
845863
}
846-
847-
contract TestCrossChainERC20 {
848-
address private _bridge;
849-
string private _name;
850-
string private _symbol;
851-
uint8 private _decimals;
852-
bytes32 private _remoteToken;
853-
854-
mapping(address => uint256) private _balances;
855-
mapping(address => mapping(address => uint256)) private _allowances;
856-
uint256 private _totalSupply;
857-
858-
modifier onlyBridge() {
859-
require(msg.sender == _bridge, "Not bridge");
860-
_;
861-
}
862-
863-
constructor(address bridge_) {
864-
_bridge = bridge_;
865-
}
866-
867-
function initialize(bytes32 remoteToken_, string memory name_, string memory symbol_, uint8 decimals_) external {
868-
_remoteToken = remoteToken_;
869-
_name = name_;
870-
_symbol = symbol_;
871-
_decimals = decimals_;
872-
}
873-
874-
function bridge() external view returns (address) {
875-
return _bridge;
876-
}
877-
878-
function remoteToken() external view returns (bytes32) {
879-
return _remoteToken;
880-
}
881-
882-
function name() external view returns (string memory) {
883-
return _name;
884-
}
885-
886-
function symbol() external view returns (string memory) {
887-
return _symbol;
888-
}
889-
890-
function decimals() external view returns (uint8) {
891-
return _decimals;
892-
}
893-
894-
function totalSupply() external view returns (uint256) {
895-
return _totalSupply;
896-
}
897-
898-
function balanceOf(address account) external view returns (uint256) {
899-
return _balances[account];
900-
}
901-
902-
function allowance(address owner, address spender) external view returns (uint256) {
903-
return _allowances[owner][spender];
904-
}
905-
906-
function mint(address to, uint256 amount) external onlyBridge {
907-
_balances[to] += amount;
908-
_totalSupply += amount;
909-
}
910-
911-
function burn(address from, uint256 amount) external onlyBridge {
912-
_balances[from] -= amount;
913-
_totalSupply -= amount;
914-
}
915-
916-
function transfer(address to, uint256 amount) external returns (bool) {
917-
_balances[msg.sender] -= amount;
918-
_balances[to] += amount;
919-
return true;
920-
}
921-
922-
function transferFrom(address from, address to, uint256 amount) external returns (bool) {
923-
_allowances[from][msg.sender] -= amount;
924-
_balances[from] -= amount;
925-
_balances[to] += amount;
926-
return true;
927-
}
928-
929-
function approve(address spender, uint256 amount) external returns (bool) {
930-
_allowances[msg.sender][spender] = amount;
931-
return true;
932-
}
933-
}

0 commit comments

Comments
 (0)