-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
714fd28
commit e2dc41f
Showing
8 changed files
with
214 additions
and
57 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.28; | ||
|
||
import {IHyperlaneMailbox} from "./interfaces/IHyperlaneMailbox.sol"; | ||
|
||
import {Utils} from "./Utils.sol"; | ||
|
||
contract OpReceiverProxy is Utils { | ||
// Errors | ||
|
||
error Unauthorized(); | ||
|
||
// Constants | ||
|
||
address public constant OP_GATEWAY = | ||
0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1; | ||
|
||
uint32 public immutable SENDER_CHAIN_ID; | ||
address public immutable HYPERLANE_MAILBOX; | ||
|
||
// Public fields | ||
|
||
address public opSenderProxy; | ||
mapping(uint256 => bool) public idWasUsed; | ||
mapping(address => uint256) public balances; | ||
|
||
// Constructor | ||
|
||
constructor( | ||
uint32 _senderChainId, | ||
address _hyperlaneMailbox, | ||
address _opSenderProxy | ||
) { | ||
SENDER_CHAIN_ID = _senderChainId; | ||
HYPERLANE_MAILBOX = _hyperlaneMailbox; | ||
|
||
opSenderProxy = _opSenderProxy; | ||
} | ||
|
||
// Public methods | ||
|
||
function handle( | ||
uint32 senderChainId, | ||
bytes32 senderAddress, | ||
bytes calldata data | ||
) external { | ||
// Only `HYPERLANE_MAILBOX` is authorized to call this method | ||
if (msg.sender != HYPERLANE_MAILBOX) { | ||
revert Unauthorized(); | ||
} | ||
|
||
// The sender chain must be `SENDER_CHAIN_ID` | ||
if (senderChainId != SENDER_CHAIN_ID) { | ||
revert Unauthorized(); | ||
} | ||
|
||
// The sender address must be `opSenderProxy` | ||
if (senderAddress != bytes32(uint256(uint160(opSenderProxy)))) { | ||
revert Unauthorized(); | ||
} | ||
|
||
(uint256 id, address to, uint256 amount) = abi.decode( | ||
data, | ||
(uint256, address, uint256) | ||
); | ||
|
||
// If the parsed id was not already used then we simply forward the received funds to the parsed recipient | ||
if (!idWasUsed[id]) { | ||
// TODO: Also charge fees | ||
_send(to, amount); | ||
|
||
// Mark the id as being used | ||
idWasUsed[id] = true; | ||
} | ||
} | ||
|
||
receive() external payable {} | ||
|
||
fallback() external payable { | ||
// Only `OP_GATEWAY` is authorized to call this | ||
if (msg.sender != OP_GATEWAY) { | ||
revert Unauthorized(); | ||
} | ||
|
||
(uint256 id, address to) = abi.decode(msg.data, (uint256, address)); | ||
|
||
// If the parsed id was not already used then we simply forward the received funds to the parsed recipient | ||
if (!idWasUsed[id]) { | ||
_send(to, msg.value); | ||
|
||
// Mark the id as being used | ||
idWasUsed[id] = true; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.28; | ||
|
||
import {IHyperlaneMailbox} from "./interfaces/IHyperlaneMailbox.sol"; | ||
import {IOpBridge} from "./interfaces/IOpBridge.sol"; | ||
|
||
import {Utils} from "./Utils.sol"; | ||
|
||
contract OpSenderProxy is Utils { | ||
// Constants | ||
|
||
IOpBridge public constant OP_BRIDGE = | ||
IOpBridge(0x4200000000000000000000000000000000000010); | ||
|
||
uint32 public immutable RECEIVER_CHAIN_ID; | ||
address public immutable HYPERLANE_MAILBOX; | ||
|
||
// Public fields | ||
|
||
address public opReceiverProxy; | ||
uint256 public nextId; | ||
|
||
// Constructor | ||
|
||
constructor( | ||
uint32 _receiverChainId, | ||
address _hyperlaneMailbox, | ||
address _opReceiverProxy | ||
) { | ||
RECEIVER_CHAIN_ID = _receiverChainId; | ||
HYPERLANE_MAILBOX = _hyperlaneMailbox; | ||
|
||
opReceiverProxy = _opReceiverProxy; | ||
} | ||
|
||
// Public methods | ||
|
||
function withdraw(uint256 amount, address to) external payable { | ||
// Associate the withdrawal to a unique id | ||
uint256 id = nextId++; | ||
|
||
// Endoce the data to be passed to the receiver chain | ||
bytes memory data = abi.encode(id, to, amount); | ||
|
||
// Trigger a canonical withdrawal to the `opReceiverProxy` contract | ||
OP_BRIDGE.withdrawTo( | ||
0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000, | ||
opReceiverProxy, | ||
amount, | ||
0, | ||
data | ||
); | ||
|
||
// Trigger a Hyperlane cross-chain message to the `opReceiverProxy` contract | ||
IHyperlaneMailbox(HYPERLANE_MAILBOX).dispatch{ | ||
value: IHyperlaneMailbox(HYPERLANE_MAILBOX).quoteDispatch( | ||
RECEIVER_CHAIN_ID, | ||
bytes32(uint256(uint160(opReceiverProxy))), | ||
data | ||
) | ||
}(RECEIVER_CHAIN_ID, bytes32(uint256(uint160(opReceiverProxy))), data); | ||
|
||
// Refund any ETH leftover back to the caller | ||
_send(msg.sender, address(this).balance); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.28; | ||
|
||
contract Utils { | ||
// Errors | ||
|
||
error NativeTransferFailed(); | ||
|
||
// Internal methods | ||
|
||
function _send(address to, uint256 value) internal { | ||
bool success; | ||
assembly { | ||
// Save gas by avoiding copying the return data to memory. | ||
// Provide at most 100k gas to the internal call, which is | ||
// more than enough to cover common use-cases of logic for | ||
// receiving native tokens (eg. SCW payable fallbacks). | ||
success := call(100000, to, value, 0, 0, 0, 0) | ||
} | ||
|
||
if (!success) { | ||
revert NativeTransferFailed(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.28; | ||
|
||
interface IHyperlaneMailbox { | ||
function dispatch( | ||
uint32 receiverChainId, | ||
bytes32 receiverAddress, | ||
bytes calldata data | ||
) external payable returns (bytes32 id); | ||
|
||
function quoteDispatch( | ||
uint32 receiverChainId, | ||
bytes32 receiverAddress, | ||
bytes calldata data | ||
) external returns (uint256 fee); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.28; | ||
|
||
interface IOpBridge { | ||
function withdrawTo( | ||
address l2Token, | ||
address to, | ||
uint256 amount, | ||
uint32 minGasLimit, | ||
bytes calldata extraData | ||
) external payable; | ||
} |
This file was deleted.
Oops, something went wrong.