Skip to content

Commit 30d5370

Browse files
authored
feat: Add Forge deploy script for Universal contracts (#1185)
Add adapter and spoke pool forge scripts
1 parent b38eadb commit 30d5370

File tree

5 files changed

+172
-1
lines changed

5 files changed

+172
-1
lines changed

deploy/consts.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ export const L2_ADDRESS_MAP: { [key: number]: { [contractName: string]: string }
206206
permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
207207
},
208208
[CHAIN_IDs.MONAD]: {
209+
helios: "0x09aea4b2242abc8bb4bb78d537a67a245a7bec64",
209210
cctpV2TokenMessenger: "0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d",
210211
},
211212
[CHAIN_IDs.PLASMA]: {

generated/constants.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,7 @@
609609
"permit2": "0x000000000022D473030F116dDEE9F6B43aC78BA3"
610610
},
611611
"143": {
612+
"helios": "0x09aea4b2242abc8bb4bb78d537a67a245a7bec64",
612613
"cctpV2TokenMessenger": "0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d"
613614
},
614615
"232": {
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.0;
3+
4+
import { Script } from "forge-std/Script.sol";
5+
import { Test } from "forge-std/Test.sol";
6+
import { console } from "forge-std/console.sol";
7+
import { Universal_Adapter } from "../contracts/chain-adapters/Universal_Adapter.sol";
8+
import { HubPoolStore } from "../contracts/chain-adapters/utilities/HubPoolStore.sol";
9+
import { Constants } from "./utils/Constants.sol";
10+
import { IERC20 } from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol";
11+
import { ITokenMessenger } from "../contracts/external/interfaces/CCTPInterfaces.sol";
12+
import { WETH9Interface } from "../contracts/external/interfaces/WETH9Interface.sol";
13+
14+
// How to run:
15+
// 1. `source .env` where `.env` has MNEMONIC="x x x ... x" and ETHERSCAN_API_KEY="x" entries
16+
// 2. forge script script/110DeployUniversalAdapter.s.sol:DeployUniversalAdapter --sig "run(string)" <DEST_CHAIN_NAME e.g. MONAD> --rpc-url $NODE_URL_1 -vvvv
17+
// 3. Verify the above works in simulation mode.
18+
// 4. Deploy on mainnet by adding --broadcast --verify flags.
19+
// 5. forge script script/110DeployUniversalAdapter.s.sol:DeployUniversalAdapter MONAD --rpc-url $NODE_URL_1 --broadcast --verify -vvvv
20+
21+
contract DeployUniversalAdapter is Script, Test, Constants {
22+
function run() external pure {
23+
revert("Not implemented, see script for run instructions");
24+
}
25+
function run(string calldata destinationChainName) external {
26+
string memory deployerMnemonic = vm.envString("MNEMONIC");
27+
uint256 deployerPrivateKey = vm.deriveKey(deployerMnemonic, 0);
28+
29+
// Get the current chain ID
30+
uint256 chainId = block.chainid;
31+
32+
// Verify this is being deployed on Ethereum mainnet or Sepolia
33+
require(
34+
chainId == getChainId("MAINNET") || chainId == getChainId("SEPOLIA"),
35+
"Universal_Adapter should only be deployed on Ethereum mainnet or Sepolia"
36+
);
37+
38+
uint256 destinationChainId = getChainId(destinationChainName);
39+
bool hasCctpDomain = hasCctpDomain(destinationChainId);
40+
address cctpTokenMessenger = hasCctpDomain ? getL1Addresses(chainId).cctpV2TokenMessenger : address(0);
41+
uint32 cctpDomainId = hasCctpDomain ? uint32(getCircleDomainId(destinationChainId)) : 0;
42+
43+
uint256 oftFeeCap = 1 ether;
44+
45+
vm.startBroadcast(deployerPrivateKey);
46+
47+
// Deploy Universal_Adapter with constructor parameters
48+
Universal_Adapter universalAdapter = new Universal_Adapter(
49+
HubPoolStore(getL1Addresses(chainId).hubPoolStore),
50+
IERC20(getUSDCAddress(chainId)),
51+
ITokenMessenger(cctpTokenMessenger),
52+
cctpDomainId,
53+
getL1Addresses(chainId).adapterStore,
54+
uint32(getOftEid(destinationChainId)),
55+
oftFeeCap
56+
);
57+
58+
// Log the deployed addresses
59+
console.log("Chain ID:", chainId);
60+
console.log("Universal_Adapter deployed to:", address(universalAdapter));
61+
console.log("L1 HubPoolStore:", getL1Addresses(chainId).hubPoolStore);
62+
console.log("L1 AdapterStore:", getL1Addresses(chainId).adapterStore);
63+
console.log("L1 USDC:", getUSDCAddress(chainId));
64+
console.log("CCTP Token Messenger:", cctpTokenMessenger);
65+
console.log("CCTP Domain ID:", cctpDomainId);
66+
console.log("OFT Destination EID:", getOftEid(destinationChainId));
67+
console.log("OFT Fee Cap:", oftFeeCap);
68+
69+
vm.stopBroadcast();
70+
}
71+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.0;
3+
4+
import { Script } from "forge-std/Script.sol";
5+
import { Test } from "forge-std/Test.sol";
6+
import { console } from "forge-std/console.sol";
7+
import { Universal_SpokePool } from "../contracts/Universal_SpokePool.sol";
8+
import { DeploymentUtils } from "./utils/DeploymentUtils.sol";
9+
import { ITokenMessenger } from "../contracts/external/interfaces/CCTPInterfaces.sol";
10+
11+
// How to run:
12+
// 1. `source .env` where `.env` has MNEMONIC="x x x ... x"
13+
// 2. forge script script/111DeployUniversalSpokePool.s.sol:DeployUniversalSpokePool --sig "run(uint256)" <OFT_FEE_CAP> --rpc-url $NODE_URL_143 -vvvv
14+
// 3. Verify the above works in simulation mode.
15+
// 4. Deploy with:
16+
// forge script script/110DeployUniversalAdapter.s.sol:DeployUniversalAdapter --sig "run(uint256)" <OFT_FEE_CAP e.g. 78000> --rpc-url \
17+
// $NODE_URL_143 --broadcast --verifier @todo --verifier-url @todo
18+
19+
contract DeployUniversalSpokePool is Script, Test, DeploymentUtils {
20+
function run() external pure {
21+
revert("Not implemented, see script for run instructions");
22+
}
23+
function run(uint256 oftFeeCap) external {
24+
string memory deployerMnemonic = vm.envString("MNEMONIC");
25+
uint256 deployerPrivateKey = vm.deriveKey(deployerMnemonic, 0);
26+
27+
// Get deployment information
28+
DeploymentInfo memory info = getSpokePoolDeploymentInfo(address(0));
29+
30+
// Get the appropriate addresses for this chain
31+
address wrappedNativeToken = getWrappedNativeToken(info.spokeChainId);
32+
33+
// Get USDC address for this chain
34+
address usdcAddress = getUSDCAddress(info.spokeChainId);
35+
36+
vm.startBroadcast(deployerPrivateKey);
37+
38+
uint256 heliosAdminBufferUpdateSeconds = 1 days;
39+
address helios = getL2Address(info.spokeChainId, "helios");
40+
address l1HubPoolStore = getL1Addresses(info.hubChainId).hubPoolStore;
41+
42+
bool hasCctpDomain = hasCctpDomain(info.spokeChainId);
43+
address cctpTokenMessenger = hasCctpDomain
44+
? getL2Address(info.spokeChainId, "cctpV2TokenMessenger")
45+
: address(0);
46+
uint32 oftDstEid = uint32(getOftEid(info.hubChainId));
47+
48+
// Prepare constructor arguments for Universal_SpokePool
49+
bytes memory constructorArgs = abi.encode(
50+
heliosAdminBufferUpdateSeconds,
51+
helios,
52+
l1HubPoolStore,
53+
wrappedNativeToken,
54+
QUOTE_TIME_BUFFER(), // _depositQuoteTimeBuffer
55+
FILL_DEADLINE_BUFFER(), // _fillDeadlineBuffer
56+
usdcAddress,
57+
cctpTokenMessenger,
58+
oftDstEid,
59+
oftFeeCap
60+
);
61+
62+
// Initialize deposit counter to 1
63+
// Set hub pool as cross domain admin since it delegatecalls the Adapter logic.
64+
bytes memory initArgs = abi.encodeWithSelector(
65+
Universal_SpokePool.initialize.selector,
66+
1, // _initialDepositId
67+
info.hubPool, // _crossDomainAdmin
68+
info.hubPool // _withdrawalRecipient
69+
);
70+
71+
// Deploy the proxy
72+
DeploymentResult memory result = deployNewProxy(
73+
"Universal_SpokePool",
74+
constructorArgs,
75+
initArgs,
76+
true // implementationOnly
77+
);
78+
79+
// Log the deployed addresses
80+
console.log("Chain ID:", info.spokeChainId);
81+
console.log("Hub Chain ID:", info.hubChainId);
82+
console.log("HubPool address:", info.hubPool);
83+
console.log("Helios address:", helios);
84+
console.log("L1 HubPoolStore address:", l1HubPoolStore);
85+
console.log("Wrapped Native Token address:", weth);
86+
console.log("USDC address:", usdcAddress);
87+
console.log("CCTP Token Messenger:", cctpTokenMessenger);
88+
console.log("OFT DST EID:", oftDstEid);
89+
console.log("OFT Fee Cap:", oftFeeCap);
90+
console.log("Universal_SpokePool proxy deployed to:", result.proxy);
91+
console.log("Universal_SpokePool implementation deployed to:", result.implementation);
92+
93+
console.log("QUOTE_TIME_BUFFER()", QUOTE_TIME_BUFFER());
94+
console.log("FILL_DEADLINE_BUFFER()", FILL_DEADLINE_BUFFER());
95+
96+
vm.stopBroadcast();
97+
}
98+
}

script/utils/DeploymentUtils.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ contract DeploymentUtils is Script, Test, Constants, DeployedAddresses {
4141
* @return info Deployment information struct
4242
*/
4343
function getSpokePoolDeploymentInfo(address hubPoolAddress) public view returns (DeploymentInfo memory info) {
44-
console.log("hubPoolAddress", hubPoolAddress);
4544
uint256 spokeChainId = block.chainid;
4645

4746
// Determine hub chain ID based on spoke chain ID
@@ -60,6 +59,7 @@ contract DeploymentUtils is Script, Test, Constants, DeployedAddresses {
6059
if (hubPool == address(0)) {
6160
hubPool = getAddress(hubChainId, "HubPool");
6261
}
62+
console.log("hubPoolAddress", hubPool);
6363

6464
require(hubPool != address(0), "HubPool address cannot be zero");
6565

0 commit comments

Comments
 (0)