diff --git a/Cargo.lock b/Cargo.lock index 5fce12785..16be52cbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3458,8 +3458,6 @@ dependencies = [ "solana-stake-program 0.20.0", "solana-storage-api 0.20.0", "solana-storage-program 0.20.0", - "solana-token-api 0.20.0", - "solana-token-program 0.20.0", "solana-vote-api 0.20.0", "solana-vote-program 0.20.0", ] @@ -3855,30 +3853,6 @@ dependencies = [ "solana-storage-api 0.20.0", ] -[[package]] -name = "solana-token-api" -version = "0.20.0" -dependencies = [ - "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "solana-logger 0.20.0", - "solana-sdk 0.20.0", -] - -[[package]] -name = "solana-token-program" -version = "0.20.0" -dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "solana-logger 0.20.0", - "solana-sdk 0.20.0", - "solana-token-api 0.20.0", -] - [[package]] name = "solana-upload-perf" version = "0.20.0" diff --git a/Cargo.toml b/Cargo.toml index d7efbbc03..3c45b73c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,8 +42,6 @@ members = [ "programs/stake_tests", "programs/storage_api", "programs/storage_program", - "programs/token_api", - "programs/token_program", "programs/vote_api", "programs/vote_program", "replicator", diff --git a/genesis_programs/Cargo.toml b/genesis_programs/Cargo.toml index 45fa41ad0..723078c62 100644 --- a/genesis_programs/Cargo.toml +++ b/genesis_programs/Cargo.toml @@ -24,8 +24,6 @@ solana-stake-api = { path = "../programs/stake_api", version = "0.20.0" } solana-stake-program = { path = "../programs/stake_program", version = "0.20.0" } solana-storage-api = { path = "../programs/storage_api", version = "0.20.0" } solana-storage-program = { path = "../programs/storage_program", version = "0.20.0" } -solana-token-api = { path = "../programs/token_api", version = "0.20.0" } -solana-token-program = { path = "../programs/token_program", version = "0.20.0" } solana-vote-api = { path = "../programs/vote_api", version = "0.20.0" } solana-vote-program = { path = "../programs/vote_program", version = "0.20.0" } diff --git a/genesis_programs/src/lib.rs b/genesis_programs/src/lib.rs index ec438cd94..2a53f014d 100644 --- a/genesis_programs/src/lib.rs +++ b/genesis_programs/src/lib.rs @@ -17,8 +17,6 @@ extern crate solana_stake_program; #[macro_use] extern crate solana_storage_program; #[macro_use] -extern crate solana_token_program; -#[macro_use] extern crate solana_vote_program; pub fn get() -> Vec<(String, Pubkey)> { @@ -32,7 +30,6 @@ pub fn get() -> Vec<(String, Pubkey)> { solana_move_loader_program!(), solana_stake_program!(), solana_storage_program!(), - solana_token_program!(), solana_vote_program!(), ] } @@ -55,7 +52,6 @@ mod tests { solana_sdk::system_program::id(), solana_stake_api::id(), solana_storage_api::id(), - solana_token_api::id(), solana_vote_api::id(), ]; assert!(ids.into_iter().all(move |id| unique.insert(id))); diff --git a/programs/token_api/Cargo.toml b/programs/token_api/Cargo.toml deleted file mode 100644 index 972dec7ff..000000000 --- a/programs/token_api/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "solana-token-api" -version = "0.20.0" -description = "Solana Token API" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana" -license = "Apache-2.0" -homepage = "https://solana.com/" -edition = "2018" - -[dependencies] -bincode = "1.2.0" -log = "0.4.8" -num-derive = "0.3" -num-traits = "0.2" -serde = "1.0.101" -serde_derive = "1.0.101" -solana-logger = { path = "../../logger", version = "0.20.0" } -solana-sdk = { path = "../../sdk", version = "0.20.0" } - -[lib] -crate-type = ["lib"] -name = "solana_token_api" diff --git a/programs/token_api/src/lib.rs b/programs/token_api/src/lib.rs deleted file mode 100644 index 47ec69e3f..000000000 --- a/programs/token_api/src/lib.rs +++ /dev/null @@ -1,13 +0,0 @@ -pub mod token_processor; -mod token_state; - -use solana_sdk::pubkey::Pubkey; - -const TOKEN_PROGRAM_ID: [u8; 32] = [ - 6, 221, 246, 225, 142, 57, 236, 63, 240, 189, 82, 112, 85, 219, 2, 165, 51, 122, 113, 201, 115, - 12, 217, 253, 72, 146, 220, 192, 0, 0, 0, 0, -]; - -pub fn id() -> Pubkey { - Pubkey::new(&TOKEN_PROGRAM_ID) -} diff --git a/programs/token_api/src/token_processor.rs b/programs/token_api/src/token_processor.rs deleted file mode 100644 index 7871f2754..000000000 --- a/programs/token_api/src/token_processor.rs +++ /dev/null @@ -1,18 +0,0 @@ -use crate::token_state::TokenState; -use log::*; -use solana_sdk::account::KeyedAccount; -use solana_sdk::instruction::InstructionError; -use solana_sdk::pubkey::Pubkey; - -pub fn process_instruction( - program_id: &Pubkey, - info: &mut [KeyedAccount], - input: &[u8], -) -> Result<(), InstructionError> { - solana_logger::setup(); - - TokenState::process(program_id, info, input).map_err(|e| { - error!("error: {:?}", e); - InstructionError::CustomError(e as u32) - }) -} diff --git a/programs/token_api/src/token_state.rs b/programs/token_api/src/token_state.rs deleted file mode 100644 index cb73dcd01..000000000 --- a/programs/token_api/src/token_state.rs +++ /dev/null @@ -1,499 +0,0 @@ -use log::*; -use num_derive::FromPrimitive; -use serde_derive::{Deserialize, Serialize}; -use solana_sdk::account::KeyedAccount; -use solana_sdk::instruction_processor_utils::DecodeError; -use solana_sdk::pubkey::Pubkey; - -#[derive(Serialize, Debug, PartialEq, FromPrimitive)] -pub enum TokenError { - InvalidArgument, - InsufficentFunds, - NotOwner, -} - -impl DecodeError for TokenError { - fn type_of() -> &'static str { - "TokenError" - } -} - -impl std::fmt::Display for TokenError { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "error") - } -} -impl std::error::Error for TokenError {} - -pub type Result = std::result::Result; - -#[derive(Debug, Default, Serialize, Deserialize, PartialEq)] -pub struct TokenInfo { - /// Total supply of tokens - supply: u64, - - /// Number of base 10 digits to the right of the decimal place in the total supply - decimals: u8, - - /// Descriptive name of this token - name: String, - - /// Symbol for this token - symbol: String, -} - -#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)] -pub struct TokenAccountDelegateInfo { - /// The source account for the tokens - source: Pubkey, - - /// The original amount that this delegate account was authorized to spend up to - original_amount: u64, -} - -#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)] -pub struct TokenAccountInfo { - /// The kind of token this account holds - token: Pubkey, - - /// Owner of this account - owner: Pubkey, - - /// Amount of tokens this account holds - amount: u64, - - /// If `delegate` None, `amount` belongs to this account. - /// If `delegate` is Option<_>, `amount` represents the remaining allowance - /// of tokens that may be transferred from the `source` account. - delegate: Option, -} - -#[derive(Debug, Serialize, Deserialize, PartialEq)] -enum TokenInstruction { - NewToken(TokenInfo), - NewTokenAccount, - Transfer(u64), - Approve(u64), - SetOwner, -} - -#[derive(Debug, Serialize, Deserialize, PartialEq)] -pub enum TokenState { - Unallocated, - Token(TokenInfo), - Account(TokenAccountInfo), - Invalid, -} -impl Default for TokenState { - fn default() -> TokenState { - TokenState::Unallocated - } -} - -impl TokenState { - #[allow(clippy::needless_pass_by_value)] - fn map_to_invalid_args(err: std::boxed::Box) -> TokenError { - warn!("invalid argument: {:?}", err); - TokenError::InvalidArgument - } - - pub fn deserialize(input: &[u8]) -> Result { - if input.is_empty() { - Err(TokenError::InvalidArgument)?; - } - match input[0] { - 0 => Ok(TokenState::Unallocated), - 1 => Ok(TokenState::Token( - bincode::deserialize(&input[1..]).map_err(Self::map_to_invalid_args)?, - )), - 2 => Ok(TokenState::Account( - bincode::deserialize(&input[1..]).map_err(Self::map_to_invalid_args)?, - )), - _ => Err(TokenError::InvalidArgument), - } - } - - fn serialize(self: &TokenState, output: &mut [u8]) -> Result<()> { - if output.is_empty() { - warn!("serialize fail: ouput.len is 0"); - Err(TokenError::InvalidArgument)?; - } - match self { - TokenState::Unallocated | TokenState::Invalid => Err(TokenError::InvalidArgument), - TokenState::Token(token_info) => { - output[0] = 1; - let writer = std::io::BufWriter::new(&mut output[1..]); - bincode::serialize_into(writer, &token_info).map_err(Self::map_to_invalid_args) - } - TokenState::Account(account_info) => { - output[0] = 2; - let writer = std::io::BufWriter::new(&mut output[1..]); - bincode::serialize_into(writer, &account_info).map_err(Self::map_to_invalid_args) - } - } - } - - #[allow(dead_code)] - pub fn amount(&self) -> Result { - if let TokenState::Account(account_info) = self { - Ok(account_info.amount) - } else { - Err(TokenError::InvalidArgument) - } - } - - #[allow(dead_code)] - pub fn only_owner(&self, key: &Pubkey) -> Result<()> { - if *key != Pubkey::default() { - if let TokenState::Account(account_info) = self { - if account_info.owner == *key { - return Ok(()); - } - } - } - warn!("TokenState: non-owner rejected"); - Err(TokenError::NotOwner) - } - - pub fn process_newtoken( - info: &mut [KeyedAccount], - token_info: TokenInfo, - input_accounts: &[TokenState], - output_accounts: &mut Vec<(usize, TokenState)>, - ) -> Result<()> { - if input_accounts.len() != 2 { - error!("Expected 2 accounts"); - Err(TokenError::InvalidArgument)?; - } - - if let TokenState::Account(dest_account) = &input_accounts[1] { - if info[0].signer_key().unwrap() != &dest_account.token { - error!("account 1 token mismatch"); - Err(TokenError::InvalidArgument)?; - } - - if dest_account.delegate.is_some() { - error!("account 1 is a delegate and cannot accept tokens"); - Err(TokenError::InvalidArgument)?; - } - - let mut output_dest_account = dest_account.clone(); - output_dest_account.amount = token_info.supply; - output_accounts.push((1, TokenState::Account(output_dest_account))); - } else { - error!("account 1 invalid"); - Err(TokenError::InvalidArgument)?; - } - - if input_accounts[0] != TokenState::Unallocated { - error!("account 0 not available"); - Err(TokenError::InvalidArgument)?; - } - output_accounts.push((0, TokenState::Token(token_info))); - Ok(()) - } - - pub fn process_newaccount( - info: &mut [KeyedAccount], - input_accounts: &[TokenState], - output_accounts: &mut Vec<(usize, TokenState)>, - ) -> Result<()> { - // key 0 - Destination new token account - // key 1 - Owner of the account - // key 2 - Token this account is associated with - // key 3 - Source account that this account is a delegate for (optional) - if input_accounts.len() < 3 { - error!("Expected 3 accounts"); - Err(TokenError::InvalidArgument)?; - } - if input_accounts[0] != TokenState::Unallocated { - error!("account 0 is already allocated"); - Err(TokenError::InvalidArgument)?; - } - let mut token_account_info = TokenAccountInfo { - token: *info[2].unsigned_key(), - owner: *info[1].unsigned_key(), - amount: 0, - delegate: None, - }; - if input_accounts.len() >= 4 { - token_account_info.delegate = Some(TokenAccountDelegateInfo { - source: *info[3].unsigned_key(), - original_amount: 0, - }); - } - output_accounts.push((0, TokenState::Account(token_account_info))); - Ok(()) - } - - pub fn process_transfer( - info: &mut [KeyedAccount], - amount: u64, - input_accounts: &[TokenState], - output_accounts: &mut Vec<(usize, TokenState)>, - ) -> Result<()> { - if input_accounts.len() < 3 { - error!("Expected 3 accounts"); - Err(TokenError::InvalidArgument)?; - } - - if let (TokenState::Account(source_account), TokenState::Account(dest_account)) = - (&input_accounts[1], &input_accounts[2]) - { - if source_account.token != dest_account.token { - error!("account 1/2 token mismatch"); - Err(TokenError::InvalidArgument)?; - } - - if dest_account.delegate.is_some() { - error!("account 2 is a delegate and cannot accept tokens"); - Err(TokenError::InvalidArgument)?; - } - - if info[0].signer_key().unwrap() != &source_account.owner { - error!("owner of account 1 not present"); - Err(TokenError::InvalidArgument)?; - } - - if source_account.amount < amount { - Err(TokenError::InsufficentFunds)?; - } - - let mut output_source_account = source_account.clone(); - output_source_account.amount -= amount; - output_accounts.push((1, TokenState::Account(output_source_account))); - - if let Some(ref delegate_info) = source_account.delegate { - if input_accounts.len() != 4 { - error!("Expected 4 accounts"); - Err(TokenError::InvalidArgument)?; - } - - let delegate_account = source_account; - if let TokenState::Account(source_account) = &input_accounts[3] { - if source_account.token != delegate_account.token { - error!("account 1/3 token mismatch"); - Err(TokenError::InvalidArgument)?; - } - if info[3].unsigned_key() != &delegate_info.source { - error!("Account 1 is not a delegate of account 3"); - Err(TokenError::InvalidArgument)?; - } - - if source_account.amount < amount { - Err(TokenError::InsufficentFunds)?; - } - - let mut output_source_account = source_account.clone(); - output_source_account.amount -= amount; - output_accounts.push((3, TokenState::Account(output_source_account))); - } else { - error!("account 3 is an invalid account"); - Err(TokenError::InvalidArgument)?; - } - } - - let mut output_dest_account = dest_account.clone(); - output_dest_account.amount += amount; - output_accounts.push((2, TokenState::Account(output_dest_account))); - } else { - error!("account 1 and/or 2 are invalid accounts"); - Err(TokenError::InvalidArgument)?; - } - Ok(()) - } - - pub fn process_approve( - info: &mut [KeyedAccount], - amount: u64, - input_accounts: &[TokenState], - output_accounts: &mut Vec<(usize, TokenState)>, - ) -> Result<()> { - if input_accounts.len() != 3 { - error!("Expected 3 accounts"); - Err(TokenError::InvalidArgument)?; - } - - if let (TokenState::Account(source_account), TokenState::Account(delegate_account)) = - (&input_accounts[1], &input_accounts[2]) - { - if source_account.token != delegate_account.token { - error!("account 1/2 token mismatch"); - Err(TokenError::InvalidArgument)?; - } - - if info[0].signer_key().unwrap() != &source_account.owner { - error!("owner of account 1 not present"); - Err(TokenError::InvalidArgument)?; - } - - if source_account.delegate.is_some() { - error!("account 1 is a delegate"); - Err(TokenError::InvalidArgument)?; - } - - match &delegate_account.delegate { - None => { - error!("account 2 is not a delegate"); - Err(TokenError::InvalidArgument)?; - } - Some(delegate_info) => { - if info[1].unsigned_key() != &delegate_info.source { - error!("account 2 is not a delegate of account 1"); - Err(TokenError::InvalidArgument)?; - } - - let mut output_delegate_account = delegate_account.clone(); - output_delegate_account.amount = amount; - output_delegate_account.delegate = Some(TokenAccountDelegateInfo { - source: delegate_info.source, - original_amount: amount, - }); - output_accounts.push((2, TokenState::Account(output_delegate_account))); - } - } - } else { - error!("account 1 and/or 2 are invalid accounts"); - Err(TokenError::InvalidArgument)?; - } - Ok(()) - } - - pub fn process_setowner( - info: &mut [KeyedAccount], - input_accounts: &[TokenState], - output_accounts: &mut Vec<(usize, TokenState)>, - ) -> Result<()> { - if input_accounts.len() < 3 { - error!("Expected 3 accounts"); - Err(TokenError::InvalidArgument)?; - } - - if let TokenState::Account(source_account) = &input_accounts[1] { - if info[0].signer_key().unwrap() != &source_account.owner { - info!("owner of account 1 not present"); - Err(TokenError::InvalidArgument)?; - } - - let mut output_source_account = source_account.clone(); - output_source_account.owner = *info[2].unsigned_key(); - output_accounts.push((1, TokenState::Account(output_source_account))); - } else { - info!("account 1 is invalid"); - Err(TokenError::InvalidArgument)?; - } - Ok(()) - } - - pub fn process(program_id: &Pubkey, info: &mut [KeyedAccount], input: &[u8]) -> Result<()> { - let command = - bincode::deserialize::(input).map_err(Self::map_to_invalid_args)?; - info!("process_transaction: command={:?}", command); - - if info[0].signer_key().is_none() { - Err(TokenError::InvalidArgument)?; - } - - let input_accounts: Vec = info - .iter() - .map(|keyed_account| { - let account = &keyed_account.account; - if account.owner == *program_id { - match Self::deserialize(&account.data) { - Ok(token_state) => token_state, - Err(err) => { - error!("deserialize failed: {:?}", err); - TokenState::Invalid - } - } - } else { - TokenState::Invalid - } - }) - .collect(); - - for account in &input_accounts { - info!("input_account: data={:?}", account); - } - - let mut output_accounts: Vec<(_, _)> = vec![]; - - match command { - TokenInstruction::NewToken(token_info) => { - Self::process_newtoken(info, token_info, &input_accounts, &mut output_accounts)? - } - TokenInstruction::NewTokenAccount => { - Self::process_newaccount(info, &input_accounts, &mut output_accounts)? - } - - TokenInstruction::Transfer(amount) => { - Self::process_transfer(info, amount, &input_accounts, &mut output_accounts)? - } - - TokenInstruction::Approve(amount) => { - Self::process_approve(info, amount, &input_accounts, &mut output_accounts)? - } - - TokenInstruction::SetOwner => { - Self::process_setowner(info, &input_accounts, &mut output_accounts)? - } - } - - for (index, account) in &output_accounts { - info!("output_account: index={} data={:?}", index, account); - Self::serialize(account, &mut info[*index].account.data)?; - } - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - #[test] - pub fn serde() { - assert_eq!(TokenState::deserialize(&[0]), Ok(TokenState::default())); - - let mut data = vec![0; 256]; - - let account = TokenState::Account(TokenAccountInfo { - token: Pubkey::new(&[1; 32]), - owner: Pubkey::new(&[2; 32]), - amount: 123, - delegate: None, - }); - account.serialize(&mut data).unwrap(); - assert_eq!(TokenState::deserialize(&data), Ok(account)); - - let account = TokenState::Token(TokenInfo { - supply: 12345, - decimals: 2, - name: "A test token".to_string(), - symbol: "TEST".to_string(), - }); - account.serialize(&mut data).unwrap(); - assert_eq!(TokenState::deserialize(&data), Ok(account)); - } - - #[test] - pub fn serde_expect_fail() { - let mut data = vec![0; 256]; - - // Certain TokenState's may not be serialized - let account = TokenState::default(); - assert_eq!(account, TokenState::Unallocated); - assert!(account.serialize(&mut data).is_err()); - assert!(account.serialize(&mut data).is_err()); - let account = TokenState::Invalid; - assert!(account.serialize(&mut data).is_err()); - - // Bad deserialize data - assert!(TokenState::deserialize(&[]).is_err()); - assert!(TokenState::deserialize(&[1]).is_err()); - assert!(TokenState::deserialize(&[1, 2]).is_err()); - assert!(TokenState::deserialize(&[2, 2]).is_err()); - assert!(TokenState::deserialize(&[3]).is_err()); - } - - // Note: business logic tests are located in the @solana/web3.js test suite -} diff --git a/programs/token_program/Cargo.toml b/programs/token_program/Cargo.toml deleted file mode 100644 index 823a94ba5..000000000 --- a/programs/token_program/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "solana-token-program" -version = "0.20.0" -description = "Solana token program" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana" -license = "Apache-2.0" -homepage = "https://solana.com/" -edition = "2018" - -[dependencies] -log = "0.4.8" -solana-logger = { path = "../../logger", version = "0.20.0" } -solana-sdk = { path = "../../sdk", version = "0.20.0" } -solana-token-api = { path = "../token_api", version = "0.20.0" } - -[lib] -crate-type = ["lib", "cdylib"] -name = "solana_token_program" diff --git a/programs/token_program/src/lib.rs b/programs/token_program/src/lib.rs deleted file mode 100644 index 69449a3cc..000000000 --- a/programs/token_program/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[macro_export] -macro_rules! solana_token_program { - () => { - ("solana_token_program".to_string(), solana_token_api::id()) - }; -} - -use solana_token_api::token_processor::process_instruction; - -solana_sdk::solana_entrypoint!(process_instruction);