Skip to content

Commit a01408f

Browse files
authored
Merge pull request #56 from BootNodeDev/native-token-intent
Native token intent
2 parents 6384a11 + 149b41a commit a01408f

File tree

5 files changed

+459
-29
lines changed

5 files changed

+459
-29
lines changed

solidity/script/DeployHyperlane7683.s.sol

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin
1111

1212
import { Hyperlane7683 } from "../src/Hyperlane7683.sol";
1313

14+
import { ICreateX } from "./utils/ICreateX.sol";
15+
1416
contract OwnableProxyAdmin is ProxyAdmin {
1517
constructor(address _owner) {
1618
_transferOwnership(_owner);
@@ -22,26 +24,16 @@ contract DeployHyperlane7683 is Script {
2224
function run() public {
2325
uint256 deployerPrivateKey = vm.envUint("DEPLOYER_PK");
2426

25-
string memory ROUTER_SALT = vm.envString("HYPERLANE7683_SALT");
26-
address mailbox = vm.envAddress("MAILBOX");
27-
address permit2 = vm.envAddress("PERMIT2");
28-
address proxyAdminOwner = vm.envOr("PROXY_ADMIN_OWNER", address(0));
29-
address owner = vm.envAddress("ROUTER_OWNER");
3027
uint256[] memory domains = vm.envUint("DOMAINS", ",");
3128
uint32[] memory _domains = new uint32[](domains.length);
3229
bytes32[] memory routers = new bytes32[](domains.length);
3330
GasRouter.GasRouterConfig[] memory gasConfigs = new GasRouter.GasRouterConfig[](domains.length);
3431

3532
vm.startBroadcast(deployerPrivateKey);
3633

37-
ProxyAdmin proxyAdmin = new OwnableProxyAdmin{salt: keccak256(abi.encode(ROUTER_SALT))}(proxyAdminOwner);
38-
39-
address routerImpl = address(new Hyperlane7683{salt: keccak256(abi.encode(ROUTER_SALT))}(mailbox, permit2));
40-
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy{salt: keccak256(abi.encode(ROUTER_SALT))}(
41-
routerImpl,
42-
address(proxyAdmin),
43-
abi.encodeWithSelector(Hyperlane7683.initialize.selector, address(0), address(0), owner)
44-
);
34+
ProxyAdmin proxyAdmin = deployProxyAdmin();
35+
address routerImpl = deployImplementation();
36+
TransparentUpgradeableProxy proxy = deployProxy(routerImpl, address(proxyAdmin));
4537

4638
for (uint i = 0; i < domains.length; i++) {
4739
routers[i] = TypeCasts.addressToBytes32(address(proxy));
@@ -61,4 +53,44 @@ contract DeployHyperlane7683 is Script {
6153
console2.log("Implementation:", routerImpl);
6254
console2.log("ProxyAdmin:", address(proxyAdmin));
6355
}
56+
57+
function deployProxyAdmin() internal returns (ProxyAdmin proxyAdmin) {
58+
string memory ROUTER_SALT = vm.envString("HYPERLANE7683_SALT");
59+
address proxyAdminOwner = vm.envOr("PROXY_ADMIN_OWNER", address(0));
60+
proxyAdmin = new OwnableProxyAdmin{salt: keccak256(abi.encode(ROUTER_SALT))}(proxyAdminOwner);
61+
}
62+
63+
function deployImplementation() internal returns (address routerImpl) {
64+
uint256 deployerPrivateKey = vm.envUint("DEPLOYER_PK");
65+
address createX = vm.envAddress("CREATEX_ADDRESS");
66+
string memory ROUTER_SALT = vm.envString("HYPERLANE7683_SALT");
67+
address mailbox = vm.envAddress("MAILBOX");
68+
address permit2 = vm.envAddress("PERMIT2");
69+
bytes32 salt = keccak256(abi.encodePacked("impl",ROUTER_SALT, vm.addr(deployerPrivateKey)));
70+
71+
bytes memory routerCreation = type(Hyperlane7683).creationCode;
72+
bytes memory routerBytecode = abi.encodePacked(routerCreation, abi.encode(mailbox, permit2));
73+
74+
routerImpl = ICreateX(createX).deployCreate3(salt, routerBytecode);
75+
}
76+
77+
function deployProxy(address routerImpl, address proxyAdmin) internal returns (TransparentUpgradeableProxy proxy) {
78+
uint256 deployerPrivateKey = vm.envUint("DEPLOYER_PK");
79+
address createX = vm.envAddress("CREATEX_ADDRESS");
80+
string memory ROUTER_SALT = vm.envString("HYPERLANE7683_SALT");
81+
address owner = vm.envAddress("ROUTER_OWNER");
82+
83+
bytes32 salt = keccak256(abi.encodePacked("proxy", ROUTER_SALT, vm.addr(deployerPrivateKey)));
84+
85+
bytes memory proxyCreation = type(TransparentUpgradeableProxy).creationCode;
86+
bytes memory proxyBytecode = abi.encodePacked(proxyCreation, abi.encode(
87+
routerImpl,
88+
proxyAdmin,
89+
abi.encodeWithSelector(Hyperlane7683.initialize.selector, address(0), address(0), owner)
90+
));
91+
92+
proxy = TransparentUpgradeableProxy(
93+
payable(ICreateX(createX).deployCreate3(salt, proxyBytecode))
94+
);
95+
}
6496
}

solidity/script/utils/ICreateX.sol

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
// SPDX-License-Identifier: AGPL-3.0-only
2+
pragma solidity 0.8.25;
3+
4+
/**
5+
* @title CreateX Factory Interface Definition
6+
* @author pcaversaccio (https://web.archive.org/web/20230921103111/https://pcaversaccio.com/)
7+
* @custom:coauthor Matt Solomon (https://web.archive.org/web/20230921103335/https://mattsolomon.dev/)
8+
*/
9+
interface ICreateX {
10+
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
11+
/* TYPES */
12+
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
13+
14+
struct Values {
15+
uint256 constructorAmount;
16+
uint256 initCallAmount;
17+
}
18+
19+
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
20+
/* EVENTS */
21+
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
22+
23+
event ContractCreation(address indexed newContract, bytes32 indexed salt);
24+
event ContractCreation(address indexed newContract);
25+
event Create3ProxyContractCreation(address indexed newContract, bytes32 indexed salt);
26+
27+
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
28+
/* CUSTOM ERRORS */
29+
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
30+
31+
error FailedContractCreation(address emitter);
32+
error FailedContractInitialisation(address emitter, bytes revertData);
33+
error InvalidSalt(address emitter);
34+
error InvalidNonceValue(address emitter);
35+
error FailedEtherTransfer(address emitter, bytes revertData);
36+
37+
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
38+
/* CREATE */
39+
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
40+
41+
function deployCreate(bytes memory initCode) external payable returns (address newContract);
42+
43+
function deployCreateAndInit(
44+
bytes memory initCode,
45+
bytes memory data,
46+
Values memory values,
47+
address refundAddress
48+
)
49+
external
50+
payable
51+
returns (address newContract);
52+
53+
function deployCreateAndInit(
54+
bytes memory initCode,
55+
bytes memory data,
56+
Values memory values
57+
)
58+
external
59+
payable
60+
returns (address newContract);
61+
62+
function deployCreateClone(address implementation, bytes memory data) external payable returns (address proxy);
63+
64+
function computeCreateAddress(address deployer, uint256 nonce) external view returns (address computedAddress);
65+
66+
function computeCreateAddress(uint256 nonce) external view returns (address computedAddress);
67+
68+
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
69+
/* CREATE2 */
70+
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
71+
72+
function deployCreate2(bytes32 salt, bytes memory initCode) external payable returns (address newContract);
73+
74+
function deployCreate2(bytes memory initCode) external payable returns (address newContract);
75+
76+
function deployCreate2AndInit(
77+
bytes32 salt,
78+
bytes memory initCode,
79+
bytes memory data,
80+
Values memory values,
81+
address refundAddress
82+
)
83+
external
84+
payable
85+
returns (address newContract);
86+
87+
function deployCreate2AndInit(
88+
bytes32 salt,
89+
bytes memory initCode,
90+
bytes memory data,
91+
Values memory values
92+
)
93+
external
94+
payable
95+
returns (address newContract);
96+
97+
function deployCreate2AndInit(
98+
bytes memory initCode,
99+
bytes memory data,
100+
Values memory values,
101+
address refundAddress
102+
)
103+
external
104+
payable
105+
returns (address newContract);
106+
107+
function deployCreate2AndInit(
108+
bytes memory initCode,
109+
bytes memory data,
110+
Values memory values
111+
)
112+
external
113+
payable
114+
returns (address newContract);
115+
116+
function deployCreate2Clone(
117+
bytes32 salt,
118+
address implementation,
119+
bytes memory data
120+
)
121+
external
122+
payable
123+
returns (address proxy);
124+
125+
function deployCreate2Clone(address implementation, bytes memory data) external payable returns (address proxy);
126+
127+
function computeCreate2Address(
128+
bytes32 salt,
129+
bytes32 initCodeHash,
130+
address deployer
131+
)
132+
external
133+
pure
134+
returns (address computedAddress);
135+
136+
function computeCreate2Address(
137+
bytes32 salt,
138+
bytes32 initCodeHash
139+
)
140+
external
141+
view
142+
returns (address computedAddress);
143+
144+
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
145+
/* CREATE3 */
146+
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
147+
148+
function deployCreate3(bytes32 salt, bytes memory initCode) external payable returns (address newContract);
149+
150+
function deployCreate3(bytes memory initCode) external payable returns (address newContract);
151+
152+
function deployCreate3AndInit(
153+
bytes32 salt,
154+
bytes memory initCode,
155+
bytes memory data,
156+
Values memory values,
157+
address refundAddress
158+
)
159+
external
160+
payable
161+
returns (address newContract);
162+
163+
function deployCreate3AndInit(
164+
bytes32 salt,
165+
bytes memory initCode,
166+
bytes memory data,
167+
Values memory values
168+
)
169+
external
170+
payable
171+
returns (address newContract);
172+
173+
function deployCreate3AndInit(
174+
bytes memory initCode,
175+
bytes memory data,
176+
Values memory values,
177+
address refundAddress
178+
)
179+
external
180+
payable
181+
returns (address newContract);
182+
183+
function deployCreate3AndInit(
184+
bytes memory initCode,
185+
bytes memory data,
186+
Values memory values
187+
)
188+
external
189+
payable
190+
returns (address newContract);
191+
192+
function computeCreate3Address(bytes32 salt, address deployer) external pure returns (address computedAddress);
193+
194+
function computeCreate3Address(bytes32 salt) external view returns (address computedAddress);
195+
}

solidity/src/Base7683.sol

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

44
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
55
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
6+
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
67
import { TypeCasts } from "@hyperlane-xyz/libs/TypeCasts.sol";
78
import { IPermit2, ISignatureTransfer } from "@uniswap/permit2/src/interfaces/IPermit2.sol";
89

@@ -76,6 +77,7 @@ abstract contract Base7683 is IOriginSettler, IDestinationSettler {
7677
error OrderFillNotExpired();
7778
error InvalidDomain();
7879
error InvalidSender();
80+
error InvalidAmount();
7981

8082
// ============ Constructor ============
8183

@@ -120,7 +122,7 @@ abstract contract Base7683 is IOriginSettler, IDestinationSettler {
120122
/// @dev To be called by the user
121123
/// @dev This method must emit the Open event
122124
/// @param order The OnchainCrossChainOrder definition
123-
function open(OnchainCrossChainOrder calldata order) external {
125+
function open(OnchainCrossChainOrder calldata order) external payable {
124126
(ResolvedCrossChainOrder memory resolvedOrder, OrderData memory orderData) = _resolvedOrder(
125127
order.orderDataType,
126128
msg.sender,
@@ -135,9 +137,13 @@ abstract contract Base7683 is IOriginSettler, IDestinationSettler {
135137
orderStatus[orderId] = OrderStatus.OPENED;
136138
senderNonce[msg.sender] += 1;
137139

138-
IERC20(TypeCasts.bytes32ToAddress(orderData.inputToken)).safeTransferFrom(
139-
msg.sender, address(this), orderData.amountIn
140-
);
140+
if (orderData.inputToken != TypeCasts.addressToBytes32(address(0))) {
141+
IERC20(TypeCasts.bytes32ToAddress(orderData.inputToken)).safeTransferFrom(
142+
msg.sender, address(this), orderData.amountIn
143+
);
144+
} else {
145+
if (msg.value != orderData.amountIn) revert InvalidAmount();
146+
}
141147

142148
emit Open(orderId, resolvedOrder);
143149
}
@@ -182,7 +188,7 @@ abstract contract Base7683 is IOriginSettler, IDestinationSettler {
182188
/// @param _originData Data emitted on the origin to parameterize the fill
183189
/// @param _fillerData Data provided by the filler to inform the fill or express their preferences. It should
184190
/// contain the bytes32 encoded address of the receiver which is the used at settlement time
185-
function fill(bytes32 _orderId, bytes calldata _originData, bytes calldata _fillerData) external virtual {
191+
function fill(bytes32 _orderId, bytes calldata _originData, bytes calldata _fillerData) external payable virtual {
186192
OrderData memory orderData = OrderEncoder.decode(_originData);
187193

188194
if (_orderId != _getOrderId(orderData)) revert InvalidOrderId();
@@ -197,9 +203,14 @@ abstract contract Base7683 is IOriginSettler, IDestinationSettler {
197203

198204
emit Filled(_orderId, _originData, _fillerData);
199205

200-
IERC20(TypeCasts.bytes32ToAddress(orderData.outputToken)).safeTransferFrom(
201-
msg.sender, TypeCasts.bytes32ToAddress(orderData.recipient), orderData.amountOut
202-
);
206+
if (orderData.outputToken != TypeCasts.addressToBytes32(address(0))) {
207+
IERC20(TypeCasts.bytes32ToAddress(orderData.outputToken)).safeTransferFrom(
208+
msg.sender, TypeCasts.bytes32ToAddress(orderData.recipient), orderData.amountOut
209+
);
210+
} else {
211+
if (msg.value != orderData.amountOut) revert InvalidAmount();
212+
Address.sendValue(payable(TypeCasts.bytes32ToAddress(orderData.recipient)), orderData.amountOut);
213+
}
203214
}
204215

205216
function settle(bytes32[] calldata _orderIds) external payable {
@@ -365,9 +376,13 @@ abstract contract Base7683 is IOriginSettler, IDestinationSettler {
365376

366377
emit Settled(_orderId, receiver);
367378

368-
IERC20(TypeCasts.bytes32ToAddress(orderData.inputToken)).safeTransfer(
369-
receiver, orderData.amountIn
370-
);
379+
if (orderData.inputToken != TypeCasts.addressToBytes32(address(0))) {
380+
IERC20(TypeCasts.bytes32ToAddress(orderData.inputToken)).safeTransfer(
381+
receiver, orderData.amountIn
382+
);
383+
} else {
384+
Address.sendValue(payable(receiver), orderData.amountIn);
385+
}
371386
}
372387

373388
/**
@@ -386,9 +401,13 @@ abstract contract Base7683 is IOriginSettler, IDestinationSettler {
386401

387402
emit Refunded(_orderId, orderSender);
388403

389-
IERC20(TypeCasts.bytes32ToAddress(orderData.inputToken)).safeTransfer(
390-
orderSender, orderData.amountIn
391-
);
404+
if (orderData.inputToken != TypeCasts.addressToBytes32(address(0))) {
405+
IERC20(TypeCasts.bytes32ToAddress(orderData.inputToken)).safeTransfer(
406+
orderSender, orderData.amountIn
407+
);
408+
} else {
409+
Address.sendValue(payable(orderSender), orderData.amountIn);
410+
}
392411
}
393412

394413
/**

solidity/src/ERC7683/IERC7683.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ interface IOriginSettler {
121121
/// @dev To be called by the user
122122
/// @dev This method must emit the Open event
123123
/// @param order The OnchainCrossChainOrder definition
124-
function open(OnchainCrossChainOrder calldata order) external;
124+
function open(OnchainCrossChainOrder calldata order) external payable;
125125

126126
/// @notice Resolves a specific GaslessCrossChainOrder into a generic ResolvedCrossChainOrder
127127
/// @dev Intended to improve standardized integration of various order types and settlement contracts
@@ -150,5 +150,5 @@ interface IDestinationSettler {
150150
/// @param orderId Unique order identifier for this order
151151
/// @param originData Data emitted on the origin to parameterize the fill
152152
/// @param fillerData Data provided by the filler to inform the fill or express their preferences
153-
function fill(bytes32 orderId, bytes calldata originData, bytes calldata fillerData) external;
153+
function fill(bytes32 orderId, bytes calldata originData, bytes calldata fillerData) external payable;
154154
}

0 commit comments

Comments
 (0)