Skip to content

Commit cd6c08e

Browse files
committed
testing progress
1 parent a3a3c0c commit cd6c08e

8 files changed

Lines changed: 1075 additions & 305 deletions

File tree

base/deployments/base_sepolia.json

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
11
{
2-
"MessagePasser": "0x3B544741299B0454EC88a9249dF1493438229aBf",
3-
"CrossChainMessenger": "0x2c85Bb93B4c1F07E80a242FfB3Fa9c0e8b72BB00",
4-
"Bridge": "0xC7ae1af5aFd9ED2E65495BFdF4639FbDB3a2ab57",
5-
"CrossChainERC20Factory": "0x3Ccf5EEa32a4f908425ddD5F3Cc744603fDC98F9",
6-
"WrappedSOL": "0x96A91f8C455390e220A4Efb0e2F9aC36dC536fC8",
7-
"WrappedSPL": "0x184Dfb2276CeB179960acbB6210b5a27544D9700",
8-
"ERC20": "0x62C1332822983B8412A6Ffda0fd77cd7d5733Ee9",
9-
"ETH": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"
2+
"Bridge": "0x9f2a3468846C423DaEc5684a3500f19ACC80c211",
3+
"CrossChainERC20Factory": "0xa127Bc025e977fc55A7f8222091665E440786898"
104
}

base/script/Deploy.s.sol

Lines changed: 89 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,89 @@
1-
// // SPDX-License-Identifier: MIT
2-
// pragma solidity 0.8.28;
3-
4-
// import {Script} from "forge-std/Script.sol";
5-
// import {console} from "forge-std/console.sol";
6-
7-
// import {ERC1967Factory} from "solady/utils/ERC1967Factory.sol";
8-
// import {ERC1967FactoryConstants} from "solady/utils/ERC1967FactoryConstants.sol";
9-
10-
// import {CrossChainERC20Factory} from "../src/CrossChainERC20Factory.sol";
11-
// import {CrossChainMessenger} from "../src/CrossChainMessenger.sol";
12-
// import {MessagePasser} from "../src/MessagePasser.sol";
13-
// import {TokenBridge} from "../src/TokenBridge.sol";
14-
15-
// contract DeployScript is Script {
16-
// address public constant PROXY_ADMIN = 0x0fe884546476dDd290eC46318785046ef68a0BA9;
17-
18-
// bytes32 public constant ORACLE = 0x0000000000000000000000000e9a877906EBc3b7098DA2404412BF0Ed1A5EFb4;
19-
// bytes32 public constant REMOTE_MESSENGER = 0x7e273983f136714ba93a740a050279b541d6f25ebc6bbc6fc67616d0d5529cea;
20-
// bytes32 public constant OTHER_BRIDGE = 0x7a25452c36304317d6fe970091c383b0d45e9b0b06485d2561156f025c6936af;
21-
22-
// function setUp() public {
23-
// vm.label(PROXY_ADMIN, "PROXY_ADMIN");
24-
// vm.label(ERC1967FactoryConstants.ADDRESS, "ERC1967_FACTORY");
25-
// }
26-
27-
// function run() public {
28-
// Chain memory chain = getChain(block.chainid);
29-
// console.log("Deploying on chain: %s", chain.name);
30-
31-
// vm.startBroadcast();
32-
// address messagePasser = _deployMessagePasser();
33-
// address messenger = _deployMessenger(messagePasser);
34-
// address bridge = _deployBridge(messenger);
35-
// address factory = _deployFactory(bridge);
36-
// vm.stopBroadcast();
37-
38-
// console.log("Deployed MessagePasser at: %s", messagePasser);
39-
// console.log("Deployed CrossChainMessenger at: %s", messenger);
40-
// console.log("Deployed TokenBridge at: %s", bridge);
41-
// console.log("Deployed CrossChainERC20Factory at: %s", factory);
42-
43-
// string memory out = "{";
44-
// out = _record(out, "MessagePasser", messagePasser, false);
45-
// out = _record(out, "CrossChainMessenger", messenger, false);
46-
// out = _record(out, "TokenBridge", bridge, false);
47-
// out = _record(out, "CrossChainERC20Factory", factory, true);
48-
// out = string.concat(out, "}");
49-
50-
// vm.createDir("deployments", true);
51-
// vm.writeFile(string.concat("deployments/", chain.chainAlias, ".json"), out);
52-
// }
53-
54-
// function _deployMessagePasser() private returns (address) {
55-
// MessagePasser messagePasser = new MessagePasser();
56-
// return address(messagePasser);
57-
// }
58-
59-
// function _deployMessenger(address messagePasser) private returns (address) {
60-
// CrossChainMessenger messengerImpl = new CrossChainMessenger(messagePasser, REMOTE_MESSENGER);
61-
// CrossChainMessenger messengerProxy = CrossChainMessenger(
62-
// ERC1967Factory(ERC1967FactoryConstants.ADDRESS).deployAndCall({
63-
// implementation: address(messengerImpl),
64-
// admin: PROXY_ADMIN,
65-
// data: abi.encodeCall(CrossChainMessenger.initialize, (ORACLE))
66-
// })
67-
// );
68-
69-
// return address(messengerProxy);
70-
// }
71-
72-
// function _deployBridge(address messenger) private returns (address) {
73-
// TokenBridge bridgeImpl = new TokenBridge();
74-
// TokenBridge bridgeProxy = TokenBridge(
75-
// ERC1967Factory(ERC1967FactoryConstants.ADDRESS).deployAndCall({
76-
// implementation: address(bridgeImpl),
77-
// admin: PROXY_ADMIN,
78-
// data: abi.encodeCall(TokenBridge.initialize, (messenger, OTHER_BRIDGE))
79-
// })
80-
// );
81-
82-
// return address(bridgeProxy);
83-
// }
84-
85-
// function _deployFactory(address bridge) private returns (address) {
86-
// CrossChainERC20Factory xChainERC20FactoryImpl = new CrossChainERC20Factory();
87-
// CrossChainERC20Factory xChainERC20Factory = CrossChainERC20Factory(
88-
// ERC1967Factory(ERC1967FactoryConstants.ADDRESS).deployAndCall({
89-
// implementation: address(xChainERC20FactoryImpl),
90-
// admin: PROXY_ADMIN,
91-
// data: abi.encodeCall(CrossChainERC20Factory.initialize, (bridge))
92-
// })
93-
// );
94-
95-
// return address(xChainERC20Factory);
96-
// }
97-
98-
// function _record(string memory out, string memory key, address addr, bool isLast)
99-
// private
100-
// pure
101-
// returns (string memory)
102-
// {
103-
// return string.concat(out, "\"", key, "\": \"", vm.toString(addr), isLast ? "\"" : "\",");
104-
// }
105-
106-
// function _addressToBytes32(address value) private pure returns (bytes32) {
107-
// return bytes32(uint256(uint160(value)));
108-
// }
109-
// }
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.28;
3+
4+
import {Script} from "forge-std/Script.sol";
5+
import {console} from "forge-std/console.sol";
6+
import {UpgradeableBeacon} from "solady/utils/UpgradeableBeacon.sol";
7+
8+
import {ERC1967Factory} from "solady/utils/ERC1967Factory.sol";
9+
import {ERC1967FactoryConstants} from "solady/utils/ERC1967FactoryConstants.sol";
10+
11+
import {Bridge} from "../src/Bridge.sol";
12+
import {CrossChainERC20} from "../src/CrossChainERC20.sol";
13+
import {CrossChainERC20Factory} from "../src/CrossChainERC20Factory.sol";
14+
15+
import {Pubkey} from "../src/libraries/SVMLib.sol";
16+
17+
contract DeployScript is Script {
18+
address public constant PROXY_ADMIN = 0x0fe884546476dDd290eC46318785046ef68a0BA9;
19+
20+
// EF3xsxZGWWJX9T7vCPb7hEgyJQKEj1mgSNLMNvF8a7cj
21+
Pubkey public constant REMOTE_BRIDGE =
22+
Pubkey.wrap(0xc4c16980efe2a570c1a7599fd2ebb40ca7f85daf897482b9c85d4b8933a61608);
23+
address public constant ORACLE = 0x0e9a877906EBc3b7098DA2404412BF0Ed1A5EFb4;
24+
25+
function setUp() public {
26+
vm.label(PROXY_ADMIN, "PROXY_ADMIN");
27+
vm.label(ERC1967FactoryConstants.ADDRESS, "ERC1967_FACTORY");
28+
}
29+
30+
function run() public {
31+
Chain memory chain = getChain(block.chainid);
32+
console.log("Deploying on chain: %s", chain.name);
33+
34+
vm.startBroadcast();
35+
address bridge = _deployBridge();
36+
address factory = _deployFactory(bridge);
37+
vm.stopBroadcast();
38+
39+
console.log("Deployed Bridge at: %s", bridge);
40+
console.log("Deployed CrossChainERC20Factory at: %s", factory);
41+
42+
string memory out = "{";
43+
out = _record(out, "Bridge", bridge, false);
44+
out = _record(out, "CrossChainERC20Factory", factory, true);
45+
out = string.concat(out, "}");
46+
47+
vm.createDir("deployments", true);
48+
vm.writeFile(string.concat("deployments/", chain.chainAlias, ".json"), out);
49+
}
50+
51+
function _deployBridge() private returns (address) {
52+
Bridge bridgeImpl = new Bridge(REMOTE_BRIDGE, ORACLE, PROXY_ADMIN);
53+
Bridge bridgeProxy = Bridge(
54+
ERC1967Factory(ERC1967FactoryConstants.ADDRESS).deploy({
55+
implementation: address(bridgeImpl),
56+
admin: PROXY_ADMIN
57+
})
58+
);
59+
60+
return address(bridgeProxy);
61+
}
62+
63+
function _deployFactory(address bridge) private returns (address) {
64+
address erc20 = address(new CrossChainERC20(bridge));
65+
address erc20Beacon = address(new UpgradeableBeacon(PROXY_ADMIN, erc20));
66+
67+
CrossChainERC20Factory xChainERC20FactoryImpl = new CrossChainERC20Factory(erc20Beacon);
68+
CrossChainERC20Factory xChainERC20Factory = CrossChainERC20Factory(
69+
ERC1967Factory(ERC1967FactoryConstants.ADDRESS).deploy({
70+
implementation: address(xChainERC20FactoryImpl),
71+
admin: PROXY_ADMIN
72+
})
73+
);
74+
75+
return address(xChainERC20Factory);
76+
}
77+
78+
function _record(string memory out, string memory key, address addr, bool isLast)
79+
private
80+
pure
81+
returns (string memory)
82+
{
83+
return string.concat(out, "\"", key, "\": \"", vm.toString(addr), isLast ? "\"" : "\",");
84+
}
85+
86+
function _addressToBytes32(address value) private pure returns (bytes32) {
87+
return bytes32(uint256(uint160(value)));
88+
}
89+
}

base/src/Bridge.sol

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

44
import {LibClone} from "solady/utils/LibClone.sol";
55
import {ReentrancyGuardTransient} from "solady/utils/ReentrancyGuardTransient.sol";
6+
import {UpgradeableBeacon} from "solady/utils/UpgradeableBeacon.sol";
67

78
import {Call} from "./libraries/CallLib.sol";
89
import {MessageStorageLib} from "./libraries/MessageStorageLib.sol";
@@ -132,7 +133,7 @@ contract Bridge is ReentrancyGuardTransient {
132133
mapping(Pubkey owner => address twinAddress) public twins;
133134

134135
/// @notice The last message's nonce relayed by the trusted relayer.
135-
uint64 public lastIncomingNonce;
136+
uint64 public nextIncomingNonce;
136137

137138
//////////////////////////////////////////////////////////////
138139
/// Public Functions ///
@@ -142,11 +143,13 @@ contract Bridge is ReentrancyGuardTransient {
142143
///
143144
/// @param remoteBridge The pubkey of the remote bridge on Solana.
144145
/// @param trustedRelayer The address of the trusted relayer.
145-
/// @param twinBeacon The address of the Twin beacon.
146-
constructor(Pubkey remoteBridge, address trustedRelayer, address twinBeacon) {
146+
/// @param initialOwner The initial owner of the Twin beacon proxy.
147+
constructor(Pubkey remoteBridge, address trustedRelayer, address initialOwner) {
147148
REMOTE_BRIDGE = remoteBridge;
148149
TRUSTED_RELAYER = trustedRelayer;
149-
TWIN_BEACON = twinBeacon;
150+
151+
address twinImpl = address(new Twin());
152+
TWIN_BEACON = address(new UpgradeableBeacon(initialOwner, twinImpl));
150153
}
151154

152155
/// @notice Get the current root of the MMR.
@@ -186,7 +189,7 @@ contract Bridge is ReentrancyGuardTransient {
186189
///
187190
/// @param transfer The token transfer to execute.
188191
/// @param ixs The optional Solana instructions.
189-
function bridgeToken(Transfer calldata transfer, Ix[] memory ixs) external {
192+
function bridgeToken(Transfer calldata transfer, Ix[] memory ixs) external payable {
190193
SolanaTokenType transferType = TokenLib.initializeTransfer({transfer: transfer});
191194
MessageStorageLib.sendMessage({
192195
sender: msg.sender,
@@ -228,8 +231,8 @@ contract Bridge is ReentrancyGuardTransient {
228231
// Check that the relay is allowed.
229232
if (isTrustedRelayer) {
230233
// TODO:Should the nonce be cached and only SSTOREd once?
231-
require(message.nonce == lastIncomingNonce + 1, NonceNotIncremental());
232-
lastIncomingNonce = message.nonce;
234+
require(message.nonce == nextIncomingNonce, NonceNotIncremental());
235+
nextIncomingNonce = message.nonce + 1;
233236

234237
require(!failures[messageHash], MessageAlreadyFailedToRelay());
235238
} else {
@@ -239,7 +242,17 @@ contract Bridge is ReentrancyGuardTransient {
239242
// Cover the gas cost upfront.
240243
failures[messageHash] = true;
241244

242-
try this.__relayMessage{gas: gasleft() - _RELAY_MESSAGES_GAS_BUFFER}({message: message}) {
245+
// Use the message's specified gas limit for execution, ensuring it doesn't exceed available gas
246+
uint256 gasLeft = gasleft();
247+
uint256 gasForRelay = gasLeft > _RELAY_MESSAGES_GAS_BUFFER
248+
? (
249+
gasLeft - _RELAY_MESSAGES_GAS_BUFFER > message.gasLimit
250+
? message.gasLimit
251+
: gasLeft - _RELAY_MESSAGES_GAS_BUFFER
252+
)
253+
: 0;
254+
255+
try this.__relayMessage{gas: gasForRelay}({message: message}) {
243256
// Register the call as successful.
244257
delete failures[messageHash];
245258
successes[messageHash] = true;
@@ -263,7 +276,7 @@ contract Bridge is ReentrancyGuardTransient {
263276
function __relayMessage(IncomingMessage calldata message) external {
264277
_assertSenderIsEntrypoint();
265278

266-
// Special case where the message sneder is directly the Solana bridge.
279+
// Special case where the message sender is directly the Solana bridge.
267280
// For now this is only the case when a Wrapped Token is deployed on Solana and is being registered on Base.
268281
// When this happens the message is guaranteed to be a single operation that encode the parameters of the
269282
// `registerRemoteToken` function.
@@ -317,13 +330,6 @@ contract Bridge is ReentrancyGuardTransient {
317330
/// Private Functions ///
318331
//////////////////////////////////////////////////////////////
319332

320-
/// @notice Asserts that the Anchor instruction is safe.
321-
///
322-
/// @param ix The Anchor instruction to assert.
323-
function _assertSafeIx(Ix memory ix) private view {
324-
require(ix.programId != REMOTE_BRIDGE, UnsafeIxTarget());
325-
}
326-
327333
/// @notice Asserts that the caller is the entrypoint.
328334
function _assertSenderIsEntrypoint() private view {
329335
require(msg.sender == address(this), SenderIsNotEntrypoint());

base/src/CrossChainERC20.sol

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
pragma solidity 0.8.28;
33

44
import {ERC20} from "solady/tokens/ERC20.sol";
5+
import {Initializable} from "solady/utils/Initializable.sol";
56

67
/// @title CrossChainERC20
78
///
89
/// @notice A cross-chain ERC20 token implementation that can be minted and burned by an authorized bridge contract.
9-
contract CrossChainERC20 is ERC20 {
10+
contract CrossChainERC20 is ERC20, Initializable {
1011
//////////////////////////////////////////////////////////////
1112
/// Events ///
1213
//////////////////////////////////////////////////////////////
@@ -43,12 +44,6 @@ contract CrossChainERC20 is ERC20 {
4344
/// @notice The bridge contract address that has minting and burning privileges.
4445
address private immutable _BRIDGE;
4546

46-
/// @notice The address of the corresponding token on the remote chain.
47-
bytes32 private immutable _REMOTE_TOKEN;
48-
49-
/// @notice The number of decimal places for this token.
50-
uint8 private immutable _DECIMALS;
51-
5247
//////////////////////////////////////////////////////////////
5348
/// Storage ///
5449
//////////////////////////////////////////////////////////////
@@ -59,6 +54,12 @@ contract CrossChainERC20 is ERC20 {
5954
/// @notice The symbol of the token.
6055
string private _symbol;
6156

57+
/// @notice The address of the corresponding token on the remote chain.
58+
bytes32 private _remoteToken;
59+
60+
/// @notice The number of decimal places for this token.
61+
uint8 private _decimals;
62+
6263
//////////////////////////////////////////////////////////////
6364
/// Modifiers ///
6465
//////////////////////////////////////////////////////////////
@@ -75,17 +76,24 @@ contract CrossChainERC20 is ERC20 {
7576

7677
/// @notice Constructs the CrossChainERC20 contract.
7778
///
78-
/// @dev Sets the bridge address, remote token address, and token metadata as immutable values.
79-
///
8079
/// @param bridge_ Address of the bridge contract that will have minting and burning privileges.
80+
constructor(address bridge_) {
81+
_BRIDGE = bridge_;
82+
_disableInitializers();
83+
}
84+
85+
/// @notice Initializes the CrossChainERC20 contract.
86+
///
8187
/// @param remoteToken_ Address of the corresponding token on the remote chain.
8288
/// @param name_ ERC20 name of the token.
8389
/// @param symbol_ ERC20 symbol of the token.
8490
/// @param decimals_ ERC20 decimals for the token.
85-
constructor(address bridge_, bytes32 remoteToken_, string memory name_, string memory symbol_, uint8 decimals_) {
86-
_BRIDGE = bridge_;
87-
_REMOTE_TOKEN = remoteToken_;
88-
_DECIMALS = decimals_;
91+
function initialize(bytes32 remoteToken_, string memory name_, string memory symbol_, uint8 decimals_)
92+
external
93+
reinitializer(1)
94+
{
95+
_remoteToken = remoteToken_;
96+
_decimals = decimals_;
8997
_name = name_;
9098
_symbol = symbol_;
9199
}
@@ -101,7 +109,7 @@ contract CrossChainERC20 is ERC20 {
101109
///
102110
/// @dev This represents the corresponding token on the remote chain.
103111
function remoteToken() public view returns (bytes32) {
104-
return _REMOTE_TOKEN;
112+
return _remoteToken;
105113
}
106114

107115
/// @notice Returns the name of the token.
@@ -122,7 +130,7 @@ contract CrossChainERC20 is ERC20 {
122130
///
123131
/// @dev Overrides the ERC20 decimals function.
124132
function decimals() public view override returns (uint8) {
125-
return _DECIMALS;
133+
return _decimals;
126134
}
127135

128136
/// @notice Allows the Bridge to mint tokens.

0 commit comments

Comments
 (0)