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