Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
crates/astria-core/src/generated/** linguist-generated=true
crates/astria-bridge-withdrawer/src/withdrawer/ethereum/generated/** linguist-generated=true
crates/astria-bridge-withdrawer/ethereum/out/** linguist-generated=true
specs/** linguist-documentation=true
7 changes: 0 additions & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,18 +133,11 @@ jobs:
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:
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[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
[submodule "crates/astria-bridge-withdrawer/ethereum/lib/openzeppelin-contracts"]
path = crates/astria-bridge-withdrawer/ethereum/lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
1 change: 1 addition & 0 deletions crates/astria-bridge-withdrawer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,4 @@ wiremock = { workspace = true }

[build-dependencies]
astria-build-info = { path = "../astria-build-info", features = ["build"] }
ethers = { workspace = true }
28 changes: 28 additions & 0 deletions crates/astria-bridge-withdrawer/build.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,32 @@
use ethers::contract::Abigen;

fn main() -> Result<(), Box<dyn std::error::Error>> {
astria_build_info::emit("bridge-withdrawer-v")?;

println!("cargo:rerun-if-changed=ethereum/src/AstriaWithdrawer.sol");
println!("cargo:rerun-if-changed=ethereum/src/IAstriaWithdrawer.sol");
println!("cargo:rerun-if-changed=ethereum/src/AstriaBridgeableERC20.sol");

Abigen::new(
"IAstriaWithdrawer",
"./ethereum/out/IAstriaWithdrawer.sol/IAstriaWithdrawer.json",
)?
.generate()?
.write_to_file("./src/withdrawer/ethereum/generated/astria_withdrawer_interface.rs")?;

Abigen::new(
"AstriaWithdrawer",
"./ethereum/out/AstriaWithdrawer.sol/AstriaWithdrawer.json",
)?
.generate()?
.write_to_file("./src/withdrawer/ethereum/generated/astria_withdrawer.rs")?;

Abigen::new(
"AstriaBridgeableERC20",
"./ethereum/out/AstriaBridgeableERC20.sol/AstriaBridgeableERC20.json",
)?
.generate()?
.write_to_file("./src/withdrawer/ethereum/generated/astria_bridgeable_erc20.rs")?;

Ok(())
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: MIT or Apache-2.0
pragma solidity ^0.8.21;

import {IAstriaWithdrawer} from "./IAstriaWithdrawer.sol";
import {ERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";

contract AstriaBridgeableERC20 is IAstriaWithdrawer, ERC20 {
// the `astriaBridgeSenderAddress` built into the astria-geth node
address public immutable BRIDGE;

// the divisor used to convert the rollup asset amount to the base chain denomination
//
// set to 10 ** (TOKEN_DECIMALS - BASE_CHAIN_ASSET_PRECISION) on contract creation
uint256 private immutable DIVISOR;

// emitted when tokens are minted from a deposit
event Mint(address indexed account, uint256 amount);

modifier onlyBridge() {
require(msg.sender == BRIDGE, "AstriaBridgeableERC20: only bridge can mint");
_;
}

constructor(
address _bridge,
uint32 _baseChainAssetPrecision,
string memory _name,
string memory _symbol
) ERC20(_name, _symbol) {
uint8 decimals = decimals();
if (_baseChainAssetPrecision > decimals) {
revert("AstriaBridgeableERC20: base chain asset precision must be less than or equal to token decimals");
}

BASE_CHAIN_ASSET_PRECISION = _baseChainAssetPrecision;
DIVISOR = 10 ** (decimals - _baseChainAssetPrecision);
BRIDGE = _bridge;
}

modifier sufficientValue(uint256 amount) {
require(amount / DIVISOR > 0, "AstriaBridgeableERC20: insufficient value, must be greater than 10 ** (TOKEN_DECIMALS - BASE_CHAIN_ASSET_PRECISION)");
_;
}

function mint(address _to, uint256 _amount)
external
onlyBridge
{
_mint(_to, _amount);
emit Mint(_to, _amount);
}

function withdrawToSequencer(uint256 _amount, address _destinationChainAddress)
external
sufficientValue(_amount)
{
_burn(msg.sender, _amount);
emit SequencerWithdrawal(msg.sender, _amount, _destinationChainAddress);
}

function withdrawToIbcChain(uint256 _amount, string calldata _destinationChainAddress, string calldata _memo)
external
sufficientValue(_amount)
{
_burn(msg.sender, _amount);
emit Ics20Withdrawal(msg.sender, _amount, _destinationChainAddress, _memo);
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
// SPDX-License-Identifier: MIT or Apache-2.0
pragma solidity ^0.8.21;

import {IAstriaWithdrawer} from "./IAstriaWithdrawer.sol";

// 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 precision of the asset on the base chain.
//
// the amount transferred on the base chain will be divided by 10 ^ (18 - BASE_CHAIN_ASSET_PRECISION).
//
// for example, if base chain asset is precision is 6, the divisor would be 10^12.
uint32 public immutable BASE_CHAIN_ASSET_PRECISION;

contract AstriaWithdrawer is IAstriaWithdrawer {
// the divisor used to convert the rollup asset amount to the base chain denomination
//
// set to 10^ASSET_WITHDRAWAL_DECIMALS on contract creation
// set to 10 ** (18 - BASE_CHAIN_ASSET_PRECISION) on contract creation
uint256 private immutable DIVISOR;

constructor(uint32 _baseChainAssetPrecision) {
Expand All @@ -25,20 +20,6 @@ contract AstriaWithdrawer {
DIVISOR = 10 ** (18 - _baseChainAssetPrecision);
}

// 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);

modifier sufficientValue(uint256 amount) {
require(amount / DIVISOR > 0, "AstriaWithdrawer: insufficient value, must be greater than 10 ** (18 - BASE_CHAIN_ASSET_PRECISION)");
_;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: MIT or Apache-2.0
pragma solidity ^0.8.21;

abstract contract IAstriaWithdrawer {
// the precision of the asset on the base chain.
//
// the amount transferred on the base chain will be divided by 10 ^ (18 - BASE_CHAIN_ASSET_PRECISION).
//
// for example, if base chain asset is precision is 6, the divisor would be 10^12.
uint32 public immutable BASE_CHAIN_ASSET_PRECISION;

// 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 IBC 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);
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use serde::{
Serialize,
};

use crate::withdrawer::ethereum::astria_withdrawer::{
use crate::withdrawer::ethereum::astria_withdrawer_interface::{
Ics20WithdrawalFilter,
SequencerWithdrawalFilter,
};
Expand Down Expand Up @@ -182,7 +182,7 @@ fn calculate_packet_timeout_time(timeout_delta: Duration) -> eyre::Result<u64> {
#[cfg(test)]
mod tests {
use super::*;
use crate::withdrawer::ethereum::astria_withdrawer::SequencerWithdrawalFilter;
use crate::withdrawer::ethereum::astria_withdrawer_interface::SequencerWithdrawalFilter;

#[test]
fn event_to_bridge_unlock() {
Expand Down
Loading