mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-07-24 00:23:13 +00:00
refactor(cross-zone): fund bridge-lock holdings with a real native balance
This commit is contained in:
parent
f4a5d85c65
commit
e278437266
@ -72,10 +72,15 @@ async fn lock_on_zone_a_mints_wrapped_token_on_zone_b() -> Result<()> {
|
||||
let (seq_a, _seq_a_home) = setup_sequencer(partial, bedrock_addr, genesis_a, channel_a, None)
|
||||
.await
|
||||
.context("Failed to set up zone A sequencer")?;
|
||||
let (_seq_b, _seq_b_home) =
|
||||
setup_sequencer(partial, bedrock_addr, vec![], channel_b, Some(cross_zone.clone()))
|
||||
.await
|
||||
.context("Failed to set up zone B sequencer")?;
|
||||
let (_seq_b, _seq_b_home) = setup_sequencer(
|
||||
partial,
|
||||
bedrock_addr,
|
||||
vec![],
|
||||
channel_b,
|
||||
Some(cross_zone.clone()),
|
||||
)
|
||||
.await
|
||||
.context("Failed to set up zone B sequencer")?;
|
||||
let (idx_b, _idx_b_home) = setup_indexer(bedrock_addr, channel_b, Some(cross_zone))
|
||||
.await
|
||||
.context("Failed to set up zone B indexer")?;
|
||||
@ -106,16 +111,12 @@ async fn lock_on_zone_a_mints_wrapped_token_on_zone_b() -> Result<()> {
|
||||
// escrow now.
|
||||
let seq_a_client = sequencer_client(seq_a.addr())?;
|
||||
let escrow_id = bridge_lock_core::escrow_account_id(programs::bridge_lock().id());
|
||||
let escrowed = bridge_lock_core::read_balance(
|
||||
&seq_a_client.get_account(escrow_id).await?.data.into_inner(),
|
||||
);
|
||||
let escrowed = seq_a_client.get_account(escrow_id).await?.balance;
|
||||
assert_eq!(
|
||||
escrowed, LOCK_AMOUNT,
|
||||
"zone A escrow must hold the locked amount"
|
||||
);
|
||||
let remaining = bridge_lock_core::read_balance(
|
||||
&seq_a_client.get_account(holder_id).await?.data.into_inner(),
|
||||
);
|
||||
let remaining = seq_a_client.get_account(holder_id).await?.balance;
|
||||
assert_eq!(
|
||||
remaining,
|
||||
INITIAL_BALANCE - LOCK_AMOUNT,
|
||||
|
||||
@ -174,12 +174,8 @@ fn lock_escrows_balance_and_emits_to_outbox() {
|
||||
holder_id,
|
||||
Account {
|
||||
program_owner: bridge_lock_id,
|
||||
balance: 0,
|
||||
data: bridge_lock_core::balance_bytes(INITIAL_BALANCE)
|
||||
.to_vec()
|
||||
.try_into()
|
||||
.expect("balance fits in account data"),
|
||||
nonce: 0_u128.into(),
|
||||
balance: INITIAL_BALANCE,
|
||||
..Default::default()
|
||||
},
|
||||
)]);
|
||||
|
||||
@ -214,16 +210,14 @@ fn lock_escrows_balance_and_emits_to_outbox() {
|
||||
.expect("lock must validate and execute");
|
||||
let public_diff = diff.public_diff();
|
||||
|
||||
let holder_after =
|
||||
bridge_lock_core::read_balance(&public_diff[&holder_id].data.clone().into_inner());
|
||||
let holder_after = public_diff[&holder_id].balance;
|
||||
assert_eq!(
|
||||
holder_after,
|
||||
INITIAL_BALANCE - LOCK_AMOUNT,
|
||||
"holder debited"
|
||||
);
|
||||
|
||||
let escrow_after =
|
||||
bridge_lock_core::read_balance(&public_diff[&escrow_id].data.clone().into_inner());
|
||||
let escrow_after = public_diff[&escrow_id].balance;
|
||||
assert_eq!(escrow_after, LOCK_AMOUNT, "escrow credited");
|
||||
|
||||
let record =
|
||||
|
||||
@ -176,17 +176,14 @@ pub fn build_inbox_init_config_tx(
|
||||
|
||||
/// Builds the genesis holding account funding a holder's bridgeable balance.
|
||||
///
|
||||
/// Owned by `bridge_lock`, data is the LE balance. Not produced by any
|
||||
/// transaction, so the sequencer and indexer both seed it through this one
|
||||
/// builder.
|
||||
/// A real native balance owned by `bridge_lock`, which can debit it on a lock; it
|
||||
/// is conserved like any other balance. Not produced by any transaction, so the
|
||||
/// sequencer and indexer both seed it through this one builder.
|
||||
#[must_use]
|
||||
pub fn build_holding_account(holder: AccountId, amount: Balance) -> (AccountId, Account) {
|
||||
let account = Account {
|
||||
program_owner: programs::bridge_lock().id(),
|
||||
data: bridge_lock_core::balance_bytes(amount)
|
||||
.to_vec()
|
||||
.try_into()
|
||||
.expect("balance fits in account data"),
|
||||
balance: amount,
|
||||
..Default::default()
|
||||
};
|
||||
(holder, account)
|
||||
|
||||
@ -39,30 +39,10 @@ pub const fn escrow_seed() -> PdaSeed {
|
||||
PdaSeed::new(ESCROW_SEED_DOMAIN)
|
||||
}
|
||||
|
||||
/// Reads a bridgeable balance from account data; empty data is a zero balance.
|
||||
#[must_use]
|
||||
pub fn read_balance(data: &[u8]) -> u128 {
|
||||
if data.len() < 16 {
|
||||
return 0;
|
||||
}
|
||||
u128::from_le_bytes(data[..16].try_into().unwrap_or_else(|_| unreachable!()))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn balance_bytes(amount: u128) -> [u8; 16] {
|
||||
amount.to_le_bytes()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn balance_round_trips() {
|
||||
assert_eq!(read_balance(&balance_bytes(7)), 7);
|
||||
assert_eq!(read_balance(&[]), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn escrow_is_stable() {
|
||||
let id: ProgramId = [4; 8];
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use bridge_lock_core::{Instruction, balance_bytes, escrow_account_id, escrow_seed, read_balance};
|
||||
use bridge_lock_core::{Instruction, escrow_account_id, escrow_seed};
|
||||
use cross_zone_outbox_core::Instruction as OutboxInstruction;
|
||||
use lee_core::{
|
||||
account::AccountWithMetadata,
|
||||
@ -50,6 +50,10 @@ fn main() {
|
||||
.expect("Lock requires holder, escrow, and outbox accounts");
|
||||
|
||||
assert!(holder.is_authorized, "holder must authorize the lock");
|
||||
// The holder holding is bridge_lock-owned, so bridge_lock may debit its native
|
||||
// balance directly (state-machine rule 5). This also pins the transfer to a
|
||||
// genuine holding: a caller cannot substitute an account owned by some other
|
||||
// program to emit the mint without an actual lock.
|
||||
assert_eq!(
|
||||
holder.account.program_owner, self_program_id,
|
||||
"holder account must be a bridge_lock holding"
|
||||
@ -60,25 +64,26 @@ fn main() {
|
||||
"second account must be the escrow PDA"
|
||||
);
|
||||
|
||||
let holder_new = read_balance(&holder.account.data.clone().into_inner())
|
||||
// Move the real native balance holder -> escrow. bridge_lock owns both accounts,
|
||||
// so it debits the holder and credits the escrow directly; conservation holds
|
||||
// because the same amount moves between them.
|
||||
let holder_new = holder
|
||||
.account
|
||||
.balance
|
||||
.checked_sub(amount)
|
||||
.expect("insufficient balance to lock");
|
||||
let escrow_new = read_balance(&escrow.account.data.clone().into_inner())
|
||||
let escrow_new = escrow
|
||||
.account
|
||||
.balance
|
||||
.checked_add(amount)
|
||||
.expect("escrow balance overflow");
|
||||
|
||||
let mut holder_account = holder.account.clone();
|
||||
holder_account.data = balance_bytes(holder_new)
|
||||
.to_vec()
|
||||
.try_into()
|
||||
.expect("balance fits in account data");
|
||||
holder_account.balance = holder_new;
|
||||
let holder_post = AccountPostState::new(holder_account);
|
||||
|
||||
let mut escrow_account = escrow.account.clone();
|
||||
escrow_account.data = balance_bytes(escrow_new)
|
||||
.to_vec()
|
||||
.try_into()
|
||||
.expect("balance fits in account data");
|
||||
escrow_account.balance = escrow_new;
|
||||
let escrow_post =
|
||||
AccountPostState::new_claimed_if_default(escrow_account, Claim::Pda(escrow_seed()));
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user