vialabs-stellar-common 0.1.8

Common interfaces, types, and utilities for Stellar contracts in the VIA cross-chain messaging system
Documentation
use soroban_sdk::{Bytes, Env};

/// Encodes bridge data in ABI format for cross-chain transfers.
///
/// # Arguments
///
/// * `env` - The Soroban environment
/// * `recipient` - Recipient address in bytes format
/// * `amount` - Transfer amount
/// * `text` - Additional text data
///
/// # Returns
///
/// Returns the encoded bytes in ABI format.
pub fn encode_abi_bridge_data(env: &Env, recipient: &Bytes, amount: u128, text: &Bytes) -> Bytes {
  let mut encoded = Bytes::new(env);

  let mut bytes_offset_bytes = [0u8; 32];
  bytes_offset_bytes[28..32].copy_from_slice(&96u32.to_be_bytes());
  encoded.extend_from_slice(&bytes_offset_bytes);

  let mut amount_bytes = [0u8; 32];
  amount_bytes[16..32].copy_from_slice(&amount.to_be_bytes());
  encoded.extend_from_slice(&amount_bytes);

  let binding = text.to_buffer::<65536>();
  let text_bytes = binding.as_slice();

  let bytes_data_length = recipient.len().div_ceil(32);
  let string_offset = 96 + bytes_data_length;

  let mut string_offset_bytes = [0u8; 32];
  string_offset_bytes[28..32].copy_from_slice(&string_offset.to_be_bytes());
  encoded.extend_from_slice(&string_offset_bytes);

  let mut recipient_len_bytes = [0u8; 32];
  recipient_len_bytes[28..32].copy_from_slice(&recipient.len().to_be_bytes());
  encoded.extend_from_slice(&recipient_len_bytes);

  let binding = recipient.to_buffer::<1024>();
  let recipient_bytes = binding.as_slice();

  encoded.extend_from_slice(recipient_bytes);

  let padding_needed = (32 - (recipient.len() % 32)) % 32;

  if padding_needed > 0 {
    let padding_zeros = [0u8; 32];

    encoded.extend_from_slice(&padding_zeros[..padding_needed as usize]);
  }

  let mut text_len_bytes = [0u8; 32];
  text_len_bytes[28..32].copy_from_slice(&(text_bytes.len() as u32).to_be_bytes());
  encoded.extend_from_slice(&text_len_bytes);

  encoded.extend_from_slice(text_bytes);

  encoded
}

/// Decodes ABI-encoded bridge data back into its components.
///
/// # Arguments
///
/// * `env` - The Soroban environment
/// * `encoded` - The ABI-encoded bytes to decode
///
/// # Returns
///
/// Returns a tuple of `(recipient, amount, text)`.
pub fn decode_abi_bridge_data(env: &Env, encoded: &Bytes) -> (Bytes, u128, Bytes) {
  let binding = encoded.to_buffer::<65536>();
  let encoded_slice = binding.as_slice();

  let amount_bytes = &encoded_slice[48..64];
  let amount = u128::from_be_bytes(amount_bytes.try_into().unwrap());

  let recipient_len_bytes = &encoded_slice[96..128];

  let recipient_len = u32::from_be_bytes([
    recipient_len_bytes[28],
    recipient_len_bytes[29],
    recipient_len_bytes[30],
    recipient_len_bytes[31],
  ]) as usize;

  let recipient_data = &encoded_slice[128..128 + recipient_len];
  let recipient = Bytes::from_slice(env, recipient_data);

  let padding_needed = (32 - (recipient_len % 32)) % 32;
  let text_len_offset = 128 + recipient_len + padding_needed;

  let text_len_bytes = &encoded_slice[text_len_offset..text_len_offset + 32];

  let text_len = u32::from_be_bytes([
    text_len_bytes[28],
    text_len_bytes[29],
    text_len_bytes[30],
    text_len_bytes[31],
  ]) as usize;

  let text_start = text_len_offset + 32;
  let text_data = &encoded_slice[text_start..text_start + text_len];
  let text = Bytes::from_slice(env, text_data);

  (recipient, amount, text)
}