Skip to content

Commit d4c41a9

Browse files
authored
feat(cher): deploy cher contracts (#856)
1 parent e03e0b6 commit d4c41a9

15 files changed

+4380
-7
lines changed

contracts/Cher_SpokePool.sol

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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+
import { IOpUSDCBridgeAdapter } from "./external/interfaces/IOpUSDCBridgeAdapter.sol";
8+
9+
/**
10+
* @notice Cher SpokePool.
11+
* @custom:security-contact [email protected]
12+
*/
13+
contract Cher_SpokePool is Ovm_SpokePool {
14+
using SafeERC20 for IERC20;
15+
16+
// Address of the custom L2 USDC bridge.
17+
address private constant USDC_BRIDGE = 0x8be79275FCfD08A931087ECf70Ba8a99aee3AC59;
18+
19+
/// @custom:oz-upgrades-unsafe-allow constructor
20+
constructor(
21+
address _wrappedNativeTokenAddress,
22+
uint32 _depositQuoteTimeBuffer,
23+
uint32 _fillDeadlineBuffer,
24+
IERC20 _l2Usdc,
25+
ITokenMessenger _cctpTokenMessenger
26+
)
27+
Ovm_SpokePool(
28+
_wrappedNativeTokenAddress,
29+
_depositQuoteTimeBuffer,
30+
_fillDeadlineBuffer,
31+
_l2Usdc,
32+
_cctpTokenMessenger
33+
)
34+
{} // solhint-disable-line no-empty-blocks
35+
36+
/**
37+
* @notice Construct the OVM Cher SpokePool.
38+
* @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate
39+
* relay hash collisions.
40+
* @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.
41+
* @param _withdrawalRecipient Address which receives token withdrawals. Can be changed by admin. For Spoke Pools on L2, this will
42+
*/
43+
function initialize(
44+
uint32 _initialDepositId,
45+
address _crossDomainAdmin,
46+
address _withdrawalRecipient
47+
) public initializer {
48+
__OvmSpokePool_init(_initialDepositId, _crossDomainAdmin, _withdrawalRecipient, Lib_PredeployAddresses.OVM_ETH);
49+
}
50+
51+
/**
52+
* @notice Cher-specific logic to bridge tokens back to the hub pool contract on L1.
53+
* @param amountToReturn Amount of the token to bridge back.
54+
* @param l2TokenAddress Address of the l2 Token to bridge back. This token will either be bridged back to the token defined in the mapping `remoteL1Tokens`,
55+
* or via the canonical mapping defined in the bridge contract retrieved from `tokenBridges`.
56+
* @dev This implementation deviates slightly from `_bridgeTokensToHubPool` in the `Ovm_SpokePool` contract since
57+
* this chain uses Circle's bridged (upgradable to native) USDC standard, which uses a custom interface.
58+
*/
59+
function _bridgeTokensToHubPool(uint256 amountToReturn, address l2TokenAddress) internal virtual override {
60+
// Handle custom USDC bridge which doesn't conform to the standard bridge interface. In the future, CCTP may be used to bridge USDC to mainnet, in which
61+
// case bridging logic is handled by the Ovm_SpokePool code. In the meantime, if CCTP is not enabled, then use the USDC bridge. Once CCTP is activated on
62+
// Cher, this block of code will be unused.
63+
if (l2TokenAddress == address(usdcToken) && !_isCCTPEnabled()) {
64+
usdcToken.safeIncreaseAllowance(USDC_BRIDGE, amountToReturn);
65+
IOpUSDCBridgeAdapter(USDC_BRIDGE).sendMessage(
66+
withdrawalRecipient, // _to. Withdraw, over the bridge, to the l1 hub pool contract.
67+
amountToReturn, // _amount.
68+
l1Gas // _minGasLimit. Same value used in other OpStack bridges.
69+
);
70+
} else super._bridgeTokensToHubPool(amountToReturn, l2TokenAddress);
71+
}
72+
}

deploy/060_deploy_cher_spokepool.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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, USDCe } 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+
// Cher's bridged USDC is upgradeable to native. There are not two different
20+
// addresses for bridges/native USDC. This address is also used in the spoke pool
21+
// to determine whether to use CCTP (in the future) or the custom USDC bridge.
22+
USDCe[spokeChainId],
23+
// L2_ADDRESS_MAP[spokeChainId].cctpTokenMessenger,
24+
// For now, we are not using the CCTP bridge and can disable by setting
25+
// the cctpTokenMessenger to the zero address.
26+
ZERO_ADDRESS,
27+
];
28+
await deployNewProxy("Cher_SpokePool", constructorArgs, initArgs);
29+
};
30+
module.exports = func;
31+
func.tags = ["CherSpokePool", "cher"];

deploy/consts.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ export const OP_STACK_ADDRESS_MAP: {
9494
L1StandardBridge: "0x88ff1e5b602916615391f55854588efcbb7663f0",
9595
L1OpUSDCBridgeAdapter: ZERO_ADDRESS,
9696
},
97+
[CHAIN_IDs.CHER]: {
98+
L1CrossDomainMessenger: "0x9cf951e3f74b644e621b36ca9cea147a78d4c39f",
99+
L1StandardBridge: "0xeb9bf100225c214efc3e7c651ebbadcf85177607",
100+
L1OpUSDCBridgeAdapter: "0xC67A8c5f22b40274Ca7C4A56Db89569Ee2AD3FAb",
101+
},
97102
[CHAIN_IDs.LISK]: {
98103
L1CrossDomainMessenger: "0x31B72D76FB666844C41EdF08dF0254875Dbb7edB",
99104
L1StandardBridge: "0x2658723Bf70c7667De6B25F99fcce13A16D25d08",

deployments/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ This is because this `deployments.json` file is used by bots in [`@across-protoc
3131
| AcrossConfigStore | [0x3B03509645713718B78951126E0A6de6f10043f5](https://etherscan.io/address/0x3B03509645713718B78951126E0A6de6f10043f5) |
3232
| Across Bond Token | [0xee1dc6bcf1ee967a350e9ac6caaaa236109002ea](https://etherscan.io/address/0xee1dc6bcf1ee967a350e9ac6caaaa236109002ea) |
3333
| MulticallHandler | [0x924a9f036260DdD5808007E1AA95f08eD08aA569](https://etherscan.io/address/0x924a9f036260DdD5808007E1AA95f08eD08aA569) |
34+
| Cher Adapter | [0x0c9d064523177dBB55CFE52b9D0c485FBFc35FD2](https://etherscan.io/address/0x0c9d064523177dBB55CFE52b9D0c485FBFc35FD2) |
3435

3536
## Optimism mainnet (10)
3637

@@ -137,3 +138,10 @@ This is because this `deployments.json` file is used by bots in [`@across-protoc
137138
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------- |
138139
| Ink_SpokePool | [0xeF684C38F94F48775959ECf2012D7E864ffb9dd4](https://explorer.inkonchain.com/address/0xeF684C38F94F48775959ECf2012D7E864ffb9dd4) |
139140
| MulticallHandler | [0x924a9f036260DdD5808007E1AA95f08eD08aA569](https://explorer.inkonchain.com/address/0x924a9f036260DdD5808007E1AA95f08eD08aA569) |
141+
142+
## Cher mainnet (1868)
143+
144+
| Contract Name | Address |
145+
| ---------------- | --------------------------------------------------------------------------------------------------------------------- |
146+
| Cher_SpokePool | [0x3baD7AD0728f9917d1Bf08af5782dCbD516cDd96](https://etherscan.io/address/0x3baD7AD0728f9917d1Bf08af5782dCbD516cDd96) |
147+
| MulticallHandler | [0x924a9f036260DdD5808007E1AA95f08eD08aA569](https://etherscan.io/address/0x924a9f036260DdD5808007E1AA95f08eD08aA569) |

deployments/cher/.chainId

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1868

0 commit comments

Comments
 (0)