From ae5e00db45ce3789e449ceb058c65cc896ff866f Mon Sep 17 00:00:00 2001 From: Aton Date: Mon, 19 Nov 2018 18:14:28 +0800 Subject: [PATCH] Feature/transfer (#111) * merge transfer from balances to tokenbalances for chainx * add test * remove public call for balances module --- cxrml/associations/src/lib.rs | 30 ++- cxrml/bridge/btc/src/lib.rs | 3 +- cxrml/bridge/btc/src/tests.rs | 2 +- cxrml/bridge/btc/src/tx/mod.rs | 32 ++- cxrml/exchange/matchorder/src/lib.rs | 7 +- cxrml/exchange/matchorder/src/tests.rs | 14 +- cxrml/exchange/pendingorders/src/lib.rs | 18 -- cxrml/exchange/pendingorders/src/tests.rs | 8 +- cxrml/tokenbalances/src/lib.rs | 230 +++++++++++++++++----- cxrml/tokenbalances/src/tests.rs | 130 ++++++++++-- runtime/src/lib.rs | 6 +- src/genesis_config.rs | 1 - 12 files changed, 365 insertions(+), 116 deletions(-) diff --git a/cxrml/associations/src/lib.rs b/cxrml/associations/src/lib.rs index 05051ff3f3f54..ed855f6d96663 100644 --- a/cxrml/associations/src/lib.rs +++ b/cxrml/associations/src/lib.rs @@ -97,6 +97,25 @@ impl Module { fn deposit_event(event: Event) { >::deposit_event(::Event::from(event).into()); } + + fn check_no_init(who: &T::AccountId) -> Result { + if Self::relationship(who).is_some() { + return Err("has register this account"); + } else { + if balances::FreeBalance::::exists(who) { + return Err("this account is exist"); + } + } + Ok(()) + } + + pub fn is_init(who: &T::AccountId) -> bool { + if let Err(_) = Self::check_no_init(who) { + true + } else { + false + } + } } impl Module { @@ -105,13 +124,8 @@ impl Module { // deduct fee first T::OnCalcFee::on_calc_fee(&from, Self::init_fee())?; - if Self::relationship(&who).is_some() { - return Err("has register this account"); - } else { - if balances::FreeBalance::::exists(&who) { - return Err("this account is exist"); - } - } + Self::check_no_init(&who)?; + Relationship::::insert(&who, from.clone()); let from_balance = balances::Module::::free_balance(&from); @@ -127,7 +141,7 @@ impl Module { }; balances::Module::::set_free_balance(&from, new_from_balance); - balances::Module::::set_free_balance(&who, new_to_balance); + balances::Module::::set_free_balance_creating(&who, new_to_balance); Self::deposit_event(RawEvent::InitAccount(from, who, value)); Ok(()) diff --git a/cxrml/bridge/btc/src/lib.rs b/cxrml/bridge/btc/src/lib.rs index f6155d6f8d04c..6289967a09a3d 100644 --- a/cxrml/bridge/btc/src/lib.rs +++ b/cxrml/bridge/btc/src/lib.rs @@ -80,7 +80,7 @@ use blockchain::Chain; use keys::DisplayLayout; pub use keys::{Address, Error as AddressError}; pub use tx::RelayTx; -use tx::{handle_input, handle_output, handle_proposal, handle_cert, validate_transaction, UTXO}; +use tx::{handle_cert, handle_input, handle_output, handle_proposal, validate_transaction, UTXO}; pub trait Trait: system::Trait + balances::Trait + timestamp::Trait + financial_records::Trait @@ -355,7 +355,6 @@ impl Module { } TxType::SendCert => { handle_cert::(&tx.raw, &tx.block_hash, &who, &cert_address); - } _ => { let _utxos = handle_output::( diff --git a/cxrml/bridge/btc/src/tests.rs b/cxrml/bridge/btc/src/tests.rs index 1f3688ded93d9..2c89577ed9dda 100644 --- a/cxrml/bridge/btc/src/tests.rs +++ b/cxrml/bridge/btc/src/tests.rs @@ -3,10 +3,10 @@ extern crate srml_consensus as consensus; use substrate_primitives::{Blake2Hasher, H256 as S_H256}; use self::base58::FromBase58; +use self::keys::DisplayLayout; use super::*; use runtime_io; use runtime_io::with_externalities; -use self::keys::DisplayLayout; use runtime_primitives::testing::{Digest, DigestItem, Header}; use runtime_primitives::traits::BlakeTwo256; use runtime_primitives::BuildStorage; diff --git a/cxrml/bridge/btc/src/tx/mod.rs b/cxrml/bridge/btc/src/tx/mod.rs index 49998e9317d19..e4d2146fc9d88 100644 --- a/cxrml/bridge/btc/src/tx/mod.rs +++ b/cxrml/bridge/btc/src/tx/mod.rs @@ -10,8 +10,8 @@ use runtime_support::{StorageMap, StorageValue}; pub use self::proposal::{handle_proposal, Proposal}; use super::{ - AccountMap, AddressMap, BlockHeaderFor, BlockTxids, CertCache, CandidateTx, DepositCache, - NetworkId, NumberForHash, RegInfoMaxIndex, RegInfoSet, ReceiveAddress, RedeemScript, Trait, + AccountMap, AddressMap, BlockHeaderFor, BlockTxids, CandidateTx, CertCache, DepositCache, + NetworkId, NumberForHash, ReceiveAddress, RedeemScript, RegInfoMaxIndex, RegInfoSet, Trait, TxProposal, TxSet, TxType, UTXOMaxIndex, UTXOSet, }; use b58::from; @@ -149,7 +149,10 @@ impl TxStorage { // todo 检查block是否存在 >::mutate(block_hash.clone(), |v| v.push(hash.clone())); - >::insert(hash, (who.clone(), address, tx_type, balance, block_hash, tx)); + >::insert( + hash, + (who.clone(), address, tx_type, balance, block_hash, tx), + ); } fn find_tx(txid: &H256) -> Option { @@ -220,7 +223,16 @@ impl RollBack for TxStorage { struct RegInfoStorage(PhantomData); impl RegInfoStorage { - fn add(accounts: (H256, keys::Address, T::AccountId, T::BlockNumber, Vec, TxType)) { + fn add( + accounts: ( + H256, + keys::Address, + T::AccountId, + T::BlockNumber, + Vec, + TxType, + ), + ) { let mut index = >::get(); >::insert(index, accounts.clone()); index += 1; @@ -499,8 +511,14 @@ pub fn handle_output( runtime_io::print("----new account-------"); let time = >::block_number(); let chainxaddr = >::get(send_address.clone()).unwrap(); - let account = (tx.hash(), send_address.clone(), chainxaddr, time, - channel[2..].to_vec(),tx_type); + let account = ( + tx.hash(), + send_address.clone(), + chainxaddr, + time, + channel[2..].to_vec(), + tx_type, + ); >::add(account); runtime_io::print("------insert new account in AccountsMap-----"); } @@ -529,7 +547,7 @@ pub fn handle_cert( runtime_io::print(&account[..]); let id: T::AccountId = Decode::decode(&mut account.as_slice()).unwrap(); - >::put((name[2..].to_vec(),id)); + >::put((name[2..].to_vec(), id)); } } } diff --git a/cxrml/exchange/matchorder/src/lib.rs b/cxrml/exchange/matchorder/src/lib.rs index 1b6a0b455fb61..49e42ca5e699f 100644 --- a/cxrml/exchange/matchorder/src/lib.rs +++ b/cxrml/exchange/matchorder/src/lib.rs @@ -371,7 +371,6 @@ impl Module { maker_fee, taker_fee, ) { - Self::deposit_event(RawEvent::MatchFail( match_bid.id, in_bid_detail.pair.clone(), @@ -494,7 +493,7 @@ impl Module { if insert_head == true { let new_nodeid = Self::new_nodeid(); - let mut list_vec:Vec=Vec::new(); + let mut list_vec: Vec = Vec::new(); list_vec.push(in_bid_detail.id); let new_bid = Bid { @@ -526,7 +525,7 @@ impl Module { if finish == false { //追加在最后 let new_nodeid = Self::new_nodeid(); - let mut list_vec:Vec=Vec::new(); + let mut list_vec: Vec = Vec::new(); list_vec.push(in_bid_detail.id); let new_bid = Bid { @@ -572,7 +571,7 @@ impl Module { } for mm in 0..node.data.list.len() { if in_bid_detail.id == node.data.list[mm] { - let mut list_vec:Vec=Vec::new(); + let mut list_vec: Vec = Vec::new(); list_vec.push(in_bid_detail.id); Self::remove_from_bid_list(&mut node, &list_vec); diff --git a/cxrml/exchange/matchorder/src/tests.rs b/cxrml/exchange/matchorder/src/tests.rs index 9b64c7fc44034..30bce8b08b9ef 100644 --- a/cxrml/exchange/matchorder/src/tests.rs +++ b/cxrml/exchange/matchorder/src/tests.rs @@ -83,7 +83,8 @@ pub fn new_test_ext() -> runtime_io::TestExternalities { transfer_fee: 0, creation_fee: 0, reclaim_rebate: 0, - }.build_storage() + } + .build_storage() .unwrap(), ); @@ -92,7 +93,8 @@ pub fn new_test_ext() -> runtime_io::TestExternalities { token_list: vec![], transfer_token_fee: 10, chainx_precision: 8, - }.build_storage() + } + .build_storage() .unwrap(), ); @@ -102,7 +104,8 @@ pub fn new_test_ext() -> runtime_io::TestExternalities { pair_list: vec![], max_command_id: 0, average_price_len: 10000, - }.build_storage() + } + .build_storage() .unwrap(), ); @@ -112,7 +115,8 @@ pub fn new_test_ext() -> runtime_io::TestExternalities { fee_precision: 100000, maker_match_fee: 50, taker_match_fee: 100, - }.build_storage() + } + .build_storage() .unwrap(), ); r.into() @@ -462,4 +466,4 @@ fn print_bid(pair: OrderPair, order_type: OrderType) { } else { println!("-------------------end -----------------"); } -} \ No newline at end of file +} diff --git a/cxrml/exchange/pendingorders/src/lib.rs b/cxrml/exchange/pendingorders/src/lib.rs index c7903194a5272..3c3741bad84e6 100644 --- a/cxrml/exchange/pendingorders/src/lib.rs +++ b/cxrml/exchange/pendingorders/src/lib.rs @@ -244,16 +244,13 @@ impl Module { ) -> Result { //判断交易对是否存在 if let Err(_) = Self::is_valid_pair(&pair) { - return Err("not a existed pair in orderpair list"); } //判定 数量和价格 if amount == Zero::zero() { - return Err("amount cann't be zero"); } if price == Zero::zero() { - return Err("price cann't be zero"); } //手续费 @@ -269,7 +266,6 @@ impl Module { pair.second.clone(), )) < sum { - return Err("transactor's free token balance too low, can't put buy order"); } // 锁定用户资产 @@ -279,7 +275,6 @@ impl Module { sum, ReservedType::Exchange, ) { - return Err(msg); } } @@ -287,7 +282,6 @@ impl Module { if >::free_token(&(sender.clone(), pair.first.clone())) < As::sa(amount.as_()) { - return Err("transactor's free token balance too low, can't put sell order"); } // 锁定用户资产 @@ -297,7 +291,6 @@ impl Module { As::sa(amount.as_()), ReservedType::Exchange, ) { - return Err(msg); } } @@ -420,7 +413,6 @@ impl Module { back_amount, ReservedType::Exchange, ) { - return Err(msg); } @@ -448,7 +440,6 @@ impl Module { )); } _ => { - return Err( "order status error( FiillAll|FillPartAndCancel|Cancel) cann't be cancel", ); @@ -456,7 +447,6 @@ impl Module { } Ok(()) } else { - Err("cann't find this index of order") } } @@ -486,14 +476,12 @@ impl Module { } else if maker_order.hasfill_amount < maker_order.amount { maker_order.status = OrderStatus::FillPart; } else { - return Err(" maker order has not enough amount"); } maker_order.lastupdate_time = >::block_number(); maker_order } else { - return Err("cann't find this maker order"); }; @@ -508,14 +496,12 @@ impl Module { } else if taker_order.hasfill_amount < taker_order.amount { taker_order.status = OrderStatus::FillPart; } else { - return Err(" taker order has not enough amount"); } taker_order.lastupdate_time = >::block_number(); taker_order } else { - return Err("cann't find this taker order"); }; @@ -554,7 +540,6 @@ impl Module { &taker_user.clone(), &maker_order.channel().clone(), ) { - return Err(msg); } //计算买家的数量,解锁second,并move 给卖家,和手续费账户 @@ -569,7 +554,6 @@ impl Module { &maker_user.clone(), &taker_order.channel().clone(), ) { - return Err(msg); } } @@ -586,7 +570,6 @@ impl Module { &taker_user.clone(), &maker_order.channel().clone(), ) { - return Err(msg); } //计算卖家的数量,解锁second,并move 给买家,和手续费账户 @@ -601,7 +584,6 @@ impl Module { &maker_user.clone(), &taker_order.channel().clone(), ) { - return Err(msg); } } diff --git a/cxrml/exchange/pendingorders/src/tests.rs b/cxrml/exchange/pendingorders/src/tests.rs index 2276a6d0561f2..2e7d3f693e806 100644 --- a/cxrml/exchange/pendingorders/src/tests.rs +++ b/cxrml/exchange/pendingorders/src/tests.rs @@ -74,7 +74,8 @@ pub fn new_test_ext() -> runtime_io::TestExternalities { transfer_fee: 0, creation_fee: 0, reclaim_rebate: 0, - }.build_storage() + } + .build_storage() .unwrap(), ); @@ -84,7 +85,8 @@ pub fn new_test_ext() -> runtime_io::TestExternalities { pair_list: vec![], max_command_id: 0, average_price_len: 10000, - }.build_storage() + } + .build_storage() .unwrap(), ); r.into() @@ -593,4 +595,4 @@ fn print_fill( println!("maker_fee={:?}", fill.maker_fee()); println!("taker_fee={:?}", fill.taker_fee()); println!("time={:?}", fill.time()); -} \ No newline at end of file +} diff --git a/cxrml/tokenbalances/src/lib.rs b/cxrml/tokenbalances/src/lib.rs index f26d891f90f45..14516f8c82da3 100644 --- a/cxrml/tokenbalances/src/lib.rs +++ b/cxrml/tokenbalances/src/lib.rs @@ -30,7 +30,6 @@ extern crate srml_balances as balances; extern crate srml_system as system; // for chainx runtime module lib -#[cfg(test)] extern crate cxrml_associations as associations; extern crate cxrml_support as cxsupport; #[cfg(test)] @@ -51,6 +50,7 @@ use runtime_support::{Parameter, StorageMap, StorageValue}; // substrate mod use balances::address::Address; +use balances::EnsureAccountLiquid; use system::ensure_signed; // use balances::EnsureAccountLiquid; @@ -204,7 +204,11 @@ decl_module! { /// register_token to module, should allow by root fn register_token(token: Token, free: T::TokenBalance, reversed: T::TokenBalance) -> Result; /// transfer between account - fn transfer_token(origin, dest: Address, sym: Symbol, value: T::TokenBalance) -> Result; + fn transfer(origin, dest: Address, sym: Symbol, value: T::TokenBalance) -> Result; + /// set free token for an account + fn set_free_token(who: Address, sym: Symbol, free: T::TokenBalance) -> Result; + /// set reserved token for an account + fn set_reserved_token(who: Address, sym: Symbol, reserved: T::TokenBalance, res_type: ReservedType) -> Result; // set transfer token fee fn set_transfer_token_fee(val: T::Balance) -> Result; } @@ -228,8 +232,10 @@ decl_event!( UnreverseToken(AccountId, Symbol, TokenBalance), /// destroy DestroyToken(AccountId, Symbol, TokenBalance), - /// Transfer succeeded (from, to, symbol, value, fees). - TransferToken(AccountId, AccountId, Symbol, TokenBalance, Balance), + /// Transfer chainx succeeded + TransferChainX(AccountId, AccountId, Balance), + /// Transfer token succeeded (from, to, symbol, value, fees). + TransferToken(AccountId, AccountId, Symbol, TokenBalance), /// Move Free Token, include chainx (from, to, symbol, value) MoveFreeToken(AccountId, AccountId, Symbol, TokenBalance), /// set transfer token fee @@ -257,7 +263,7 @@ decl_storage! { /// total locked token of a symbol pub TotalReservedToken get(total_reserved_token): map Symbol => T::TokenBalance; - pub ReservedToken get(reserved_token): map (T::AccountId, Symbol, ReservedType) => T::TokenBalance; + pub ReservedToken: map (T::AccountId, Symbol, ReservedType) => T::TokenBalance; /// token list of a account pub TokenListOf get(token_list_of): map T::AccountId => Vec = [T::CHAINX_SYMBOL.to_vec()].to_vec(); @@ -330,11 +336,19 @@ impl Module { } } + pub fn reserved_token(who_sym: &(T::AccountId, Symbol, ReservedType)) -> T::TokenBalance { + if who_sym.1.as_slice() == T::CHAINX_SYMBOL { + As::sa(balances::ReservedBalance::::get(&who_sym.0).as_()) + } else { + >::get(who_sym) + } + } + /// The combined token balance of `who` for symbol. pub fn total_token_of(who: &T::AccountId, symbol: &Symbol) -> T::TokenBalance { let mut v = Self::free_token(&(who.clone(), symbol.clone())); for t in ReservedType::iterator() { - v += Self::reserved_token((who.clone(), symbol.clone(), *t)) + v += Self::reserved_token(&(who.clone(), symbol.clone(), *t)) } v } @@ -770,57 +784,181 @@ impl TokenErr { } impl Module { + fn transfer_chainx(from: &T::AccountId, to: &T::AccountId, value: T::Balance) -> Result { + let from_balance = balances::Module::::free_balance(from); + let to_balance = balances::Module::::free_balance(to); + + let new_from_balance = match from_balance.checked_sub(&value) { + Some(b) => b, + None => return Err("balance too low to send value"), + }; + + let new_to_balance = match to_balance.checked_add(&value) { + Some(b) => b, + None => return Err("destination balance too high to receive value"), + }; + + balances::Module::::set_free_balance(&from, new_from_balance); + balances::Module::::set_free_balance_creating(&to, new_to_balance); + + Self::deposit_event(RawEvent::TransferChainX(from.clone(), to.clone(), value)); + Ok(()) + } + + fn transfer_token( + from: &T::AccountId, + to: &T::AccountId, + sym: &Symbol, + value: T::TokenBalance, + ) -> Result { + Self::is_valid_token_for(from, sym)?; + Self::init_token_for(to, sym); + + let key_from = (from.clone(), sym.clone()); + let key_to = (to.clone(), sym.clone()); + + // get storage + let from_token = FreeToken::::get(&key_from); + let to_token = FreeToken::::get(&key_to); + // check + let new_from_token = match from_token.checked_sub(&value) { + Some(b) => b, + None => return Err("free token too low to send value"), + }; + let new_to_token = match to_token.checked_add(&value) { + Some(b) => b, + None => return Err("destination free token too high to receive value"), + }; + // set to storage + FreeToken::::insert(&key_from, new_from_token); + FreeToken::::insert(&key_to, new_to_token); + + Self::deposit_event(RawEvent::TransferToken( + from.clone(), + to.clone(), + sym.clone(), + value, + )); + Ok(()) + } + // public call /// transfer token between accountid, notice the fee is chainx - pub fn transfer_token( + pub fn transfer( origin: T::Origin, dest: balances::Address, sym: Symbol, value: T::TokenBalance, ) -> Result { + let transactor = ensure_signed(origin)?; + let dest = balances::Module::::lookup(dest)?; + // sub fee first + cxsupport::Module::::handle_fee_before( + &transactor, + Self::transfer_token_fee(), + true, + || Ok(()), + )?; + // if account not exist, init it first + if associations::Module::::is_init(&dest) == false { + return Err("account not exist yet, should init account first"); + } + + if transactor == dest { + return Err("transactor and dest account are same"); + } + + T::EnsureAccountLiquid::ensure_account_liquid(&transactor)?; + + // chainx transfer if sym.as_slice() == T::CHAINX_SYMBOL { - return Err("not allow to transfer chainx use transfer_token"); + let value: T::Balance = As::sa(value.as_() as u64); // change to balance for balances module + Self::transfer_chainx(&transactor, &dest, value) + } else { + Self::transfer_token(&transactor, &dest, &sym, value) } - let transactor = ensure_signed(origin)?; - Self::is_valid_token_for(&transactor, &sym)?; - let dest = >::lookup(dest)?; - Self::init_token_for(&dest, &sym); - - let fee = Self::transfer_token_fee(); - - let key_from = (transactor.clone(), sym.clone()); - let key_to = (dest.clone(), sym.clone()); - - let sender = &transactor; - let receiver = &dest; - >::handle_fee_after(sender, fee, true, || { - // get storage - let from_token = FreeToken::::get(&key_from); - let to_token = FreeToken::::get(&key_to); - // check - let new_from_token = match from_token.checked_sub(&value) { - Some(b) => b, - None => return Err("free token too low to send value"), - }; - let new_to_token = match to_token.checked_add(&value) { - Some(b) => b, - None => return Err("destination free token too high to receive value"), - }; - if sender != receiver { - // set to storage - FreeToken::::insert(&key_from, new_from_token); - FreeToken::::insert(&key_to, new_to_token); - Self::deposit_event(RawEvent::TransferToken( - sender.clone(), - receiver.clone(), - sym.clone(), - value, - fee, - )); + } + + pub fn set_free_token(who: balances::Address, sym: Symbol, free: T::TokenBalance) -> Result { + let who = balances::Module::::lookup(who)?; + // for chainx + if sym.as_slice() == T::CHAINX_SYMBOL { + let free: T::Balance = As::sa(free.as_() as u64); // change to balance for balances module + balances::Module::::set_free_balance(&who, free); + return Ok(()); + } + // other token + let key = (who.clone(), sym.clone()); + let old_free = Self::free_token(&key); + let old_total_free = Self::total_free_token(&sym); + + if old_free == free { + return Err("some value for free token"); + } + + let new_total_free = if free > old_free { + match free.checked_sub(&old_free) { + None => return Err("free token too low to sub value"), + Some(b) => match old_total_free.checked_add(&b) { + None => return Err("old total free token too high to add value"), + Some(new) => new, + }, } - Ok(()) - })?; + } else { + match old_free.checked_sub(&free) { + None => return Err("old free token too low to sub value"), + Some(b) => match old_total_free.checked_sub(&b) { + None => return Err("old total free token too low to sub value"), + Some(new) => new, + }, + } + }; + TotalFreeToken::::insert(sym, new_total_free); + FreeToken::::insert(key, free); + Ok(()) + } + pub fn set_reserved_token( + who: Address, + sym: Symbol, + reserved: T::TokenBalance, + res_type: ReservedType, + ) -> Result { + let who = balances::Module::::lookup(who)?; + // for chainx + if sym.as_slice() == T::CHAINX_SYMBOL { + let reserved: T::Balance = As::sa(reserved.as_() as u64); // change to balance for balances module + balances::Module::::set_reserved_balance(&who, reserved); + return Ok(()); + } + // other token + let key = (who.clone(), sym.clone(), res_type); + let old_reserved = Self::reserved_token(&key); + let old_total_reserved = Self::total_reserved_token(&sym); + + if old_reserved == reserved { + return Err("some value for reserved token"); + } + + let new_total_reserved = if reserved > old_reserved { + match reserved.checked_sub(&old_reserved) { + None => return Err("reserved token too low to sub value"), + Some(b) => match old_total_reserved.checked_add(&b) { + None => return Err("old total reserved token too high to add value"), + Some(new) => new, + }, + } + } else { + match old_reserved.checked_sub(&reserved) { + None => return Err("old reserved token too low to sub value"), + Some(b) => match old_total_reserved.checked_sub(&b) { + None => return Err("old total reserved token too high to sub value"), + Some(new) => new, + }, + } + }; + TotalReservedToken::::insert(sym, new_total_reserved); + ReservedToken::::insert(key, reserved); Ok(()) } diff --git a/cxrml/tokenbalances/src/tests.rs b/cxrml/tokenbalances/src/tests.rs index 5632466771e0d..03d4275fe610f 100644 --- a/cxrml/tokenbalances/src/tests.rs +++ b/cxrml/tokenbalances/src/tests.rs @@ -359,7 +359,75 @@ fn test_error_issue_and_destroy3() { } #[test] -fn test_transfer() { +fn test_transfer_not_init() { + with_externalities(&mut new_test_ext2(), || { + let a: u64 = 1; // accountid + let new_id: u64 = 100; + let btc_symbol = b"x-btc".to_vec(); + TokenBalances::issue(&a, &btc_symbol.clone(), 50).unwrap(); + assert_err!( + TokenBalances::transfer(Some(a).into(), new_id.into(), btc_symbol.clone(), 25), + "account not exist yet, should init account first" + ); + assert_ok!(associations::Module::::init_account( + Some(a).into(), + new_id.into(), + 25 + )); + assert_ok!(TokenBalances::transfer( + Some(a).into(), + new_id.into(), + btc_symbol.clone(), + 25 + )); + assert_ok!(TokenBalances::transfer( + Some(a).into(), + new_id.into(), + Test::CHAINX_SYMBOL.to_vec(), + 25 + )); + + assert_eq!( + TokenBalances::free_token(&(a, Test::CHAINX_SYMBOL.to_vec())), + 1000 - 10 - 25 - 10 - 25 - 10 + ); + assert_eq!( + TokenBalances::free_token(&(new_id, Test::CHAINX_SYMBOL.to_vec())), + 50 + ); + }) +} + +#[test] +fn test_transfer_chainx() { + with_externalities(&mut new_test_ext2(), || { + let a: u64 = 1; // accountid + let b: u64 = 2; // accountid + assert_ok!(TokenBalances::transfer( + Some(a).into(), + b.into(), + Test::CHAINX_SYMBOL.to_vec(), + 25 + )); + + assert_eq!( + TokenBalances::free_token(&(a, Test::CHAINX_SYMBOL.to_vec())), + 1000 - 10 - 25 + ); + assert_eq!( + TokenBalances::free_token(&(b, Test::CHAINX_SYMBOL.to_vec())), + 510 + 25 + ); + + assert_err!( + TokenBalances::transfer(Some(a).into(), b.into(), Test::CHAINX_SYMBOL.to_vec(), 1000), + "balance too low to send value" + ); + }) +} + +#[test] +fn test_transfer_token() { with_externalities(&mut new_test_ext(), || { let a: u64 = 1; // accountid let b: u64 = 2; // accountid @@ -367,8 +435,7 @@ fn test_transfer() { // issue 50 to account 1 TokenBalances::issue(&a, &btc_symbol.clone(), 50).unwrap(); // transfer - TokenBalances::transfer_token(Some(a).into(), b.into(), btc_symbol.clone().clone(), 25) - .unwrap(); + TokenBalances::transfer(Some(a).into(), b.into(), btc_symbol.clone(), 25).unwrap(); // sum not change assert_eq!(TokenBalances::total_free_token(&btc_symbol.clone()), 150); assert_eq!(TokenBalances::total_token_of(&a, &btc_symbol.clone()), 25); @@ -376,7 +443,7 @@ fn test_transfer() { assert_eq!(Balances::free_balance(&a), 990); assert_err!( - TokenBalances::transfer_token(Some(a).into(), b.into(), btc_symbol.clone().clone(), 50), + TokenBalances::transfer(Some(a).into(), b.into(), btc_symbol.clone(), 50), "free token too low to send value" ) }) @@ -390,8 +457,11 @@ fn test_transfer_to_self() { // issue 50 to account 1 TokenBalances::issue(&a, &btc_symbol.clone(), 50).unwrap(); // transfer - TokenBalances::transfer_token(Some(a).into(), a.into(), btc_symbol.clone().clone(), 25) - .unwrap(); + assert_err!( + TokenBalances::transfer(Some(a).into(), a.into(), btc_symbol.clone(), 25), + "transactor and dest account are same" + ); + // sum not change assert_eq!(TokenBalances::total_free_token(&btc_symbol.clone()), 150); assert_eq!(TokenBalances::total_token_of(&a, &btc_symbol.clone()), 50); @@ -408,8 +478,7 @@ fn test_transfer_err() { // issue 50 to account 2 TokenBalances::issue(&b, &btc_symbol.clone(), 50).unwrap(); // transfer - TokenBalances::transfer_token(Some(b).into(), a.into(), btc_symbol.clone().clone(), 25) - .unwrap(); + TokenBalances::transfer(Some(b).into(), a.into(), btc_symbol.clone(), 25).unwrap(); // sum not change assert_eq!(TokenBalances::total_free_token(&btc_symbol.clone()), 150); assert_eq!(TokenBalances::free_token(&(b, btc_symbol.clone())), 25); @@ -417,13 +486,44 @@ fn test_transfer_err() { assert_eq!(Balances::free_balance(&b), 500); assert_err!( - TokenBalances::transfer_token(Some(b).into(), a.into(), btc_symbol.clone(), 1), + TokenBalances::transfer(Some(b).into(), a.into(), btc_symbol.clone(), 1), "chainx balance is not enough after this tx, not allow to be killed at here" ); assert_eq!(Balances::free_balance(&b), 500); }) } +#[test] +fn test_set_token() { + with_externalities(&mut new_test_ext2(), || { + let a: u64 = 1; // accountid + let btc_symbol = b"x-btc".to_vec(); + TokenBalances::issue(&a, &btc_symbol.clone(), 50).unwrap(); + assert_ok!(TokenBalances::set_free_token( + a.into(), + Test::CHAINX_SYMBOL.to_vec(), + 500 + )); + assert_eq!(Balances::free_balance(&a), 500); + + assert_ok!(TokenBalances::set_free_token( + a.into(), + btc_symbol.clone(), + 500 + )); + assert_eq!(TokenBalances::free_token(&(a, btc_symbol.clone())), 500); + assert_eq!(TokenBalances::total_token(&btc_symbol), 500 + 100); + + assert_ok!(TokenBalances::set_free_token( + a.into(), + btc_symbol.clone(), + 600 + )); + assert_eq!(TokenBalances::free_token(&(a, btc_symbol.clone())), 600); + assert_eq!(TokenBalances::total_token(&btc_symbol), 600 + 100); + }) +} + #[test] fn test_char_valid() { with_externalities(&mut new_test_ext(), || { @@ -431,21 +531,21 @@ fn test_char_valid() { let origin = system::RawOrigin::Signed(1).into(); let sym = b"".to_vec(); assert_err!( - TokenBalances::transfer_token(origin, to.clone(), sym, 10), + TokenBalances::transfer(origin, to.clone(), sym, 10), "symbol length too long or zero" ); let origin = system::RawOrigin::Signed(1).into(); let sym = b"dfasdlfjkalsdjfklasjdflkasjdfklasjklfasjfkdlsajf".to_vec(); assert_err!( - TokenBalances::transfer_token(origin, to.clone(), sym, 10), + TokenBalances::transfer(origin, to.clone(), sym, 10), "symbol length too long or zero" ); let origin = system::RawOrigin::Signed(1).into(); let sym = b"23jfkldae(".to_vec(); assert_err!( - TokenBalances::transfer_token(origin, to.clone(), sym, 10), + TokenBalances::transfer(origin, to.clone(), sym, 10), "not a valid symbol char for number, capital/small letter or '-', '.', '|', '~'" ); @@ -466,7 +566,6 @@ fn test_char_valid() { fn test_chainx() { with_externalities(&mut new_test_ext2(), || { let a: u64 = 1; // accountid - let b: u64 = 2; // accountid let sym = Test::CHAINX_SYMBOL.to_vec(); assert_err!( TokenBalances::issue(&a, &sym, 100), @@ -492,11 +591,6 @@ fn test_chainx() { TokenBalances::destroy(&a, &sym, 50, Default::default()), "can't destroy chainx token" ); - - assert_err!( - TokenBalances::transfer_token(Some(b).into(), a.into(), sym.clone(), 1), - "not allow to transfer chainx use transfer_token" - ); }) } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index b64750d225bd7..cb45ad851fd6c 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -265,8 +265,8 @@ impl pendingorders::Trait for Runtime { type Amount = TokenBalance; type Price = TokenBalance; type Event = Event; - const FEE_BUY_ACCOUNT:AccountId = primitives::H256([1; 32]); - const FEE_DESTROY_ACCOUNT:AccountId = primitives::H256([0;32]); + const FEE_BUY_ACCOUNT: AccountId = primitives::H256([1; 32]); + const FEE_DESTROY_ACCOUNT: AccountId = primitives::H256([0; 32]); } impl matchorder::Trait for Runtime { @@ -296,7 +296,7 @@ construct_runtime!( pub enum Runtime with Log(InternalLog: DigestItem) { System: system::{default, Log(ChangesTrieRoot)}, Consensus: consensus::{Module, Call, Storage, Config, Log(AuthoritiesChange)}, - Balances: balances, + Balances: balances::{Module, Storage, Config, Event}, // no call for public Timestamp: timestamp::{Module, Call, Storage, Config}, Session: session, Staking: staking, diff --git a/src/genesis_config.rs b/src/genesis_config.rs index ca7cdbe0cb586..607b009f9f4a4 100644 --- a/src/genesis_config.rs +++ b/src/genesis_config.rs @@ -6,7 +6,6 @@ extern crate cxrml_tokenbalances; extern crate keys; extern crate primitives as btc_primitives; - use self::base58::FromBase58; use self::cxrml_exchange_pendingorders::OrderPair; use chainx_runtime::{