Skip to content

Commit

Permalink
add move_free_token for tokenbalances
Browse files Browse the repository at this point in the history
  • Loading branch information
Aton authored and gguoss committed Nov 5, 2018
1 parent 46a9577 commit dc17385
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 30 deletions.
103 changes: 73 additions & 30 deletions cxrml/tokenbalances/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,19 @@ mod mock;
mod tests;

use rstd::prelude::*;
pub use rstd::result::Result as StdResult;
use codec::Codec;
use runtime_support::{StorageValue, StorageMap, Parameter};
use runtime_support::dispatch::Result;
use primitives::traits::{SimpleArithmetic, As, Member, CheckedAdd, CheckedSub, OnFinalise};

//use cxsupport::StorageDoubleMap;

// substrate mod
use system::ensure_signed;
use balances::address::Address;
use balances::EnsureAccountLiquid;


//#[cfg(feature = "std")]
//pub type SymbolString = ::std::borrow::Cow<'static, [u8]>;
//#[cfg(not(feature = "std"))]
pub type SymbolString = &'static [u8];

//#[cfg(feature = "std")]
//pub type TokenString = SymbolString;
//#[cfg(not(feature = "std"))]
pub type DescString = SymbolString;

pub trait Trait: balances::Trait + cxsupport::Trait {
Expand Down Expand Up @@ -184,6 +176,8 @@ decl_event!(
DestroyToken(AccountId, Symbol, TokenBalance),
/// Transfer succeeded (from, to, symbol, value, fees).
TransferToken(AccountId, AccountId, Symbol, TokenBalance, Balance),
/// Move Free Token, include chainx (from, to, symbol, value)
MoveFreeToken(AccountId, AccountId, Symbol, TokenBalance),
/// set transfer token fee
SetTransferTokenFee(Balance),
}
Expand Down Expand Up @@ -231,7 +225,9 @@ decl_storage! {
// 0 token list length
storage.insert(GenesisConfig::<T>::hash(&<TokenListLen<T>>::key()).to_vec(), (config.token_list.len() as u32 + list_count).encode());
for (index, (token, free_token, reserved_token)) in config.token_list.iter().enumerate() {
// token.is_valid().map_err(|e| e.to_string())?;
if let Err(e) = token.is_valid() {
panic!(e);
}
// 1 token balance
storage.insert(GenesisConfig::<T>::hash(&<TotalFreeToken<T>>::key_for(token.symbol())).to_vec(), free_token.encode());
storage.insert(GenesisConfig::<T>::hash(&<TotalReservedToken<T>>::key_for(token.symbol())).to_vec(), reserved_token.encode());
Expand Down Expand Up @@ -326,14 +322,6 @@ impl<T: Trait> Module<T> {
.collect()
}

// /// return valid token list, only valid token
// pub fn token_list() -> Vec<Symbol> {
// Self::all_token_list().into_iter()
// .filter(|(flag, _)| *flag == true)
// .map(|(_, sym)| sym)
// .collect()
// }

pub fn is_valid_token(symbol: &Symbol) -> Result {
is_valid_symbol(symbol)?;
if let Some(info) = TokenInfo::<T>::get(symbol) {
Expand All @@ -343,11 +331,6 @@ impl<T: Trait> Module<T> {
return Err("not a valid token");
}
Err("not a registered token")
// if Self::token_list().contains(symbol) {
// Ok(())
// } else {
// Err("not in the valid token list")
// }
}

pub fn is_valid_token_for(who: &T::AccountId, symbol: &Symbol) -> Result {
Expand All @@ -360,11 +343,6 @@ impl<T: Trait> Module<T> {
}

fn add_token(symbol: &Symbol, free: T::TokenBalance, reserved: T::TokenBalance) -> Result {

// let list = Self::all_token_list();
// if !list.iter().find(|(_, sym)| *sym == *symbol).is_none() {
// return Err("already has this token symbol");
// }
if TokenInfo::<T>::exists(symbol) {
return Err("already has this token symbol");
}
Expand All @@ -381,7 +359,6 @@ impl<T: Trait> Module<T> {

fn remove_token(symbol: &Symbol) -> Result {
is_valid_symbol(symbol)?;
// let list = Self::token_list();
if let Some(mut info) = TokenInfo::<T>::get(symbol) {
info.1 = false;
TokenInfo::<T>::insert(symbol.clone(), info);
Expand Down Expand Up @@ -604,6 +581,72 @@ impl<T: Trait> Module<T> {
Self::deposit_event(RawEvent::UnreverseToken(who.clone(), symbol.clone(), value));
Ok(())
}

pub fn move_free_token(from: &T::AccountId, to: &T::AccountId, symbol: &Symbol, value: T::TokenBalance) -> StdResult<(), TokenErr> {
Self::is_valid_token_for(from, symbol).map_err(|_| TokenErr::InvalidToken)?;
<T as balances::Trait>::EnsureAccountLiquid::ensure_account_liquid(from).map_err(|_| TokenErr::InvalidAccount)?;
//TODO validator`

// for chainx
if symbol.as_slice() == T::CHAINX_SYMBOL {
let value: T::Balance = As::sa(value.as_() as u64); // change to balance for balances module
let from_token: T::Balance = balances::FreeBalance::<T>::get(from);
let to_token: T::Balance = balances::FreeBalance::<T>::get(to);

let new_from_token = match from_token.checked_sub(&value) {
Some(b) => b,
None => return Err(TokenErr::NotEnough),
};
let new_to_token = match to_token.checked_add(&value) {
Some(b) => b,
None => return Err(TokenErr::OverFlow),
};
balances::FreeBalance::<T>::insert(from, new_from_token);
balances::FreeBalance::<T>::insert(to, new_to_token);
Self::deposit_event(RawEvent::MoveFreeToken(from.clone(), to.clone(), symbol.clone(), As::sa(value.as_())));
return Ok(());
}

Self::init_token_for(to, symbol);
let key_from = (from.clone(), symbol.clone());
let key_to = (to.clone(), symbol.clone());

let from_token: T::TokenBalance = FreeToken::<T>::get(&key_from);
let to_token: T::TokenBalance = FreeToken::<T>::get(&key_to);

let new_from_token = match from_token.checked_sub(&value) {
Some(b) => b,
None => return Err(TokenErr::NotEnough),
};
let new_to_token = match to_token.checked_add(&value) {
Some(b) => b,
None => return Err(TokenErr::OverFlow),
};
FreeToken::<T>::insert(key_from, new_from_token);
FreeToken::<T>::insert(key_to, new_to_token);
Self::deposit_event(RawEvent::MoveFreeToken(from.clone(), to.clone(), symbol.clone(), value));
Ok(())
}
}

#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub enum TokenErr {
NotEnough,
OverFlow,
InvalidToken,
InvalidAccount,
}

impl TokenErr {
pub fn info(&self) -> &'static str {
match *self {
TokenErr::NotEnough => "free token too low",
TokenErr::OverFlow => "overflow for this value",
TokenErr::InvalidToken => "not a valid token for this account",
TokenErr::InvalidAccount => "Account Locked",
}
}
}

impl<T: Trait> Module<T> {
Expand All @@ -617,7 +660,7 @@ impl<T: Trait> Module<T> {
Self::is_valid_token_for(&transactor, &sym)?;
let dest = <balances::Module<T>>::lookup(dest)?;
Self::init_token_for(&dest, &sym);
//

let fee = Self::transfer_token_fee();

let key_from = (transactor.clone(), sym.clone());
Expand Down
26 changes: 26 additions & 0 deletions cxrml/tokenbalances/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,32 @@ pub fn new_test_ext() -> runtime_io::TestExternalities<Blake2Hasher> {
r.into()
}

pub fn err_test_ext() -> runtime_io::TestExternalities<Blake2Hasher> {
let mut r = system::GenesisConfig::<Test>::default().build_storage().unwrap();
// balance
r.extend(balances::GenesisConfig::<Test> {
balances: vec![(1, 1000), (2, 510)],
transaction_base_fee: 0,
transaction_byte_fee: 0,
existential_deposit: 500,
transfer_fee: 0,
creation_fee: 0,
reclaim_rebate: 0,
}.build_storage().unwrap());
// token
let t: Token = Token::new(b"x-btc?...".to_vec(), b"btc token".to_vec(), 8);
let t2: Token = Token::new(b"x-eth".to_vec(), b"eth token".to_vec(), 4);

r.extend(GenesisConfig::<Test> {
token_list: vec![
(t, 100, 0),
(t2, 100, 0),
],
transfer_token_fee: 10,
}.build_storage().unwrap());
r.into()
}

pub fn new_test_ext2() -> runtime_io::TestExternalities<Blake2Hasher> {
let mut r = system::GenesisConfig::<Test>::default().build_storage().unwrap();
// balance
Expand Down
29 changes: 29 additions & 0 deletions cxrml/tokenbalances/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ fn test_genesis() {
});
}

#[test]
#[should_panic]
fn test_err_genesis() {
with_externalities(&mut err_test_ext(), || {})
}

#[test]
fn test_register() {
with_externalities(&mut new_test_ext(), || {
Expand Down Expand Up @@ -370,4 +376,27 @@ fn test_chainx_err() {
assert_eq!(max_balance as u64, 18446744073709551615);
assert_err!(TokenBalances::reserve(&a, &sym, max_balance), "chainx free token too low to reserve");
})
}

#[test]
fn test_move() {
with_externalities(&mut new_test_ext2(), || {
let a: u64 = 1; // accountid
let b: u64 = 2; // accountid
let sym = Test::CHAINX_SYMBOL.to_vec();
assert_ok!(TokenBalances::move_free_token(&a, &b, &sym, 100));
assert_err!(TokenBalances::move_free_token(&a, &b, &sym, 1000), TokenErr::NotEnough);
assert_eq!(Balances::free_balance(&a), 900);
assert_eq!(Balances::free_balance(&b), 510 + 100);

let sym = b"x-btc".to_vec();
assert_err!(TokenBalances::move_free_token(&a, &b, &sym, 100), TokenErr::InvalidToken);

TokenBalances::issue(&a, &sym, 100).unwrap();
assert_ok!(TokenBalances::move_free_token(&a, &b, &sym, 100));
assert_err!(TokenBalances::move_free_token(&a, &b, &sym, 1000), TokenErr::NotEnough);

assert_eq!(TokenBalances::free_token(&(a.clone(), sym.clone())), 0);
assert_eq!(TokenBalances::free_token(&(b.clone(), sym.clone())), 100);
})
}

0 comments on commit dc17385

Please sign in to comment.