Skip to content

Commit 793e700

Browse files
pnowosiekmazurek
andauthored
zksync driver deposit (enter CLI command) (#1208)
* Set up goth integration tests Adds files necessary for running goth tests as part of yagna repository. This also includes moving the VM E2E test from goth to yagna. * Add dev-dependencies for goth tests * Add --config-override option to goth tests * Add VM test assets directory * Include upload dir in VM assets * add deposit as in the std example * token needs to be approved before deposit * feat: enter command * feat: signing transactions works * [after review] Gert-Jan comments * [after review] Gert-Jan suggestions /2 * [after review] Adam comments * Adam's comments /2 * Add e2e WASI integration test * Add ya-provider multi-activity integration test * Add payments integration tests * Specify goth patch version explicitly * Update poetry.lock * Add integration tests readme * Review: update integration tests readme * Review: make config_overrides non-optional * Review: move task packages to activity helpers module Co-authored-by: Kuba Mazurek <[email protected]>
1 parent 9ced270 commit 793e700

File tree

10 files changed

+225
-32
lines changed

10 files changed

+225
-32
lines changed

.env-template

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@ YAGNA_DATADIR="."
3737
#ACCOUNT_LIST="${YAGNA_DATADIR}/accounts.json"
3838
#PAYMENT_SHUTDOWN_TIMEOUT_SECS=10
3939

40+
## All drivers
41+
#RINKEBY_GETH_ADDR=http://1.geth.testnet.golem.network:55555
42+
#MAINNET_GETH_ADDR=https://geth.golem.network:55555
43+
4044
## ERC20 driver.
4145
#ETH_FAUCET_ADDRESS=http://faucet.testnet.golem.network:4000/donate
42-
#ERC20_RINKEBY_GETH_ADDR=http://1.geth.testnet.golem.network:55555
43-
#ERC20_MAINNET_GETH_ADDR=https://geth.golem.network:55555
4446
#ERC20_RINKEBY_REQUIRED_CONFIRMATIONS=3
4547
#ERC20_MAINNET_REQUIRED_CONFIRMATIONS=5
4648
#RINKEBY_TGLM_CONTRACT_ADDRESS=0xd94e3DC39d4Cad1DAd634e7eb585A57A19dC7EFE
@@ -52,6 +54,7 @@ YAGNA_DATADIR="."
5254
## ZkSync driver
5355
#ZKSYNC_RINKEBY_RPC_ADDRESS=https://rinkeby-api.zksync.io/jsrpc
5456
#ZKSYNC_MAINNET_RPC_ADDRESS=https://api.zksync.io/jsrpc
57+
#ZKSYNC_ETH_CONFIRMATION_TIMEOUT_SECONDS=60
5558
#ZKSYNC_FAUCET_ADDR=
5659
#ZKSYNC_SENDOUT_INTERVAL_SECS=10
5760
#ZKSYNC_CONFIRMATION_INTERVAL_SECS=5

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/model/src/driver.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -332,10 +332,10 @@ impl RpcMessage for ValidateAllocation {
332332

333333
#[derive(Clone, Debug, Serialize, Deserialize)]
334334
pub struct Enter {
335-
amount: BigDecimal,
336-
address: String,
337-
network: Option<String>,
338-
token: Option<String>,
335+
pub amount: BigDecimal,
336+
pub address: String,
337+
pub network: Option<String>,
338+
pub token: Option<String>,
339339
}
340340

341341
impl Enter {

core/payment-driver/erc20/src/erc20/ethereum.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,9 @@ pub async fn get_tx_receipt(
195195

196196
fn get_rpc_addr_from_env(network: Network) -> String {
197197
match network {
198-
Network::Mainnet => std::env::var("ERC20_MAINNET_GETH_ADDR")
198+
Network::Mainnet => std::env::var("MAINNET_GETH_ADDR")
199199
.unwrap_or("https://geth.golem.network:55555".to_string()),
200-
Network::Rinkeby => std::env::var("ERC20_RINKEBY_GETH_ADDR")
200+
Network::Rinkeby => std::env::var("RINKEBY_GETH_ADDR")
201201
.unwrap_or("http://geth.testnet.golem.network:55555".to_string()),
202202
}
203203
}

core/payment-driver/zksync/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ log = "0.4.8"
2020
maplit = "1.0"
2121
metrics-macros = "=0.1.0-alpha.5"
2222
num-bigint = { version = "0.3", features = ["serde"] }
23+
rlp = "0.4"
2324
serde = "1.0"
2425
serde_json = "^1.0"
2526
tiny-keccak = "1.4.2"
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#[macro_use]
2+
extern crate log;
3+
4+
use bigdecimal::BigDecimal;
5+
use std::str::FromStr;
6+
use ya_payment_driver::db::models::Network as DbNetwork;
7+
use ya_zksync_driver::zksync::wallet as driver_wallet;
8+
use zksync::zksync_types::H256;
9+
use zksync::{Network, RpcProvider, Wallet, WalletCredentials};
10+
use zksync_eth_signer::{EthereumSigner, PrivateKeySigner};
11+
12+
const PRIVATE_KEY: &str = "e0c704b6e925c3be222337f9c94610c46b7fec95c14b8f5b9800d20ed4782670";
13+
14+
#[actix_rt::main]
15+
async fn main() -> anyhow::Result<()> {
16+
let log_level = std::env::var("RUST_LOG").unwrap_or("info".to_owned());
17+
std::env::set_var("RUST_LOG", log_level);
18+
env_logger::init();
19+
20+
dotenv::dotenv().expect("Failed to read .env file");
21+
22+
let private_key = H256::from_str(PRIVATE_KEY).expect("Cannot decode bytes from hex-encoded PK");
23+
let signer = PrivateKeySigner::new(private_key);
24+
let address = signer.get_address().await?;
25+
info!("Account address {:#x}", address);
26+
27+
info!("Creating wallet");
28+
let provider = RpcProvider::new(Network::Rinkeby);
29+
let cred = WalletCredentials::from_eth_signer(address, signer, Network::Rinkeby).await?;
30+
let wallet = Wallet::new(provider, cred).await?;
31+
32+
let one_tglm = BigDecimal::from(1);
33+
34+
let deposit_tx_hash = driver_wallet::deposit(wallet, DbNetwork::Rinkeby, one_tglm).await?;
35+
info!(
36+
"Check out deposit transaction at https://rinkeby.etherscan.io/tx/{:#x}",
37+
deposit_tx_hash
38+
);
39+
40+
Ok(())
41+
}

core/payment-driver/zksync/src/driver.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,14 @@ impl PaymentDriver for ZksyncDriver {
175175
_caller: String,
176176
msg: Enter,
177177
) -> Result<String, GenericError> {
178-
log::info!("ENTER = Not Implemented: {:?}", msg);
179-
Ok("NOT_IMPLEMENTED".to_string())
178+
let tx_hash = wallet::enter(msg).await?;
179+
180+
Ok(format!(
181+
"Deposit transaction has been sent on Ethereum and soon funds should be available \
182+
on ZkSync network. You can check transaction status in the block explorer. \
183+
Tracking link: https://rinkeby.zkscan.io/explorer/transactions/{}",
184+
tx_hash
185+
))
180186
}
181187

182188
async fn exit(

core/payment-driver/zksync/src/zksync/signer.rs

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// External uses
1010
use async_trait::async_trait;
1111
use futures::{Future, FutureExt};
12+
use rlp::RlpStream;
1213
use std::pin::Pin;
1314
use tiny_keccak::keccak256;
1415
use tokio::task;
@@ -56,9 +57,16 @@ impl EthereumSigner for YagnaEthSigner {
5657
Ok(tx_eth_sig)
5758
}
5859

59-
async fn sign_transaction(&self, _raw_tx: RawTransaction) -> Result<Vec<u8>, SignerError> {
60+
async fn sign_transaction(&self, raw_tx: RawTransaction) -> Result<Vec<u8>, SignerError> {
6061
log::debug!("YagnaEthSigner sign_transaction");
61-
todo!();
62+
63+
let node_id = self.eth_address.as_bytes().into();
64+
let payload: Vec<u8> = raw_tx.hash().into();
65+
let chain_id = raw_tx.chain_id as u64;
66+
67+
let signature = sign_tx(node_id, payload.clone()).await?;
68+
69+
Ok(encode_signed_tx(&raw_tx, signature, chain_id))
6270
}
6371
}
6472

@@ -105,3 +113,56 @@ fn sign_tx(
105113
});
106114
Box::pin(fut)
107115
}
116+
117+
fn encode_signed_tx(raw_tx: &RawTransaction, signature: Vec<u8>, chain_id: u64) -> Vec<u8> {
118+
let (sig_v, sig_r, sig_s) = prepare_signature(signature, chain_id);
119+
120+
let mut tx = RlpStream::new();
121+
122+
tx.begin_unbounded_list();
123+
124+
tx_encode(&raw_tx, &mut tx);
125+
tx.append(&sig_v);
126+
tx.append(&sig_r);
127+
tx.append(&sig_s);
128+
129+
tx.finalize_unbounded_list();
130+
131+
tx.out()
132+
}
133+
134+
fn prepare_signature(signature: Vec<u8>, chain_id: u64) -> (u64, Vec<u8>, Vec<u8>) {
135+
// TODO ugly solution
136+
assert_eq!(signature.len(), 65);
137+
138+
let sig_v = signature[0];
139+
let sig_v = sig_v as u64 + chain_id * 2 + 35;
140+
141+
let mut sig_r = signature.to_owned().split_off(1);
142+
let mut sig_s = sig_r.split_off(32);
143+
144+
prepare_signature_part(&mut sig_r);
145+
prepare_signature_part(&mut sig_s);
146+
147+
(sig_v, sig_r, sig_s)
148+
}
149+
150+
fn prepare_signature_part(part: &mut Vec<u8>) {
151+
assert_eq!(part.len(), 32);
152+
while part[0] == 0 {
153+
part.remove(0);
154+
}
155+
}
156+
157+
fn tx_encode(tx: &RawTransaction, s: &mut RlpStream) {
158+
s.append(&tx.nonce);
159+
s.append(&tx.gas_price);
160+
s.append(&tx.gas);
161+
if let Some(ref t) = tx.to {
162+
s.append(t);
163+
} else {
164+
s.append(&vec![]);
165+
}
166+
s.append(&tx.value);
167+
s.append(&tx.data);
168+
}

core/payment-driver/zksync/src/zksync/wallet.rs

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use zksync::types::BlockStatus;
1212
use zksync::zksync_types::{
1313
tokens::{ChangePubKeyFeeType, ChangePubKeyFeeTypeArg},
1414
tx::TxHash,
15-
Address, Nonce, TxFeeTypes,
15+
Address, Nonce, TxFeeTypes, H256,
1616
};
1717
use zksync::{
1818
provider::{Provider, RpcProvider},
@@ -23,7 +23,8 @@ use zksync_eth_signer::EthereumSigner;
2323
// Workspace uses
2424
use ya_payment_driver::{
2525
db::models::Network,
26-
model::{AccountMode, Exit, GenericError, Init, PaymentDetails},
26+
model::{AccountMode, Enter, Exit, GenericError, Init, PaymentDetails},
27+
utils as base_utils,
2728
};
2829

2930
// Local uses
@@ -120,6 +121,16 @@ pub async fn exit(msg: &Exit) -> Result<String, GenericError> {
120121
}
121122
}
122123

124+
pub async fn enter(msg: Enter) -> Result<String, GenericError> {
125+
let network = msg.network.unwrap_or(DEFAULT_NETWORK.to_string());
126+
let network = Network::from_str(&network).map_err(|e| GenericError::new(e))?;
127+
let wallet = get_wallet(&msg.address, network).await?;
128+
129+
let tx_hash = deposit(wallet, network, msg.amount).await?;
130+
131+
Ok(hex::encode(tx_hash.as_fixed_bytes()))
132+
}
133+
123134
pub async fn get_tx_fee(address: &str, network: Network) -> Result<BigDecimal, GenericError> {
124135
let token = get_network_token(network, None);
125136
let wallet = get_wallet(&address, network).await?;
@@ -276,6 +287,21 @@ fn get_rpc_addr(network: Network) -> String {
276287
}
277288
}
278289

290+
fn get_ethereum_node_addr_from_env(network: Network) -> String {
291+
match network {
292+
Network::Mainnet => {
293+
env::var("MAINNET_GETH_ADDR").unwrap_or("https://geth.golem.network:55555".to_string())
294+
}
295+
Network::Rinkeby => env::var("RINKEBY_GETH_ADDR")
296+
.unwrap_or("http://geth.testnet.golem.network:55555".to_string()),
297+
}
298+
}
299+
300+
fn get_ethereum_confirmation_timeout() -> std::time::Duration {
301+
let value = std::env::var("ZKSYNC_ETH_CONFIRMATION_TIMEOUT_SECONDS").unwrap_or("60".to_owned());
302+
std::time::Duration::from_secs(value.parse::<u64>().unwrap())
303+
}
304+
279305
async fn get_wallet(
280306
address: &str,
281307
network: Network,
@@ -448,3 +474,57 @@ async fn get_unlock_fee<S: EthereumSigner + Clone, P: Provider + Clone>(
448474
.total_fee;
449475
Ok(unlock_fee)
450476
}
477+
478+
pub async fn deposit<S: EthereumSigner + Clone, P: Provider + Clone>(
479+
wallet: Wallet<S, P>,
480+
network: Network,
481+
amount: BigDecimal,
482+
) -> Result<H256, GenericError> {
483+
let token = get_network_token(network, None);
484+
let amount = base_utils::big_dec_to_u256(amount);
485+
let address = wallet.address();
486+
487+
log::info!(
488+
"Starting deposit into ZkSync network. Address {:#x}, amount: {} of {}",
489+
address,
490+
amount,
491+
token
492+
);
493+
494+
let mut ethereum = wallet
495+
.ethereum(get_ethereum_node_addr_from_env(network))
496+
.await
497+
.map_err(|err| GenericError::new(err))?;
498+
ethereum.set_confirmation_timeout(get_ethereum_confirmation_timeout());
499+
500+
if !ethereum
501+
.is_limited_erc20_deposit_approved(token.as_str(), amount)
502+
.await
503+
.unwrap()
504+
{
505+
let tx = ethereum
506+
.limited_approve_erc20_token_deposits(token.as_str(), amount)
507+
.await
508+
.map_err(|err| GenericError::new(err))?;
509+
info!(
510+
"Approve erc20 token for ZkSync deposit. Tx: https://rinkeby.etherscan.io/tx/{:#x}",
511+
tx
512+
);
513+
514+
ethereum
515+
.wait_for_tx(tx)
516+
.await
517+
.map_err(|err| GenericError::new(err))?;
518+
}
519+
520+
let deposit_tx_hash = ethereum
521+
.deposit(token.as_str(), amount, address)
522+
.await
523+
.map_err(|err| GenericError::new(err))?;
524+
info!(
525+
"Check out deposit transaction at https://rinkeby.etherscan.io/tx/{:#x}",
526+
deposit_tx_hash
527+
);
528+
529+
Ok(deposit_tx_hash)
530+
}

core/payment/src/cli.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,14 @@ pub enum PaymentCli {
4141
account: pay::AccountCli,
4242
},
4343

44-
// TODO: Uncomment when operation is supported by drivers
45-
// Enter {
46-
// #[structopt(flatten)]
47-
// account: AccountCli,
48-
// #[structopt(long)]
49-
// amount: String,
50-
// },
44+
/// Enter layer 2 (deposit funds to layer 2 network)
45+
Enter {
46+
#[structopt(flatten)]
47+
account: pay::AccountCli,
48+
#[structopt(long)]
49+
amount: String,
50+
},
51+
5152
/// Exit layer 2 (withdraw funds to Ethereum)
5253
Exit {
5354
#[structopt(flatten)]
@@ -215,17 +216,16 @@ impl PaymentCli {
215216
.await??,
216217
)
217218
}
218-
// TODO: Uncomment when operation is supported by drivers
219-
// PaymentCli::Enter {
220-
// account,
221-
// driver,
222-
// network,
223-
// amount
224-
// } => {
225-
// let address = resolve_address(account).await?;
226-
// let amount = BigDecimal::from_str(&amount)?;
227-
// CommandOutput::object(wallet::enter(amount, address, driver, network, token).await?)
228-
// }
219+
PaymentCli::Enter { account, amount } => CommandOutput::object(
220+
wallet::enter(
221+
BigDecimal::from_str(&amount)?,
222+
resolve_address(account.address()).await?,
223+
account.driver(),
224+
Some(account.network()),
225+
None,
226+
)
227+
.await?,
228+
),
229229
PaymentCli::Exit {
230230
account,
231231
to_address,

0 commit comments

Comments
 (0)