-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(bridge-withdrawer): PoC astria-bridge-withdrawer implementation (#…
…984) ## Summary implement `ethereum` and `submitter` modules for astria-bridge-withdrawer. ## Background required to implement rollup bridge withdrawals. ## Changes ethereum: - implement `AstriaWithdrawer.sol` contract, put inside `ethereum/` dir as a foundry project - implement `ethereum` module which contains a `Watcher` that watches the contract for `Withdrawal` events - implement event to action conversion - the events are sent to a `Batcher` which batches all events by block number and sends a batch of actions to a sequencer handler sequencer: - submit txs to sequencer when a batch of actions is received ## Testing unit tests manual testing: 1. run sequencer+cometbft as normal (`just run` + `just run-cometbft` in astria-sequencer) 2. run anvil as normal (`anvil` in a terminal) 3. init the bridge account: ```sh export SEQUENCER_PRIVATE_KEY=2bd806c97f0e00af1a1fc3328fa763a9269723c8db8fac4f93af71db186d6e90 ./target/debug/astria-cli sequencer init-bridge-account --sequencer-url=http://localhost:26657 --rollup-name=astria --sequencer.chain-id=astria ``` 4. `just copy-env` in `astria-bridge-withdrawer`, put the private key from above into a file, update .env to use that 5. go to `astria-bridge-withdrawer/ethereum`, `cp local.env.example .env` 6. deploy the withdrawer contract: ```sh source .env forge create --rpc-url $RPC_URL --private-key $PRIVATE_KEY src/AstriaWithdrawer.sol:AstriaWithdrawer ``` 7. run this twice, makes 2 withdrawals (forces anvil to make 2 blocks) note: the withdrawer will only submit the withdraw for the first tx, as it's waiting for the next block before submitting the second and anvil doesn't auto-build blocks by default ```sh forge script script/AstriaWithdrawer.s.sol:AstriaWithdrawerScript \ --rpc-url $RPC_URL --broadcast --sig "withdrawToSequencer()" -vvvv ``` 8. in `astria-bridge-withdrawer`, update `ASTRIA_BRIDGE_WITHDRAWER_ETHEREUM_CONTRACT_ADDRESS` to be the contract address deployed in step 6. 9. `just run` and you should see a withdrawal being submitted: ```sh 2024-05-24T19:36:22.952210Z DEBUG astria_bridge_withdrawer::withdrawer::submitter: fetched latest nonce nonce=1 2024-05-24T19:36:23.003380Z DEBUG astria_bridge_withdrawer::withdrawer::submitter: signed transaction tx_hash=faad567d4f71ba20bdd9a1f679c4c3875c4b172c96d236155d52eb7ca02cd389 2024-05-24T19:36:23.003742Z DEBUG submit_tx: astria_bridge_withdrawer::withdrawer::submitter: submitting signed transaction to sequencer nonce=1 transaction.hash=faad567d4f71ba20bdd9a1f679c4c3875c4b172c96d236155d52eb7ca02cd389 2024-05-24T19:36:24.049943Z INFO astria_bridge_withdrawer::withdrawer::submitter: withdraw batch successfully executed. sequencer.block=881 sequencer.tx_hash=FAAD567D4F71BA20BDD9A1F679C4C3875C4B172C96D236155D52EB7CA02CD389 rollup.height=2 ``` ## Related Issues #913 closes #1109 --------- Co-authored-by: elizabeth <[email protected]> Co-authored-by: noot <[email protected]>
- Loading branch information
1 parent
d54b5bf
commit afe4901
Showing
37 changed files
with
2,450 additions
and
16 deletions.
There are no files selected for viewing
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 |
---|---|---|
|
@@ -115,7 +115,37 @@ jobs: | |
- name: Run tests | ||
timeout-minutes: 20 | ||
run: | | ||
cargo nextest run --archive-file=archive.tar.zst -- --include-ignored | ||
cargo nextest run --archive-file=archive.tar.zst | ||
rust-ethereum: | ||
runs-on: buildjet-8vcpu-ubuntu-2204 | ||
needs: run_checker | ||
if: needs.run_checker.outputs.run_tests == 'true' | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: dtolnay/[email protected] | ||
- uses: Swatinem/[email protected] | ||
with: | ||
cache-provider: "buildjet" | ||
- name: Install nextest | ||
uses: taiki-e/install-action@nextest | ||
- uses: arduino/setup-protoc@v3 | ||
with: | ||
version: "24.4" | ||
repo-token: ${{ secrets.GITHUB_TOKEN }} | ||
- name: Install python and solc | ||
uses: actions/setup-python@v5 | ||
with: | ||
python-version: '3.10' | ||
- name: Install Foundry | ||
uses: foundry-rs/foundry-toolchain@v1 | ||
- name: Run tests | ||
timeout-minutes: 20 | ||
run: | | ||
pip install solc-select | ||
solc-select install 0.8.21 | ||
solc-select use 0.8.21 | ||
cargo nextest run --package astria-bridge-withdrawer -- --include-ignored | ||
doctest: | ||
runs-on: buildjet-8vcpu-ubuntu-2204 | ||
|
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,3 @@ | ||
[submodule "crates/astria-bridge-withdrawer/ethereum/lib/forge-std"] | ||
path = crates/astria-bridge-withdrawer/ethereum/lib/forge-std | ||
url = https://github.com/foundry-rs/forge-std |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
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
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,55 @@ | ||
[package] | ||
name = "astria-bridge-withdrawer" | ||
version = "0.1.0" | ||
edition = "2021" | ||
rust-version = "1.73" | ||
license = "MIT OR Apache-2.0" | ||
readme = "README.md" | ||
repository = "https://github.com/astriaorg/astria" | ||
homepage = "https://astria.org" | ||
|
||
[[bin]] | ||
name = "astria-bridge-withdrawer" | ||
|
||
[dependencies] | ||
http = "0.2.9" | ||
|
||
axum = { workspace = true } | ||
futures = { workspace = true } | ||
hex = { workspace = true } | ||
ethers = { workspace = true, features = ["ethers-solc", "ws"] } | ||
hyper = { workspace = true } | ||
humantime = { workspace = true } | ||
ibc-types = { workspace = true } | ||
metrics = { workspace = true } | ||
pin-project-lite = { workspace = true } | ||
prost = { workspace = true } | ||
serde = { workspace = true, features = ["derive"] } | ||
serde_json = { workspace = true } | ||
sha2 = { workspace = true } | ||
tendermint = { workspace = true } | ||
tracing = { workspace = true } | ||
tryhard = { workspace = true } | ||
tokio = { workspace = true, features = ["macros", "rt-multi-thread", "signal"] } | ||
tokio-util = { workspace = true } | ||
|
||
astria-build-info = { path = "../astria-build-info", features = ["runtime"] } | ||
astria-core = { path = "../astria-core", features = ["serde", "server"] } | ||
astria-eyre = { path = "../astria-eyre" } | ||
config = { package = "astria-config", path = "../astria-config" } | ||
sequencer-client = { package = "astria-sequencer-client", path = "../astria-sequencer-client", features = [ | ||
"http", | ||
] } | ||
telemetry = { package = "astria-telemetry", path = "../astria-telemetry", features = [ | ||
"display", | ||
] } | ||
|
||
[dev-dependencies] | ||
astria-core = { path = "../astria-core", features = ["server", "test-utils"] } | ||
astria-grpc-mock = { path = "../astria-grpc-mock" } | ||
config = { package = "astria-config", path = "../astria-config", features = [ | ||
"tests", | ||
] } | ||
|
||
[build-dependencies] | ||
astria-build-info = { path = "../astria-build-info", features = ["build"] } |
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,4 @@ | ||
fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
astria_build_info::emit("bridge-withdrawer-v")?; | ||
Ok(()) | ||
} |
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,14 @@ | ||
# Compiler files | ||
cache/ | ||
out/ | ||
|
||
# Ignores development broadcast logs | ||
!/broadcast | ||
/broadcast/*/31337/ | ||
/broadcast/**/dry-run/ | ||
|
||
# Docs | ||
docs/ | ||
|
||
# Dotenv file | ||
.env |
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,38 @@ | ||
# astria-bridge-withdrawer | ||
|
||
Forge project for the bridge withdrawer contract. | ||
|
||
Requirements: | ||
|
||
- foundry | ||
|
||
Build: | ||
|
||
```sh | ||
forge build | ||
``` | ||
|
||
Copy the example .env: `cp local.example.env .env` | ||
|
||
Put your private key in `.env` and `source .env`. | ||
|
||
Deploy `AstriaWithdrawer.sol`: | ||
|
||
```sh | ||
forge script script/AstriaWithdrawer.s.sol:AstriaWithdrawerScript \ | ||
--rpc-url $RPC_URL --broadcast --sig "deploy()" -vvvv | ||
``` | ||
|
||
Call `withdrawToSequencer` in `AstriaWithdrawer.sol`: | ||
|
||
```sh | ||
forge script script/AstriaWithdrawer.s.sol:AstriaWithdrawerScript \ | ||
--rpc-url $RPC_URL --broadcast --sig "withdrawToSequencer()" -vvvv | ||
``` | ||
|
||
Call `withdrawToOriginChain` in `AstriaWithdrawer.sol`: | ||
|
||
```sh | ||
forge script script/AstriaWithdrawer.s.sol:AstriaWithdrawerScript \ | ||
--rpc-url $RPC_URL --broadcast --sig "withdrawToOriginChain()" -vvvv | ||
``` |
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,6 @@ | ||
[profile.default] | ||
src = "src" | ||
out = "out" | ||
libs = ["lib"] | ||
|
||
# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options |
20 changes: 20 additions & 0 deletions
20
crates/astria-bridge-withdrawer/ethereum/local.env.example
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,20 @@ | ||
# private key to submit txs with | ||
PRIVATE_KEY=0x | ||
|
||
# default local rpc url | ||
RPC_URL="http://localhost:8545" | ||
|
||
# divide withdrawn values by 10^ASSET_WITHDRAWAL_DECIMALS | ||
ASSET_WITHDRAWAL_DECIMALS=12 | ||
|
||
# contract address | ||
ASTRIA_WITHDRAWER=0x5FbDB2315678afecb367f032d93F642f64180aa3 | ||
|
||
# destination chain address to withdraw to on the sequencer | ||
SEQUENCER_DESTINATION_CHAIN_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 | ||
|
||
# destination chain address to withdraw to on the origin chain | ||
ORIGIN_DESTINATION_CHAIN_ADDRESS="astring" | ||
|
||
# amount to withdraw | ||
AMOUNT=1000000000 |
1 change: 1 addition & 0 deletions
1
crates/astria-bridge-withdrawer/ethereum/out/AstriaWithdrawer.sol/AstriaWithdrawer.json
Large diffs are not rendered by default.
Oops, something went wrong.
46 changes: 46 additions & 0 deletions
46
crates/astria-bridge-withdrawer/ethereum/script/AstriaWithdrawer.s.sol
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,46 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.13; | ||
|
||
import {Script, console} from "forge-std/Script.sol"; | ||
import {AstriaWithdrawer} from "../src/AstriaWithdrawer.sol"; | ||
|
||
contract AstriaWithdrawerScript is Script { | ||
function setUp() public {} | ||
|
||
function deploy() public { | ||
uint32 assetWithdrawalDecimals = uint32(vm.envUint("ASSET_WITHDRAWAL_DECIMALS")); | ||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); | ||
vm.startBroadcast(deployerPrivateKey); | ||
AstriaWithdrawer astriaWithdrawer = new AstriaWithdrawer(assetWithdrawalDecimals); | ||
console.logAddress(address(astriaWithdrawer)); | ||
vm.stopBroadcast(); | ||
} | ||
|
||
function withdrawToSequencer() public { | ||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); | ||
vm.startBroadcast(deployerPrivateKey); | ||
|
||
address contractAddress = vm.envAddress("ASTRIA_WITHDRAWER"); | ||
AstriaWithdrawer astriaWithdrawer = AstriaWithdrawer(contractAddress); | ||
|
||
address destinationChainAddress = vm.envAddress("SEQUENCER_DESTINATION_CHAIN_ADDRESS"); | ||
uint256 amount = vm.envUint("AMOUNT"); | ||
astriaWithdrawer.withdrawToSequencer{value: amount}(destinationChainAddress); | ||
|
||
vm.stopBroadcast(); | ||
} | ||
|
||
function withdrawToOriginChain() public { | ||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); | ||
vm.startBroadcast(deployerPrivateKey); | ||
|
||
address contractAddress = vm.envAddress("ASTRIA_WITHDRAWER"); | ||
AstriaWithdrawer astriaWithdrawer = AstriaWithdrawer(contractAddress); | ||
|
||
string memory destinationChainAddress = vm.envString("ORIGIN_DESTINATION_CHAIN_ADDRESS"); | ||
uint256 amount = vm.envUint("AMOUNT"); | ||
astriaWithdrawer.withdrawToOriginChain{value: amount}(destinationChainAddress, ""); | ||
|
||
vm.stopBroadcast(); | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
crates/astria-bridge-withdrawer/ethereum/src/AstriaWithdrawer.sol
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,41 @@ | ||
// SPDX-License-Identifier: MIT or Apache-2.0 | ||
pragma solidity ^0.8.21; | ||
|
||
// This contract facilitates withdrawals of the native asset from the rollup to the base chain. | ||
// | ||
// Funds can be withdrawn to either the sequencer or the origin chain via IBC. | ||
contract AstriaWithdrawer { | ||
// the number of decimal places more the asset has on the rollup versus the base chain. | ||
// | ||
// the amount transferred on the base chain will be divided by 10^ASSET_WITHDRAWAL_DECIMALS. | ||
// | ||
// for example, if the rollup specifies the asset has 18 decimal places and the base chain specifies 6, | ||
// the ASSET_WITHDRAWAL_DECIMALS would be 12. | ||
uint32 public immutable ASSET_WITHDRAWAL_DECIMALS; | ||
|
||
constructor(uint32 assetWithdrawalDecimals) { | ||
ASSET_WITHDRAWAL_DECIMALS = assetWithdrawalDecimals; | ||
} | ||
|
||
// emitted when a withdrawal to the sequencer is initiated | ||
// | ||
// the `sender` is the evm address that initiated the withdrawal | ||
// the `destinationChainAddress` is the address on the sequencer the funds will be sent to | ||
event SequencerWithdrawal(address indexed sender, uint256 indexed amount, address destinationChainAddress); | ||
|
||
// emitted when a withdrawal to the origin chain is initiated. | ||
// the withdrawal is sent to the origin chain via IBC from the sequencer using the denomination trace. | ||
// | ||
// the `sender` is the evm address that initiated the withdrawal | ||
// the `destinationChainAddress` is the address on the origin chain the funds will be sent to | ||
// the `memo` is an optional field that will be used as the ICS20 packet memo | ||
event Ics20Withdrawal(address indexed sender, uint256 indexed amount, string destinationChainAddress, string memo); | ||
|
||
function withdrawToSequencer(address destinationChainAddress) external payable { | ||
emit SequencerWithdrawal(msg.sender, msg.value, destinationChainAddress); | ||
} | ||
|
||
function withdrawToOriginChain(string calldata destinationChainAddress, string calldata memo) external payable { | ||
emit Ics20Withdrawal(msg.sender, msg.value, destinationChainAddress, memo); | ||
} | ||
} |
Oops, something went wrong.