vialabs-stellar-common 0.1.10

Common interfaces, types, and utilities for Stellar contracts in the VIA cross-chain messaging system
Documentation
/// # Encoding EVM Chain Data
///
/// This module provides functions for encoding and decoding EVM chain data.
use soroban_sdk::{Bytes, Env};

pub fn encode_abi_chain_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 padding_needed = (32 - (recipient.len() % 32)) % 32;
  let string_offset = 96 + 32 + recipient.len() + padding_needed;

  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);

  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
}

pub fn decode_abi_chain_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)
}