#[cfg(any(
target_os = "stax",
target_os = "flex",
target_os = "apex_p",
feature = "nano_nbgl"
))]
use crate::nbgl::NbglSpinner;
use ledger_secure_sdk_sys::{
check_address_parameters_t, create_transaction_parameters_t, get_printable_amount_parameters_t,
libargs_s__bindgen_ty_1, libargs_t, MAX_PRINTABLE_AMOUNT_SIZE,
};
extern crate alloc;
pub const DEFAULT_COIN_CONFIG_BUF_SIZE: usize = 16;
pub const DEFAULT_ADDRESS_BUF_SIZE: usize = 64;
pub const DEFAULT_ADDRESS_EXTRA_ID_BUF_SIZE: usize = 32;
const DPATH_STAGE_SIZE: usize = 16;
const AMOUNT_BUF_SIZE: usize = 16;
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SwapErrorCommonCode {
ErrorInternal = 0x00,
ErrorWrongAmount = 0x01,
ErrorWrongDestination = 0x02,
ErrorWrongFees = 0x03,
ErrorWrongMethod = 0x04,
ErrorCrosschainWrongMode = 0x05,
ErrorCrosschainWrongMethod = 0x06,
ErrorCrosschainWrongHash = 0x07,
ErrorGeneric = 0xFF,
}
pub trait SwapAppErrorCodeTrait: Copy {
fn as_u8(self) -> u8;
}
pub struct SwapError<T: SwapAppErrorCodeTrait> {
pub common_code: SwapErrorCommonCode,
pub app_code: T,
pub message: Option<alloc::string::String>,
}
impl<T: SwapAppErrorCodeTrait> SwapError<T> {
pub fn with_message(
common_code: SwapErrorCommonCode,
app_code: T,
message: alloc::string::String,
) -> Self {
Self {
common_code,
app_code,
message: Some(message),
}
}
pub fn without_message(common_code: SwapErrorCommonCode, app_code: T) -> Self {
Self {
common_code,
app_code,
message: None,
}
}
pub fn append_to_comm(&self, comm: &mut crate::io::Comm) -> [u8; 2] {
let error_bytes = [self.common_code as u8, self.app_code.as_u8()];
comm.append(&error_bytes);
if let Some(ref msg) = self.message {
comm.append(msg.as_bytes());
}
error_bytes
}
}
fn read_c_string<const N: usize>(ptr: *const i8) -> ([u8; N], usize) {
let mut buffer = [0u8; N];
if ptr.is_null() {
return (buffer, 0);
}
let mut length = 0usize;
let mut c = unsafe { *ptr.add(length) };
while c != '\0' as i8 && length < N {
buffer[length] = c as u8;
length += 1;
c = unsafe { *ptr.add(length) };
}
if c != '\0' as i8 && length == N {
crate::log::warn!("C string truncated");
}
(buffer, length)
}
pub struct CheckAddressParams<
const COIN_CONFIG_BUF_SIZE: usize = DEFAULT_COIN_CONFIG_BUF_SIZE,
const ADDRESS_BUF_SIZE: usize = DEFAULT_ADDRESS_BUF_SIZE,
const ADDRESS_EXTRA_ID_BUF_SIZE: usize = DEFAULT_ADDRESS_EXTRA_ID_BUF_SIZE,
> {
pub coin_config: [u8; COIN_CONFIG_BUF_SIZE],
pub coin_config_len: usize,
pub dpath: [u8; DPATH_STAGE_SIZE * 4],
pub dpath_len: usize,
pub ref_address: [u8; ADDRESS_BUF_SIZE],
pub ref_address_len: usize,
pub result: *mut i32,
}
impl<
const COIN_CONFIG_BUF_SIZE: usize,
const ADDRESS_BUF_SIZE: usize,
const ADDRESS_EXTRA_ID_BUF_SIZE: usize,
> Default
for CheckAddressParams<COIN_CONFIG_BUF_SIZE, ADDRESS_BUF_SIZE, ADDRESS_EXTRA_ID_BUF_SIZE>
{
fn default() -> Self {
CheckAddressParams {
coin_config: [0; COIN_CONFIG_BUF_SIZE],
coin_config_len: 0,
dpath: [0; DPATH_STAGE_SIZE * 4],
dpath_len: 0,
ref_address: [0; ADDRESS_BUF_SIZE],
ref_address_len: 0,
result: core::ptr::null_mut(),
}
}
}
pub struct PrintableAmountParams<
const COIN_CONFIG_BUF_SIZE: usize = DEFAULT_COIN_CONFIG_BUF_SIZE,
const ADDRESS_BUF_SIZE: usize = DEFAULT_ADDRESS_BUF_SIZE,
const ADDRESS_EXTRA_ID_BUF_SIZE: usize = DEFAULT_ADDRESS_EXTRA_ID_BUF_SIZE,
> {
pub coin_config: [u8; COIN_CONFIG_BUF_SIZE],
pub coin_config_len: usize,
pub amount: [u8; AMOUNT_BUF_SIZE],
pub amount_len: usize,
pub amount_str: *mut i8,
pub is_fee: bool,
}
impl<
const COIN_CONFIG_BUF_SIZE: usize,
const ADDRESS_BUF_SIZE: usize,
const ADDRESS_EXTRA_ID_BUF_SIZE: usize,
> Default
for PrintableAmountParams<COIN_CONFIG_BUF_SIZE, ADDRESS_BUF_SIZE, ADDRESS_EXTRA_ID_BUF_SIZE>
{
fn default() -> Self {
PrintableAmountParams {
coin_config: [0; COIN_CONFIG_BUF_SIZE],
coin_config_len: 0,
amount: [0; AMOUNT_BUF_SIZE],
amount_len: 0,
amount_str: core::ptr::null_mut(),
is_fee: false,
}
}
}
pub struct CreateTxParams<
const COIN_CONFIG_BUF_SIZE: usize = DEFAULT_COIN_CONFIG_BUF_SIZE,
const ADDRESS_BUF_SIZE: usize = DEFAULT_ADDRESS_BUF_SIZE,
const ADDRESS_EXTRA_ID_BUF_SIZE: usize = DEFAULT_ADDRESS_EXTRA_ID_BUF_SIZE,
> {
pub coin_config: [u8; COIN_CONFIG_BUF_SIZE],
pub coin_config_len: usize,
pub amount: [u8; AMOUNT_BUF_SIZE],
pub amount_len: usize,
pub fee_amount: [u8; AMOUNT_BUF_SIZE],
pub fee_amount_len: usize,
pub dest_address: [u8; ADDRESS_BUF_SIZE],
pub dest_address_len: usize,
pub dest_address_extra_id: [u8; ADDRESS_EXTRA_ID_BUF_SIZE],
pub dest_address_extra_id_len: usize,
pub result: *mut u8,
}
impl<
const COIN_CONFIG_BUF_SIZE: usize,
const ADDRESS_BUF_SIZE: usize,
const ADDRESS_EXTRA_ID_BUF_SIZE: usize,
> Default
for CreateTxParams<COIN_CONFIG_BUF_SIZE, ADDRESS_BUF_SIZE, ADDRESS_EXTRA_ID_BUF_SIZE>
{
fn default() -> Self {
CreateTxParams {
coin_config: [0; COIN_CONFIG_BUF_SIZE],
coin_config_len: 0,
amount: [0; AMOUNT_BUF_SIZE],
amount_len: 0,
fee_amount: [0; AMOUNT_BUF_SIZE],
fee_amount_len: 0,
dest_address: [0; ADDRESS_BUF_SIZE],
dest_address_len: 0,
dest_address_extra_id: [0; ADDRESS_EXTRA_ID_BUF_SIZE],
dest_address_extra_id_len: 0,
result: core::ptr::null_mut(),
}
}
}
pub fn get_check_address_params<
const COIN_CONFIG_BUF_SIZE: usize,
const ADDRESS_BUF_SIZE: usize,
const ADDRESS_EXTRA_ID_BUF_SIZE: usize,
>(
arg0: u32,
) -> CheckAddressParams<COIN_CONFIG_BUF_SIZE, ADDRESS_BUF_SIZE, ADDRESS_EXTRA_ID_BUF_SIZE> {
crate::log::info!("=> get_check_address_params");
let mut libarg: libargs_t = libargs_t::default();
let arg = arg0 as *const u32;
libarg.id = unsafe { *arg };
libarg.command = unsafe { *arg.add(1) };
libarg.unused = unsafe { *arg.add(2) };
libarg.__bindgen_anon_1 = unsafe { *(arg.add(3) as *const libargs_s__bindgen_ty_1) };
let params: check_address_parameters_t =
unsafe { *(libarg.__bindgen_anon_1.check_address as *const check_address_parameters_t) };
let mut check_address_params: CheckAddressParams<
COIN_CONFIG_BUF_SIZE,
ADDRESS_BUF_SIZE,
ADDRESS_EXTRA_ID_BUF_SIZE,
> = Default::default();
crate::log::info!("==> GET_COIN_CONFIG_LENGTH");
check_address_params.coin_config_len = params.coin_configuration_length as usize;
crate::log::info!("==> GET_COIN_CONFIG");
unsafe {
params.coin_configuration.copy_to_nonoverlapping(
check_address_params.coin_config.as_mut_ptr(),
check_address_params
.coin_config_len
.min(COIN_CONFIG_BUF_SIZE),
);
}
crate::log::info!("==> GET_DPATH_LENGTH");
check_address_params.dpath_len =
DPATH_STAGE_SIZE.min(unsafe { *(params.address_parameters as *const u8) as usize });
crate::log::info!("==> GET_DPATH");
for i in 1..1 + check_address_params.dpath_len * 4 {
check_address_params.dpath[i - 1] = unsafe { *(params.address_parameters.add(i)) };
}
crate::log::info!("==> GET_REF_ADDRESS");
let (address, address_len) =
read_c_string::<ADDRESS_BUF_SIZE>(params.address_to_check as *const i8);
check_address_params.ref_address = address;
check_address_params.ref_address_len = address_len;
check_address_params.result = unsafe {
&(*(libarg.__bindgen_anon_1.check_address as *mut check_address_parameters_t)).result
as *const i32 as *mut i32
};
check_address_params
}
pub fn get_printable_amount_params<
const COIN_CONFIG_BUF_SIZE: usize,
const ADDRESS_BUF_SIZE: usize,
const ADDRESS_EXTRA_ID_BUF_SIZE: usize,
>(
arg0: u32,
) -> PrintableAmountParams<COIN_CONFIG_BUF_SIZE, ADDRESS_BUF_SIZE, ADDRESS_EXTRA_ID_BUF_SIZE> {
crate::log::info!("=> get_printable_amount_params");
let mut libarg: libargs_t = libargs_t::default();
let arg = arg0 as *const u32;
libarg.id = unsafe { *arg };
libarg.command = unsafe { *arg.add(1) };
libarg.unused = unsafe { *arg.add(2) };
libarg.__bindgen_anon_1 = unsafe { *(arg.add(3) as *const libargs_s__bindgen_ty_1) };
let params: get_printable_amount_parameters_t = unsafe {
*(libarg.__bindgen_anon_1.get_printable_amount as *const get_printable_amount_parameters_t)
};
let mut printable_amount_params: PrintableAmountParams<
COIN_CONFIG_BUF_SIZE,
ADDRESS_BUF_SIZE,
ADDRESS_EXTRA_ID_BUF_SIZE,
> = Default::default();
crate::log::info!("==> GET_COIN_CONFIG_LENGTH");
printable_amount_params.coin_config_len = params.coin_configuration_length as usize;
crate::log::info!("==> GET_COIN_CONFIG");
unsafe {
params.coin_configuration.copy_to_nonoverlapping(
printable_amount_params.coin_config.as_mut_ptr(),
printable_amount_params
.coin_config_len
.min(COIN_CONFIG_BUF_SIZE),
);
}
crate::log::info!("==> GET_IS_FEE");
printable_amount_params.is_fee = params.is_fee == true;
crate::log::info!("==> GET_AMOUNT_LENGTH");
printable_amount_params.amount_len = AMOUNT_BUF_SIZE.min(params.amount_length as usize);
crate::log::info!("==> GET_AMOUNT");
for i in 0..printable_amount_params.amount_len {
printable_amount_params.amount[AMOUNT_BUF_SIZE - printable_amount_params.amount_len + i] =
unsafe { *(params.amount.add(i)) };
}
crate::log::info!("==> GET_AMOUNT_STR");
printable_amount_params.amount_str = unsafe {
&(*(libarg.__bindgen_anon_1.get_printable_amount as *mut get_printable_amount_parameters_t))
.printable_amount as *const core::ffi::c_char as *mut i8
};
printable_amount_params
}
extern "C" {
fn c_reset_bss();
fn c_boot_std();
}
pub fn sign_tx_params<
const COIN_CONFIG_BUF_SIZE: usize,
const ADDRESS_BUF_SIZE: usize,
const ADDRESS_EXTRA_ID_BUF_SIZE: usize,
>(
arg0: u32,
) -> CreateTxParams<COIN_CONFIG_BUF_SIZE, ADDRESS_BUF_SIZE, ADDRESS_EXTRA_ID_BUF_SIZE> {
crate::log::info!("=> sign_tx_params");
let mut libarg: libargs_t = libargs_t::default();
let arg = arg0 as *const u32;
libarg.id = unsafe { *arg };
libarg.command = unsafe { *arg.add(1) };
libarg.unused = unsafe { *arg.add(2) };
libarg.__bindgen_anon_1 = unsafe { *(arg.add(3) as *const libargs_s__bindgen_ty_1) };
let params: create_transaction_parameters_t = unsafe {
*(libarg.__bindgen_anon_1.create_transaction as *const create_transaction_parameters_t)
};
let mut create_tx_params: CreateTxParams<
COIN_CONFIG_BUF_SIZE,
ADDRESS_BUF_SIZE,
ADDRESS_EXTRA_ID_BUF_SIZE,
> = Default::default();
crate::log::info!("==> GET_COIN_CONFIG_LENGTH");
create_tx_params.coin_config_len = params.coin_configuration_length as usize;
crate::log::info!("==> GET_COIN_CONFIG");
unsafe {
params.coin_configuration.copy_to_nonoverlapping(
create_tx_params.coin_config.as_mut_ptr(),
create_tx_params.coin_config_len.min(COIN_CONFIG_BUF_SIZE),
);
}
crate::log::info!("==> GET_AMOUNT");
create_tx_params.amount_len = AMOUNT_BUF_SIZE.min(params.amount_length as usize);
for i in 0..create_tx_params.amount_len {
create_tx_params.amount[AMOUNT_BUF_SIZE - create_tx_params.amount_len + i] =
unsafe { *(params.amount.add(i)) };
}
crate::log::info!("==> GET_FEE");
create_tx_params.fee_amount_len = AMOUNT_BUF_SIZE.min(params.fee_amount_length as usize);
for i in 0..create_tx_params.fee_amount_len {
create_tx_params.fee_amount[AMOUNT_BUF_SIZE - create_tx_params.fee_amount_len + i] =
unsafe { *(params.fee_amount.add(i)) };
}
crate::log::info!("==> GET_DESTINATION_ADDRESS");
let (address, address_len) =
read_c_string::<ADDRESS_BUF_SIZE>(params.destination_address as *const i8);
create_tx_params.dest_address = address;
create_tx_params.dest_address_len = address_len;
crate::log::info!("==> GET_DESTINATION_ADDRESS_EXTRA_ID");
let (extra_id, extra_id_len) = read_c_string::<ADDRESS_EXTRA_ID_BUF_SIZE>(
params.destination_address_extra_id as *const i8,
);
create_tx_params.dest_address_extra_id = extra_id;
create_tx_params.dest_address_extra_id_len = extra_id_len;
create_tx_params.result = unsafe {
&(*(libarg.__bindgen_anon_1.create_transaction as *mut create_transaction_parameters_t))
.result as *const u8 as *mut u8
};
unsafe {
c_reset_bss();
c_boot_std();
}
#[cfg(any(
target_os = "stax",
target_os = "flex",
target_os = "apex_p",
feature = "nano_nbgl"
))]
NbglSpinner::new().show("Signing");
create_tx_params
}
pub enum SwapResult<
'a,
const COIN_CONFIG_BUF_SIZE: usize = DEFAULT_COIN_CONFIG_BUF_SIZE,
const ADDRESS_BUF_SIZE: usize = DEFAULT_ADDRESS_BUF_SIZE,
const ADDRESS_EXTRA_ID_BUF_SIZE: usize = DEFAULT_ADDRESS_EXTRA_ID_BUF_SIZE,
> {
CheckAddressResult(
&'a mut CheckAddressParams<
COIN_CONFIG_BUF_SIZE,
ADDRESS_BUF_SIZE,
ADDRESS_EXTRA_ID_BUF_SIZE,
>,
i32,
),
PrintableAmountResult(
&'a mut PrintableAmountParams<
COIN_CONFIG_BUF_SIZE,
ADDRESS_BUF_SIZE,
ADDRESS_EXTRA_ID_BUF_SIZE,
>,
&'a str,
),
CreateTxResult(
&'a mut CreateTxParams<COIN_CONFIG_BUF_SIZE, ADDRESS_BUF_SIZE, ADDRESS_EXTRA_ID_BUF_SIZE>,
u8,
),
}
pub fn swap_return<
const COIN_CONFIG_BUF_SIZE: usize,
const ADDRESS_BUF_SIZE: usize,
const ADDRESS_EXTRA_ID_BUF_SIZE: usize,
>(
res: SwapResult<COIN_CONFIG_BUF_SIZE, ADDRESS_BUF_SIZE, ADDRESS_EXTRA_ID_BUF_SIZE>,
) {
match res {
SwapResult::CheckAddressResult(&mut ref p, r) => {
unsafe { *(p.result) = r };
}
SwapResult::PrintableAmountResult(&mut ref p, s) => {
if s.len() < (MAX_PRINTABLE_AMOUNT_SIZE - 1).try_into().unwrap() {
for (i, c) in s.chars().enumerate() {
unsafe { *(p.amount_str.add(i)) = c as i8 };
}
unsafe { *(p.amount_str.add(s.len())) = '\0' as i8 };
} else {
unsafe { *(p.amount_str) = '\0' as i8 };
}
}
SwapResult::CreateTxResult(&mut ref p, r) => {
unsafe { *(p.result) = r };
}
}
unsafe { ledger_secure_sdk_sys::os_lib_end() };
}