Skip to content

Commit

Permalink
fix(bridge): fix bridge deposit
Browse files Browse the repository at this point in the history
  • Loading branch information
zcabter committed Aug 22, 2024
1 parent 0e4da48 commit 48d8056
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 63 deletions.
18 changes: 10 additions & 8 deletions contracts/jstz_native_bridge.mligo
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@

module Tezos = Tezos.Next

type deposit_request =
{ jstz_address: address (* Jstz rollup address. *)
; l2_address: address
type deposit_request = {
l2_address: address
(* L2 address - supports tz1, tz2, tz3, tz4, kt1 *)
(* TODO: https://linear.app/tezos/issue/JSTZ-34
Add check for supported addresses
Expand All @@ -24,6 +23,7 @@ type deposit_request =

type storage =
{ exchanger: address (* Address of exchanger contract minting tez tickets. *)
; jstz_address: address (* Jstz rollup address. *)
; deposit_request: deposit_request option; (* Address of L2 depositee *)
}

Expand All @@ -39,7 +39,8 @@ type return = operation list * storage
Throws if [exchanger] contract does not have %mint entrypoint. This is a fatal bug.
*)
[@entry]
let deposit (request: deposit_request) ({exchanger; deposit_request}: storage) : return =
let deposit (request: deposit_request) (s: storage) : return =
let { exchanger; jstz_address = _; deposit_request } = s in
let () =
match deposit_request with
| None -> ()
Expand All @@ -54,7 +55,7 @@ let deposit (request: deposit_request) ({exchanger; deposit_request}: storage) :
| None -> failwith "Invalid tez ticket contract"
| Some contract ->
let mint = Tezos.Operation.transaction callback amount contract in
let callback_storage = { exchanger; deposit_request = Some request } in
let callback_storage = { s with deposit_request = Some request } in
[ mint ], callback_storage

(* [callback ticket {exchanger; deposit_request}] sends a [Deposit_Ticket]
Expand All @@ -65,13 +66,14 @@ let deposit (request: deposit_request) ({exchanger; deposit_request}: storage) :
[deposit_request] is unset at the end of the function.
*)
[@entry]
let callback (ticket: tez_ticket) ({exchanger; deposit_request}: storage) : return =
let callback (ticket: tez_ticket) (s: storage) : return =
let { exchanger = _ ; jstz_address; deposit_request } = s in
let deposit_request =
match deposit_request with
| None -> failwith "Callback on non-locked deposit"
| Some r -> r
in
let { jstz_address; l2_address } = deposit_request in
let { l2_address } = deposit_request in
let jstz_address: jstz contract =
Tezos.get_contract_with_error jstz_address "Invalid rollup address"
in
Expand All @@ -81,5 +83,5 @@ let callback (ticket: tez_ticket) ({exchanger; deposit_request}: storage) : retu
0mutez
jstz_address
in
let reset_storage = { exchanger; deposit_request = None } in
let reset_storage = { s with deposit_request = None } in
[ deposit ], reset_storage
37 changes: 19 additions & 18 deletions contracts/jstz_native_bridge.tz
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
{ parameter
(or (ticket %callback (pair nat (option bytes)))
(pair %deposit (address %jstz_address) (address %l2_address))) ;
{ parameter (or (ticket %callback (pair nat (option bytes))) (address %deposit)) ;
storage
(pair (address %exchanger)
(option %deposit_request (pair (address %jstz_address) (address %l2_address)))) ;
(address %jstz_address)
(option %deposit_request address)) ;
code { UNPAIR ;
IF_LEFT
{ SWAP ;
UNPAIR ;
{ DUP 2 ;
UNPAIR 3 ;
DROP ;
SWAP ;
IF_NONE { PUSH string "Callback on non-locked deposit" ; FAILWITH } {} ;
UNPAIR ;
SWAP ;
CONTRACT
(or (pair %deposit_ticket address (ticket (pair nat (option bytes))))
(pair %deposit_fa_ticket
Expand All @@ -19,42 +19,43 @@
(ticket %ticket (pair nat (option bytes))))) ;
IF_NONE { PUSH string "Invalid rollup address" ; FAILWITH } {} ;
PUSH mutez 0 ;
DIG 4 ;
DIG 3 ;
DIG 3 ;
PAIR ;
LEFT (pair address (option address) (ticket (pair nat (option bytes)))) ;
TRANSFER_TOKENS ;
NONE (pair address address) ;
DIG 2 ;
PAIR ;
SWAP ;
NONE address ;
UPDATE 4 ;
NIL operation ;
DIG 2 ;
CONS ;
PAIR }
{ SWAP ;
UNPAIR ;
{ DUP 2 ;
UNPAIR 3 ;
SWAP ;
DROP ;
SWAP ;
IF_NONE {} { DROP ; PUSH string "Deposit locked" ; FAILWITH } ;
AMOUNT ;
PUSH mutez 0 ;
DUP 2 ;
COMPARE ;
LE ;
IF { DROP 3 ;
IF { DROP 4 ;
PUSH string "Invalid deposit amount: Deposit amount must be greater than 0." ;
FAILWITH }
{ SELF %callback ;
ADDRESS ;
DUP 3 ;
DIG 2 ;
CONTRACT %mint address ;
IF_NONE
{ DROP 4 ; PUSH string "Invalid tez ticket contract" ; FAILWITH }
{ DUG 2 ;
TRANSFER_TOKENS ;
DIG 2 ;
DUG 2 ;
SOME ;
DIG 2 ;
PAIR ;
UPDATE 4 ;
NIL operation ;
DIG 2 ;
CONS ;
Expand Down
20 changes: 10 additions & 10 deletions contracts/test/test_jstz_native_bridge.mligo
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

(* Sets up the exchanger, bridge, mock jstz rollup, l2 address and deposit request *)
let setup_contracts_and_request () =
let jstz_rollup = init_jstz_rollup () in
let jstz_address = Test.Next.Typed_address.to_address jstz_rollup.taddr in
let exchanger =
let exchanger_contract =
Test.Next.Originate.contract
Expand All @@ -24,47 +26,45 @@ let setup_contracts_and_request () =
let bridge =
Test.Next.Originate.contract
(contract_of Jstz_native_bridge)
{ exchanger; deposit_request = None}
{ exchanger; jstz_address; deposit_request = None}
0tez
in
let jstz_rollup = init_jstz_rollup () in
let l2_address = Test.Next.Account.bob () in
let deposit_request = {
jstz_address = (Test.Next.Typed_address.to_address jstz_rollup.taddr);
l2_address;
}
in
{ exchanger; bridge; jstz_rollup; l2_address; deposit_request }
{ exchanger; bridge; jstz_rollup; jstz_address; l2_address; deposit_request }

let test_deposit_successful =
let { exchanger; bridge; jstz_rollup; l2_address; deposit_request } = setup_contracts_and_request () in
let { exchanger; bridge; jstz_rollup; jstz_address; l2_address; deposit_request } = setup_contracts_and_request () in
let _ = Test.Next.Typed_address.transfer_exn bridge.taddr (Deposit deposit_request) 100tez in
let expected: normalized_deposit list = [ (l2_address, exchanger, (0n, None), 100000000n) ] in
let { native_deposit = actual; fa_deposit = _; } =
Test.Next.get_storage jstz_rollup.taddr in
let () = assert_lists (fun x y -> assert (Test.equal x y)) expected actual in
let bridge_storage = Test.Next.get_storage bridge.taddr in
assert (Test.equal bridge_storage { exchanger; deposit_request = None })
assert (Test.equal bridge_storage { exchanger; jstz_address; deposit_request = None })

let test_deposit_deposit_request_locked_throws_error =
let { exchanger; bridge = _; jstz_rollup = _; l2_address = _; deposit_request } = setup_contracts_and_request () in
let { exchanger; bridge = _; jstz_rollup = _; jstz_address; l2_address = _; deposit_request } = setup_contracts_and_request () in
let bridge =
// Override the bridge initial storage
Test.Next.Originate.contract
(contract_of Jstz_native_bridge)
{ exchanger; deposit_request = Some deposit_request}
{ exchanger; jstz_address; deposit_request = Some deposit_request}
0tez
in
let result = Test.Next.Typed_address.transfer bridge.taddr (Deposit deposit_request) 100tez in
assert_failed result "Expected error when deposit request is locked"

let test_callback_direct_call_throws_error =
let { exchanger = _; bridge; jstz_rollup = _; l2_address = _; deposit_request = _ } = setup_contracts_and_request () in
let ctx = setup_contracts_and_request () in
let ticket : tez_ticket =
Option.value_exn
"Failed to create ticket"
(Tezos.Next.Ticket.create (0n, None) 100n)
in
let result = Test.Next.Typed_address.transfer bridge.taddr (Callback ticket) 0tez in
let result = Test.Next.Typed_address.transfer ctx.bridge.taddr (Callback ticket) 0tez in
assert_failed result "Expected error when callback is called directly"

16 changes: 7 additions & 9 deletions crates/jstz_cli/src/bridge/deposit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ pub fn exec(
}

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

// Check if trying to deposit to a bootsrap account.
if let Some(bootstrap_account) = SANDBOX_BOOTSTRAP_ACCOUNTS
Expand All @@ -37,27 +36,26 @@ pub fn exec(
bootstrap_account.address
);
}
let pkh = to_pkh.to_base58();
debug!("resolved `to` -> {}", &pkh);

// Execute the octez-client command
if cfg
.octez_client(&network)?
.call_contract(
&from,
"jstz_bridge",
"jstz_native_bridge",
"deposit",
&format!(
"(Pair 0x{} {})",
hex::encode_upper(to_pkh.as_bytes()),
amount,
),
&format!("\"{}\"", &pkh),
amount,
)
.is_err()
{
bail_user_error!("Failed to deposit CTEZ. Please check whether the addresses and network are correct.");
bail_user_error!("Failed to deposit XTZ. Please check whether the addresses and network are correct.");
}

info!(
"Deposited {} CTEZ from {} to {}",
"Deposited {} XTZ from {} to {}",
amount,
from,
to.to_string()
Expand Down
4 changes: 2 additions & 2 deletions crates/jstz_cli/src/bridge/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ use crate::{config::NetworkName, error::Result, utils::AddressOrAlias};

#[derive(Debug, Subcommand)]
pub enum Command {
/// 💰 Deposits CTEZ from an existing Tezos L1 address to a jstz address.
/// 💰 Deposits XTZ from an existing Tezos L1 address to a jstz address.
Deposit {
/// Tezos L1 address or alias to withdraw from (must be stored in octez-client's wallet).
#[arg(short, long)]
from: String,
/// jstz address or alias to deposit to.
#[arg(short, long)]
to: AddressOrAlias,
/// The amount in CTEZ to transfer.
/// The amount in XTZ to transfer.
#[arg(short, long)]
amount: u64,
/// Specifies the network from the config file, defaulting to the configured default network.
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 @@ -64,7 +64,7 @@ enum Command {
#[arg(short, long)]
trace: bool,
},
/// 🌉 Move CTEZ between L1 and jstz with the jstz bridge {n}
/// 🌉 Move XTZ between L1 and jstz with the jstz bridge {n}
#[command(subcommand)]
Bridge(bridge::Command),

Expand Down
28 changes: 15 additions & 13 deletions crates/jstz_cli/src/sandbox/daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,7 @@ fn start_sandbox(
let config = Rc::new(RefCell::new(cfg.clone()));
let logs = Rc::new(RefCell::new(log_file.try_clone()?));
let mut sandbox = Sandbox::new(config, logs);

// 1. Init node
init_node(log_file, progress, cfg)?;

Expand All @@ -518,21 +519,12 @@ fn start_sandbox(
sandbox.set_baker(baker)?;
debug!(log_file, "Started baker (using octez-client)");

// 5. Deploy bridge
progress_step(log_file, progress);
debug!(log_file, "Deploying bridge...");
// 4.1 Deploy the XTZ ticket exchanger
let client = cfg.octez_client_sandbox()?;

let exchanger = Exchanger::deploy(&client, OPERATOR_ADDRESS)?;
debug!(log_file, "Exchanger deployed at {}", exchanger);

progress_step(log_file, progress);

let bridge = NativeBridge::deploy(&client, OPERATOR_ADDRESS, &exchanger)?;

debug!(log_file, "Bridge deployed at {}", bridge);

// 6. Create an installer kernel
// 5. Create an installer kernel
progress_step(log_file, progress);
debug!(log_file, "Creating installer kernel...");

Expand All @@ -544,13 +536,13 @@ fn start_sandbox(
"Installer kernel created with preimages at {:?}", preimages_dir
);

// 7. Originate the rollup
// 6. Originate the rollup
progress_step(log_file, progress);
let rollup =
JstzRollup::deploy(&cfg.octez_client_sandbox()?, OPERATOR_ADDRESS, &installer)?;
debug!(log_file, "`jstz_rollup` originated at {}", rollup);

// 8. As a thread, start rollup node
// 7. As a thread, start rollup node
progress_step(log_file, progress);
debug!(log_file, "Starting rollup node...");

Expand All @@ -566,6 +558,16 @@ fn start_sandbox(
sandbox.set_rollup_node(rollup_node)?;
debug!(log_file, "Started octez-smart-rollup-node");

// 8. Deploy bridge
progress_step(log_file, progress);
debug!(log_file, "Deploying bridge...");

progress_step(log_file, progress);

let bridge = NativeBridge::deploy(&client, OPERATOR_ADDRESS, &exchanger, &rollup)?;

debug!(log_file, "Bridge deployed at {}", bridge);

// 9. Set the rollup address in the bridge
progress_step(log_file, progress);
debug!(log_file, "`jstz_bridge` `rollup` address set to {}", rollup);
Expand Down
5 changes: 4 additions & 1 deletion crates/jstz_rollup/src/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ impl NativeBridge {
client: &OctezClient,
operator: &str,
exchanger: &Exchanger,
rollup_address: &str,
) -> Result<NativeBridge> {
let storage_init = format!("(Pair \"{}\" None)", exchanger.0);
let storage_init =
format!("(Pair \"{}\" \"{}\" None)", exchanger.0, rollup_address);
client
.originate_contract(
"jstz_native_bridge",
Expand Down Expand Up @@ -133,6 +135,7 @@ impl BridgeContract {
&self.0,
"set_rollup",
&format!("\"{}\"", rollup_address),
0,
)
}
}
3 changes: 2 additions & 1 deletion crates/octez/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,11 @@ impl OctezClient {
to: &str,
entrypoint: &str,
parameter: &str,
amount: u64,
) -> Result<()> {
run_command(self.command().args([
"transfer",
"0",
&format!("{}", amount),
"from",
from,
"to",
Expand Down

0 comments on commit 48d8056

Please sign in to comment.