lib.rs 3.5 KB

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