Skip to content

Commit 9f42480

Browse files
committed
feat: WorldChain deployments (#634)
1 parent a01609e commit 9f42480

21 files changed

+4696
-7
lines changed

contracts/WorldChain_SpokePool.sol

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.0;
3+
import "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
4+
5+
import "./Ovm_SpokePool.sol";
6+
import "./external/interfaces/CCTPInterfaces.sol";
7+
8+
/**
9+
* @notice World Chain Spoke pool.
10+
* @custom:security-contact [email protected]
11+
*/
12+
contract WorldChain_SpokePool is Ovm_SpokePool {
13+
/// @custom:oz-upgrades-unsafe-allow constructor
14+
constructor(
15+
address _wrappedNativeTokenAddress,
16+
uint32 _depositQuoteTimeBuffer,
17+
uint32 _fillDeadlineBuffer,
18+
IERC20 _l2Usdc,
19+
ITokenMessenger _cctpTokenMessenger
20+
)
21+
Ovm_SpokePool(
22+
_wrappedNativeTokenAddress,
23+
_depositQuoteTimeBuffer,
24+
_fillDeadlineBuffer,
25+
_l2Usdc,
26+
_cctpTokenMessenger
27+
)
28+
{} // solhint-disable-line no-empty-blocks
29+
30+
/**
31+
* @notice Construct the OVM World Chain SpokePool.
32+
* @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate
33+
* relay hash collisions.
34+
* @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.
35+
* @param _hubPool Hub pool address to set. Can be changed by admin.
36+
*/
37+
function initialize(
38+
uint32 _initialDepositId,
39+
address _crossDomainAdmin,
40+
address _hubPool
41+
) public initializer {
42+
__OvmSpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, Lib_PredeployAddresses.OVM_ETH);
43+
}
44+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.0;
3+
4+
import "./interfaces/AdapterInterface.sol";
5+
import "../external/interfaces/WETH9Interface.sol";
6+
7+
// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need
8+
// this contract's state variables to be `immutable` because of the delegateCall call.
9+
import "./CrossDomainEnabled.sol";
10+
import "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol";
11+
12+
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
13+
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
14+
15+
import "../libraries/CircleCCTPAdapter.sol";
16+
import "../external/interfaces/CCTPInterfaces.sol";
17+
18+
/**
19+
* @notice Contract containing logic to send messages from L1 to World Chain. This is a clone of the Base/Mode adapter
20+
* @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be
21+
* called via delegatecall, which will execute this contract's logic within the context of the originating contract.
22+
* For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods
23+
* that call this contract's logic guard against reentrancy.
24+
* @custom:security-contact [email protected]
25+
*/
26+
27+
// solhint-disable-next-line contract-name-camelcase
28+
contract WorldChain_Adapter is CrossDomainEnabled, AdapterInterface, CircleCCTPAdapter {
29+
using SafeERC20 for IERC20;
30+
uint32 public constant L2_GAS_LIMIT = 200_000;
31+
32+
WETH9Interface public immutable L1_WETH;
33+
34+
IL1StandardBridge public immutable L1_STANDARD_BRIDGE;
35+
36+
/**
37+
* @notice Constructs new Adapter.
38+
* @param _l1Weth WETH address on L1.
39+
* @param _crossDomainMessenger XDomainMessenger World Chain system contract.
40+
* @param _l1StandardBridge Standard bridge contract.
41+
* @param _l1Usdc USDC address on L1.
42+
*/
43+
constructor(
44+
WETH9Interface _l1Weth,
45+
address _crossDomainMessenger,
46+
IL1StandardBridge _l1StandardBridge,
47+
IERC20 _l1Usdc
48+
)
49+
CrossDomainEnabled(_crossDomainMessenger)
50+
CircleCCTPAdapter(
51+
_l1Usdc,
52+
// Hardcode cctp messenger to 0x0 to disable CCTP bridging.
53+
ITokenMessenger(address(0)),
54+
CircleDomainIds.UNINTIALIZED
55+
)
56+
{
57+
L1_WETH = _l1Weth;
58+
L1_STANDARD_BRIDGE = _l1StandardBridge;
59+
}
60+
61+
/**
62+
* @notice Send cross-chain message to target on World Chain.
63+
* @param target Contract on World Chain that will receive message.
64+
* @param message Data to send to target.
65+
*/
66+
function relayMessage(address target, bytes calldata message) external payable override {
67+
sendCrossDomainMessage(target, L2_GAS_LIMIT, message);
68+
emit MessageRelayed(target, message);
69+
}
70+
71+
/**
72+
* @notice Bridge tokens to World Chain.
73+
* @param l1Token L1 token to deposit.
74+
* @param l2Token L2 token to receive.
75+
* @param amount Amount of L1 tokens to deposit and L2 tokens to receive.
76+
* @param to Bridge recipient.
77+
*/
78+
function relayTokens(
79+
address l1Token,
80+
address l2Token,
81+
uint256 amount,
82+
address to
83+
) external payable override {
84+
// If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.
85+
if (l1Token == address(L1_WETH)) {
86+
L1_WETH.withdraw(amount);
87+
L1_STANDARD_BRIDGE.depositETHTo{ value: amount }(to, L2_GAS_LIMIT, "");
88+
}
89+
// Check if this token is USDC, which requires a custom bridge via CCTP.
90+
else if (_isCCTPEnabled() && l1Token == address(usdcToken)) {
91+
_transferUsdc(to, amount);
92+
} else {
93+
IL1StandardBridge _l1StandardBridge = L1_STANDARD_BRIDGE;
94+
95+
IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);
96+
_l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, L2_GAS_LIMIT, "");
97+
}
98+
emit TokensRelayed(l1Token, l2Token, amount, to);
99+
}
100+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { HardhatRuntimeEnvironment } from "hardhat/types";
2+
import { DeployFunction } from "hardhat-deploy/types";
3+
import { L1_ADDRESS_MAP, WETH, ZERO_ADDRESS } from "./consts";
4+
5+
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
6+
const { deployer } = await hre.getNamedAccounts();
7+
const chainId = parseInt(await hre.getChainId());
8+
9+
await hre.deployments.deploy("WorldChain_Adapter", {
10+
from: deployer,
11+
log: true,
12+
skipIfAlreadyDeployed: true,
13+
args: [
14+
WETH[chainId],
15+
L1_ADDRESS_MAP[chainId].worldChainCrossDomainMessenger,
16+
L1_ADDRESS_MAP[chainId].worldChainStandardBridge,
17+
ZERO_ADDRESS,
18+
],
19+
});
20+
};
21+
22+
module.exports = func;
23+
func.tags = ["WorldChainAdapter", "mainnet"];
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { DeployFunction } from "hardhat-deploy/types";
2+
import { HardhatRuntimeEnvironment } from "hardhat/types";
3+
import { deployNewProxy, getSpokePoolDeploymentInfo } from "../utils/utils.hre";
4+
import { FILL_DEADLINE_BUFFER, WETH, QUOTE_TIME_BUFFER, ZERO_ADDRESS } from "./consts";
5+
6+
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
7+
const { hubPool, spokeChainId } = await getSpokePoolDeploymentInfo(hre);
8+
9+
const initArgs = [
10+
1,
11+
// Set hub pool as cross domain admin since it delegatecalls the Adapter logic.
12+
hubPool.address,
13+
hubPool.address,
14+
];
15+
const constructorArgs = [
16+
WETH[spokeChainId],
17+
QUOTE_TIME_BUFFER,
18+
FILL_DEADLINE_BUFFER,
19+
ZERO_ADDRESS,
20+
// L2_ADDRESS_MAP[spokeChainId].cctpTokenMessenger,
21+
// For now, we are not using the CCTP bridge and can disable by setting
22+
// the cctpTokenMessenger to the zero address.
23+
ZERO_ADDRESS,
24+
];
25+
await deployNewProxy("WorldChain_SpokePool", constructorArgs, initArgs);
26+
};
27+
module.exports = func;
28+
func.tags = ["WorldChainSpokePool", "worldchain"];

deploy/consts.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ export const L1_ADDRESS_MAP: { [key: number]: { [contractName: string]: string }
4646
redstoneStandardBridge: "0xc473ca7E02af24c129c2eEf51F2aDf0411c1Df69",
4747
zoraCrossDomainMessenger: "0xdC40a14d9abd6F410226f1E6de71aE03441ca506",
4848
zoraStandardBridge: "0x3e2Ea9B92B7E48A52296fD261dc26fd995284631",
49+
worldChainCrossDomainMessenger: "0xf931a81D18B1766d15695ffc7c1920a62b7e710a",
50+
worldChainStandardBridge: "0x470458C91978D2d929704489Ad730DC3E3001113",
4951
},
5052
[CHAIN_IDs.SEPOLIA]: {
5153
optimismCrossDomainMessenger: "0x58Cc85b8D04EA49cC6DBd3CbFFd00B4B8D6cb3ef",

deployments/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ This is because this `deployments.json` file is used by bots in [`@across-protoc
2525
| Lisk Adapter | [0x8229E812f20537caA1e8Fb41749b4887B8a75C3B](https://etherscan.io/address/0x8229E812f20537caA1e8Fb41749b4887B8a75C3B) |
2626
| Blast Adapter | [0xF2bEf5E905AAE0295003ab14872F811E914EdD81](https://etherscan.io/address/0xF2bEf5E905AAE0295003ab14872F811E914EdD81) |
2727
| Scroll Adapter | [0xb6129Ab69aEA75e6884c2D6ecf25293C343C519F](https://etherscan.io/address/0xb6129Ab69aEA75e6884c2D6ecf25293C343C519F) |
28+
| Redstone Adapter | [0x188F8C95B7cfB7993B53a4F643efa687916f73fA](https://etherscan.io/address/0x188F8C95B7cfB7993B53a4F643efa687916f73fA) |
29+
| Zora Adapter | [0x024F2fC31CBDD8de17194b1892c834f98Ef5169b](https://etherscan.io/address/0x024F2fC31CBDD8de17194b1892c834f98Ef5169b) |
30+
| WorldChain Adapter | [0x8eBebfc894047bEE213A561b8792fCa71241731f](https://etherscan.io/address/0x8eBebfc894047bEE213A561b8792fCa71241731f) |
2831
| AcrossConfigStore | [0x3B03509645713718B78951126E0A6de6f10043f5](https://etherscan.io/address/0x3B03509645713718B78951126E0A6de6f10043f5) |
2932
| Across Bond Token | [0xee1dc6bcf1ee967a350e9ac6caaaa236109002ea](https://etherscan.io/address/0xee1dc6bcf1ee967a350e9ac6caaaa236109002ea) |
3033
| MulticallHandler | [0x924a9f036260DdD5808007E1AA95f08eD08aA569](https://etherscan.io/address/0x924a9f036260DdD5808007E1AA95f08eD08aA569) |
@@ -113,3 +116,10 @@ This is because this `deployments.json` file is used by bots in [`@across-protoc
113116
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------ |
114117
| Zora_SpokePool | [0x13fDac9F9b4777705db45291bbFF3c972c6d1d97](https://zorascan.xyz/address/0x13fDac9F9b4777705db45291bbFF3c972c6d1d97) |
115118
| MulticallHandler | [0x924a9f036260DdD5808007E1AA95f08eD08aA569](https://explorer.redstone.xyz/address/0x924a9f036260DdD5808007E1AA95f08eD08aA569) |
119+
120+
## World Chain mainnet (480)
121+
122+
| Contract Name | Address |
123+
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
124+
| WorldChain_SpokePool | [0x09aea4b2242abC8bb4BB78D537A67a245A7bEC64](https://worldchain-mainnet.explorer.alchemy.com/address/0x09aea4b2242abC8bb4BB78D537A67a245A7bEC64) |
125+
| MulticallHandler | [0x924a9f036260DdD5808007E1AA95f08eD08aA569](https://worldchain-mainnet.explorer.alchemy.com/address/0x924a9f036260DdD5808007E1AA95f08eD08aA569) |

deployments/deployments.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
"Blast_DaiRetriever": { "address": "0x98Dd57048d7d5337e92D9102743528ea4Fea64aB", "blockNumber": 20378862 },
2727
"Blast_RescueAdapter": { "address": "0xE5Dea263511F5caC27b15cBd58Ff103F4Ce90957", "blockNumber": 20378872 },
2828
"Redstone_Adapter": { "address": "0x188F8C95B7cfB7993B53a4F643efa687916f73fA", "blockNumber": 20432774 },
29-
"Zora_Adapter": { "address": "0x024f2fc31cbdd8de17194b1892c834f98ef5169b", "blockNumber": 20512287 }
29+
"Zora_Adapter": { "address": "0x024f2fc31cbdd8de17194b1892c834f98ef5169b", "blockNumber": 20512287 },
30+
"WorldChain_Adapter": { "address": "0x8eBebfc894047bEE213A561b8792fCa71241731f", "blockNumber": 20921874 }
3031
},
3132
"10": {
3233
"SpokePool": { "address": "0x6f26Bf09B1C792e3228e5467807a900A503c0281", "blockNumber": 93903076 },
@@ -62,6 +63,11 @@
6263
"SpokePool": { "address": "0xE0B015E54d54fc84a6cB9B666099c46adE9335FF", "blockNumber": 10352565 },
6364
"MulticallHandler": { "address": "0x863859ef502F0Ee9676626ED5B418037252eFeb2", "blockNumber": 36906393 }
6465
},
66+
"480": {
67+
"SpokePool": { "address": "0x09aea4b2242abC8bb4BB78D537A67a245A7bEC64", "blockNumber": 4524742 },
68+
"SpokePoolVerifier": { "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", "blockNumber": 4529956 },
69+
"MulticallHandler": { "address": "0x924a9f036260DdD5808007E1AA95f08eD08aA569", "blockNumber": 4528295 }
70+
},
6571
"690": {
6672
"SpokePool": { "address": "0x13fDac9F9b4777705db45291bbFF3c972c6d1d97", "blockNumber": 5512122 },
6773
"SpokePoolVerifier": { "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", "blockNumber": 5161326 },

0 commit comments

Comments
 (0)