fixed token name validation
This commit is contained in:
parent
bdca5ed1ff
commit
e044f15e76
|
|
@ -1,4 +1,5 @@
|
|||
use blockchain::blocks::burn::{BurnTransaction, UnsignedBurnTransaction};
|
||||
use blockchain::common::asset_names::padded_normalized_asset_input;
|
||||
use blockchain::common::cli_prompts::{prompt_hidden_nonempty, prompt_visible, prompt_wallet_path};
|
||||
use blockchain::common::network_paths_and_settings::block_extension_and_paths;
|
||||
|
||||
|
|
@ -9,13 +10,6 @@ use blockchain::File;
|
|||
use blockchain::Utc;
|
||||
use blockchain::{create_dir_all, AsyncWriteExt};
|
||||
|
||||
// Pad the asset name so it matches the 15-byte on-chain asset format.
|
||||
fn pad_to_width(input: &str, width: usize) -> String {
|
||||
let mut result = String::with_capacity(width);
|
||||
let _ = std::fmt::write(&mut result, format_args!("{input:<width$}"));
|
||||
result
|
||||
}
|
||||
|
||||
fn display_fee(value: u64) -> f64 {
|
||||
// Fees are stored as atomic units and displayed as whole-coin decimals for the CLI.
|
||||
value as f64 / 100_000_000.0
|
||||
|
|
@ -29,7 +23,10 @@ async fn main() {
|
|||
|
||||
// Burnable assets are tokens or NFTs, never the base coin for this transaction type.
|
||||
let coin_name = prompt_visible("Please enter the token or NFT name you wish to burn: ").await;
|
||||
let coin = pad_to_width(&coin_name.trim().to_lowercase(), 15);
|
||||
let Some(coin) = padded_normalized_asset_input(coin_name.trim()) else {
|
||||
println!("Burn asset must normalize to 3-15 alphanumeric characters.");
|
||||
return;
|
||||
};
|
||||
|
||||
if coin.trim().to_lowercase() == block_extension_and_paths().1.trim().to_lowercase() {
|
||||
println!("Base coin cannot be burned with this transaction type.");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use blockchain::blocks::issue_token::{IssueTokenTransaction, UnsignedIssueTokenTransaction};
|
||||
use blockchain::common::asset_names::padded_normalized_asset_input;
|
||||
use blockchain::common::cli_prompts::{prompt_hidden_nonempty, prompt_visible, prompt_wallet_path};
|
||||
use blockchain::common::types::ISSUE_TOKEN_FEE;
|
||||
|
||||
|
|
@ -8,13 +9,6 @@ use blockchain::File;
|
|||
use blockchain::Utc;
|
||||
use blockchain::{create_dir_all, AsyncWriteExt};
|
||||
|
||||
// Pad the ticker so it matches the fixed-width 15-byte on-chain format.
|
||||
fn pad_to_width(input: &str, width: usize) -> String {
|
||||
let mut result = String::with_capacity(width);
|
||||
let _ = std::fmt::write(&mut result, format_args!("{input:<width$}"));
|
||||
result
|
||||
}
|
||||
|
||||
fn display_fee(value: u64) -> f64 {
|
||||
// Fees are stored as atomic units and displayed as whole-coin decimals for the CLI.
|
||||
value as f64 / 100_000_000.0
|
||||
|
|
@ -29,7 +23,10 @@ async fn main() {
|
|||
// The ticker is stored as a fixed-width 15-byte asset field.
|
||||
let ticker_name =
|
||||
prompt_visible("Please enter the ticker / token name you wish to issue more of: ").await;
|
||||
let ticker = pad_to_width(&ticker_name.trim().to_lowercase(), 15);
|
||||
let Some(ticker) = padded_normalized_asset_input(ticker_name.trim()) else {
|
||||
println!("Ticker must normalize to 3-15 alphanumeric characters.");
|
||||
return;
|
||||
};
|
||||
|
||||
// Token amounts are entered as whole tokens and stored as atomic units.
|
||||
let number_string =
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use blockchain::blocks::loans::UnsignedLoanContractTransaction;
|
||||
use blockchain::common::asset_names::padded_normalized_asset_input;
|
||||
use blockchain::common::cli_prompts::{prompt_hidden_nonempty, prompt_visible, prompt_wallet_path};
|
||||
use blockchain::common::network_paths_and_settings::block_extension_and_paths;
|
||||
use blockchain::common::types::LENDER_FEE;
|
||||
|
||||
use blockchain::json;
|
||||
|
|
@ -9,11 +11,13 @@ use blockchain::File;
|
|||
use blockchain::{create_dir_all, AsyncWriteExt};
|
||||
use blockchain::{Local, LocalResult, NaiveDate, NaiveTime, TimeZone};
|
||||
|
||||
fn pad_to_width(input: &str, width: usize) -> String {
|
||||
// Asset names are fixed-width fields in the loan transaction bytes.
|
||||
let mut result = String::with_capacity(width);
|
||||
let _ = std::fmt::write(&mut result, format_args!("{input:<width$}"));
|
||||
result
|
||||
fn normalize_asset_or_base(input: &str) -> Option<String> {
|
||||
let base_coin = block_extension_and_paths().1;
|
||||
if input.trim().eq_ignore_ascii_case(base_coin.trim()) {
|
||||
Some(base_coin)
|
||||
} else {
|
||||
padded_normalized_asset_input(input.trim())
|
||||
}
|
||||
}
|
||||
|
||||
fn display_fee(value: u64) -> f64 {
|
||||
|
|
@ -63,8 +67,10 @@ async fn main() {
|
|||
|
||||
// Coin/token and collateral names are padded to fixed-width transaction fields.
|
||||
let loan_coin_name = prompt_visible("What coin or token will you be lending out? ").await;
|
||||
let loan_coin_name = loan_coin_name.trim().to_lowercase();
|
||||
let loan_coin = pad_to_width(&loan_coin_name, 15);
|
||||
let Some(loan_coin) = normalize_asset_or_base(&loan_coin_name) else {
|
||||
println!("Loan asset must be the base coin or normalize to 3-15 alphanumeric characters.");
|
||||
return;
|
||||
};
|
||||
|
||||
let loan_amount_string = prompt_visible("How many coins or tokens will you be lending? ").await;
|
||||
let loan_amount_f64: f64 = loan_amount_string
|
||||
|
|
@ -123,8 +129,10 @@ async fn main() {
|
|||
let collateral_name =
|
||||
prompt_visible("What collateral coin, token, or NFT will you be accepting for this loan? ")
|
||||
.await;
|
||||
let collateral_name = collateral_name.trim().to_lowercase();
|
||||
let collateral = pad_to_width(&collateral_name, 15);
|
||||
let Some(collateral) = padded_normalized_asset_input(collateral_name.trim()) else {
|
||||
println!("Collateral asset must normalize to 3-15 alphanumeric characters.");
|
||||
return;
|
||||
};
|
||||
|
||||
let collateral_amount_string = prompt_visible("How many collateral coins or tokens will you be accepting for this loan (enter 1 for NFT collateral)? ").await;
|
||||
let collateral_amount_f64: f64 = collateral_amount_string
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use blockchain::blocks::nft::{CreateNftTransaction, UnsignedCreateNftTransaction};
|
||||
use blockchain::common::asset_names::padded_normalized_asset_input;
|
||||
use blockchain::common::cli_prompts::{prompt_hidden_nonempty, prompt_visible, prompt_wallet_path};
|
||||
use blockchain::common::types::CREATE_NFT_FEE;
|
||||
|
||||
|
|
@ -31,7 +32,10 @@ async fn main() {
|
|||
|
||||
// get user input ticker
|
||||
let nft_ticker_name = prompt_visible("Please enter the name for your NFT. This can be 3 to 15 characters and must be 100% unique. First come first serve: ").await;
|
||||
let nft_name = pad_to_width(nft_ticker_name.trim(), 15);
|
||||
let Some(nft_name) = padded_normalized_asset_input(nft_ticker_name.trim()) else {
|
||||
println!("NFT name must normalize to 3-15 alphanumeric characters.");
|
||||
return;
|
||||
};
|
||||
|
||||
// get the padded CID string
|
||||
let ipfs_hash = prompt_visible("Enter your IPFS CID for your NFT. This will be stored in a fixed 100 character field, so shorter CIDs are padded with spaces: ").await;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use blockchain::blocks::swap::UnsignedSwapTransaction;
|
||||
use blockchain::common::asset_names::padded_normalized_asset_input;
|
||||
use blockchain::common::cli_prompts::{prompt_hidden_nonempty, prompt_visible, prompt_wallet_path};
|
||||
use blockchain::common::network_paths_and_settings::block_extension_and_paths;
|
||||
use blockchain::common::types::SWAP_FEE;
|
||||
|
||||
use blockchain::json;
|
||||
|
|
@ -10,11 +12,13 @@ use blockchain::File;
|
|||
use blockchain::Utc;
|
||||
use blockchain::{create_dir_all, AsyncWriteExt};
|
||||
|
||||
// pad the coin to ensure 15 characters
|
||||
fn pad_to_width(input: &str, width: usize) -> String {
|
||||
let mut result = String::with_capacity(width); // Pre-allocate string with capacity
|
||||
let _ = std::fmt::write(&mut result, format_args!("{input:<width$}"));
|
||||
result
|
||||
fn normalize_asset_or_base(input: &str) -> Option<String> {
|
||||
let base_coin = block_extension_and_paths().1;
|
||||
if input.trim().eq_ignore_ascii_case(base_coin.trim()) {
|
||||
Some(base_coin)
|
||||
} else {
|
||||
padded_normalized_asset_input(input.trim())
|
||||
}
|
||||
}
|
||||
|
||||
fn display_fee(value: u64) -> f64 {
|
||||
|
|
@ -30,8 +34,10 @@ async fn main() {
|
|||
// get user input tocken1
|
||||
let ticker1_name =
|
||||
prompt_visible("Please enter the coin or token you wish to send during the swap: ").await;
|
||||
let ticker1_name = ticker1_name.trim().to_lowercase();
|
||||
let ticker1 = pad_to_width(&ticker1_name, 15);
|
||||
let Some(ticker1) = normalize_asset_or_base(&ticker1_name) else {
|
||||
println!("Swap asset must be the base coin or normalize to 3-15 alphanumeric characters.");
|
||||
return;
|
||||
};
|
||||
|
||||
let nft_series1_string = prompt_visible("Please enter the NFT series number for the asset you are sending, or 0 for coins/tokens/1of1 NFTs: ").await;
|
||||
let nft_series1: u32 = nft_series1_string
|
||||
|
|
@ -52,8 +58,10 @@ async fn main() {
|
|||
let ticker2_name =
|
||||
prompt_visible("Please enter the coin or token you wish to receive during the swap: ")
|
||||
.await;
|
||||
let ticker2_name = ticker2_name.trim().to_lowercase();
|
||||
let ticker2 = pad_to_width(&ticker2_name, 15);
|
||||
let Some(ticker2) = normalize_asset_or_base(&ticker2_name) else {
|
||||
println!("Swap asset must be the base coin or normalize to 3-15 alphanumeric characters.");
|
||||
return;
|
||||
};
|
||||
|
||||
let nft_series2_string = prompt_visible("Please enter the NFT series number for the asset you expect to receive, or 0 for coins/tokens/1of1 NFTs: ").await;
|
||||
let nft_series2: u32 = nft_series2_string
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use blockchain::blocks::token::{CreateTokenTransaction, UnsignedCreateTokenTransaction};
|
||||
use blockchain::common::asset_names::padded_normalized_asset_input;
|
||||
use blockchain::common::cli_prompts::{prompt_hidden_nonempty, prompt_visible, prompt_wallet_path};
|
||||
use blockchain::common::types::CREATE_TOKEN_FEE;
|
||||
|
||||
|
|
@ -8,13 +9,6 @@ use blockchain::File;
|
|||
use blockchain::Utc;
|
||||
use blockchain::{create_dir_all, AsyncWriteExt};
|
||||
|
||||
// pad the coin to ensure 15 characters
|
||||
fn pad_to_width(input: &str, width: usize) -> String {
|
||||
let mut result = String::with_capacity(width); // Pre-allocate string with capacity
|
||||
let _ = std::fmt::write(&mut result, format_args!("{input:<width$}"));
|
||||
result
|
||||
}
|
||||
|
||||
fn display_fee(value: u64) -> f64 {
|
||||
value as f64 / 100_000_000.0
|
||||
}
|
||||
|
|
@ -27,7 +21,10 @@ async fn main() {
|
|||
|
||||
// get user input ticker
|
||||
let ticker_name = prompt_visible("Please enter the ticker / token name you wish to create. This can be 3 to 15 characters and must be 100% unique. First come first serve: ").await;
|
||||
let ticker = pad_to_width(ticker_name.trim(), 15);
|
||||
let Some(ticker) = padded_normalized_asset_input(ticker_name.trim()) else {
|
||||
println!("Ticker must normalize to 3-15 alphanumeric characters.");
|
||||
return;
|
||||
};
|
||||
|
||||
// get user input value
|
||||
let number_string = prompt_visible(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use blockchain::blocks::transfer::{TransferTransaction, UnsignedTransferTransaction};
|
||||
use blockchain::common::asset_names::padded_normalized_asset_input;
|
||||
use blockchain::common::cli_prompts::{prompt_hidden_nonempty, prompt_visible, prompt_wallet_path};
|
||||
use blockchain::common::network_paths_and_settings::block_extension_and_paths;
|
||||
|
||||
|
|
@ -11,11 +12,13 @@ use blockchain::File;
|
|||
use blockchain::Utc;
|
||||
use blockchain::{create_dir_all, AsyncWriteExt};
|
||||
|
||||
// pad the coin to ensure 15 characters
|
||||
fn pad_to_width(input: &str, width: usize) -> String {
|
||||
let mut result = String::with_capacity(width); // Pre-allocate string with capacity
|
||||
let _ = std::fmt::write(&mut result, format_args!("{input:<width$}"));
|
||||
result
|
||||
fn normalize_asset_or_base(input: &str) -> Option<String> {
|
||||
let base_coin = block_extension_and_paths().1;
|
||||
if input.trim().eq_ignore_ascii_case(base_coin.trim()) {
|
||||
Some(base_coin)
|
||||
} else {
|
||||
padded_normalized_asset_input(input.trim())
|
||||
}
|
||||
}
|
||||
|
||||
fn display_fee(value: u64) -> f64 {
|
||||
|
|
@ -42,9 +45,11 @@ async fn main() {
|
|||
} else {
|
||||
prompt_visible("Please enter the coin or token you wish to transfer: ").await
|
||||
};
|
||||
let coin = pad_to_width(&coin_name, 15);
|
||||
let is_base_coin =
|
||||
coin.trim().to_lowercase() == block_extension_and_paths().1.trim().to_lowercase();
|
||||
let Some(coin) = normalize_asset_or_base(&coin_name) else {
|
||||
println!("Transfer asset must be the base coin or normalize to 3-15 alphanumeric characters.");
|
||||
return;
|
||||
};
|
||||
let is_base_coin = coin.trim().eq_ignore_ascii_case(block_extension_and_paths().1.trim());
|
||||
|
||||
let value_string = if args.len() > 2 {
|
||||
args[2].clone()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use blockchain::blocks::swap::UnsignedSwapTransaction;
|
||||
use blockchain::common::asset_names::padded_normalized_asset_input;
|
||||
use blockchain::common::cli_prompts::{
|
||||
ask_yes_no_question, prompt_hidden_nonempty, prompt_wallet_path,
|
||||
};
|
||||
|
|
@ -12,11 +13,12 @@ use blockchain::standalone_tools::vanity_resolver::resolve_wallet_address_input;
|
|||
use blockchain::wallets::structures::Wallet;
|
||||
use blockchain::Value;
|
||||
|
||||
// padd the coin to ensure 15 characters
|
||||
fn pad_to_width(input: &str, width: usize) -> String {
|
||||
let mut result = String::with_capacity(width); // Pre-allocate string with capacity
|
||||
let _ = std::fmt::write(&mut result, format_args!("{input:<width$}"));
|
||||
result
|
||||
fn normalize_asset_or_base(input: &str, base_coin: &str) -> Option<String> {
|
||||
if input.trim().eq_ignore_ascii_case(base_coin.trim()) {
|
||||
Some(base_coin.to_string())
|
||||
} else {
|
||||
padded_normalized_asset_input(input.trim())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
|
|
@ -162,8 +164,14 @@ async fn main() {
|
|||
return;
|
||||
}
|
||||
|
||||
let padded_token_name1 = pad_to_width(&token_name1, 15);
|
||||
let padded_token_name2 = pad_to_width(&token_name2, 15);
|
||||
let Some(padded_token_name1) = normalize_asset_or_base(&token_name1, &network_coin) else {
|
||||
println!("Ticker1 must be the base coin or normalize to 3-15 alphanumeric characters.");
|
||||
return;
|
||||
};
|
||||
let Some(padded_token_name2) = normalize_asset_or_base(&token_name2, &network_coin) else {
|
||||
println!("Ticker2 must be the base coin or normalize to 3-15 alphanumeric characters.");
|
||||
return;
|
||||
};
|
||||
|
||||
let unsigned_swap = UnsignedSwapTransaction::new(
|
||||
txtype,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
use crate::common::types::COIN_LENGTH;
|
||||
|
||||
pub fn normalize_asset_identifier(input: &str) -> String {
|
||||
input
|
||||
.chars()
|
||||
.filter(|character| character.is_ascii_alphanumeric())
|
||||
.flat_map(char::to_lowercase)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn padded_normalized_asset_identifier(input: &str) -> Option<String> {
|
||||
let normalized = normalize_asset_identifier(input);
|
||||
if normalized.len() < 3 || normalized.len() > COIN_LENGTH {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(format!("{normalized:<COIN_LENGTH$}"))
|
||||
}
|
||||
|
||||
pub fn padded_normalized_asset_input(input: &str) -> Option<String> {
|
||||
if !input
|
||||
.chars()
|
||||
.all(|character| character.is_ascii_alphanumeric() || character.is_ascii_whitespace())
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
padded_normalized_asset_identifier(input)
|
||||
}
|
||||
|
||||
pub fn is_canonical_padded_asset_identifier(input: &str) -> bool {
|
||||
padded_normalized_asset_identifier(input).is_some_and(|canonical| canonical == input)
|
||||
}
|
||||
|
||||
pub fn is_canonical_padded_asset_or_base(input: &str, base_coin: &str) -> bool {
|
||||
input.trim().eq_ignore_ascii_case(base_coin.trim())
|
||||
|| is_canonical_padded_asset_identifier(input)
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
pub mod binary_conversions;
|
||||
pub mod asset_names;
|
||||
pub mod check_genesis;
|
||||
pub mod cli_prompts;
|
||||
pub mod network_paths_and_settings;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::blocks::burn::BurnTransaction;
|
||||
use crate::common::asset_names::is_canonical_padded_asset_identifier;
|
||||
use crate::common::nft_assets::nft_asset_name;
|
||||
use crate::common::types::{BURN_FEE, COIN_LENGTH};
|
||||
use crate::encode;
|
||||
|
|
@ -51,6 +52,9 @@ impl BurnTransaction {
|
|||
if self.unsigned_burn.coin.len() != COIN_LENGTH {
|
||||
return Err("Coin length is invalid.".to_string());
|
||||
}
|
||||
if !is_canonical_padded_asset_identifier(&self.unsigned_burn.coin) {
|
||||
return Err("Burn asset must be a canonical alphanumeric asset id.".to_string());
|
||||
}
|
||||
|
||||
// The base coin can never be destroyed through the burn path.
|
||||
if self.unsigned_burn.coin.trim().to_lowercase() == BASECOIN.trim().to_lowercase() {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::blocks::nft::CreateNftTransaction;
|
||||
use crate::common::asset_names::is_canonical_padded_asset_identifier;
|
||||
use crate::common::nft_assets::nft_asset_name;
|
||||
use crate::common::types::{COIN_LENGTH, CREATE_NFT_FEE};
|
||||
use crate::encode;
|
||||
|
|
@ -27,6 +28,11 @@ impl CreateNftTransaction {
|
|||
)
|
||||
.map_err(|s| s.to_string())?;
|
||||
}
|
||||
if !is_canonical_padded_asset_identifier(&self.unsigned_create_nft.nft_name) {
|
||||
return Err(
|
||||
"NFT name must normalize to 3-15 lowercase alphanumeric characters.".to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
if is_reserved_base_coin_ticker(&self.unsigned_create_nft.nft_name) {
|
||||
return Err("NFT name is reserved for the base coin.".to_string());
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::blocks::token::CreateTokenTransaction;
|
||||
use crate::common::asset_names::is_canonical_padded_asset_identifier;
|
||||
use crate::common::types::{COIN_LENGTH, CREATE_TOKEN_FEE};
|
||||
use crate::encode;
|
||||
use crate::records::memory::mempool::BASECOIN;
|
||||
|
|
@ -27,6 +28,11 @@ impl CreateTokenTransaction {
|
|||
return Err("Ticker length must be 15 characters. Consider padding with empty spaces")
|
||||
.map_err(|s| s.to_string())?;
|
||||
}
|
||||
if !is_canonical_padded_asset_identifier(&self.unsigned_create_token.ticker) {
|
||||
return Err(
|
||||
"Ticker must normalize to 3-15 lowercase alphanumeric characters.".to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
if is_reserved_base_coin_ticker(&self.unsigned_create_token.ticker) {
|
||||
return Err("Ticker is reserved for the base coin.".to_string());
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::blocks::issue_token::IssueTokenTransaction;
|
||||
use crate::blocks::token::CreateTokenTransaction;
|
||||
use crate::common::asset_names::is_canonical_padded_asset_identifier;
|
||||
use crate::common::network_paths_and_settings::block_extension_and_paths;
|
||||
use crate::common::types::{COIN_LENGTH, ISSUE_TOKEN_FEE};
|
||||
use crate::records::memory::mempool::BASECOIN;
|
||||
|
|
@ -88,6 +89,11 @@ impl IssueTokenTransaction {
|
|||
.to_string(),
|
||||
);
|
||||
}
|
||||
if !is_canonical_padded_asset_identifier(ticker) {
|
||||
return Err(
|
||||
"Ticker must normalize to 3-15 lowercase alphanumeric characters.".to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
// Check reserved keywords not used
|
||||
if reserved_base_coins()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
use crate::blocks::loans::LoanContractTransaction;
|
||||
use crate::common::asset_names::{
|
||||
is_canonical_padded_asset_identifier, is_canonical_padded_asset_or_base,
|
||||
};
|
||||
use crate::common::types::{COIN_LENGTH, LENDER_FEE};
|
||||
use crate::encode;
|
||||
use crate::records::memory::mempool::BASECOIN;
|
||||
|
|
@ -91,6 +94,14 @@ impl LoanContractTransaction {
|
|||
)
|
||||
.map_err(|s| s.to_string())?;
|
||||
}
|
||||
if !is_canonical_padded_asset_or_base(&loan_coin, &BASECOIN)
|
||||
|| !is_canonical_padded_asset_identifier(&collateral)
|
||||
{
|
||||
return Err(
|
||||
"Loan assets must use the base coin or canonical alphanumeric asset ids."
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
// Loaned assets must already exist as either the network base coin
|
||||
// or a previously created token.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::blocks::swap::SwapTransaction;
|
||||
use crate::common::asset_names::is_canonical_padded_asset_or_base;
|
||||
use crate::common::network_paths_and_settings::block_extension_and_paths;
|
||||
use crate::common::nft_assets::nft_asset_name;
|
||||
use crate::common::types::{COIN_LENGTH, SWAP_FEE};
|
||||
|
|
@ -75,6 +76,18 @@ impl SwapTransaction {
|
|||
"Ticker lengths are invalid. Consider padding with empty spaces".to_string(),
|
||||
);
|
||||
}
|
||||
let network_base_coin_padded = block_extension_and_paths().1;
|
||||
if !is_canonical_padded_asset_or_base(&self.unsigned_swap.ticker1, &network_base_coin_padded)
|
||||
|| !is_canonical_padded_asset_or_base(
|
||||
&self.unsigned_swap.ticker2,
|
||||
&network_base_coin_padded,
|
||||
)
|
||||
{
|
||||
return Err(
|
||||
"Swap assets must be the base coin or canonical alphanumeric asset ids."
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
// Build concrete asset names for NFT series swaps before checking
|
||||
// balances and registry existence.
|
||||
|
|
@ -83,7 +96,7 @@ impl SwapTransaction {
|
|||
|
||||
// The base coin name comes from the active network settings so
|
||||
// mainnet and testnet validate against their own ticker.
|
||||
let network_base_coin = block_extension_and_paths().1.trim().to_lowercase();
|
||||
let network_base_coin = network_base_coin_padded.trim().to_lowercase();
|
||||
|
||||
// Numbered NFT swaps are single-item transfers, while non-series
|
||||
// assets must already exist as a token, NFT, or base coin.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::blocks::transfer::TransferTransaction;
|
||||
use crate::common::asset_names::is_canonical_padded_asset_or_base;
|
||||
use crate::common::nft_assets::nft_asset_name;
|
||||
use crate::common::types::{minimum_transfer_fee, COIN_LENGTH};
|
||||
use crate::encode;
|
||||
|
|
@ -138,6 +139,12 @@ impl TransferTransaction {
|
|||
if self.unsigned_transfer.coin.len() != COIN_LENGTH {
|
||||
return Err("Coin length is invalid.".to_string());
|
||||
}
|
||||
if !is_canonical_padded_asset_or_base(&self.unsigned_transfer.coin, &BASECOIN) {
|
||||
return Err(
|
||||
"Transfer asset must be the base coin or a canonical alphanumeric asset id."
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
// Saved-chain duplicates are rejected by txid even if the mempool
|
||||
// did not already contain the transaction.
|
||||
|
|
|
|||
Loading…
Reference in New Issue