-
Notifications
You must be signed in to change notification settings - Fork 3
fix: migrate mailbox deprecations to bridgehub/nullifier paths #352
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 5 commits
107f73a
e218259
4469ed3
64f8ce8
f8f7d20
9c6fbc1
6df3a0b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -406,28 +406,29 @@ impl<S: EthereumSigner> EthereumProvider<S> { | |||||||||||||||||||||
| .base_cost(gas_limit, L1_TO_L2_GAS_PER_PUBDATA, Some(gas_price)) | ||||||||||||||||||||||
| .await | ||||||||||||||||||||||
| .map_err(|e| ClientError::NetworkError(e.to_string()))?; | ||||||||||||||||||||||
| let value = base_cost + operator_tip + l2_value; | ||||||||||||||||||||||
| let tx_data = self.client().encode_tx_data( | ||||||||||||||||||||||
| "requestL2Transaction", | ||||||||||||||||||||||
| ( | ||||||||||||||||||||||
| contract_address, | ||||||||||||||||||||||
| l2_value, | ||||||||||||||||||||||
| calldata, | ||||||||||||||||||||||
| gas_limit, | ||||||||||||||||||||||
| U256::from(L1_TO_L2_GAS_PER_PUBDATA), | ||||||||||||||||||||||
| factory_deps, | ||||||||||||||||||||||
| refund_recipient, | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| .into_tokens(), | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
| let mint_value = base_cost + operator_tip + l2_value; | ||||||||||||||||||||||
| let request_token = ethabi::Token::Tuple(vec![ | ||||||||||||||||||||||
| ethabi::Token::Address(self.client().sender_account()), | ||||||||||||||||||||||
| ethabi::Token::Address(contract_address), | ||||||||||||||||||||||
| ethabi::Token::Uint(mint_value), | ||||||||||||||||||||||
| ethabi::Token::Uint(l2_value), | ||||||||||||||||||||||
| ethabi::Token::Bytes(calldata), | ||||||||||||||||||||||
| ethabi::Token::Uint(gas_limit), | ||||||||||||||||||||||
| ethabi::Token::Uint(U256::from(L1_TO_L2_GAS_PER_PUBDATA)), | ||||||||||||||||||||||
| ethabi::Token::Array(factory_deps.into_iter().map(ethabi::Token::Bytes).collect()), | ||||||||||||||||||||||
| ethabi::Token::Address(refund_recipient), | ||||||||||||||||||||||
| ]); | ||||||||||||||||||||||
| let tx_data = self | ||||||||||||||||||||||
| .client() | ||||||||||||||||||||||
| .encode_tx_data("bridgehubRequestL2Transaction", vec![request_token]); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| let tx = self | ||||||||||||||||||||||
| .client() | ||||||||||||||||||||||
| .sign_prepared_tx( | ||||||||||||||||||||||
| tx_data, | ||||||||||||||||||||||
| Options::with(|f| { | ||||||||||||||||||||||
| f.gas = Some(U256::from(300000)); | ||||||||||||||||||||||
| f.value = Some(value); | ||||||||||||||||||||||
| f.value = Some(mint_value); | ||||||||||||||||||||||
| f.gas_price = Some(gas_price) | ||||||||||||||||||||||
| }), | ||||||||||||||||||||||
|
Comment on lines
429
to
433
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Suggested change
|
||||||||||||||||||||||
| ) | ||||||||||||||||||||||
|
|
@@ -535,7 +536,7 @@ impl<S: EthereumSigner> EthereumProvider<S> { | |||||||||||||||||||||
| ) | ||||||||||||||||||||||
| .await? | ||||||||||||||||||||||
| } else { | ||||||||||||||||||||||
| // TODO(EVM-571): This should be moved to the shared bridge, and the `requestL2Transaction` method | ||||||||||||||||||||||
| // TODO(EVM-571): This should be moved to the shared bridge end-to-end for deposit flows | ||||||||||||||||||||||
| let bridge_address = | ||||||||||||||||||||||
| bridge_address.unwrap_or(self.default_bridges.l1_erc20_default_bridge.unwrap()); | ||||||||||||||||||||||
| let contract_function = self | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -103,8 +103,14 @@ Input: 0xeb672419000000000000000000000000618263ce921f7dd5f4f40c29f6c524aaf97b9bb | |
| ``` | ||
|
|
||
| The deposit command has called the contract on address `0xa6B` (which is exactly the `CONTRACTS_DIAMOND_PROXY_ADDR` from | ||
| `deployL1.log`), and it has called the method `0xeb672419` - which is the `requestL2Transaction` from | ||
| [Mailbox.sol](https://github.com/matter-labs/era-contracts/blob/f06a58360a2b8e7129f64413998767ac169d1efd/ethereum/contracts/zksync/facets/Mailbox.sol#L220) | ||
| `deployL1.log`), and it has called the method `0xeb672419` - which is the legacy `requestL2Transaction` from | ||
| [Mailbox.sol](https://github.com/matter-labs/era-contracts/blob/f06a58360a2b8e7129f64413998767ac169d1efd/ethereum/contracts/zksync/facets/Mailbox.sol#L220). | ||
|
|
||
| Deprecation note: `requestL2Transaction` is deprecated. New integrations should use | ||
| `Bridgehub.requestL2TransactionDirect`. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The documentation mentions |
||
|
|
||
| Implementation note: some SDK/internal call paths expose this via a wrapper entrypoint | ||
| (e.g. `bridgehubRequestL2Transaction` on Hyperchain ABI), which ultimately maps to the Bridgehub flow. | ||
|
|
||
| #### Quick note on our L1 contracts | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,10 +18,18 @@ between system and user logs. | |
|
|
||
| ### Initiation | ||
|
|
||
| A new priority operation can be appended by calling the | ||
| [requestL2Transaction](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/contracts/ethereum/contracts/zksync/facets/Mailbox.sol#L236) | ||
| method on L1. This method will perform several checks for the transaction, making sure that it is processable and | ||
| provides enough fee to compensate the operator for this transaction. Then, this transaction will be | ||
| Historically, a new priority operation was appended by calling | ||
| [`requestL2Transaction`](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/contracts/ethereum/contracts/zksync/facets/Mailbox.sol#L236) | ||
| on Mailbox. | ||
|
|
||
| Deprecation note: `requestL2Transaction` is deprecated. New integrations should use | ||
| `Bridgehub.requestL2TransactionDirect`. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The documentation mentions |
||
|
|
||
| Implementation note: some SDK/internal call paths expose this via wrapper entrypoints | ||
| (such as `bridgehubRequestL2Transaction` on Hyperchain ABI), while preserving the same Bridgehub migration intent. | ||
|
|
||
| This flow performs several checks for the transaction, making sure that it is processable and provides enough fee to | ||
| compensate the operator. Then, this transaction is | ||
| [appended](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/contracts/ethereum/contracts/zksync/facets/Mailbox.sol#L369C1-L369C1) | ||
| to the priority queue. | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -6,7 +6,7 @@ use bitcoin::{ | |||||||||||||||||||||||||||||||||||||||||||||||||
| Address as BitcoinAddress, Amount, Network, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| use ethers::abi::{decode, ParamType}; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| use via_da_client::types::WITHDRAW_FUNC_SIG; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| use via_da_client::types::WITHDRAW_FUNC_SIGS; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| use via_verifier_types::withdrawal::WithdrawalRequest; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| use zksync_basic_types::{web3::keccak256, U256}; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| use zksync_types::{api::Log, Address}; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -35,7 +35,10 @@ pub fn parse_l2_withdrawal_message( | |||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| let func_selector_bytes = &l2_to_l1_message[0..4]; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if func_selector_bytes != _get_withdraw_function_selector() { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if !_get_supported_withdraw_function_selectors() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .iter() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .any(|selector| func_selector_bytes == selector) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return Err(anyhow::format_err!("Invalid message function selector.")); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -112,10 +115,15 @@ pub fn parse_l2_withdrawal_message( | |||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Get the withdrawal function selector. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| fn _get_withdraw_function_selector() -> Vec<u8> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let hash = keccak256(WITHDRAW_FUNC_SIG.as_bytes()); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| hash[0..4].to_vec() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Get all supported withdrawal function selectors. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| fn _get_supported_withdraw_function_selectors() -> Vec<Vec<u8>> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| WITHDRAW_FUNC_SIGS | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .iter() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .map(|sig| { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let hash = keccak256(sig.as_bytes()); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| hash[0..4].to_vec() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .collect() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| #[cfg(test)] | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -215,4 +223,50 @@ mod tests { | |||||||||||||||||||||||||||||||||||||||||||||||||
| assert_eq!(res.receiver, expected_receiver); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_eq!(res.amount, expected_amount); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| #[test] | ||||||||||||||||||||||||||||||||||||||||||||||||||
| fn test_parse_l2_withdrawal_message_accepts_nullifier_selector() { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let btc_bytes = b"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".to_vec(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let amount = U256::from("0000000000000000000000000000000000000000000000000de0b6b3a7640000"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let encoded_data = encode(&[Token::Bytes(btc_bytes.clone()), Token::Uint(amount.clone())]); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let data = Bytes::from(encoded_data); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| let log = Log { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| block_timestamp: None, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| l1_batch_number: Some(U64::one()), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| address: H160::random(), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| topics: vec![ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| H256::from_str( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "0x2d6ef0fc97a54b2a96a5f3c96e3e69dca5b8d5ef4f68f01472c9e7c2b8d1f17b", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .unwrap(), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| H256::from_str( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "0x000000000000000000000000aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .unwrap(), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||||
| data, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| block_hash: None, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| block_number: Some(U64::one()), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| transaction_hash: Some(H256::zero()), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| transaction_index: None, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| log_index: Some(U256::zero()), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| transaction_log_index: Some(U256::zero()), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| log_type: None, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| removed: None, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| let mut l2_to_l1_message = hex::decode("6c0960f93141317a5031655035514765666932444d505466544c35534c6d7637446976664e610000000000000000000000000000000000000000000000000de0b6b3a7640000").unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let supported_selectors = _get_supported_withdraw_function_selectors(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| l2_to_l1_message[0..4].copy_from_slice(&supported_selectors[1]); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| let expected_receiver = BitcoinAddress::from_str("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .unwrap() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .assume_checked(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let expected_amount = Amount::from_sat(1000000000000000000); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let res = parse_l2_withdrawal_message(l2_to_l1_message, log, Network::Bitcoin).unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_eq!(res.receiver, expected_receiver); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_eq!(res.amount, expected_amount); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| let mut l2_to_l1_message = hex::decode("6c0960f93141317a5031655035514765666932444d505466544c35534c6d7637446976664e610000000000000000000000000000000000000000000000000de0b6b3a7640000").unwrap(); | |
| let supported_selectors = _get_supported_withdraw_function_selectors(); | |
| l2_to_l1_message[0..4].copy_from_slice(&supported_selectors[1]); | |
| let expected_receiver = BitcoinAddress::from_str("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa") | |
| .unwrap() | |
| .assume_checked(); | |
| let expected_amount = Amount::from_sat(1000000000000000000); | |
| let res = parse_l2_withdrawal_message(l2_to_l1_message, log, Network::Bitcoin).unwrap(); | |
| assert_eq!(res.receiver, expected_receiver); | |
| assert_eq!(res.amount, expected_amount); | |
| let mut l2_to_l1_message = hex::decode("6c0960f93141317a5031655035514765666932444d505466544c35534c6d7637446976664e610000000000000000000000000000000000000000000000000000000005f5e100").unwrap(); | |
| let supported_selectors = _get_supported_withdraw_function_selectors(); | |
| l2_to_l1_message[0..4].copy_from_slice(&supported_selectors[1]); | |
| let expected_receiver = BitcoinAddress::from_str("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa") | |
| .unwrap() | |
| .assume_checked(); | |
| let expected_amount = Amount::from_sat(100000000); | |
| let res = parse_l2_withdrawal_message(l2_to_l1_message, log, Network::Bitcoin).unwrap(); | |
| assert_eq!(res.receiver, expected_receiver); | |
| assert_eq!(res.amount, expected_amount); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
f.valuefield is missing in theOptionsstruct. In the previous implementation,f.valuewas set to the total cost (base_cost + operator_tip + l2_value). Since this transaction initiates an L2 transaction that requires ETH for the base cost and value, omittingf.valuewill result in amsg.valueof 0, which will cause the transaction to fail on-chain as the contract expects the sent value to match themint_valueprovided in the request tuple.