Deprecate UiTokenAmount::ui_amount (#15616)
* Add TokenAmount::ui_amount_string * Fixup solana-tokens * Update docs
This commit is contained in:
parent
a9c8dbfd0c
commit
19ac79b5cc
|
@ -24,6 +24,7 @@ use {
|
|||
};
|
||||
|
||||
pub type StringAmount = String;
|
||||
pub type StringDecimals = String;
|
||||
|
||||
/// A duplicate representation of an Account for pretty JSON serialization
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
parse_account_data::{ParsableAccount, ParseAccountError},
|
||||
StringAmount,
|
||||
StringAmount, StringDecimals,
|
||||
};
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use spl_token_v2_0::{
|
||||
|
@ -158,46 +158,64 @@ impl From<AccountState> for UiAccountState {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn real_number_string(amount: u64, decimals: u8) -> StringDecimals {
|
||||
let decimals = decimals as usize;
|
||||
if decimals > 0 {
|
||||
// Left-pad zeros to decimals + 1, so we at least have an integer zero
|
||||
let mut s = format!("{:01$}", amount, decimals + 1);
|
||||
// Add the decimal point (Sorry, "," locales!)
|
||||
s.insert(s.len() - decimals, '.');
|
||||
s
|
||||
} else {
|
||||
amount.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn real_number_string_trimmed(amount: u64, decimals: u8) -> StringDecimals {
|
||||
let s = real_number_string(amount, decimals);
|
||||
let zeros_trimmed = s.trim_end_matches('0');
|
||||
let decimal_trimmed = zeros_trimmed.trim_end_matches('.');
|
||||
decimal_trimmed.to_string()
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UiTokenAmount {
|
||||
pub ui_amount: f64,
|
||||
pub ui_amount: Option<f64>,
|
||||
pub decimals: u8,
|
||||
pub amount: StringAmount,
|
||||
pub ui_amount_string: StringDecimals,
|
||||
}
|
||||
|
||||
impl UiTokenAmount {
|
||||
pub fn real_number_string(&self) -> String {
|
||||
let decimals = self.decimals as usize;
|
||||
if decimals > 0 {
|
||||
let amount = u64::from_str(&self.amount).unwrap_or(0);
|
||||
|
||||
// Left-pad zeros to decimals + 1, so we at least have an integer zero
|
||||
let mut s = format!("{:01$}", amount, decimals + 1);
|
||||
|
||||
// Add the decimal point (Sorry, "," locales!)
|
||||
s.insert(s.len() - decimals, '.');
|
||||
s
|
||||
} else {
|
||||
self.amount.clone()
|
||||
}
|
||||
real_number_string(
|
||||
u64::from_str(&self.amount).unwrap_or_default(),
|
||||
self.decimals as u8,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn real_number_string_trimmed(&self) -> String {
|
||||
let s = self.real_number_string();
|
||||
let zeros_trimmed = s.trim_end_matches('0');
|
||||
let decimal_trimmed = zeros_trimmed.trim_end_matches('.');
|
||||
decimal_trimmed.to_string()
|
||||
if !self.ui_amount_string.is_empty() {
|
||||
self.ui_amount_string.clone()
|
||||
} else {
|
||||
real_number_string_trimmed(
|
||||
u64::from_str(&self.amount).unwrap_or_default(),
|
||||
self.decimals as u8,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn token_amount_to_ui_amount(amount: u64, decimals: u8) -> UiTokenAmount {
|
||||
// Use `amount_to_ui_amount()` once spl_token is bumped to a version that supports it: https://github.com/solana-labs/solana-program-library/pull/211
|
||||
let amount_decimals = amount as f64 / 10_usize.pow(decimals as u32) as f64;
|
||||
let amount_decimals = 10_usize
|
||||
.checked_pow(decimals as u32)
|
||||
.map(|dividend| amount as f64 / dividend as f64);
|
||||
UiTokenAmount {
|
||||
ui_amount: amount_decimals,
|
||||
decimals,
|
||||
amount: amount.to_string(),
|
||||
ui_amount_string: real_number_string_trimmed(amount, decimals),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,9 +271,10 @@ mod test {
|
|||
mint: mint_pubkey.to_string(),
|
||||
owner: owner_pubkey.to_string(),
|
||||
token_amount: UiTokenAmount {
|
||||
ui_amount: 0.42,
|
||||
ui_amount: Some(0.42),
|
||||
decimals: 2,
|
||||
amount: "42".to_string()
|
||||
amount: "42".to_string(),
|
||||
ui_amount_string: "0.42".to_string()
|
||||
},
|
||||
delegate: None,
|
||||
state: UiAccountState::Initialized,
|
||||
|
@ -336,17 +355,51 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_ui_token_amount_real_string() {
|
||||
assert_eq!(&real_number_string(1, 0), "1");
|
||||
assert_eq!(&real_number_string_trimmed(1, 0), "1");
|
||||
let token_amount = token_amount_to_ui_amount(1, 0);
|
||||
assert_eq!(&token_amount.real_number_string(), "1");
|
||||
assert_eq!(&token_amount.real_number_string_trimmed(), "1");
|
||||
assert_eq!(
|
||||
token_amount.ui_amount_string,
|
||||
real_number_string_trimmed(1, 0)
|
||||
);
|
||||
assert_eq!(token_amount.ui_amount, Some(1.0));
|
||||
assert_eq!(&real_number_string(1, 9), "0.000000001");
|
||||
assert_eq!(&real_number_string_trimmed(1, 9), "0.000000001");
|
||||
let token_amount = token_amount_to_ui_amount(1, 9);
|
||||
assert_eq!(&token_amount.real_number_string(), "0.000000001");
|
||||
assert_eq!(&token_amount.real_number_string_trimmed(), "0.000000001");
|
||||
assert_eq!(
|
||||
token_amount.ui_amount_string,
|
||||
real_number_string_trimmed(1, 9)
|
||||
);
|
||||
assert_eq!(token_amount.ui_amount, Some(0.000000001));
|
||||
assert_eq!(&real_number_string(1_000_000_000, 9), "1.000000000");
|
||||
assert_eq!(&real_number_string_trimmed(1_000_000_000, 9), "1");
|
||||
let token_amount = token_amount_to_ui_amount(1_000_000_000, 9);
|
||||
assert_eq!(&token_amount.real_number_string(), "1.000000000");
|
||||
assert_eq!(&token_amount.real_number_string_trimmed(), "1");
|
||||
assert_eq!(
|
||||
token_amount.ui_amount_string,
|
||||
real_number_string_trimmed(1_000_000_000, 9)
|
||||
);
|
||||
assert_eq!(token_amount.ui_amount, Some(1.0));
|
||||
assert_eq!(&real_number_string(1_234_567_890, 3), "1234567.890");
|
||||
assert_eq!(&real_number_string_trimmed(1_234_567_890, 3), "1234567.89");
|
||||
let token_amount = token_amount_to_ui_amount(1_234_567_890, 3);
|
||||
assert_eq!(&token_amount.real_number_string(), "1234567.890");
|
||||
assert_eq!(&token_amount.real_number_string_trimmed(), "1234567.89");
|
||||
assert_eq!(
|
||||
token_amount.ui_amount_string,
|
||||
real_number_string_trimmed(1_234_567_890, 3)
|
||||
);
|
||||
assert_eq!(token_amount.ui_amount, Some(1234567.89));
|
||||
assert_eq!(
|
||||
&real_number_string(1_234_567_890, 25),
|
||||
"0.0000000000000001234567890"
|
||||
);
|
||||
assert_eq!(
|
||||
&real_number_string_trimmed(1_234_567_890, 25),
|
||||
"0.000000000000000123456789"
|
||||
);
|
||||
let token_amount = token_amount_to_ui_amount(1_234_567_890, 20);
|
||||
assert_eq!(
|
||||
token_amount.ui_amount_string,
|
||||
real_number_string_trimmed(1_234_567_890, 20)
|
||||
);
|
||||
assert_eq!(token_amount.ui_amount, None);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5699,9 +5699,10 @@ pub mod tests {
|
|||
let balance: UiTokenAmount =
|
||||
serde_json::from_value(result["result"]["value"].clone()).unwrap();
|
||||
let error = f64::EPSILON;
|
||||
assert!((balance.ui_amount - 4.2).abs() < error);
|
||||
assert!((balance.ui_amount.unwrap() - 4.2).abs() < error);
|
||||
assert_eq!(balance.amount, 420.to_string());
|
||||
assert_eq!(balance.decimals, 2);
|
||||
assert_eq!(balance.ui_amount_string, "4.2".to_string());
|
||||
|
||||
// Test non-existent token account
|
||||
let req = format!(
|
||||
|
@ -5724,9 +5725,10 @@ pub mod tests {
|
|||
let supply: UiTokenAmount =
|
||||
serde_json::from_value(result["result"]["value"].clone()).unwrap();
|
||||
let error = f64::EPSILON;
|
||||
assert!((supply.ui_amount - 5.0).abs() < error);
|
||||
assert!((supply.ui_amount.unwrap() - 5.0).abs() < error);
|
||||
assert_eq!(supply.amount, 500.to_string());
|
||||
assert_eq!(supply.decimals, 2);
|
||||
assert_eq!(supply.ui_amount_string, "5".to_string());
|
||||
|
||||
// Test non-existent mint address
|
||||
let req = format!(
|
||||
|
@ -6022,17 +6024,19 @@ pub mod tests {
|
|||
RpcTokenAccountBalance {
|
||||
address: token_with_different_mint_pubkey.to_string(),
|
||||
amount: UiTokenAmount {
|
||||
ui_amount: 0.42,
|
||||
ui_amount: Some(0.42),
|
||||
decimals: 2,
|
||||
amount: "42".to_string(),
|
||||
ui_amount_string: "0.42".to_string(),
|
||||
}
|
||||
},
|
||||
RpcTokenAccountBalance {
|
||||
address: token_with_smaller_balance.to_string(),
|
||||
amount: UiTokenAmount {
|
||||
ui_amount: 0.1,
|
||||
ui_amount: Some(0.1),
|
||||
decimals: 2,
|
||||
amount: "10".to_string(),
|
||||
ui_amount_string: "0.1".to_string(),
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -6107,6 +6111,7 @@ pub mod tests {
|
|||
"uiAmount": 4.2,
|
||||
"decimals": 2,
|
||||
"amount": "420",
|
||||
"uiAmountString": "4.2",
|
||||
},
|
||||
"delegate": delegate.to_string(),
|
||||
"state": "initialized",
|
||||
|
@ -6115,11 +6120,13 @@ pub mod tests {
|
|||
"uiAmount": 0.1,
|
||||
"decimals": 2,
|
||||
"amount": "10",
|
||||
"uiAmountString": "0.1",
|
||||
},
|
||||
"delegatedAmount": {
|
||||
"uiAmount": 0.3,
|
||||
"decimals": 2,
|
||||
"amount": "30",
|
||||
"uiAmountString": "0.3",
|
||||
},
|
||||
"closeAuthority": owner.to_string(),
|
||||
}
|
||||
|
|
|
@ -677,7 +677,8 @@ The JSON structure of token balances is defined as a list of objects in the foll
|
|||
- `uiTokenAmount: <object>` -
|
||||
- `amount: <string>` - Raw amount of tokens as a string, ignoring decimals.
|
||||
- `decimals: <number>` - Number of decimals configured for token's mint.
|
||||
- `uiAmount: <string>` - Token amount as a float, accounting for decimals.
|
||||
- `uiAmount: <number | null>` - Token amount as a float, accounting for decimals. **DEPRECATED**
|
||||
- `uiAmountString: <string>` - Token amount as a string, accounting for decimals.
|
||||
|
||||
### getConfirmedBlocks
|
||||
|
||||
|
@ -2380,9 +2381,10 @@ Returns the token balance of an SPL Token account. **UNSTABLE**
|
|||
|
||||
The result will be an RpcResponse JSON object with `value` equal to a JSON object containing:
|
||||
|
||||
- `uiAmount: <string>` - the balance, using mint-prescribed decimals
|
||||
- `amount: <string>` - the raw balance without decimals, a string representation of u64
|
||||
- `decimals: <u8>` - number of base 10 digits to the right of the decimal place
|
||||
- `uiAmount: <number | null>` - the balance, using mint-prescribed decimals **DEPRECATED**
|
||||
- `uiAmountString: <string>` - the balance as a string, using mint-prescribed decimals
|
||||
|
||||
#### Example:
|
||||
|
||||
|
@ -2402,9 +2404,10 @@ Result:
|
|||
"slot": 1114
|
||||
},
|
||||
"value": {
|
||||
"uiAmount": "98.64",
|
||||
"amount": "9864",
|
||||
"decimals": 2
|
||||
"decimals": 2,
|
||||
"uiAmount": 98.64,
|
||||
"uiAmountString": "98.64",
|
||||
},
|
||||
"id": 1
|
||||
}
|
||||
|
@ -2477,8 +2480,9 @@ Result:
|
|||
"info": {
|
||||
"tokenAmount": {
|
||||
"amount": "1",
|
||||
"uiAmount": "0.1",
|
||||
"decimals": 1
|
||||
"decimals": 1,
|
||||
"uiAmount": 0.1,
|
||||
"uiAmountString": "0.1",
|
||||
},
|
||||
"delegate": "4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T",
|
||||
"delegatedAmount": 1,
|
||||
|
@ -2566,8 +2570,9 @@ Result:
|
|||
"info": {
|
||||
"tokenAmount": {
|
||||
"amount": "1",
|
||||
"uiAmount": "0.1",
|
||||
"decimals": 1
|
||||
"decimals": 1,
|
||||
"uiAmount": 0.1,
|
||||
"uiAmountString": "0.1",
|
||||
},
|
||||
"delegate": null,
|
||||
"delegatedAmount": 1,
|
||||
|
@ -2603,9 +2608,10 @@ Returns the 20 largest accounts of a particular SPL Token type. **UNSTABLE**
|
|||
The result will be an RpcResponse JSON object with `value` equal to an array of JSON objects containing:
|
||||
|
||||
- `address: <string>` - the address of the token account
|
||||
- `uiAmount: <string>` - the token account balance, using mint-prescribed decimals
|
||||
- `amount: <string>` - the raw token account balance without decimals, a string representation of u64
|
||||
- `decimals: <u8>` - number of base 10 digits to the right of the decimal place
|
||||
- `uiAmount: <number | null>` - the token account balance, using mint-prescribed decimals **DEPRECATED**
|
||||
- `uiAmountString: <string>` - the token account balance as a string, using mint-prescribed decimals
|
||||
|
||||
#### Example:
|
||||
|
||||
|
@ -2628,13 +2634,15 @@ Result:
|
|||
"address": "FYjHNoFtSQ5uijKrZFyYAxvEr87hsKXkXcxkcmkBAf4r",
|
||||
"amount": "771",
|
||||
"decimals": 2,
|
||||
"uiAmount": "7.71"
|
||||
"uiAmount": 7.71,
|
||||
"uiAmountString": "7.71"
|
||||
},
|
||||
{
|
||||
"address": "BnsywxTcaYeNUtzrPxQUvzAWxfzZe3ZLUJ4wMMuLESnu",
|
||||
"amount": "229",
|
||||
"decimals": 2,
|
||||
"uiAmount": "2.29"
|
||||
"uiAmount": 2.29,
|
||||
"uiAmountString": "2.29"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -2655,9 +2663,10 @@ Returns the total supply of an SPL Token type. **UNSTABLE**
|
|||
|
||||
The result will be an RpcResponse JSON object with `value` equal to a JSON object containing:
|
||||
|
||||
- `uiAmount: <string>` - the total token supply, using mint-prescribed decimals
|
||||
- `amount: <string>` - the raw total token supply without decimals, a string representation of u64
|
||||
- `decimals: <u8>` - number of base 10 digits to the right of the decimal place
|
||||
- `uiAmount: <number | null>` - the total token supply, using mint-prescribed decimals **DEPRECATED**
|
||||
- `uiAmountString: <string>` - the total token supply as a string, using mint-prescribed decimals
|
||||
|
||||
#### Example:
|
||||
|
||||
|
@ -2676,9 +2685,10 @@ Result:
|
|||
"slot": 1114
|
||||
},
|
||||
"value": {
|
||||
"uiAmount": "1000",
|
||||
"amount": "100000",
|
||||
"decimals": 2
|
||||
"decimals": 2,
|
||||
"uiAmount": 1000,
|
||||
"uiAmountString": "1000",
|
||||
}
|
||||
},
|
||||
"id": 1
|
||||
|
|
|
@ -104,6 +104,8 @@ pub struct UiTokenAmount {
|
|||
pub decimals: u32,
|
||||
#[prost(string, tag = "3")]
|
||||
pub amount: ::prost::alloc::string::String,
|
||||
#[prost(string, tag = "4")]
|
||||
pub ui_amount_string: ::prost::alloc::string::String,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Reward {
|
||||
|
|
|
@ -70,6 +70,7 @@ message UiTokenAmount {
|
|||
double ui_amount = 1;
|
||||
uint32 decimals = 2;
|
||||
string amount = 3;
|
||||
string ui_amount_string = 4;
|
||||
}
|
||||
|
||||
enum RewardType {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::StoredExtendedRewards;
|
||||
use solana_account_decoder::parse_token::UiTokenAmount;
|
||||
use solana_account_decoder::parse_token::{real_number_string_trimmed, UiTokenAmount};
|
||||
use solana_sdk::{
|
||||
hash::Hash,
|
||||
instruction::CompiledInstruction,
|
||||
|
@ -14,7 +14,10 @@ use solana_transaction_status::{
|
|||
ConfirmedBlock, InnerInstructions, Reward, RewardType, TransactionByAddrInfo,
|
||||
TransactionStatusMeta, TransactionTokenBalance, TransactionWithStatusMeta,
|
||||
};
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::{
|
||||
convert::{TryFrom, TryInto},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
pub mod generated {
|
||||
include!(concat!(
|
||||
|
@ -383,9 +386,10 @@ impl From<TransactionTokenBalance> for generated::TokenBalance {
|
|||
account_index: value.account_index as u32,
|
||||
mint: value.mint,
|
||||
ui_token_amount: Some(generated::UiTokenAmount {
|
||||
ui_amount: value.ui_token_amount.ui_amount,
|
||||
ui_amount: value.ui_token_amount.ui_amount.unwrap_or_default(),
|
||||
decimals: value.ui_token_amount.decimals as u32,
|
||||
amount: value.ui_token_amount.amount,
|
||||
ui_amount_string: value.ui_token_amount.ui_amount_string,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -398,9 +402,21 @@ impl From<generated::TokenBalance> for TransactionTokenBalance {
|
|||
account_index: value.account_index as u8,
|
||||
mint: value.mint,
|
||||
ui_token_amount: UiTokenAmount {
|
||||
ui_amount: ui_token_amount.ui_amount,
|
||||
ui_amount: if (ui_token_amount.ui_amount - f64::default()).abs() > f64::EPSILON {
|
||||
Some(ui_token_amount.ui_amount)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
decimals: ui_token_amount.decimals as u8,
|
||||
amount: ui_token_amount.amount,
|
||||
amount: ui_token_amount.amount.clone(),
|
||||
ui_amount_string: if !ui_token_amount.ui_amount_string.is_empty() {
|
||||
ui_token_amount.ui_amount_string
|
||||
} else {
|
||||
real_number_string_trimmed(
|
||||
u64::from_str(&ui_token_amount.amount).unwrap_or_default(),
|
||||
ui_token_amount.decimals as u8,
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use indicatif::{ProgressBar, ProgressStyle};
|
|||
use pickledb::PickleDb;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use solana_account_decoder::parse_token::{
|
||||
pubkey_from_spl_token_v2_0, spl_token_v2_0_pubkey, token_amount_to_ui_amount,
|
||||
pubkey_from_spl_token_v2_0, real_number_string, spl_token_v2_0_pubkey,
|
||||
};
|
||||
use solana_client::{
|
||||
client_error::{ClientError, Result as ClientResult},
|
||||
|
@ -103,8 +103,8 @@ pub enum Error {
|
|||
ClientError(#[from] ClientError),
|
||||
#[error("Missing lockup authority")]
|
||||
MissingLockupAuthority,
|
||||
#[error("insufficient funds in {0:?}, requires {1} SOL")]
|
||||
InsufficientFunds(FundingSources, f64),
|
||||
#[error("insufficient funds in {0:?}, requires {1}")]
|
||||
InsufficientFunds(FundingSources, String),
|
||||
#[error("Program error")]
|
||||
ProgramError(#[from] ProgramError),
|
||||
#[error("Exit signal received")]
|
||||
|
@ -273,33 +273,34 @@ fn build_messages(
|
|||
Some(allocation.lockup_date.parse::<DateTime<Utc>>().unwrap())
|
||||
};
|
||||
|
||||
let (display_amount, decimals, do_create_associated_token_account) =
|
||||
if let Some(spl_token_args) = &args.spl_token_args {
|
||||
let wallet_address = allocation.recipient.parse().unwrap();
|
||||
let associated_token_address = get_associated_token_address(
|
||||
&wallet_address,
|
||||
&spl_token_v2_0_pubkey(&spl_token_args.mint),
|
||||
);
|
||||
let do_create_associated_token_account =
|
||||
client.get_multiple_accounts(&[pubkey_from_spl_token_v2_0(
|
||||
&associated_token_address,
|
||||
)])?[0]
|
||||
.is_none();
|
||||
if do_create_associated_token_account {
|
||||
*created_accounts += 1;
|
||||
}
|
||||
(
|
||||
token_amount_to_ui_amount(allocation.amount, spl_token_args.decimals).ui_amount,
|
||||
spl_token_args.decimals as usize,
|
||||
do_create_associated_token_account,
|
||||
)
|
||||
} else {
|
||||
(lamports_to_sol(allocation.amount), 9, false)
|
||||
};
|
||||
println!(
|
||||
"{:<44} {:>24.2$}",
|
||||
allocation.recipient, display_amount, decimals
|
||||
);
|
||||
let do_create_associated_token_account = if let Some(spl_token_args) = &args.spl_token_args
|
||||
{
|
||||
let wallet_address = allocation.recipient.parse().unwrap();
|
||||
let associated_token_address = get_associated_token_address(
|
||||
&wallet_address,
|
||||
&spl_token_v2_0_pubkey(&spl_token_args.mint),
|
||||
);
|
||||
let do_create_associated_token_account = client
|
||||
.get_multiple_accounts(&[pubkey_from_spl_token_v2_0(&associated_token_address)])?
|
||||
[0]
|
||||
.is_none();
|
||||
if do_create_associated_token_account {
|
||||
*created_accounts += 1;
|
||||
}
|
||||
println!(
|
||||
"{:<44} {:>24}",
|
||||
allocation.recipient,
|
||||
real_number_string(allocation.amount, spl_token_args.decimals)
|
||||
);
|
||||
do_create_associated_token_account
|
||||
} else {
|
||||
println!(
|
||||
"{:<44} {:>24.9}",
|
||||
allocation.recipient,
|
||||
lamports_to_sol(allocation.amount)
|
||||
);
|
||||
false
|
||||
};
|
||||
let instructions = distribution_instructions(
|
||||
allocation,
|
||||
&new_stake_account_keypair.pubkey(),
|
||||
|
@ -719,7 +720,7 @@ fn check_payer_balances(
|
|||
if staker_balance < undistributed_tokens {
|
||||
return Err(Error::InsufficientFunds(
|
||||
vec![FundingSource::StakeAccount].into(),
|
||||
lamports_to_sol(undistributed_tokens),
|
||||
lamports_to_sol(undistributed_tokens).to_string(),
|
||||
));
|
||||
}
|
||||
if args.fee_payer.pubkey() == unlocked_sol_source {
|
||||
|
@ -727,7 +728,7 @@ fn check_payer_balances(
|
|||
if balance < fees + total_unlocked_sol {
|
||||
return Err(Error::InsufficientFunds(
|
||||
vec![FundingSource::SystemAccount, FundingSource::FeePayer].into(),
|
||||
lamports_to_sol(fees + total_unlocked_sol),
|
||||
lamports_to_sol(fees + total_unlocked_sol).to_string(),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
|
@ -735,14 +736,14 @@ fn check_payer_balances(
|
|||
if fee_payer_balance < fees {
|
||||
return Err(Error::InsufficientFunds(
|
||||
vec![FundingSource::FeePayer].into(),
|
||||
lamports_to_sol(fees),
|
||||
lamports_to_sol(fees).to_string(),
|
||||
));
|
||||
}
|
||||
let unlocked_sol_balance = client.get_balance(&unlocked_sol_source)?;
|
||||
if unlocked_sol_balance < total_unlocked_sol {
|
||||
return Err(Error::InsufficientFunds(
|
||||
vec![FundingSource::SystemAccount].into(),
|
||||
lamports_to_sol(total_unlocked_sol),
|
||||
lamports_to_sol(total_unlocked_sol).to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -751,7 +752,7 @@ fn check_payer_balances(
|
|||
if balance < fees + undistributed_tokens {
|
||||
return Err(Error::InsufficientFunds(
|
||||
vec![FundingSource::SystemAccount, FundingSource::FeePayer].into(),
|
||||
lamports_to_sol(fees + undistributed_tokens),
|
||||
lamports_to_sol(fees + undistributed_tokens).to_string(),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
|
@ -759,14 +760,14 @@ fn check_payer_balances(
|
|||
if fee_payer_balance < fees {
|
||||
return Err(Error::InsufficientFunds(
|
||||
vec![FundingSource::FeePayer].into(),
|
||||
lamports_to_sol(fees),
|
||||
lamports_to_sol(fees).to_string(),
|
||||
));
|
||||
}
|
||||
let sender_balance = client.get_balance(&distribution_source)?;
|
||||
if sender_balance < undistributed_tokens {
|
||||
return Err(Error::InsufficientFunds(
|
||||
vec![FundingSource::SystemAccount].into(),
|
||||
lamports_to_sol(undistributed_tokens),
|
||||
lamports_to_sol(undistributed_tokens).to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -1415,7 +1416,7 @@ mod tests {
|
|||
sources,
|
||||
vec![FundingSource::SystemAccount, FundingSource::FeePayer].into()
|
||||
);
|
||||
assert!((amount - (allocation_amount + fees_in_sol)).abs() < f64::EPSILON);
|
||||
assert_eq!(amount, (allocation_amount + fees_in_sol).to_string());
|
||||
} else {
|
||||
panic!("check_payer_balances should have errored");
|
||||
}
|
||||
|
@ -1452,7 +1453,7 @@ mod tests {
|
|||
sources,
|
||||
vec![FundingSource::SystemAccount, FundingSource::FeePayer].into()
|
||||
);
|
||||
assert!((amount - (allocation_amount + fees_in_sol)).abs() < f64::EPSILON);
|
||||
assert_eq!(amount, (allocation_amount + fees_in_sol).to_string());
|
||||
} else {
|
||||
panic!("check_payer_balances should have errored");
|
||||
}
|
||||
|
@ -1508,7 +1509,7 @@ mod tests {
|
|||
let err_result = check_payer_balances(1, &allocations, &client, &args).unwrap_err();
|
||||
if let Error::InsufficientFunds(sources, amount) = err_result {
|
||||
assert_eq!(sources, vec![FundingSource::SystemAccount].into());
|
||||
assert!((amount - allocation_amount).abs() < f64::EPSILON);
|
||||
assert_eq!(amount, allocation_amount.to_string());
|
||||
} else {
|
||||
panic!("check_payer_balances should have errored");
|
||||
}
|
||||
|
@ -1522,7 +1523,7 @@ mod tests {
|
|||
let err_result = check_payer_balances(1, &allocations, &client, &args).unwrap_err();
|
||||
if let Error::InsufficientFunds(sources, amount) = err_result {
|
||||
assert_eq!(sources, vec![FundingSource::FeePayer].into());
|
||||
assert!((amount - fees_in_sol).abs() < f64::EPSILON);
|
||||
assert_eq!(amount, fees_in_sol.to_string());
|
||||
} else {
|
||||
panic!("check_payer_balances should have errored");
|
||||
}
|
||||
|
@ -1609,7 +1610,10 @@ mod tests {
|
|||
check_payer_balances(1, &expensive_allocations, &client, &args).unwrap_err();
|
||||
if let Error::InsufficientFunds(sources, amount) = err_result {
|
||||
assert_eq!(sources, vec![FundingSource::StakeAccount].into());
|
||||
assert!((amount - (expensive_allocation_amount - unlocked_sol)).abs() < f64::EPSILON);
|
||||
assert_eq!(
|
||||
amount,
|
||||
(expensive_allocation_amount - unlocked_sol).to_string()
|
||||
);
|
||||
} else {
|
||||
panic!("check_payer_balances should have errored");
|
||||
}
|
||||
|
@ -1631,7 +1635,7 @@ mod tests {
|
|||
sources,
|
||||
vec![FundingSource::SystemAccount, FundingSource::FeePayer].into()
|
||||
);
|
||||
assert!((amount - (unlocked_sol + fees_in_sol)).abs() < f64::EPSILON);
|
||||
assert_eq!(amount, (unlocked_sol + fees_in_sol).to_string());
|
||||
} else {
|
||||
panic!("check_payer_balances should have errored");
|
||||
}
|
||||
|
@ -1668,7 +1672,7 @@ mod tests {
|
|||
sources,
|
||||
vec![FundingSource::SystemAccount, FundingSource::FeePayer].into()
|
||||
);
|
||||
assert!((amount - (unlocked_sol + fees_in_sol)).abs() < f64::EPSILON);
|
||||
assert_eq!(amount, (unlocked_sol + fees_in_sol).to_string());
|
||||
} else {
|
||||
panic!("check_payer_balances should have errored");
|
||||
}
|
||||
|
@ -1731,7 +1735,7 @@ mod tests {
|
|||
let err_result = check_payer_balances(1, &allocations, &client, &args).unwrap_err();
|
||||
if let Error::InsufficientFunds(sources, amount) = err_result {
|
||||
assert_eq!(sources, vec![FundingSource::SystemAccount].into());
|
||||
assert!((amount - unlocked_sol).abs() < f64::EPSILON);
|
||||
assert_eq!(amount, unlocked_sol.to_string());
|
||||
} else {
|
||||
panic!("check_payer_balances should have errored");
|
||||
}
|
||||
|
@ -1745,7 +1749,7 @@ mod tests {
|
|||
let err_result = check_payer_balances(1, &allocations, &client, &args).unwrap_err();
|
||||
if let Error::InsufficientFunds(sources, amount) = err_result {
|
||||
assert_eq!(sources, vec![FundingSource::FeePayer].into());
|
||||
assert!((amount - fees_in_sol).abs() < f64::EPSILON);
|
||||
assert_eq!(amount, fees_in_sol.to_string());
|
||||
} else {
|
||||
panic!("check_payer_balances should have errored");
|
||||
}
|
||||
|
|
|
@ -4,7 +4,8 @@ use crate::{
|
|||
};
|
||||
use console::style;
|
||||
use solana_account_decoder::parse_token::{
|
||||
pubkey_from_spl_token_v2_0, spl_token_v2_0_pubkey, token_amount_to_ui_amount,
|
||||
pubkey_from_spl_token_v2_0, real_number_string, real_number_string_trimmed,
|
||||
spl_token_v2_0_pubkey,
|
||||
};
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_sdk::{instruction::Instruction, native_token::lamports_to_sol};
|
||||
|
@ -109,7 +110,7 @@ pub fn check_spl_token_balances(
|
|||
if fee_payer_balance < fees + account_creation_amount {
|
||||
return Err(Error::InsufficientFunds(
|
||||
vec![FundingSource::FeePayer].into(),
|
||||
lamports_to_sol(fees + account_creation_amount),
|
||||
lamports_to_sol(fees + account_creation_amount).to_string(),
|
||||
));
|
||||
}
|
||||
let source_token_account = client
|
||||
|
@ -119,7 +120,7 @@ pub fn check_spl_token_balances(
|
|||
if source_token.amount < allocation_amount {
|
||||
return Err(Error::InsufficientFunds(
|
||||
vec![FundingSource::SplTokenAccount].into(),
|
||||
token_amount_to_ui_amount(allocation_amount, spl_token_args.decimals).ui_amount,
|
||||
real_number_string_trimmed(allocation_amount, spl_token_args.decimals),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
|
@ -142,20 +143,12 @@ pub fn print_token_balances(
|
|||
let (actual, difference) = if let Ok(recipient_token) =
|
||||
SplTokenAccount::unpack(&recipient_account.data)
|
||||
{
|
||||
let actual_ui_amount =
|
||||
token_amount_to_ui_amount(recipient_token.amount, spl_token_args.decimals).ui_amount;
|
||||
let expected_ui_amount =
|
||||
token_amount_to_ui_amount(expected, spl_token_args.decimals).ui_amount;
|
||||
let actual_ui_amount = real_number_string(recipient_token.amount, spl_token_args.decimals);
|
||||
let delta_string =
|
||||
real_number_string(recipient_token.amount - expected, spl_token_args.decimals);
|
||||
(
|
||||
style(format!(
|
||||
"{:>24.1$}",
|
||||
actual_ui_amount, spl_token_args.decimals as usize
|
||||
)),
|
||||
format!(
|
||||
"{:>24.1$}",
|
||||
actual_ui_amount - expected_ui_amount,
|
||||
spl_token_args.decimals as usize
|
||||
),
|
||||
style(format!("{:>24}", actual_ui_amount)),
|
||||
format!("{:>24}", delta_string),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
|
@ -164,12 +157,11 @@ pub fn print_token_balances(
|
|||
)
|
||||
};
|
||||
println!(
|
||||
"{:<44} {:>24.4$} {:>24} {:>24}",
|
||||
"{:<44} {:>24} {:>24} {:>24}",
|
||||
allocation.recipient,
|
||||
token_amount_to_ui_amount(expected, spl_token_args.decimals).ui_amount,
|
||||
real_number_string(expected, spl_token_args.decimals),
|
||||
actual,
|
||||
difference,
|
||||
spl_token_args.decimals as usize
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use solana_account_decoder::parse_token::token_amount_to_ui_amount;
|
||||
use solana_account_decoder::parse_token::real_number_string_trimmed;
|
||||
use solana_sdk::native_token::lamports_to_sol;
|
||||
use std::{
|
||||
fmt::{Debug, Display, Formatter, Result},
|
||||
|
@ -27,7 +27,7 @@ impl Token {
|
|||
write!(f, "{}{}", SOL_SYMBOL, amount)
|
||||
}
|
||||
TokenType::SplToken => {
|
||||
let amount = token_amount_to_ui_amount(self.amount, self.decimals).ui_amount;
|
||||
let amount = real_number_string_trimmed(self.amount, self.decimals);
|
||||
write!(f, "{} tokens", amount)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -890,7 +890,8 @@ mod test {
|
|||
"tokenAmount": {
|
||||
"uiAmount": 0.42,
|
||||
"decimals": 2,
|
||||
"amount": "42"
|
||||
"amount": "42",
|
||||
"uiAmountString": "0.42",
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -922,7 +923,8 @@ mod test {
|
|||
"tokenAmount": {
|
||||
"uiAmount": 0.42,
|
||||
"decimals": 2,
|
||||
"amount": "42"
|
||||
"amount": "42",
|
||||
"uiAmountString": "0.42",
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -954,7 +956,8 @@ mod test {
|
|||
"tokenAmount": {
|
||||
"uiAmount": 0.42,
|
||||
"decimals": 2,
|
||||
"amount": "42"
|
||||
"amount": "42",
|
||||
"uiAmountString": "0.42",
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -986,7 +989,8 @@ mod test {
|
|||
"tokenAmount": {
|
||||
"uiAmount": 0.42,
|
||||
"decimals": 2,
|
||||
"amount": "42"
|
||||
"amount": "42",
|
||||
"uiAmountString": "0.42",
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1016,7 +1020,8 @@ mod test {
|
|||
"tokenAmount": {
|
||||
"uiAmount": 0.42,
|
||||
"decimals": 2,
|
||||
"amount": "42"
|
||||
"amount": "42",
|
||||
"uiAmountString": "0.42",
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1046,7 +1051,8 @@ mod test {
|
|||
"tokenAmount": {
|
||||
"uiAmount": 0.42,
|
||||
"decimals": 2,
|
||||
"amount": "42"
|
||||
"amount": "42",
|
||||
"uiAmountString": "0.42",
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue