Skip to content

Commit 5f7bde7

Browse files
committed
feat: basic third-party bridge app
1 parent ff20708 commit 5f7bde7

File tree

15 files changed

+391
-25
lines changed

15 files changed

+391
-25
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@
77
[submodule "lib/zenith"]
88
path = lib/zenith
99
url = https://github.com/init4tech/zenith
10+
[submodule "lib/simple-erc20"]
11+
path = lib/simple-erc20
12+
url = https://github.com/init4tech/simple-erc20

foundry.lock

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
11
{
2-
"lib/zenith": {
3-
"tag": {
4-
"name": "v0.1.55",
5-
"rev": "914146a3904541192f2cb0906c0990cc6f90b1e3"
6-
}
7-
},
82
"lib/forge-std": {
93
"tag": {
104
"name": "v1.10.0",
@@ -16,5 +10,14 @@
1610
"name": "v5.4.0",
1711
"rev": "c64a1edb67b6e3f4a15cca8909c9482ad33a02b0"
1812
}
13+
},
14+
"lib/simple-erc20": {
15+
"rev": "f5c2597ec179ea13e219ccbca415dc59d5a33398"
16+
},
17+
"lib/zenith": {
18+
"tag": {
19+
"name": "v0.1.55",
20+
"rev": "914146a3904541192f2cb0906c0990cc6f90b1e3"
21+
}
1922
}
2023
}

lib/simple-erc20

Submodule simple-erc20 added at f5c2597

src/apps/bridge/BridgeL2.sol

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.13;
3+
4+
import {RollupOrders} from "zenith/src/orders/RollupOrders.sol";
5+
import {SimpleERC20} from "simple-erc20/SimpleERC20.sol";
6+
7+
import {SignetL2} from "../../l2/Signet.sol";
8+
9+
abstract contract BridgeL2 is SignetL2, SimpleERC20 {
10+
address immutable HOST_ASSET;
11+
address immutable HOST_BANK;
12+
13+
constructor(
14+
address _hostAsset,
15+
address _hostBank,
16+
address _initialOwner,
17+
string memory _name,
18+
string memory _symbol,
19+
uint8 _decimals
20+
) SimpleERC20(_initialOwner, _name, _symbol, _decimals) {
21+
HOST_ASSET = _hostAsset;
22+
HOST_BANK = _hostBank;
23+
}
24+
25+
function _bridgeIn(address recipient, uint256 amount, RollupOrders.Input[] memory inputs) internal virtual {
26+
RollupOrders.Output[] memory outputs = new RollupOrders.Output[](1);
27+
outputs[0] = makeHostOutput(HOST_ASSET, amount, HOST_BANK);
28+
29+
ORDERS.initiate(block.timestamp, inputs, outputs);
30+
31+
_mint(recipient, amount);
32+
}
33+
34+
function bridgeIn(address recipient, uint256 amount) public virtual {
35+
_bridgeIn(recipient, amount, new RollupOrders.Input[](0));
36+
}
37+
38+
function _bridgeOut(address recipient, uint256 amount, RollupOrders.Input[] memory inputs) internal virtual {
39+
RollupOrders.Output[] memory outputs = new RollupOrders.Output[](1);
40+
outputs[0] = makeHostOutput(HOST_ASSET, amount, recipient);
41+
42+
ORDERS.initiate(block.timestamp, inputs, outputs);
43+
44+
_burn(msg.sender, amount);
45+
}
46+
47+
function bridgeOut(address recipient, uint256 amount) public virtual {
48+
_bridgeOut(recipient, amount, new RollupOrders.Input[](0));
49+
}
50+
}

src/apps/lido/LidoL2.sol

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.13;
3+
4+
import {RollupOrders} from "zenith/src/orders/RollupOrders.sol";
5+
import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
6+
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
7+
8+
import {SignetL2} from "../../l2/Signet.sol";
9+
import {BurnMintERC20} from "../../vendor/BurnMintERC20.sol";
10+
11+
12+
contract LidoL2 is SignetL2(), BurnMintERC20 {
13+
using SafeERC20 for IERC20;
14+
15+
address public immutable HOST_WSTETH;
16+
17+
constructor(address _hostWsteth)
18+
BurnMintERC20("Signet Lido Staked Ether", "stETH", 18, 0, 0)
19+
{
20+
HOST_WSTETH = _hostWsteth;
21+
WETH.forceApprove(address(ORDERS), type(uint256).max);
22+
}
23+
24+
function _bridgeIn(address recipient, uint256 amount, RollupOrders.Input[] memory inputs) internal {
25+
RollupOrders.Output[] memory outputs = new RollupOrders.Output[](1);
26+
outputs[0] = makeHostOutput(HOST_WSTETH, amount, address(HOST_PASSAGE));
27+
28+
ORDERS.initiate(block.timestamp, inputs, outputs);
29+
30+
_mint(recipient, amount);
31+
}
32+
33+
function bridgeIn(address recipient, uint256 amount) external {
34+
_bridgeIn(recipient, amount, new RollupOrders.Input[](0));
35+
}
36+
37+
function bridgeOut(address recipient, uint256 amount) public {
38+
_burn(msg.sender, amount);
39+
40+
RollupOrders.Output[] memory outputs = new RollupOrders.Output[](1);
41+
outputs[0] = makeHostOutput(HOST_WSTETH, amount, recipient);
42+
43+
ORDERS.initiate(block.timestamp, new RollupOrders.Input[](0), outputs);
44+
}
45+
46+
function enter(address funder, uint256 amountIn, address recipient, uint256 amountOut) external {
47+
WETH.safeTransferFrom(funder, address(this), amountIn);
48+
49+
RollupOrders.Input[] memory inputs = new RollupOrders.Input[](1);
50+
inputs[0] = makeWethInput(amountIn);
51+
52+
_bridgeIn(recipient, amountOut, inputs);
53+
}
54+
}

src/chains/Pecorino.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ library PecorinoConstants {
2525
HostOrders constant HOST_ORDERS = HostOrders(0x0A4f505364De0Aa46c66b15aBae44eBa12ab0380);
2626

2727
/// @notice The Rollup Passage contract for the Pecorino testnet.
28-
RollupPassage constant PECORINO_ROLLUP_PASSAGE = RollupPassage(payable(0x0000000000007369676E65742D70617373616765));
28+
RollupPassage constant ROLLUP_PASSAGE = RollupPassage(payable(0x0000000000007369676E65742D70617373616765));
2929

3030
/// @notice The Rollup Orders contract for the Pecorino testnet.
31-
RollupOrders constant PECORINO_ROLLUP_ORDERS = RollupOrders(0x000000000000007369676E65742D6f7264657273);
31+
RollupOrders constant ROLLUP_ORDERS = RollupOrders(0x000000000000007369676E65742D6f7264657273);
3232

3333
/// USDC token for the Pecorino testnet host chain.
3434
address constant HOST_USDC = 0x65Fb255585458De1F9A246b476aa8d5C5516F6fd;

src/l2/SelfOwned.sol

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.13;
3+
4+
import {Ownable} from "openzeppelin-contracts/contracts/access/Ownable.sol";
5+
6+
import {SignetL2} from "./Signet.sol";
7+
8+
abstract contract SelfOwned is SignetL2(), Ownable {
9+
constructor() {
10+
Ownable(aliasedSelf());
11+
}
12+
}

src/l2/Signet.sol

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {RollupPassage} from "zenith/src/passage/RollupPassage.sol";
66
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
77

88
import {PecorinoConstants} from "../chains/Pecorino.sol";
9+
import {AddressAliasHelper} from "../vendor/AddressAliasHelper.sol";
910

1011
contract SignetL2 {
1112
/// @notice Sentinal value for the native asset in order inputs/outputs
@@ -19,6 +20,9 @@ contract SignetL2 {
1920
/// @notice The Rollup Orders contract.
2021
RollupOrders internal immutable ORDERS;
2122

23+
/// @notice The address of the Rollup Passage on the host network.
24+
address immutable HOST_PASSAGE;
25+
2226
/// @notice The WETH token address.
2327
IERC20 internal immutable WETH;
2428
/// @notice The WBTC token address.
@@ -43,8 +47,10 @@ contract SignetL2 {
4347
if (block.chainid == PecorinoConstants.ROLLUP_CHAIN_ID) {
4448
HOST_CHAIN_ID = PecorinoConstants.HOST_CHAIN_ID;
4549

46-
PASSAGE = PecorinoConstants.PECORINO_ROLLUP_PASSAGE;
47-
ORDERS = PecorinoConstants.PECORINO_ROLLUP_ORDERS;
50+
HOST_PASSAGE = address(PecorinoConstants.HOST_PASSAGE);
51+
52+
PASSAGE = PecorinoConstants.ROLLUP_PASSAGE;
53+
ORDERS = PecorinoConstants.ROLLUP_ORDERS;
4854

4955
WETH = PecorinoConstants.WETH;
5056
WBTC = PecorinoConstants.WBTC;
@@ -59,6 +65,12 @@ contract SignetL2 {
5965
}
6066
}
6167

68+
/// @notice Gets the aliased address of this contracat, representing itself
69+
/// on L1. Use with caustion.
70+
function aliasedSelf() internal view returns (address) {
71+
return AddressAliasHelper.applyL1ToL2Alias(address(this));
72+
}
73+
6274
/// @notice Creates an Input struct for the RollupOrders.
6375
/// @param token The address of the token.
6476
/// @param amount The amount of the token.
@@ -68,14 +80,24 @@ contract SignetL2 {
6880
input.amount = amount;
6981
}
7082

71-
/// @notice Creates an Input struct for the native asset (ETH).
83+
/// @notice Creates an Input struct for the native asset (USD).
7284
/// @param amount The amount of the native asset (in wei).
7385
/// @return input The created Input struct for the native asset.
74-
function makeEthInput(uint256 amount) internal pure returns (RollupOrders.Input memory input) {
86+
function makeUsdInput(uint256 amount) internal pure returns (RollupOrders.Input memory input) {
7587
input.token = address(0);
7688
input.amount = amount;
7789
}
7890

91+
function makeWethInput(uint256 amount) internal view returns (RollupOrders.Input memory input) {
92+
input.token = address(WETH);
93+
input.amount = amount;
94+
}
95+
96+
function makeWbtcInput(uint256 amount) internal view returns (RollupOrders.Input memory input) {
97+
input.token = address(WBTC);
98+
input.amount = amount;
99+
}
100+
79101
/// @notice Creates an Output struct for the RollupOrders.
80102
/// @param token The address of the token.
81103
/// @param amount The amount of the token.

src/l2/examples/GetOut.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ contract GetOut is SignetL2 {
3030
uint256 desired = msg.value * 995 / 1000; // 0.5% fee
3131

3232
RollupOrders.Input[] memory inputs = new RollupOrders.Input[](1);
33-
inputs[0] = makeEthInput(msg.value);
33+
inputs[0] = makeUsdInput(msg.value);
3434

3535
RollupOrders.Output[] memory outputs = new RollupOrders.Output[](1);
3636
outputs[0] = hostUsdcOutput(desired, msg.sender);

0 commit comments

Comments
 (0)