Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
1 change: 1 addition & 0 deletions Cargo.lock

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

27 changes: 9 additions & 18 deletions shared/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ use alloy::{
consensus::Eip658Value,
hex,
network::EthereumWallet,
primitives::{Address, Bloom, Log, B256},
primitives::{Address, Bloom, Bytes, FixedBytes, Log, B256, U256},
providers::{
fillers::{
BlobGasFiller, ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller,
WalletFiller,
},
Identity, ProviderBuilder, RootProvider,
},
rpc::types::Block,
signers::local::PrivateKeySigner,
};
use async_trait::async_trait;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::{
collections::HashMap,
fmt::{Display, Formatter},
str::FromStr as _,
};
Expand Down Expand Up @@ -86,27 +86,18 @@ pub struct Receipt {
}

/// `PartialBlock` contains block transactions, event logs, and metadata
#[allow(missing_docs)]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
pub struct PartialBlock {
/// reference to the block that this partial block was built from
pub block_ref: BlockRef,
/// hash of the parent block
pub parent_hash: B256,
/// log data
pub logs: Vec<Log>,
}

/// Convert a block and its receipts to a `PartialBlock`
pub fn convert_block_to_partial_block(block: &Block, receipts: &[Receipt]) -> PartialBlock {
let filtered_logs: Vec<Log> =
receipts.iter().flat_map(|receipt| receipt.logs.clone()).collect();
PartialBlock {
block_ref: BlockRef {
number: block.header.number,
hash: block.header.hash,
timestamp: block.header.timestamp,
},
parent_hash: block.header.parent_hash,
logs: filtered_logs,
}
/// associated transaction hashes for each log
pub log_tx_hashes: Vec<FixedBytes<32>>,
/// auxiliary tx data for `InboxMessageDeliveredFromOrigin` events (mapped by seqNum)
pub log_txs: HashMap<U256, Bytes>,
Comment thread
jorgemmsilva marked this conversation as resolved.
Outdated
}

impl GetBlockRef for PartialBlock {
Expand Down
98 changes: 68 additions & 30 deletions shared/test-utils/src/nitro_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{chain_info::PRIVATE_KEY, docker::E2EProcess};
use alloy::{
consensus::{EthereumTxEnvelope, TxEip4844Variant},
network::TransactionBuilder,
primitives::{address, Address, Bytes, B256, U256},
primitives::{address, Address, Bytes, B256, U160, U256},
providers::{Provider, WalletProvider},
};
use contract_bindings::synd::{
Expand Down Expand Up @@ -126,6 +126,27 @@ pub struct NitroBlock {
pub timestamp: U256,
}

/// Computes the L2 alias of an L1 address.
///
/// When a contract on L1 sends a message to L2 via the Inbox, the sender address
/// on L2 is aliased by adding this offset. This prevents address collisions and
/// distinguishes L1-originated messages from native L2 messages.
///
/// The offset is: 0x1111000000000000000000000000000000001111
///
/// # Arguments
/// * `l1_address` - The original L1 address
///
/// # Returns
/// The aliased L2 address
const L1_TO_L2_ALIAS_OFFSET: Address = address!("0x1000000000000000000000000000000000000001");
pub fn apply_l1_to_l2_alias(l1_address: Address) -> Address {
Comment thread
jorgemmsilva marked this conversation as resolved.
Address::from(
U160::from_be_slice(&l1_address[..])
.wrapping_add(U160::from_be_slice(&L1_TO_L2_ALIAS_OFFSET[..])),
)
}

pub async fn init_withdrawal_tx(
to_address: Address,
withdrawal_value: U256,
Expand All @@ -147,51 +168,68 @@ pub async fn init_withdrawal_tx(
Ok(tx)
}

pub async fn execute_withdrawal(
to_address: Address,
withdrawal_value: U256,
bridge_address: Address,
settlement_provider: &FilledProvider,
appchain_provider: &FilledProvider,
) -> eyre::Result<()> {
pub struct ExecuteWithdrawalParams<'a> {
pub to_address: Address,
pub withdrawal_value: U256,
pub appchain_block_hash_to_prove: B256,
pub bridge_address: Address,
pub settlement_provider: &'a FilledProvider,
pub appchain_provider: &'a FilledProvider,
pub l2_sender: Address,
pub send_root_size: u64,
pub withdrawal_position: u64,
}

pub async fn execute_withdrawal(params: ExecuteWithdrawalParams<'_>) {
// Generate proof
let node_interface = NodeInterface::new(NODE_INTERFACE_PRECOMPILE_ADDRESS, &appchain_provider);
let proof = node_interface.constructOutboxProof(1, 0).call().await?;
let node_interface =
NodeInterface::new(NODE_INTERFACE_PRECOMPILE_ADDRESS, &params.appchain_provider);
let proof = node_interface
.constructOutboxProof(params.send_root_size, params.withdrawal_position)
.call()
.await
.unwrap();

// Execute withdrawal
let bridge = IBridge::new(bridge_address, &settlement_provider);
let bridge = IBridge::new(params.bridge_address, &params.settlement_provider);
let outbox = IOutbox::new(
IRollupCore::new(bridge.rollup().call().await?, &settlement_provider)
IRollupCore::new(bridge.rollup().call().await.unwrap(), &params.settlement_provider)
.outbox()
.call()
.await?,
&settlement_provider,
.await
.unwrap(),
&params.settlement_provider,
);

let block: NitroBlock =
appchain_provider.raw_request("eth_getBlockByNumber".into(), ("latest", false)).await?;
let block: NitroBlock = params
.appchain_provider
.raw_request("eth_getBlockByHash".into(), (params.appchain_block_hash_to_prove, false))
.await
.unwrap();

let _ = outbox
.executeTransaction(
proof.proof, // proof
U256::from(0), // index
settlement_provider.default_signer_address(), // l2Sender
to_address, // to
block.number, // l2Block,
block.l1_block_number, // l1Block,
block.timestamp, // l2Timestamp,
withdrawal_value, // value
Bytes::new(), // data (always empty)
proof.proof, // proof
U256::from(params.withdrawal_position), // index
params.l2_sender, // l2Sender
params.to_address, // to
block.number, // l2Block,
block.l1_block_number, // l1Block,
block.timestamp, // l2Timestamp,
params.withdrawal_value, // value
Bytes::new(), // data (always empty)
)
// NOTE: manually setting the nonce shouldn't be necessary, likey an artifact of: https://github.com/alloy-rs/alloy/issues/2668
Comment thread
jorgemmsilva marked this conversation as resolved.
Outdated
.nonce(
settlement_provider
.get_transaction_count(settlement_provider.default_signer_address())
.await?,
params
.settlement_provider
.get_transaction_count(params.settlement_provider.default_signer_address())
.await
.unwrap(),
)
.send()
.await?;
Ok(())
.await
.unwrap();
}

#[allow(dead_code)]
Expand Down
1 change: 1 addition & 0 deletions synd-chain-ingestor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ version.workspace = true
[dependencies]
alloy = { workspace = true, features = ["provider-ws"] }
clap = { workspace = true, features = ["derive", "env"] }
contract-bindings = { workspace = true }
derivative = { workspace = true }
eyre = { workspace = true }
fs2 = { workspace = true }
Expand Down
Loading
Loading