apl_token/
lib.rs

1#![allow(clippy::arithmetic_side_effects)]
2#![deny(missing_docs)]
3#![cfg_attr(not(test), forbid(unsafe_code))]
4#![allow(unexpected_cfgs)]
5
6//! An ERC20-like Token program for the Arch blockchain
7
8pub mod error;
9pub mod instruction;
10pub mod native_mint;
11pub mod processor;
12pub mod state;
13
14#[cfg(not(feature = "no-entrypoint"))]
15mod entrypoint;
16
17// Export current sdk types for downstream users building with a different sdk
18// version
19pub use arch_program;
20use arch_program::{entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey};
21
22/// Convert the UI representation of a token amount (using the decimals field
23/// defined in its mint) to the raw amount
24pub fn ui_amount_to_amount(ui_amount: f64, decimals: u8) -> u64 {
25    (ui_amount * 10_usize.pow(decimals as u32) as f64) as u64
26}
27
28/// Convert a raw amount to its UI representation (using the decimals field
29/// defined in its mint)
30pub fn amount_to_ui_amount(amount: u64, decimals: u8) -> f64 {
31    amount as f64 / 10_usize.pow(decimals as u32) as f64
32}
33
34/// Convert a raw amount to its UI representation (using the decimals field
35/// defined in its mint)
36pub fn amount_to_ui_amount_string(amount: u64, decimals: u8) -> String {
37    let decimals = decimals as usize;
38    if decimals > 0 {
39        // Left-pad zeros to decimals + 1, so we at least have an integer zero
40        let mut s = format!("{:01$}", amount, decimals + 1);
41        // Add the decimal point (Sorry, "," locales!)
42        s.insert(s.len() - decimals, '.');
43        s
44    } else {
45        amount.to_string()
46    }
47}
48
49/// Convert a raw amount to its UI representation using the given decimals field
50/// Excess zeroes or unneeded decimal point are trimmed.
51pub fn amount_to_ui_amount_string_trimmed(amount: u64, decimals: u8) -> String {
52    let mut s = amount_to_ui_amount_string(amount, decimals);
53    if decimals > 0 {
54        let zeros_trimmed = s.trim_end_matches('0');
55        s = zeros_trimmed.trim_end_matches('.').to_string();
56    }
57    s
58}
59
60/// Try to convert a UI representation of a token amount to its raw amount using
61/// the given decimals field
62pub fn try_ui_amount_into_amount(ui_amount: String, decimals: u8) -> Result<u64, ProgramError> {
63    let decimals = decimals as usize;
64    let mut parts = ui_amount.split('.');
65    // splitting a string, even an empty one, will always yield an iterator of
66    // at least length == 1
67    let mut amount_str = parts.next().unwrap().to_string();
68    let after_decimal = parts.next().unwrap_or("");
69    let after_decimal = after_decimal.trim_end_matches('0');
70    if (amount_str.is_empty() && after_decimal.is_empty())
71        || parts.next().is_some()
72        || after_decimal.len() > decimals
73    {
74        return Err(ProgramError::InvalidArgument);
75    }
76
77    amount_str.push_str(after_decimal);
78    for _ in 0..decimals.saturating_sub(after_decimal.len()) {
79        amount_str.push('0');
80    }
81    amount_str
82        .parse::<u64>()
83        .map_err(|_| ProgramError::InvalidArgument)
84}
85
86/// The program ID for the APL-token program
87pub fn id() -> Pubkey {
88    Pubkey::from_slice(b"AplToken111111111111111111111111")
89}
90
91/// The program ID for the APL-token program
92pub const ID: Pubkey = Pubkey::new_from_array(*b"AplToken111111111111111111111111");
93
94/// Checks that the supplied program ID is the correct one for APL-token
95pub fn check_program_account(apl_token_program_id: &Pubkey) -> ProgramResult {
96    if apl_token_program_id != &id() {
97        return Err(ProgramError::IncorrectProgramId);
98    }
99    Ok(())
100}