Skip to content

feat(sdk): add function to withdraw erc20 tokens #162

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

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
9 changes: 5 additions & 4 deletions cli/src/commands/l2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,18 +364,19 @@ impl Command {
private_key,
rpc_url,
} => {
let from = get_address_from_secret_key(&private_key)?;

let client = EthClient::new(&rpc_url)?;

if explorer_url {
todo!("Display transaction URL in the explorer")
}

if token_address.is_some() {
// withdraw_erc20(..)
todo!("Handle ERC20 withdrawals")
}

let from = get_address_from_secret_key(&private_key)?;

let client = EthClient::new(&rpc_url)?;

let tx_hash = withdraw(amount, from, private_key, &client, nonce).await?;

println!("Withdrawal sent: {tx_hash:#x}");
Expand Down
5 changes: 5 additions & 0 deletions sdk/src/l2/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,9 @@ pub const COMMON_BRIDGE_L2_ADDRESS: Address = H160([

pub const L2_WITHDRAW_SIGNATURE: &str = "withdraw(address)";

pub const L2_WITHDRAW_SIGNATURE_ERC20: &str = "withdrawERC20(address,address,address,uint256)";

pub const CLAIM_WITHDRAWAL_ERC20_SIGNATURE: &str =
"claimWithdrawalERC20(address,address,uint256,uint256,uint256,bytes32[])";

// Function Selectors
90 changes: 88 additions & 2 deletions sdk/src/l2/withdraw.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
use crate::{
calldata::{Value, encode_calldata},
client::{EthClient, EthClientError, Overrides, eth::L1MessageProof},
client::{
EthClient, EthClientError, Overrides,
eth::{L1MessageProof, get_address_from_secret_key},
},
l2::{
constants::{COMMON_BRIDGE_L2_ADDRESS, L2_WITHDRAW_SIGNATURE},
constants::{
CLAIM_WITHDRAWAL_ERC20_SIGNATURE, COMMON_BRIDGE_L2_ADDRESS, L2_WITHDRAW_SIGNATURE,
L2_WITHDRAW_SIGNATURE_ERC20,
},
merkle_tree::merkle_proof,
},
};
Expand Down Expand Up @@ -42,6 +48,36 @@ pub async fn withdraw(
.await
}

pub async fn withdraw_erc20(
amount: U256,
from: Address,
from_pk: SecretKey,
token_l1: Address,
token_l2: Address,
l2_client: &EthClient,
) -> Result<H256, EthClientError> {
let data = [
Value::Address(token_l1),
Value::Address(token_l2),
Value::Address(from),
Value::Uint(amount),
];
let withdraw_data = encode_calldata(L2_WITHDRAW_SIGNATURE_ERC20, &data)
.expect("Failed to encode calldata for withdraw ERC20");
let withdraw_transaction = l2_client
.build_eip1559_transaction(
COMMON_BRIDGE_L2_ADDRESS,
from,
Bytes::from(withdraw_data),
Default::default(),
)
.await?;

l2_client
.send_eip1559_transaction(&withdraw_transaction, &from_pk)
.await
}

pub async fn claim_withdraw(
amount: U256,
from: Address,
Expand Down Expand Up @@ -92,6 +128,56 @@ pub async fn claim_withdraw(
.await
}

pub async fn claim_erc20withdraw(
token_l1: Address,
token_l2: Address,
amount: U256,
from_pk: SecretKey,
eth_client: &EthClient,
message_proof: &L1MessageProof,
bridge_address: Address,
) -> Result<H256, EthClientError> {
let from = get_address_from_secret_key(&from_pk)?;
let calldata_values = vec![
Value::Address(token_l1),
Value::Address(token_l2),
Value::Uint(amount),
Value::Uint(U256::from(message_proof.batch_number)),
Value::Uint(message_proof.message_id),
Value::Array(
message_proof
.merkle_proof
.iter()
.map(|v| Value::Uint(U256::from_big_endian(v.as_bytes())))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be FixedBytes

.collect(),
),
];

let claim_withdrawal_data =
encode_calldata(CLAIM_WITHDRAWAL_ERC20_SIGNATURE, &calldata_values)?;

println!(
"Claiming withdrawal with calldata: {}",
hex::encode(&claim_withdrawal_data)
);

let claim_tx = eth_client
.build_eip1559_transaction(
bridge_address,
from,
claim_withdrawal_data.into(),
Overrides {
from: Some(from),
..Default::default()
},
)
.await?;

eth_client
.send_eip1559_transaction(&claim_tx, &from_pk)
.await
}

/// Returns the formatted hash of the withdrawal transaction,
/// or None if the transaction is not a withdrawal.
/// The hash is computed as keccak256(to || value || tx_hash)
Expand Down
Loading