Skip to content

Commit 80f0199

Browse files
authored
feat: Add Everclear bridge for native ETH (#6720)
1 parent 2c65067 commit 80f0199

File tree

5 files changed

+701
-101
lines changed

5 files changed

+701
-101
lines changed

solidity/contracts/interfaces/IEverclearAdapter.sol

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,19 @@ interface IEverclear {
3232
uint32[] destinations;
3333
bytes data;
3434
}
35+
36+
enum IntentStatus {
37+
NONE, // 0
38+
ADDED, // 1
39+
DEPOSIT_PROCESSED, // 2
40+
FILLED, // 3
41+
ADDED_AND_FILLED, // 4
42+
INVOICED, // 5
43+
SETTLED, // 6
44+
SETTLED_AND_MANUALLY_EXECUTED, // 7
45+
UNSUPPORTED, // 8
46+
UNSUPPORTED_RETURNED // 9
47+
}
3548
}
3649
interface IEverclearAdapter {
3750
struct FeeParams {
@@ -93,4 +106,19 @@ interface IEverclearAdapter {
93106
function updateFeeSigner(address _feeSigner) external;
94107

95108
function owner() external view returns (address);
109+
110+
function spoke() external view returns (IEverclearSpoke spoke);
111+
}
112+
113+
interface IEverclearSpoke {
114+
/**
115+
* @notice returns the status of an intent
116+
* @param _intentId The ID of the intent
117+
* @return _status The status of the intent
118+
*/
119+
function status(
120+
bytes32 _intentId
121+
) external view returns (IEverclear.IntentStatus _status);
122+
123+
function executeIntentCalldata(IEverclear.Intent calldata _intent) external;
96124
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
pragma solidity ^0.8.22;
3+
4+
import {EverclearTokenBridge, Quote} from "./EverclearTokenBridge.sol";
5+
import {IEverclearAdapter, IEverclear} from "../../interfaces/IEverclearAdapter.sol";
6+
import {IWETH} from "../interfaces/IWETH.sol";
7+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
8+
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
9+
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
10+
import {TypeCasts} from "../../libs/TypeCasts.sol";
11+
import {HypERC20Collateral} from "../HypERC20Collateral.sol";
12+
import {TokenMessage} from "../libs/TokenMessage.sol";
13+
14+
/**
15+
* @title EverclearEthBridge
16+
* @author Hyperlane Team
17+
* @notice A specialized ETH bridge that integrates with Everclear's intent-based architecture
18+
* @dev Extends EverclearTokenBridge to handle ETH by wrapping to WETH for transfers and unwrapping on destination
19+
*/
20+
contract EverclearEthBridge is EverclearTokenBridge {
21+
using TokenMessage for bytes;
22+
using SafeERC20 for IERC20;
23+
using Address for address payable;
24+
using TypeCasts for bytes32;
25+
26+
/**
27+
* @notice Constructor to initialize the Everclear ETH bridge
28+
* @param _everclearAdapter The address of the Everclear adapter contract
29+
*/
30+
constructor(
31+
IWETH _weth,
32+
uint256 _scale,
33+
address _mailbox,
34+
IEverclearAdapter _everclearAdapter
35+
)
36+
EverclearTokenBridge(
37+
address(_weth),
38+
_scale,
39+
_mailbox,
40+
_everclearAdapter
41+
)
42+
{}
43+
44+
function quoteTransferRemote(
45+
uint32 _destination,
46+
bytes32 _recipient,
47+
uint256 _amount
48+
) public view override returns (Quote[] memory quotes) {
49+
quotes = new Quote[](1);
50+
quotes[0] = Quote({
51+
token: address(0),
52+
amount: _amount +
53+
feeParams.fee +
54+
_quoteGasPayment(_destination, _recipient, _amount)
55+
});
56+
}
57+
58+
/**
59+
* @notice Transfers ETH from sender, wrapping to WETH
60+
*/
61+
function _transferFromSender(uint256 _amount) internal override {
62+
// The `_amount` here will be amount + fee where amount is what the user wants to send,
63+
// And `fee` is what is being payed to everclear.
64+
// The user will also include the gas payment in the msg.value.
65+
require(msg.value >= _amount, "EEB: ETH amount mismatch");
66+
IWETH(address(wrappedToken)).deposit{value: _amount}();
67+
}
68+
69+
function _transferTo(
70+
address _recipient,
71+
uint256 _amount
72+
) internal override {
73+
// Withdraw WETH to ETH
74+
IWETH(address(wrappedToken)).withdraw(_amount);
75+
76+
// Send ETH to recipient
77+
payable(_recipient).sendValue(_amount);
78+
}
79+
80+
function _chargeSender(
81+
uint32 _destination,
82+
bytes32 _recipient,
83+
uint256 _amount
84+
) internal virtual override returns (uint256 dispatchValue) {
85+
uint256 fee = _feeAmount(_destination, _recipient, _amount);
86+
87+
uint256 totalAmount = _amount + fee + feeParams.fee;
88+
_transferFromSender(totalAmount);
89+
dispatchValue = msg.value - totalAmount;
90+
if (fee > 0) {
91+
_transferTo(feeRecipient(), fee);
92+
}
93+
return dispatchValue;
94+
}
95+
}

0 commit comments

Comments
 (0)