Skip to content

Commit

Permalink
feat(cli): add bridge withdraw command
Browse files Browse the repository at this point in the history
  • Loading branch information
zcabter committed Sep 6, 2024
1 parent 69a2dde commit 045203c
Show file tree
Hide file tree
Showing 9 changed files with 226 additions and 30 deletions.
50 changes: 38 additions & 12 deletions crates/jstz_cli/sandbox-params.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@
"delay_increment_per_round": "1",
"consensus_committee_size": 256,
"consensus_threshold": 0,
"minimal_participation_ratio": { "numerator": 2, "denominator": 3 },
"minimal_participation_ratio": {
"numerator": 2,
"denominator": 3
},
"limit_of_delegation_over_baking": 19,
"percentage_of_frozen_deposits_slashed_per_double_baking": 500,
"percentage_of_frozen_deposits_slashed_per_double_attestation": 5000,
Expand All @@ -62,18 +65,20 @@
},
"smart_rollup_arith_pvm_enable": false,
"smart_rollup_origination_size": 6314,
"smart_rollup_challenge_window_in_blocks": 120960,
"smart_rollup_challenge_window_in_blocks": 1,
"smart_rollup_stake_amount": "10000000000",
"smart_rollup_commitment_period_in_blocks": 90,
"smart_rollup_commitment_period_in_blocks": 5,
"smart_rollup_max_lookahead_in_blocks": 259200,
"smart_rollup_max_active_outbox_levels": 120960,
"smart_rollup_max_outbox_messages_per_level": 100,
"smart_rollup_number_of_sections_in_dissection": 32,
"smart_rollup_timeout_period_in_blocks": 60480,
"smart_rollup_max_number_of_cemented_commitments": 5,
"smart_rollup_max_number_of_cemented_commitments": 10000,
"smart_rollup_max_number_of_parallel_games": 32,
"smart_rollup_reveal_activation_level": {
"raw_data": { "Blake2B": 0 },
"raw_data": {
"Blake2B": 0
},
"metadata": 0,
"dal_page": 1,
"dal_parameters": 1,
Expand All @@ -89,16 +94,37 @@
"edge_of_staking_over_delegation": 2,
"adaptive_issuance_launch_ema_threshold": 0,
"adaptive_rewards_params": {
"issuance_ratio_final_min": { "numerator": "1", "denominator": "400" },
"issuance_ratio_final_max": { "numerator": "1", "denominator": "10" },
"issuance_ratio_initial_min": { "numerator": "9", "denominator": "200" },
"issuance_ratio_initial_max": { "numerator": "11", "denominator": "200" },
"issuance_ratio_final_min": {
"numerator": "1",
"denominator": "400"
},
"issuance_ratio_final_max": {
"numerator": "1",
"denominator": "10"
},
"issuance_ratio_initial_min": {
"numerator": "9",
"denominator": "200"
},
"issuance_ratio_initial_max": {
"numerator": "11",
"denominator": "200"
},
"initial_period": 10,
"transition_period": 50,
"max_bonus": "50000000000000",
"growth_rate": { "numerator": "1", "denominator": "100" },
"center_dz": { "numerator": "1", "denominator": "2" },
"radius_dz": { "numerator": "1", "denominator": "50" }
"growth_rate": {
"numerator": "1",
"denominator": "100"
},
"center_dz": {
"numerator": "1",
"denominator": "2"
},
"radius_dz": {
"numerator": "1",
"denominator": "50"
}
},
"adaptive_issuance_activation_vote_enable": true,
"autostaking_enable": true,
Expand Down
41 changes: 39 additions & 2 deletions crates/jstz_cli/src/bridge/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
use clap::Subcommand;

mod deposit;
mod withdraw;

use crate::{config::NetworkName, error::Result, utils::AddressOrAlias};
use crate::{
config::NetworkName,
error::{user_error, Result},
utils::AddressOrAlias,
};

#[derive(Debug, Subcommand)]
pub enum Command {
Expand All @@ -22,15 +27,47 @@ pub enum Command {
#[arg(short, long, default_value = None)]
network: Option<NetworkName>,
},
/// 💰 Withdraws XTZ from the current jstz account to a Tezos L1 address. This command will push
/// a withdraw outbox message into the jstz outbox which can be executed after the L2 commitment
/// period has passed to transfer the funds.
Withdraw {
/// Tezos L1 address or alias to deposit to (must be stored in octez-client's wallet).
#[arg(short, long)]
to: AddressOrAlias,
/// The amount in XTZ to transfer.
#[arg(short, long)]
amount: f64,
/// Specifies the network from the config file, defaulting to the configured default network.
/// Use `dev` for the local sandbox.
#[arg(short, long, default_value = None)]
network: Option<NetworkName>,
},
}

pub fn exec(command: Command) -> Result<()> {
pub async fn exec(command: Command) -> Result<()> {
match command {
Command::Deposit {
from,
to,
amount,
network,
} => deposit::exec(from, to, amount, network),
Command::Withdraw {
to,
amount,
network,
} => withdraw::exec(to, amount, network).await,
}
}

pub fn convert_tez_to_mutez(tez: f64) -> Result<u64> {
// 1 XTZ = 1,000,000 Mutez
let mutez = tez * 1_000_000.0;
if mutez.fract() != 0. {
Err(user_error!(
"Invalid amount: XTZ can have at most 6 decimal places"
))?;
}

Ok(mutez as u64)
}
39 changes: 39 additions & 0 deletions crates/jstz_cli/src/bridge/withdraw.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use crate::{
bridge::convert_tez_to_mutez,
config::{Config, NetworkName},
error::{bail_user_error, Result},
run,
term::styles,
utils::AddressOrAlias,
};
use log::debug;

pub async fn exec(
to: AddressOrAlias,
amount: f64,
network: Option<NetworkName>,
) -> Result<()> {
let cfg = Config::load()?;

// Check network
if cfg.network_name(&network)? == NetworkName::Dev && cfg.sandbox.is_none() {
bail_user_error!(
"No sandbox is currently running. Please run {}.",
styles::command("jstz sandbox start")
);
}

let to_pkh = to.resolve_l1(&cfg, &network)?;
debug!("resolved `to` -> {}", &to_pkh.to_base58());

let amount = convert_tez_to_mutez(amount)?;
let url = "tezos://jstz/withdraw".to_string();
let http_method = "POST".to_string();
let gas_limit = 10; // TODO: set proper gas limit
let withdraw = jstz_proto::executor::withdraw::Withdrawal {
amount,
receiver: to_pkh,
};
let json_data = serde_json::to_string(&withdraw)?;
run::exec(url, http_method, gas_limit, Some(json_data), network, false).await
}
23 changes: 23 additions & 0 deletions crates/jstz_cli/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,29 @@ impl AddressOrAlias {
.map(|(_, user)| user.address.clone()),
}
}

pub fn resolve_l1(
&self,
cfg: &Config,
network: &Option<NetworkName>,
) -> Result<Address> {
match self {
AddressOrAlias::Address(address) => Ok(address.clone()),
AddressOrAlias::Alias(alias) => {
let alias_info = cfg
.octez_client(network)?
.alias_info(alias)
.map_err(|_|
user_error!(
"Alias '{}' not found in octez-client. Please provide a valid address or alias.",
alias
))?;

let address = Address::from_base58(&alias_info.address)?;
Ok(address)
}
}
}
}

pub struct AccountsIter<'a> {
Expand Down
2 changes: 1 addition & 1 deletion crates/jstz_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ async fn exec(command: Command) -> Result<()> {
Command::Docs => docs::exec(),
Command::Completions { shell } => completions::exec(shell),
Command::Sandbox(sandbox_command) => sandbox::exec(sandbox_command).await,
Command::Bridge(bridge_command) => bridge::exec(bridge_command),
Command::Bridge(bridge_command) => bridge::exec(bridge_command).await,
Command::Account(account_command) => account::exec(account_command).await,
Command::Deploy {
code,
Expand Down
48 changes: 40 additions & 8 deletions crates/jstz_cli/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::logs::{exec_trace, DEFAULT_LOG_LEVEL};
use anyhow::bail;
use http::{HeaderMap, Method, Uri};
use jstz_proto::context::account::Address;
use jstz_proto::executor::JSTZ_HOST;
use jstz_proto::{
operation::{Content as OperationContent, Operation, RunFunction, SignedOperation},
receipt::Content as ReceiptContent,
Expand All @@ -27,6 +28,36 @@ use crate::{
// where the FA2 transfer function was called 1000 times.
pub const DEFAULT_GAS_LIMIT: u32 = 550000;

pub enum Host {
AddressOrAlias(AddressOrAlias),
Jstz,
}

impl Host {
pub fn resolve(&self, config: &Config) -> Result<String> {
match self {
Host::AddressOrAlias(address_or_alias) => {
Ok(address_or_alias.resolve(config)?.to_base58())
}
Host::Jstz => Ok(JSTZ_HOST.to_string()),
}
}
}

impl TryFrom<&str> for Host {
type Error = crate::error::Error;

fn try_from(value: &str) -> Result<Self> {
match value {
JSTZ_HOST => Ok(Host::Jstz),
_ => {
let address_or_alias = AddressOrAlias::from_str(value)?;
Ok(Host::AddressOrAlias(address_or_alias))
}
}
}
}

pub async fn exec(
url: String,
http_method: String,
Expand Down Expand Up @@ -55,15 +86,14 @@ pub async fn exec(
.host_str()
.ok_or(user_error!("URL {} requires a host.", styles::url(&url)))?;

let address_or_alias = AddressOrAlias::from_str(host)?;

if address_or_alias.is_alias() {
let address = address_or_alias.resolve(&cfg)?;
let parsed_host = Host::try_from(host)?;
let resolved_host = parsed_host.resolve(&cfg)?;

info!("Resolved host '{}' to '{}'.", host, address);
if host != resolved_host.as_str() {
info!("Resolved host '{}' to '{}'.", host, resolved_host);

url_object
.set_host(Some(&address.to_string()))
.set_host(Some(&resolved_host.to_string()))
.map_err(|_| anyhow!("Failed to set host"))?;
}

Expand Down Expand Up @@ -125,8 +155,10 @@ pub async fn exec(
};

if trace {
let address = address_or_alias.resolve(&cfg)?;
spawn_trace(&address, &jstz_client).await?;
if let Host::AddressOrAlias(address_or_alias) = parsed_host {
let address = address_or_alias.resolve(&cfg)?;
spawn_trace(&address, &jstz_client).await?;
}
}

jstz_client.post_operation(&signed_op).await?;
Expand Down
6 changes: 0 additions & 6 deletions crates/jstz_cli/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@ pub enum AddressOrAlias {
Alias(String),
}

impl AddressOrAlias {
pub fn is_alias(&self) -> bool {
matches!(self, Self::Alias(_))
}
}

impl FromStr for AddressOrAlias {
type Err = Error;

Expand Down
2 changes: 1 addition & 1 deletion crates/jstz_proto/src/executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub mod fa_deposit;
pub mod smart_function;
pub mod withdraw;

const JSTZ_HOST: &str = "jstz";
pub const JSTZ_HOST: &str = "jstz";

fn execute_operation_inner(
hrt: &mut impl HostRuntime,
Expand Down
45 changes: 45 additions & 0 deletions scripts/execute_latest_outbox_message.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
run() {
# Get the current level of the chain.
level="$(curl -s "http://127.0.0.1:18730/chains/main/blocks/head/metadata" | jq .level_info.level)"
if [ -z "$level" ]; then
echo 'Error: No "level_info" found from octez-client rpc get "/chains/main/blocks/head/metadata".\n'
return 1 # Failure
fi
octez_client="$1"
found=false
counter=0
max="200"
# Search back a $max number of levels for a non-empty rollup outbox message.
while [ "$found" = "false" ] && [ "$counter" -lt "$max" ]; do
msg=$(curl -s "http://127.0.0.1:8932/global/block/head/outbox/${level}/messages")
case "$msg" in
*'[]'*)
level=$((level - 1))
;;
*)
found=true
;;
esac
counter=$((counter + 1))
done
if [ "$found" = "true" ]; then
echo "Found outbox message at $level"
while true; do
payload=$(curl -s "http://127.0.0.1:8932/global/block/head/helpers/proofs/outbox/${level}/messages?index=0")
proof=$(echo $payload | jq -r ".proof" 2>/dev/null)
if [ "$?" -ne 0 ]; then
sleep 1
else
break
fi
done
proof=$(echo $payload | jq -r ".proof")
commitment_hash=$(echo $payload | jq -r ".commitment")
$octez_client -E http://127.0.0.1:18730 -d "$(cat ~/.jstz/config.json | jq -r ".sandbox.octez_client_dir")" execute outbox message of smart rollup jstz_rollup from bootstrap1 for commitment hash $commitment_hash and output proof "0x$proof" --burn-cap 999
else
echo "No messages in the last $max levels.\n"
return 1
fi
}

run $1

0 comments on commit 045203c

Please sign in to comment.