diff --git a/Cargo.lock b/Cargo.lock index d31a031cc2d0f..fd42432091b6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -412,7 +412,6 @@ dependencies = [ "srml-democracy 0.1.0 (git+https://github.com/chainpool/substrate)", "srml-grandpa 0.1.0 (git+https://github.com/chainpool/substrate)", "srml-session 0.1.0 (git+https://github.com/chainpool/substrate)", - "srml-staking 0.1.0 (git+https://github.com/chainpool/substrate)", "srml-support 0.1.0 (git+https://github.com/chainpool/substrate)", "srml-system 0.1.0 (git+https://github.com/chainpool/substrate)", "srml-timestamp 0.1.0 (git+https://github.com/chainpool/substrate)", @@ -423,6 +422,8 @@ dependencies = [ "substrate-primitives 0.1.0 (git+https://github.com/chainpool/substrate)", "xrml-executive 0.4.0", "xrml-fee-manager 0.4.0", + "xrml-xassets-assets 0.4.0", + "xrml-xsystem 0.4.0", ] [[package]] @@ -4343,9 +4344,27 @@ dependencies = [ "srml-system 0.1.0 (git+https://github.com/chainpool/substrate)", ] +[[package]] +name = "xrml-xassets-assets" +version = "0.4.0" +dependencies = [ + "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 0.1.0 (git+https://github.com/chainpool/substrate)", + "sr-primitives 0.1.0 (git+https://github.com/chainpool/substrate)", + "sr-std 0.1.0 (git+https://github.com/chainpool/substrate)", + "srml-balances 0.1.0 (git+https://github.com/chainpool/substrate)", + "srml-support 0.1.0 (git+https://github.com/chainpool/substrate)", + "srml-system 0.1.0 (git+https://github.com/chainpool/substrate)", + "substrate-primitives 0.1.0 (git+https://github.com/chainpool/substrate)", +] + [[package]] name = "xrml-xsupport" -version = "0.3.0" +version = "0.4.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 143b65165fed7..d04c4e2cc73e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,9 @@ members = [ "xrml/xsystem", "xrml/xsupport", "xrml/xexecutive", + # xrml/xfee "xrml/xfee/manager", "xrml/xfee/config", + # xrml/assets + "xrml/xassets/assets", ] diff --git a/cli/src/genesis_config.rs b/cli/src/genesis_config.rs index 0ca82d288adc4..180898d73dd75 100644 --- a/cli/src/genesis_config.rs +++ b/cli/src/genesis_config.rs @@ -9,17 +9,14 @@ extern crate substrate_primitives; use self::base58::FromBase58; use chainx_runtime::GrandpaConfig; use chainx_runtime::{ - BalancesConfig, ConsensusConfig, ContractConfig, CouncilVotingConfig, DemocracyConfig, - GenesisConfig, Perbill, Permill, SessionConfig, StakingConfig, TimestampConfig, TreasuryConfig, - XFeeManagerConfig, /*TokenBalancesConfig, FinancialRecordsConfig, - MultiSigConfig, BalancesConfigCopy, BridgeOfBTCConfig, Params, Token, PendingOrdersConfig, MatchOrderConfig*/ + BalancesConfig, ConsensusConfig, GenesisConfig, Perbill, Permill, SessionConfig, + TimestampConfig, XAssetsConfig, XFeeManagerConfig, XSystemConfig, }; use ed25519; use ed25519::Public; use self::btc_chain::BlockHeader; use self::btc_primitives::{compact::Compact, hash::H256}; -//use self::cxrml_tokenbalances::{TokenT, Trait}; use self::keys::DisplayLayout; pub enum GenesisSpec { @@ -81,11 +78,10 @@ pub fn testnet_genesis(genesis_spec: GenesisSpec) -> GenesisConfig { authorities: initial_authorities.clone(), }), system: None, - fee_manager: Some(XFeeManagerConfig { - switch: false, - _genesis_phantom_data: Default::default(), - }), balances: Some(balances_config), + timestamp: Some(TimestampConfig { + period: SECS_PER_BLOCK, // 3 second block time. + }), session: Some(SessionConfig { validators: initial_authorities .iter() @@ -94,130 +90,6 @@ pub fn testnet_genesis(genesis_spec: GenesisSpec) -> GenesisConfig { .collect(), session_length: 1 * MINUTES, // that's 1 hour per session. }), - staking: Some(StakingConfig { - current_era: 0, - intentions: initial_authorities - .iter() - .cloned() - .map(Into::into) - .collect(), - offline_slash: Perbill::from_billionths(1_000_000), - session_reward: Perbill::from_billionths(2_065), - current_offline_slash: 0, - current_session_reward: 0, - validator_count: 7, - sessions_per_era: 12, - bonding_duration: 1 * DAYS, - offline_slash_grace: 4, - minimum_validator_count: 4, - }), - /* - staking: Some(StakingConfig { - current_era: 0, - bonding_duration: 3 * MINUTES, // 3 days per bond. - intentions: initial_authorities.clone().into_iter().map(|i| i.0.into()).collect(), - intention_profiles: initial_authorities.clone().into_iter().map(|i| (i.0.into(), b"ChainX".to_vec(), b"chainx.org".to_vec())).collect(), - minimum_validator_count: 1, - validator_count: 6, - reward_per_sec: 3, // 3 PCX per second - sessions_per_era: 4, // 24 hours per era. - session_reward: Perbill::from_millionths(10800), - offline_slash_grace: 0, - offline_slash: Perbill::from_millionths(0), - current_offline_slash: 0, - current_session_reward: 0, - }),*/ - democracy: Some(DemocracyConfig { - launch_period: 5 * MINUTES, // 1 day per public referendum - voting_period: 5 * MINUTES, // 3 days to discuss & vote on an active referendum - minimum_deposit: 50 * DOLLARS, // 12000 as the minimum deposit for a referendum - public_delay: 0, - max_lock_periods: 6, - }), - council_voting: Some(CouncilVotingConfig { - cooloff_period: 4 * DAYS, - voting_period: 1 * DAYS, - enact_delay_period: 0, - }), - timestamp: Some(TimestampConfig { - period: SECS_PER_BLOCK, // 3 second block time. - }), - treasury: Some(TreasuryConfig { - proposal_bond: Permill::from_percent(5), - proposal_bond_minimum: 1_000_000, - spend_period: 1 * DAYS, - burn: Permill::from_percent(50), - }), - contract: Some(ContractConfig { - contract_fee: 21, - call_base_fee: 135, - create_base_fee: 175, - gas_price: 1, - max_depth: 1024, - block_gas_limit: 10_000_000, - current_schedule: Default::default(), - }), - /* cxsystem: Some(CXSystemConfig { - death_account: substrate_primitives::H256([0; 32]), - fee_buy_account: substrate_primitives::H256([1; 32]), - }), - tokenbalances: Some(TokenBalancesConfig { - chainx_precision: pcx_precision, - // token_list: Vec<(Token, Vec<(T::AccountId, T::TokenBalance)>)> - // e.g. [("btc", [(account1, value), (account2, value)].to_vec()), ("eth", [(account1, value), (account2, value)].to_vec())] - token_list: vec![ - (Token::new(BridgeOfBTC::SYMBOL.to_vec(), b"BTC Token".to_vec(), 8), - // [(Keyring::Alice.to_raw_public().into(), 1_000_000), (Keyring::Bob.to_raw_public().into(), 1_000_000)].to_vec()) - vec![]) - ], - - transfer_token_fee: 10, - }), - financialrecords: Some(FinancialRecordsConfig { - withdrawal_fee: 10, - }), - multisig: Some(MultiSigConfig { - genesis_multi_sig: vec![], - deploy_fee: 0, - exec_fee: 0, - confirm_fee: 0, - balances_config: balances_config_copy, - _genesis_phantom_data: Default::default(), - }), - bridge_btc: Some(BridgeOfBTCConfig { - // start genesis block: (genesis, blocknumber) - genesis: (BlockHeader { - version: 536870912, - previous_header_hash: H256::from_reversed_str("000000000000012651bf407efcc567df3529049085711572eaee8d243ec815d4"), - merkle_root_hash: H256::from_reversed_str("ecec3d2eb31c04a844dc18b233c819c64b6a56c2a51bc77078ef4cc8f434bc21"), - time: 1541642229, - bits: Compact::new(436299432), - nonce: 937513642, - }, 1442480), - params_info: Params::new(520159231, // max_bits - 2 * 60 * 60, // block_max_future - 64, // max_fork_route_preset - 2 * 7 * 24 * 60 * 60, // target_timespan_seconds - 10 * 60, // target_spacing_seconds - 4), // retargeting_factor - network_id: 1, - utxo_max_index: 0, - irr_block: 0, - btc_fee: 10, - accounts_max_index: 0, - receive_address: keys::Address::from_layout(&"2N4C127fBSmqBsNuHeLmAbZEVSPfV6GB2j2".from_base58().unwrap()).unwrap(), - redeem_script: b"52210257aff1270e3163aaae9d972b3d09a2385e0d4877501dbeca3ee045f8de00d21c2103fd58c689594b87bbe20a9a00091d074dc0d9f49a988a7ad4c2575adeda1b507c2102bb2a5aa53ba7c0d77bdd86bb9553f77dd0971d3a6bb6ad609787aa76eb17b6b653ae".to_vec(), - fee: 0, - }), - pendingorders: Some(PendingOrdersConfig { - order_fee: 0, - pair_list: vec![ - OrderPair::new(b"pcx".to_vec(), b"btc".to_vec(), 8)], - max_command_id: 0, - _genesis_phantom_data: Default::default(), - }), - matchorder: Some(MatchOrderConfig { match_fee: 10, _genesis_phantom_data: Default::default(),}), - */ grandpa: Some(GrandpaConfig { authorities: initial_authorities .clone() @@ -225,5 +97,15 @@ pub fn testnet_genesis(genesis_spec: GenesisSpec) -> GenesisConfig { .map(|k| (k, 1)) .collect(), }), + // chainx runtime module + xsystem: Some(XSystemConfig { + death_account: substrate_primitives::H256::zero(), + fee_buy_account: substrate_primitives::H256::repeat_byte(0x1), + }), + fee_manager: Some(XFeeManagerConfig { + switch: false, + _genesis_phantom_data: Default::default(), + }), + xassets: None, } } diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 3b856deb8221a..30c21fd6f3d50 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -8,72 +8,78 @@ rustc-hex = "1.0" hex-literal = "0.1.0" safe-mix = { version = "1.0", default_features = false} serde = { version = "1.0", default_features = false } -parity-codec = "2.0" -parity-codec-derive = "2.0" -sr-std = { git = "https://github.com/chainpool/substrate" } +parity-codec = "2.1" +parity-codec-derive = "2.1" + substrate-client = { git = "https://github.com/chainpool/substrate" } -srml-support = { git = "https://github.com/chainpool/substrate" } substrate-primitives = { git = "https://github.com/chainpool/substrate" } -srml-consensus = { git = "https://github.com/chainpool/substrate" } -srml-contract = { git = "https://github.com/chainpool/substrate" } -srml-balances = { git = "https://github.com/chainpool/substrate" } -srml-council = { git = "https://github.com/chainpool/substrate" } -srml-democracy = { git = "https://github.com/chainpool/substrate" } -xrml-executive = { path = "../xrml/xexecutive" } -sr-primitives = { git = "https://github.com/chainpool/substrate" } -srml-session = { git = "https://github.com/chainpool/substrate" } -srml-grandpa = { git = "https://github.com/chainpool/substrate" } -srml-staking = { git = "https://github.com/chainpool/substrate" } substrate-finality-grandpa-primitives = { git = "https://github.com/chainpool/substrate" } substrate-consensus-aura-primitives = { git = "https://github.com/chainpool/substrate" } + +sr-primitives = { git = "https://github.com/chainpool/substrate" } +sr-version = { git = "https://github.com/chainpool/substrate" } +sr-std = { git = "https://github.com/chainpool/substrate" } + +srml-support = { git = "https://github.com/chainpool/substrate" } srml-system = { git = "https://github.com/chainpool/substrate" } -srml-aura = { git = "https://github.com/chainpool/substrate" } +srml-balances = { git = "https://github.com/chainpool/substrate" } srml-timestamp = { git = "https://github.com/chainpool/substrate" } +srml-consensus = { git = "https://github.com/chainpool/substrate" } +srml-session = { git = "https://github.com/chainpool/substrate" } +srml-grandpa = { git = "https://github.com/chainpool/substrate" } +srml-aura = { git = "https://github.com/chainpool/substrate" } + +srml-contract = { git = "https://github.com/chainpool/substrate" } +srml-council = { git = "https://github.com/chainpool/substrate" } +srml-democracy = { git = "https://github.com/chainpool/substrate" } srml-treasury = { git = "https://github.com/chainpool/substrate" } -sr-version = { git = "https://github.com/chainpool/substrate" } + +# chainx chainx-primitives = { path = "../primitives" } -xrml-fee-manager = { path = "../xrml/xfee/manager", default-features = false } # chainx runtime module -#cxrml-system = { path = "../cxrml/system" } -#cxrml-support = { path = "../cxrml/support" } -#cxrml-staking = { path = "../cxrml/staking" } -#cxrml-tokenbalances = { path = "../cxrml/tokenbalances" } -#cxrml-funds-financialrecords = { path = "../cxrml/funds/financialrecords" } -#cxrml-multisig = { path = "../cxrml/multisig" } -#cxrml-bridge-btc = { path = "../cxrml/bridge/btc" } -#cxrml-exchange-pendingorders = { path = "../cxrml/exchange/pendingorders" } -#cxrml-exchange-matchorder = { path = "../cxrml/exchange/matchorder" } +xrml-xsystem = { path = "../xrml/xsystem" } +xrml-executive = { path = "../xrml/xexecutive" } +# fee +xrml-fee-manager = { path = "../xrml/xfee/manager" } +# assets +xrml-xassets-assets = { path = "../xrml/xassets/assets" } + [features] default = ["std"] std = [ + "serde/std", + "safe-mix/std", "parity-codec/std", "substrate-primitives/std", "substrate-consensus-aura-primitives/std", + + # substrate runtime module + "sr-primitives/std", + "sr-version/std", "sr-std/std", + "srml-support/std", - "srml-aura/std", + "srml-system/std", + "srml-balances/std", + "srml-timestamp/std", "srml-consensus/std", + "srml-session/std", + "srml-grandpa/std", + "srml-aura/std", + + "srml-contract/std", "srml-council/std", "srml-democracy/std", + "srml-treasury/std", + # chainx + "chainx-primitives/std", + # chainx runtime + "xrml-xsystem/std", "xrml-executive/std", + # fee "xrml-fee-manager/std", - "sr-primitives/std", - "srml-session/std", - "srml-system/std", - "srml-timestamp/std", - "sr-version/std", - "chainx-primitives/std", - "safe-mix/std", - "serde/std", -# "cxrml-system/std", -# "cxrml-support/std", -# "srml-staking/std", -# "cxrml-tokenbalances/std", -# "cxrml-funds-financialrecords/std", -# "cxrml-multisig/std", -# "cxrml-bridge-btc/std", -# "cxrml-pendingorders/std", -# "cxrml-matchorder/std", + # asset + "xrml-xassets-assets/std" ] diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index ff5a003140140..d814c8058e616 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -6,97 +6,84 @@ // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. #![recursion_limit = "256"] -#[macro_use] -extern crate srml_support; -#[macro_use] -extern crate sr_primitives as runtime_primitives; extern crate parity_codec as codec; +#[macro_use] +extern crate parity_codec_derive; #[cfg(feature = "std")] extern crate serde; -extern crate substrate_primitives as primitives; + #[macro_use] extern crate substrate_client as client; +extern crate substrate_consensus_aura_primitives as consensus_aura; +extern crate substrate_primitives as primitives; + #[macro_use] -extern crate parity_codec_derive; +extern crate sr_primitives as runtime_primitives; +#[macro_use] +extern crate sr_version as version; #[cfg_attr(not(feature = "std"), macro_use)] extern crate sr_std as rstd; + +// substrate runtime module +#[macro_use] +extern crate srml_support; extern crate srml_aura as aura; extern crate srml_balances as balances; extern crate srml_consensus as consensus; -extern crate srml_contract as contract; -extern crate srml_council as council; -extern crate srml_democracy as democracy; +extern crate srml_grandpa as grandpa; extern crate srml_session as session; -extern crate srml_staking as staking; extern crate srml_system as system; extern crate srml_timestamp as timestamp; +// unused +extern crate srml_contract as contract; +extern crate srml_council as council; +extern crate srml_democracy as democracy; extern crate srml_treasury as treasury; -extern crate substrate_consensus_aura_primitives as consensus_aura; -extern crate substrate_primitives; -extern crate xrml_executive as executive; -extern crate xrml_fee_manager as fee_manager; -// cx runtime module -//extern crate cxrml_associations as associations; -/*extern crate cxrml_multisig as multisig; -extern crate cxrml_support as cxsupport; -//extern crate cxrml_staking as staking; -extern crate cxrml_tokenbalances as tokenbalances; -*/ -extern crate srml_grandpa as grandpa; -/* -extern crate cxrml_financialrecords as financialrecords; -//extern crate cxrml_multisig as multisig; -// chainx runtime bridge -extern crate cxrml_bridge_btc as bridge_btc; -// funds -extern crate cxrml_funds_financialrecords as financialrecords; -extern crate cxrml_funds_withdrawal as withdrawal; -*/ -// exchange -//extern crate cxrml_exchange_matchorder as matchorder; -//extern crate cxrml_exchange_pendingorders as pendingorders; - -#[macro_use] -extern crate sr_version as version; +// chainx extern crate chainx_primitives; +// chainx runtime module +extern crate xrml_executive as xexective; +extern crate xrml_xsystem as xsystem; +// fee; +extern crate xrml_fee_manager as fee_manager; +// assets; +extern crate xrml_xassets_assets as xassets; pub use balances::address::Address as RawAddress; use consensus_aura::api as aura_api; pub use runtime_primitives::{Perbill, Permill}; -//pub use tokenbalances::Token; -use chainx_primitives::{ - AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, SessionKey, Signature, -}; -use client::{block_builder::api as block_builder_api, runtime_api as client_api}; #[cfg(feature = "std")] use council::{motions as council_motions, voting as council_voting}; use grandpa::fg_primitives::{self, ScheduledChange}; use rstd::prelude::*; + +use primitives::u32_trait::{_2, _4}; +use primitives::OpaqueMetadata; + use runtime_primitives::generic; use runtime_primitives::traits::{BlakeTwo256, Block as BlockT, Convert, DigestFor, NumberFor}; +//#[cfg(feature = "std")] +//use council::{motions as council_motions, voting as council_voting}; use runtime_primitives::transaction_validity::TransactionValidity; use runtime_primitives::{ApplyResult, BasicInherentData, CheckInherentError}; -use srml_support::inherent::ProvideInherent; -use substrate_primitives::u32_trait::{_2, _4}; -use substrate_primitives::OpaqueMetadata; #[cfg(any(feature = "std", test))] use version::NativeVersion; use version::RuntimeVersion; +use client::{block_builder::api as block_builder_api, runtime_api as client_api}; + +use srml_support::inherent::ProvideInherent; + // for set consensus period pub use srml_support::{RuntimeMetadata, StorageValue}; pub use timestamp::BlockPeriod; pub use timestamp::Call as TimestampCall; -//#[cfg(feature = "std")] -//pub use multisig::BalancesConfigCopy; -/*#[cfg(feature = "std")] -pub use bridge_btc::Params; -#[cfg(feature = "std")] -pub use multisig::BalancesConfigCopy; -*/ +use chainx_primitives::{ + AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, SessionKey, Signature, +}; #[cfg(any(feature = "std", test))] pub use runtime_primitives::BuildStorage; @@ -143,13 +130,17 @@ impl system::Trait for Runtime { impl balances::Trait for Runtime { type Balance = Balance; type AccountIndex = AccountIndex; - type OnFreeBalanceZero = (Staking, Contract); - type EnsureAccountLiquid = Staking; + // type OnFreeBalanceZero = (Staking, Contract); + // type EnsureAccountLiquid = Staking; + type OnFreeBalanceZero = (); + type EnsureAccountLiquid = (); type Event = Event; } -impl fee_manager::Trait for Runtime { - type Event = Event; +impl timestamp::Trait for Runtime { + const TIMESTAMP_SET_POSITION: u32 = TIMESTAMP_SET_POSITION; + type Moment = u64; + type OnTimestampSet = Aura; } impl consensus::Trait for Runtime { @@ -159,12 +150,6 @@ impl consensus::Trait for Runtime { type InherentOfflineReport = (); } -impl timestamp::Trait for Runtime { - const TIMESTAMP_SET_POSITION: u32 = TIMESTAMP_SET_POSITION; - type Moment = u64; - type OnTimestampSet = Aura; -} - /// Session key conversion. pub struct SessionKeyConversion; @@ -176,95 +161,66 @@ impl Convert for SessionKeyConversion { impl session::Trait for Runtime { type ConvertAccountIdToSessionKey = SessionKeyConversion; - type OnSessionChange = (Staking, grandpa::SyncedAuthorities); - type Event = Event; -} - -impl treasury::Trait for Runtime { - type ApproveOrigin = council_motions::EnsureMembers<_4>; - type RejectOrigin = council_motions::EnsureMembers<_2>; - type Event = Event; -} - -impl democracy::Trait for Runtime { - type Proposal = Call; - type Event = Event; -} - -impl council::Trait for Runtime { + // type OnSessionChange = (Staking, grandpa::SyncedAuthorities); + type OnSessionChange = grandpa::SyncedAuthorities; type Event = Event; } -impl contract::Trait for Runtime { - type DetermineContractAddress = contract::SimpleAddressDeterminator; - type Gas = u64; +impl grandpa::Trait for Runtime { + type SessionKey = SessionKey; + type Log = Log; type Event = Event; } -// TODO add voting and motions at here -impl council::voting::Trait for Runtime { - type Event = Event; +impl aura::Trait for Runtime { + // type HandleReport = aura::StakingSlasher; + type HandleReport = (); } -impl council::motions::Trait for Runtime { - type Origin = Origin; - type Proposal = Call; - type Event = Event; -} +//impl treasury::Trait for Runtime { +// type ApproveOrigin = council_motions::EnsureMembers<_4>; +// type RejectOrigin = council_motions::EnsureMembers<_2>; +// type Event = Event; +//} +// +//impl democracy::Trait for Runtime { +// type Proposal = Call; +// type Event = Event; +//} +// +//impl council::Trait for Runtime { +// type Event = Event; +//} +// +//impl contract::Trait for Runtime { +// type DetermineContractAddress = contract::SimpleAddressDeterminator; +// type Gas = u64; +// type Event = Event; +//} +// +//// TODO add voting and motions at here +//impl council::voting::Trait for Runtime { +// type Event = Event; +//} +// +//impl council::motions::Trait for Runtime { +// type Origin = Origin; +// type Proposal = Call; +// type Event = Event; +//} // cxrml trait - -/* -//impl cxsystem::Trait for Runtime {} - -impl cxsupport::Trait for Runtime {} - -impl tokenbalances::Trait for Runtime { - const CHAINX_SYMBOL: tokenbalances::SymbolString = b"PCX"; - const CHAINX_TOKEN_DESC: tokenbalances::DescString = b"Polkadot ChainX"; - type TokenBalance = TokenBalance; - type Event = Event; - type OnMoveToken = (); +impl xsystem::Trait for Runtime { + const XSYSTEM_SET_POSITION: u32 = 3; } - -impl multisig::Trait for Runtime { - type MultiSig = multisig::SimpleMultiSigIdFor; - type Event = Event; -} - -impl tokenstaking::Trait for Runtime { - type Event = Event; -} - -// bridge -impl bridge_btc::Trait for Runtime { - type Event = Event; -} - -impl pendingorders::Trait for Runtime { - type Event = Event; - type Amount = TokenBalance; - type Price = TokenBalance; -} -impl matchorder::Trait for Runtime { - type Event = Event; -} -*/ - -// mining staking -impl staking::Trait for Runtime { - type OnRewardMinted = Treasury; - type Event = Event; +// fees +impl fee_manager::Trait for Runtime { + // type Event = Event; } - -impl grandpa::Trait for Runtime { - type SessionKey = SessionKey; - type Log = Log; +// assets +impl xassets::Trait for Runtime { type Event = Event; -} - -impl aura::Trait for Runtime { - type HandleReport = aura::StakingSlasher; + type OnAssetChanged = (); } construct_runtime!( @@ -274,32 +230,19 @@ construct_runtime!( InherentData = BasicInherentData { System: system::{default, Log(ChangesTrieRoot)}, - Aura: aura::{Module}, + Balances: balances, Timestamp: timestamp::{Module, Call, Storage, Config, Inherent}, Consensus: consensus::{Module, Call, Storage, Config, Log(AuthoritiesChange), Inherent}, - Balances: balances, Session: session, - Staking: staking, - XFeeManager: fee_manager, - Democracy: democracy, - Council: council::{Module, Call, Storage, Event}, - CouncilVoting: council_voting, - CouncilMotions: council_motions::{Module, Call, Storage, Event, Origin}, - Treasury: treasury, - Contract: contract::{Module, Call, Config, Event}, Grandpa: grandpa::{Module, Call, Storage, Config, Log(), Event}, - /*TokenBalances: tokenbalances, - FinancialRecords: financialrecords, - //MultiSig: multisig, - PendingOrders : pendingorders, - MatchOrder : matchorder, - // bridge - BridgeOfBTC: bridge_btc, - // put end of this marco - CXSupport: cxsupport::{Module}, - // must put end of all chainx runtime module - //CXSystem: cxsystem::{Module, Call, Storage, Config}, - Balances: balances::{Module, Storage, Config, Event},*/ // no call for public + Aura: aura::{Module}, + + // chainx runtime module + XSystem: xsystem::{Module, Call, Storage, Config}, //, Inherent}, + // fee + XFeeManager: fee_manager::{Module, Call, Storage, Config}, + // assets + XAssets: xassets, } ); @@ -315,10 +258,10 @@ pub type BlockId = generic::BlockId; pub type UncheckedExtrinsic = generic::UncheckedMortalExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = - executive::Executive, XFeeManager, AllModules>; + xexective::Executive, XFeeManager, AllModules>; // define tokenbalances module type -pub type TokenBalance = u128; +//pub type TokenBalance = u128; impl_runtime_apis! { impl client_api::Core for Runtime { diff --git a/runtime/wasm/Cargo.toml b/runtime/wasm/Cargo.toml index 394c9964612ab..01c43d5bb7936 100644 --- a/runtime/wasm/Cargo.toml +++ b/runtime/wasm/Cargo.toml @@ -9,50 +9,42 @@ crate-type = ["cdylib"] [dependencies] integer-sqrt = { git = "https://github.com/paritytech/integer-sqrt-rs.git", branch = "master" } safe-mix = { version = "1.0", default_features = false} -parity-codec-derive = { version = "2.1" } + parity-codec = { version = "2.1", default-features = false } +parity-codec-derive = { version = "2.1" } + +substrate-primitives = { git = "https://github.com/chainpool/substrate", default-features = false } +substrate-finality-grandpa-primitives = { git = "https://github.com/chainpool/substrate", default-features = false } + +sr-primitives = { git = "https://github.com/chainpool/substrate", default-features = false } +sr-version = { git = "https://github.com/chainpool/substrate", default-features = false } sr-std = { git = "https://github.com/chainpool/substrate", default-features = false } sr-io = { git = "https://github.com/chainpool/substrate", default-features = false } + srml-support = { git = "https://github.com/chainpool/substrate", default-features = false } -substrate-primitives = { git = "https://github.com/chainpool/substrate", default-features = false } +srml-system = { git = "https://github.com/chainpool/substrate", default-features = false } +srml-balances = { git = "https://github.com/chainpool/substrate", default-features = false } +srml-timestamp = { git = "https://github.com/chainpool/substrate", default-features = false } srml-consensus = { git = "https://github.com/chainpool/substrate", default-features = false } +srml-session = { git = "https://github.com/chainpool/substrate", default-features = false } +srml-grandpa = { git = "https://github.com/chainpool/substrate", default-features = false } +srml-aura = { git = "https://github.com/chainpool/substrate", default-features = false } + srml-contract = { git = "https://github.com/chainpool/substrate", default-features = false } -srml-balances = { git = "https://github.com/chainpool/substrate", default-features = false } srml-council = { git = "https://github.com/chainpool/substrate", default-features = false } srml-democracy = { git = "https://github.com/chainpool/substrate", default-features = false } -srml-executive = { git = "https://github.com/chainpool/substrate", default-features = false } -sr-primitives = { git = "https://github.com/chainpool/substrate", default-features = false } -srml-session = { git = "https://github.com/chainpool/substrate", default-features = false } -srml-system = { git = "https://github.com/chainpool/substrate", default-features = false } -srml-timestamp = { git = "https://github.com/chainpool/substrate", default-features = false } -srml-grandpa = { git = "https://github.com/chainpool/substrate", default-features = false } -substrate-finality-grandpa-primitives = { git = "https://github.com/chainpool/substrate", default-features = false } srml-treasury = { git = "https://github.com/chainpool/substrate", default-features = false } -sr-version = { git = "https://github.com/chainpool/substrate", default-features = false } -# chainx runtime module -cxrml-system = { path = "../../cxrml/system", default-features = false } -cxrml-support = { path = "../../cxrml/support", default-features = false } -cxrml-tokenbalances = { path = "../../cxrml/tokenbalances", default-features = false } -cxrml-multisig = { path = "../../cxrml/multisig", default-features = false } -cxrml-associations = { path = "../../cxrml/associations", default-features = false } -# mining -cxrml-mining-staking = { path = "../../cxrml/mining/staking", default-features = false } -cxrml-mining-tokenstaking = { path = "../../cxrml/mining/tokenstaking", default-features = false } -# bridge -cxrml-bridge-btc = { path = "../../cxrml/bridge/btc", default-features = false } -<<<<<<< HEAD -cxrml-pendingorders = { path = "../../cxrml/pendingorders", default-features = false } -cxrml-matchorder = { path = "../../cxrml/matchorder", default-features = false } +# chain chainx-primitives = { path = "../../primitives", default-features = false } -======= -# funds -cxrml-funds-financialrecords = { path = "../../cxrml/funds/financialrecords", default-features = false } -cxrml-funds-withdrawal = { path = "../../cxrml/funds/withdrawal", default-features = false } -# exchange -cxrml-exchange-pendingorders = { path = "../../cxrml/exchange/pendingorders", default-features = false } -cxrml-exchange-matchorder = { path = "../../cxrml/exchange/matchorder", default-features = false } ->>>>>>> develop + +# chainx runtime module +xrml-xsystem = { path = "../../xrml/xsystem", default-features = false } +xrml-executive = { path = "../../xrml/xexecutive", default-features = false } +# fee +xrml-fee-manager = { path = "../../xrml/xfee/manager", default-features = false } +# assets +xrml-xassets-assets = { path = "../../xrml/xassets/assets", default-features = false } [features] default = [] @@ -60,41 +52,36 @@ std = [ "safe-mix/std", "parity-codec/std", "substrate-primitives/std", + "substrate-finality-grandpa-primitives/std", + + # substrate runtime module + "sr-primitives/std", + "sr-version/std", "sr-std/std", "sr-io/std", - "srml-grandpa/std", + "srml-support/std", + "srml-system/std", "srml-balances/std", + "srml-timestamp/std", "srml-consensus/std", + "srml-session/std", + "srml-grandpa/std", + "srml-aura/std", + + "srml-contract/std", "srml-council/std", "srml-democracy/std", - "srml-executive/std", - "substrate-finality-grandpa-primitives/std", - "sr-primitives/std", - "srml-session/std", - "srml-system/std", - "srml-timestamp/std", "srml-treasury/std", - "sr-version/std", + # chainx "chainx-primitives/std", - "cxrml-system/std", - "cxrml-support/std", - "cxrml-tokenbalances/std", - "cxrml-multisig/std", -<<<<<<< HEAD - "cxrml-bridge-btc/std", - "cxrml-pendingorders/std", - "cxrml-matchorder/std", -======= - "cxrml-associations/std", - "cxrml-mining-staking/std", - "cxrml-mining-tokenstaking/std", - "cxrml-bridge-btc/std", - "cxrml-funds-financialrecords/std", - "cxrml-funds-withdrawal/std", - "cxrml-exchange-pendingorders/std", - "cxrml-exchange-matchorder/std", ->>>>>>> develop + # chainx runtime + "xrml-xsystem/std", + "xrml-executive/std", + # fee + "xrml-fee-manager/std", + # asset + "xrml-xassets-assets/std" ] [profile.release] diff --git a/xrml/xassets/assets/.gitkeep b/xrml/xassets/assets/.gitkeep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/xrml/xassets/assets/Cargo.toml b/xrml/xassets/assets/Cargo.toml new file mode 100644 index 0000000000000..191876fe004b4 --- /dev/null +++ b/xrml/xassets/assets/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "xrml-xassets-assets" +version = "0.4.0" +authors = ["Chainpool "] + +[dependencies] +hex-literal = "0.1.0" +serde = { version = "1.0", default_features = false } +serde_derive = { version = "1.0", optional = true } +parity-codec = { version = "2.0", default-features = false } +parity-codec-derive = { version = "2.0", default-features = false } +substrate-primitives = { git = "https://github.com/chainpool/substrate", default_features = false } +sr-std = { git = "https://github.com/chainpool/substrate", default_features = false } +sr-io = { git = "https://github.com/chainpool/substrate", default_features = false } +sr-primitives = { git = "https://github.com/chainpool/substrate", default_features = false } +srml-support = { git = "https://github.com/chainpool/substrate", default_features = false } +srml-system = { git = "https://github.com/chainpool/substrate", default_features = false } +srml-balances = { git = "https://github.com/chainpool/substrate", default_features = false } + + +[features] +default = ["std"] +std=[ + "serde/std", + "serde_derive", + "parity-codec/std", + "parity-codec-derive/std", + "substrate-primitives/std", + "sr-std/std", + "sr-io/std", + "sr-primitives/std", + "srml-support/std", + "srml-system/std", + "srml-balances/std", +] diff --git a/xrml/xassets/assets/src/assetdef.rs b/xrml/xassets/assets/src/assetdef.rs new file mode 100644 index 0000000000000..daaad1a7c31f7 --- /dev/null +++ b/xrml/xassets/assets/src/assetdef.rs @@ -0,0 +1,124 @@ +// Copyright 2018 Chainpool. + +use rstd::prelude::*; +use rstd::result::Result as StdResult; + +use runtime_support::dispatch::Result; + +pub type TokenString = &'static [u8]; +pub type DescString = TokenString; +pub type Token = Vec; +pub type Desc = Vec; +pub type Precision = u16; + +pub trait ChainT { + const TOKEN: &'static [u8]; + fn chain() -> Chain; + fn check_addr(_addr: &[u8], _ext: &[u8]) -> Result { + Ok(()) + } +} + +#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +pub enum Chain { + PCX, + BTC, + ETH, +} + +impl Default for Chain { + fn default() -> Self { + Chain::PCX + } +} + +#[derive(PartialEq, Eq, Clone, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +pub struct Asset { + token: Token, + chain: Chain, + precision: Precision, + desc: Desc, +} + +impl Asset { + pub fn new( + token: Token, + chain: Chain, + precision: Precision, + desc: Desc, + ) -> StdResult { + let a = Asset { + token, + chain, + precision, + desc, + }; + a.is_valid()?; + Ok(a) + } + pub fn is_valid(&self) -> Result { + is_valid_token(&self.token)?; + is_valid_desc(&self.desc) + } + + pub fn token(&self) -> Token { + self.token.clone() + } + pub fn chain(&self) -> Chain { + self.chain + } + pub fn desc(&self) -> Desc { + self.desc.clone() + } + pub fn set_desc(&mut self, desc: Desc) { + self.desc = desc + } + pub fn precision(&self) -> Precision { + self.precision + } +} + +const MAX_TOKEN_LEN: usize = 32; +const MAX_DESC_LEN: usize = 128; + +pub fn is_valid_token(v: &[u8]) -> Result { + if v.len() > MAX_TOKEN_LEN || v.len() == 0 { + Err("symbol length too long or zero") + } else { + for c in v.iter() { + // allow number (0x30~0x39), capital letter (0x41~0x5A), small letter (0x61~0x7A), - 0x2D, . 0x2E, | 0x7C, ~ 0x7E + if (*c >= 0x30 && *c <= 0x39) // number + || (*c >= 0x41 && *c <= 0x5A) // capital + || (*c >= 0x61 && *c <= 0x7A) // small + || (*c == 0x2D) // - + || (*c == 0x2E) // . + || (*c == 0x7C) // | + || (*c == 0x7E) + // ~ + { + continue; + } else { + return Err("not a valid symbol char for number, capital/small letter or '-', '.', '|', '~'"); + } + } + Ok(()) + } +} + +pub fn is_valid_desc(v: &[u8]) -> Result { + if v.len() > MAX_DESC_LEN { + Err("token desc length too long") + } else { + for c in v.iter() { + // ascii visible char + if *c >= 20 && *c <= 0x7E { + continue; + } else { + return Err("not a valid ascii visible char"); + } + } + Ok(()) + } +} diff --git a/xrml/xassets/assets/src/lib.rs b/xrml/xassets/assets/src/lib.rs new file mode 100644 index 0000000000000..4971968705700 --- /dev/null +++ b/xrml/xassets/assets/src/lib.rs @@ -0,0 +1,731 @@ +// Copyright 2018 Chainpool. +//! Assets: Handles token asset balances. + +// Ensure we're `no_std` when compiling for Wasm. +#![cfg_attr(not(feature = "std"), no_std)] + +#[macro_use] +extern crate parity_codec_derive; +extern crate parity_codec as codec; + +// for substrate +extern crate substrate_primitives; + +// for substrate runtime +extern crate sr_std as rstd; + +extern crate sr_io as runtime_io; +extern crate sr_primitives as primitives; + +// for substrate runtime module lib +#[macro_use] +extern crate srml_support as runtime_support; +extern crate srml_balances as balances; +extern crate srml_system as system; + +//#[cfg(test)] +//mod mock; +//#[cfg(test)] +//mod tests; + +pub mod assetdef; + +use rstd::prelude::*; +use rstd::result::Result as StdResult; +use rstd::slice::Iter; +use runtime_support::dispatch::Result; + +use primitives::traits::{As, CheckedAdd, CheckedSub}; +use runtime_support::{StorageMap, StorageValue}; +// substrate mod +//use balances::address::Address as RawAddress; +//use balances::EnsureAccountLiquid; +// substrate mod +use system::ensure_signed; + +pub use assetdef::{ + is_valid_desc, is_valid_token, Asset, Chain, ChainT, Desc, DescString, Precision, Token, + TokenString, +}; + +pub type Address = balances::address::Address; + +pub trait Trait: balances::Trait { + /// Event + type Event: From> + Into<::Event>; + + type OnAssetChanged: OnAssetChanged; +} + +pub trait OnAssetChanged { + fn on_move(from: &AccountId, to: &AccountId, token: &Token, value: Balance); + fn on_issue(who: &AccountId, token: &Token, value: Balance); + fn on_destroy(who: &AccountId, token: &Token, value: Balance); + fn on_reserve(_who: &AccountId, _token: &Token, _value: Balance) {} + fn on_unreserve(_who: &AccountId, _token: &Token, _value: Balance) {} + fn on_set_free(_who: &AccountId, _token: &Token, _value: Balance) {} + fn on_set_reserved(_who: &AccountId, _token: &Token, _value: Balance) {} +} + +impl OnAssetChanged for () { + fn on_move(_: &AccountId, _: &AccountId, _: &Token, _: Balance) {} + fn on_issue(_: &AccountId, _: &Token, _: Balance) {} + fn on_destroy(_: &AccountId, _: &Token, _: Balance) {} +} + +#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +pub enum ReservedType { + Others, + Funds, + Staking, + Exchange, +} + +impl ReservedType { + pub fn iterator() -> Iter<'static, ReservedType> { + static TYPES: [ReservedType; 4] = [ + ReservedType::Others, + ReservedType::Funds, + ReservedType::Staking, + ReservedType::Exchange, + ]; + TYPES.into_iter() + } +} + +impl Default for ReservedType { + fn default() -> Self { + ReservedType::Others + } +} + +decl_event!( + pub enum Event where + ::Balance + { + Fee(Balance), + } +); + +decl_module! { + pub struct Module for enum Call where origin: T::Origin { + /// register_asset to module, should allow by root + fn register_asset(asset: Asset, free: T::Balance, reserved: T::Balance) -> Result { + asset.is_valid()?; + Self::add_asset(asset, free, reserved)?; + Ok(()) + } + fn cancel_asset(token: Token) -> Result { + is_valid_token(&token)?; + Self::remove_asset(&token)?; + Ok(()) + } + + /// set free token for an account + fn set_asset_free_balance(who: Address, token: Token, free: T::Balance) -> Result { + let who = balances::Module::::lookup(who)?; + Self::set_free_balance(&who, &token, free)?; + Ok(()) + } + /// set reserved token for an account + fn set_asset_reserved_balance(who: Address, token: Token, reserved: T::Balance, res_type: ReservedType) -> Result { + let who = balances::Module::::lookup(who)?; + Self::set_reserved_balance(&who, &token, reserved, res_type)?; + Ok(()) + } + + /// transfer between account + fn transfer(origin, dest: Address, token: Token, value: T::Balance) -> Result { + runtime_io::print("[tokenbalances] transfer"); + let transactor = ensure_signed(origin)?; + let dest = balances::Module::::lookup(dest)?; + if transactor == dest { + return Err("transactor and dest account are same"); + } + Self::move_free_balance(&transactor, &dest, &token, value).map_err(|e| e.info()) + } + } +} + +decl_storage! { + trait Store for Module as XAssets { +// /// Native asset list len +// pub NativeAssetsLen get(native_assets_len): map u32 => Token; + /// Native asset list + pub NativeAssets get(native_assets): Vec; + /// supported cross chain asset list length + pub CrossChainAssetsLen get(crosschain_assets_len): u32; + /// supported cross chain asset list + pub CrossChainAssets: map u32 => Token; + + /// asset info for every token, key is token token + pub AssetInfo get(asset_info): map Token => Option<(Asset, bool, T::BlockNumber)>; + + /// asset list of a account + pub CrossChainAssetsOf get(crosschain_assets_of): map T::AccountId => Vec; + + /// total free token of a token + pub TotalXFreeBalance get(total_free_balance): map Token => T::Balance; + /// free x-asset free balance for this accout and token + pub XFreeBalance: map (T::AccountId, Token) => T::Balance; + + /// total locked token of a token + pub TotalXReservedBalance get(total_reserved_balance): map Token => T::Balance; + /// reserved x-asset free balance for this accout and token + pub XReservedBalance get(reserved_balance): map (T::AccountId, Token, ReservedType) => T::Balance; + + /// price + pub PCXPriceFor get(pcx_price_for): map Token => Option; + } + add_extra_genesis { + config(token_list): Vec<(Asset, Vec<(T::AccountId, u64)>)>; + config(pcx): (Precision, Desc); + build(|storage: &mut primitives::StorageMap, _: &mut primitives::ChildrenStorageMap, config: &GenesisConfig| { + use runtime_io::with_externalities; + use substrate_primitives::Blake2Hasher; + use primitives::traits::Zero; + let src_r = storage.clone().build_storage().unwrap().0; + let mut tmp_storage: runtime_io::TestExternalities = src_r.into(); + with_externalities(&mut tmp_storage, || { + let chainx: Token = as ChainT>::TOKEN.to_vec(); + let pcx = Asset::new(chainx, Chain::PCX, config.pcx.0, config.pcx.1.clone()).unwrap(); + Module::::add_asset(pcx, Zero::zero(), Zero::zero()).unwrap(); + }); + let map: primitives::StorageMap = tmp_storage.into(); + storage.extend(map); + }); + } +} + +impl ChainT for Module { + const TOKEN: &'static [u8] = b"PCX"; + fn chain() -> Chain { + Chain::PCX + } +} + +impl Module { + // token storage + /// free balance for a account for a token + pub fn free_balance(who_token: &(T::AccountId, Token)) -> T::Balance { + if who_token.1.as_slice() == ::TOKEN { + As::sa(balances::FreeBalance::::get(&who_token.0).as_()) + } else { + >::get(who_token) + } + } + + /// The combined token balance of `who` for token + pub fn total_balance_of(who: &T::AccountId, token: &Token) -> T::Balance { + let mut v = Self::free_balance(&(who.clone(), token.clone())); + for t in ReservedType::iterator() { + v += Self::reserved_balance(&(who.clone(), token.clone(), *t)) + } + v + } + + /// total balance of a token + pub fn total_balance(token: &Token) -> T::Balance { + if token.as_slice() == ::TOKEN { + As::sa(balances::TotalIssuance::::get().as_()) + } else { + Self::total_free_balance(token) + Self::total_reserved_balance(token) + } + } +} + +// asset related +impl Module { + /// add an asset into the storage, notice the asset must be valid + fn add_asset(asset: Asset, free: T::Balance, reserved: T::Balance) -> Result { + let token = asset.token(); + if AssetInfo::::exists(&token) { + return Err("already has this token"); + } + match asset.chain() { + Chain::PCX => { + NativeAssets::::mutate(|v| { + v.push(token.clone()); + }); + } + _ => { + let index = Self::crosschain_assets_len(); + CrossChainAssets::::insert(index, &token); + CrossChainAssetsLen::::put(index + 1); + } + } + + AssetInfo::::insert(&token, (asset, true, system::Module::::block_number())); + Self::init_asset_balance(&token, free, reserved); + Ok(()) + } + fn remove_asset(token: &Token) -> Result { + if let Some(mut info) = AssetInfo::::get(token) { + info.1 = false; + AssetInfo::::insert(token.clone(), info); + Ok(()) + } else { + Err("this token dose not register yet or is invalid") + } + } + + fn init_asset_balance(token: &Token, free: T::Balance, reserved: T::Balance) { + if token.as_slice() == ::TOKEN { + return; + } + + >::insert(token, free); + >::insert(token, reserved); + } + + pub fn is_valid_asset(token: &Token) -> Result { + is_valid_token(token)?; + if let Some(info) = Self::asset_info(token) { + if info.1 == true { + return Ok(()); + } + return Err("not a valid token"); + } + Err("not a registered token") + } + + pub fn is_valid_asset_for(who: &T::AccountId, token: &Token) -> Result { + Self::is_valid_asset(token)?; + // if it's native asset + if let Some((asset, _, _)) = Self::asset_info(token) { + if let Chain::PCX = asset.chain() { + return Ok(()); + } + } + + if Self::crosschain_assets_of(who).contains(token) { + Ok(()) + } else { + Err("not a existed token in this account token list") + } + } + + pub fn assets() -> Vec { + let mut v = Self::native_assets(); + v.extend(Self::crosschain_assets()); + v + } + + pub fn assets_of(who: &T::AccountId) -> Vec { + let mut v = Self::native_assets(); + v.extend(Self::crosschain_assets_of(who)); + v + } + + pub fn crosschain_assets() -> Vec { + let len: u32 = Self::crosschain_assets_len(); + let mut v: Vec = Vec::new(); + for i in 0..len { + let token = CrossChainAssets::::get(i); + v.push(token); + } + v + } + + /// notice don't call this func in runtime + pub fn valid_assets() -> Vec { + Self::assets() + .into_iter() + .filter(|t| { + if let Some(t) = AssetInfo::::get(t) { + t.1 + } else { + false + } + }) + .collect() + } +} + +/// token issue destroy reserve/unreserve +impl Module { + fn init_asset_for(who: &T::AccountId, token: &Token) { + if let Err(_) = Self::is_valid_asset_for(who, token) { + >::mutate(who, |assets| assets.push(token.clone())); + } + } + + pub fn issue(who: &T::AccountId, token: &Token, value: T::Balance) -> Result { + if token.as_slice() == ::TOKEN { + return Err("can't issue chainx token"); + } + Self::is_valid_asset(token)?; + + let key = (who.clone(), token.clone()); + let total_free_token = TotalXFreeBalance::::get(token); + let free_token = XFreeBalance::::get(&key); + // check + let new_free_token = match free_token.checked_add(&value) { + Some(b) => b, + None => return Err("free token too high to issue"), + }; + let new_total_free_token = match total_free_token.checked_add(&value) { + Some(b) => b, + None => return Err("total free token too high to issue"), + }; + // set to storage + Self::init_asset_for(who, token); + + TotalXFreeBalance::::insert(token, new_total_free_token); + XFreeBalance::::insert(&key, new_free_token); + + T::OnAssetChanged::on_issue(who, token, value); + Ok(()) + } + + pub fn destroy( + who: &T::AccountId, + token: &Token, + value: T::Balance, + t: ReservedType, + ) -> Result { + if token.as_slice() == ::TOKEN { + return Err("can't destroy chainx token"); + } + Self::is_valid_asset_for(who, token)?; + + // get storage + let key = (who.clone(), token.clone(), t); + let total_reserved_token = TotalXReservedBalance::::get(token); + let reserved_token = XReservedBalance::::get(&key); + // check + let new_reserved_token = match reserved_token.checked_sub(&value) { + Some(b) => b, + None => return Err("reserved token too low to destroy"), + }; + let new_total_reserved_token = match total_reserved_token.checked_sub(&value) { + Some(b) => b, + None => return Err("total reserved token too low to destroy"), + }; + // set to storage + TotalXReservedBalance::::insert(token, new_total_reserved_token); + XReservedBalance::::insert(&key, new_reserved_token); + + T::OnAssetChanged::on_destroy(who, token, value); + Ok(()) + } + + pub fn reserve( + who: &T::AccountId, + token: &Token, + value: T::Balance, + t: ReservedType, + ) -> Result { + Self::is_valid_asset_for(who, token)?; + + let key = (who.clone(), token.clone()); + let reserved_key = (who.clone(), token.clone(), t); + // for chainx + if token.as_slice() == ::TOKEN { + let free_token: T::Balance = balances::FreeBalance::::get(who); + let reserved_token = XReservedBalance::::get(&reserved_key); + let total_reserved_token = TotalXReservedBalance::::get(token); + match free_token.checked_sub(&value) { + Some(b) => b, + None => return Err("chainx free token too low to reserve"), + }; + let new_reserved_token = match reserved_token.checked_add(&value) { + Some(b) => b, + None => return Err("chainx reserved token too high to reserve"), + }; + let new_total_reserved_token = match total_reserved_token.checked_add(&value) { + Some(b) => b, + None => return Err("chainx total reserved token too high to reserve"), + }; + // do not call reserve in balance + // balances::Module::::reserve(who, value)?; + XReservedBalance::::insert(reserved_key, new_reserved_token); + TotalXReservedBalance::::insert(token, new_total_reserved_token); + } else { + // for other token + // get from storage + let total_free_token = TotalXFreeBalance::::get(token); + let total_reserved_token = TotalXReservedBalance::::get(token); + let free_token = XFreeBalance::::get(&key); + let reserved_token = XReservedBalance::::get(&reserved_key); + // test overflow + let new_free_token = match free_token.checked_sub(&value) { + Some(b) => b, + None => return Err("free token too low to reserve"), + }; + let new_reserved_token = match reserved_token.checked_add(&value) { + Some(b) => b, + None => return Err("reserved token too high to reserve"), + }; + let new_total_free_token = match total_free_token.checked_sub(&value) { + Some(b) => b, + None => return Err("total free token too low to reserve"), + }; + let new_total_reserved_token = match total_reserved_token.checked_add(&value) { + Some(b) => b, + None => return Err("total reserved token too high to reserve"), + }; + // set to storage + TotalXFreeBalance::::insert(token, new_total_free_token); + TotalXReservedBalance::::insert(token, new_total_reserved_token); + XFreeBalance::::insert(&key, new_free_token); + XReservedBalance::::insert(&reserved_key, new_reserved_token); + } + T::OnAssetChanged::on_reserve(who, token, value); + Ok(()) + } + + pub fn unreserve( + who: &T::AccountId, + token: &Token, + value: T::Balance, + t: ReservedType, + ) -> Result { + Self::is_valid_asset_for(who, token)?; + + let key = (who.clone(), token.clone()); + let reserved_key = (who.clone(), token.clone(), t); + // for chainx + if token.as_slice() == ::TOKEN { + let free_token: T::Balance = balances::FreeBalance::::get(who); + let reserved_token = XReservedBalance::::get(&reserved_key); + let total_reserved_token = TotalXReservedBalance::::get(token); + match free_token.checked_add(&value) { + Some(b) => b, + None => return Err("chainx free token too high to unreserve"), + }; + let new_reserved_token = match reserved_token.checked_sub(&value) { + Some(b) => b, + None => return Err("chainx reserved token too low to unreserve"), + }; + let new_total_reserved_token = match total_reserved_token.checked_sub(&value) { + Some(b) => b, + None => return Err("chainx total reserved token too low to unreserve"), + }; + // do not call unreserve in balance + // balances::Module::::unreserve(who, value); + XReservedBalance::::insert(reserved_key, new_reserved_token); + TotalXReservedBalance::::insert(token, new_total_reserved_token); + } else { + // for other token + // get from storage + let total_free_token = TotalXFreeBalance::::get(token); + let total_reserved_token = TotalXReservedBalance::::get(token); + let free_token = XFreeBalance::::get(&key); + let reserved_token = XReservedBalance::::get(&reserved_key); + // test overflow + let new_free_token = match free_token.checked_add(&value) { + Some(b) => b, + None => return Err("free token too high to unreserve"), + }; + let new_reserved_token = match reserved_token.checked_sub(&value) { + Some(b) => b, + None => return Err("reserved token too low to unreserve"), + }; + let new_total_free_token = match total_free_token.checked_add(&value) { + Some(b) => b, + None => return Err("total free token too high to unreserve"), + }; + let new_total_reserved_token = match total_reserved_token.checked_sub(&value) { + Some(b) => b, + None => return Err("total reserved token too low to unreserve"), + }; + // set to storage + TotalXFreeBalance::::insert(token, new_total_free_token); + TotalXReservedBalance::::insert(token, new_total_reserved_token); + XFreeBalance::::insert(&key, new_free_token); + XReservedBalance::::insert(&reserved_key, new_reserved_token); + } + T::OnAssetChanged::on_unreserve(who, token, value); + Ok(()) + } + + pub fn move_free_balance( + from: &T::AccountId, + to: &T::AccountId, + token: &Token, + value: T::Balance, + ) -> StdResult<(), TokenErr> { + Self::is_valid_asset_for(from, token).map_err(|_| TokenErr::InvalidToken)?; + + // for chainx + if token.as_slice() == ::TOKEN { + let from_token: T::Balance = balances::FreeBalance::::get(from); + let to_token: T::Balance = balances::FreeBalance::::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::::insert(from, new_from_token); + balances::FreeBalance::::insert(to, new_to_token); + } else { + Self::init_asset_for(to, token); + let key_from = (from.clone(), token.clone()); + let key_to = (to.clone(), token.clone()); + + let from_token: T::Balance = XFreeBalance::::get(&key_from); + let to_token: T::Balance = XFreeBalance::::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), + }; + + XFreeBalance::::insert(key_from, new_from_token); + XFreeBalance::::insert(key_to, new_to_token); + } + T::OnAssetChanged::on_move(from, to, token, value); + Ok(()) + } + + pub fn set_free_balance(who: &T::AccountId, token: &Token, free: T::Balance) -> Result { + if token.as_slice() == ::TOKEN { + balances::Module::::set_free_balance(&who, free); + } else { + let key = (who.clone(), token.clone()); + let old_free = XFreeBalance::::get(&key); + let old_total_free = TotalXFreeBalance::::get(token); + 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, + }, + } + } 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, + }, + } + }; + TotalXFreeBalance::::insert(token, new_total_free); + XFreeBalance::::insert(key, free); + } + T::OnAssetChanged::on_set_free(who, token, free); + Ok(()) + } + + pub fn set_reserved_balance( + who: &T::AccountId, + token: &Token, + reserved: T::Balance, + res_type: ReservedType, + ) -> Result { + let key = (who.clone(), token.clone(), res_type); + let old_reserved = XReservedBalance::::get(&key); + let old_total_reserved = TotalXReservedBalance::::get(token); + + 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, + }, + } + }; + TotalXReservedBalance::::insert(token, new_total_reserved); + XReservedBalance::::insert(key, reserved); + + T::OnAssetChanged::on_set_reserved(who, token, reserved); + Ok(()) + } +} + +#[derive(PartialEq, Eq, Clone, Copy, 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", + } + } +} + +// wrapper for balances module +impl Module { + pub fn pcx_free_balance(who: &T::AccountId) -> T::Balance { + balances::Module::::free_balance(who) + } + + pub fn pcx_total_balance(who: &T::AccountId) -> T::Balance { + Self::total_balance_of(who, &::TOKEN.to_vec()) + } + + pub fn pcx_set_free_balance(who: &T::AccountId, value: T::Balance) { + balances::Module::::set_free_balance(who, value); + } + + pub fn pcx_reward(who: &T::AccountId, value: T::Balance) -> Result { + balances::Module::::reward(who, value) + } + + pub fn pcx_staking_reserve(who: &T::AccountId, value: T::Balance) -> Result { + Self::reserve( + who, + &::TOKEN.to_vec(), + value, + ReservedType::Staking, + ) + } + + pub fn pcx_staking_unreserve(who: &T::AccountId, value: T::Balance) -> Result { + Self::unreserve( + who, + &::TOKEN.to_vec(), + value, + ReservedType::Staking, + ) + } + + pub fn increase_total_stake_by(value: T::Balance) { + balances::Module::::increase_total_stake_by(value); + } + + pub fn lookup_index(index: T::AccountIndex) -> Option { + balances::Module::::lookup_index(index) + } + + pub fn lookup_address(a: Address) -> Option { + balances::Module::::lookup_address(a) + } +} diff --git a/xrml/xassets/assets/src/mock.rs b/xrml/xassets/assets/src/mock.rs new file mode 100644 index 0000000000000..53281adccffac --- /dev/null +++ b/xrml/xassets/assets/src/mock.rs @@ -0,0 +1,231 @@ +// Copyright 2018 Chainpool. + +use substrate_primitives::{Blake2Hasher, H256}; + +use primitives::testing::{Digest, DigestItem, Header}; +use primitives::traits::BlakeTwo256; +use primitives::BuildStorage; +use runtime_io; + +use super::*; + +impl_outer_origin! { + pub enum Origin for Test {} +} + +#[derive(Clone, Eq, PartialEq)] +pub struct Test; + +impl system::Trait for Test { + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type Digest = Digest; + type AccountId = u64; + type Header = Header; + type Event = (); + type Log = DigestItem; +} + +impl balances::Trait for Test { + type Balance = u64; + type AccountIndex = u64; + type OnFreeBalanceZero = (); + type EnsureAccountLiquid = (); + type Event = (); +} + +impl cxsystem::Trait for Test {} + +impl associations::Trait for Test { + type OnCalcFee = cxsupport::Module; + type Event = (); +} + +impl cxsupport::Trait for Test {} + +// define tokenbalances module type +pub type TokenBalance = u128; + +impl Trait for Test { + const CHAINX_SYMBOL: SymbolString = b"pcx"; + const CHAINX_TOKEN_DESC: DescString = b"this is pcx for mock"; + type TokenBalance = TokenBalance; + type Event = (); + type OnMoveToken = (); +} + +pub type TokenBalances = Module; +pub type Balances = balances::Module; + +// This function basically just builds a genesis storage key/value store according to +// our desired mockup. +pub fn new_test_ext() -> runtime_io::TestExternalities { + let mut r = system::GenesisConfig::::default() + .build_storage() + .unwrap(); + // balance +<<<<<<< HEAD + r.extend(balances::GenesisConfig:: { + balances: vec![(1, 1000), (2, 510), (3, 1000)], + transaction_base_fee: 0, + transaction_byte_fee: 0, + existential_deposit: 500, + transfer_fee: 0, + creation_fee: 0, + reclaim_rebate: 0, + }.build_storage().unwrap()); +======= + r.extend( + balances::GenesisConfig:: { + balances: vec![(1, 1000), (2, 510), (3, 1000)], + transaction_base_fee: 0, + transaction_byte_fee: 0, + existential_deposit: 500, + transfer_fee: 0, + creation_fee: 0, + reclaim_rebate: 0, + } + .build_storage() + .unwrap(), + ); +>>>>>>> develop + // 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); + +<<<<<<< HEAD + r.extend(GenesisConfig:: { + token_list: vec![ + (t, [(3, 100)].to_vec()), + (t2, [(3, 100)].to_vec()), + ], + transfer_token_fee: 10, + }.build_storage().unwrap()); +======= + r.extend( + GenesisConfig:: { + chainx_precision: 8, + token_list: vec![(t, [(3, 100)].to_vec()), (t2, [(3, 100)].to_vec())], + transfer_token_fee: 10, + } + .build_storage() + .unwrap(), + ); +>>>>>>> develop + r.into() +} + +pub fn err_test_ext() -> runtime_io::TestExternalities { + let mut r = system::GenesisConfig::::default() + .build_storage() + .unwrap(); + // balance +<<<<<<< HEAD + r.extend(balances::GenesisConfig:: { + balances: vec![(1, 1000), (2, 510), (3, 1000)], + transaction_base_fee: 0, + transaction_byte_fee: 0, + existential_deposit: 500, + transfer_fee: 0, + creation_fee: 0, + reclaim_rebate: 0, + }.build_storage().unwrap()); +======= + r.extend( + balances::GenesisConfig:: { + balances: vec![(1, 1000), (2, 510), (3, 1000)], + transaction_base_fee: 0, + transaction_byte_fee: 0, + existential_deposit: 500, + transfer_fee: 0, + creation_fee: 0, + reclaim_rebate: 0, + } + .build_storage() + .unwrap(), + ); +>>>>>>> develop + // 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); + +<<<<<<< HEAD + r.extend(GenesisConfig:: { + token_list: vec![ + (t, [(3, 100)].to_vec()), + (t2, [(3, 100)].to_vec()), + ], + transfer_token_fee: 10, + }.build_storage().unwrap()); +======= + r.extend( + GenesisConfig:: { + chainx_precision: 8, + token_list: vec![(t, [(3, 100)].to_vec()), (t2, [(3, 100)].to_vec())], + transfer_token_fee: 10, + } + .build_storage() + .unwrap(), + ); +>>>>>>> develop + r.into() +} + +pub fn new_test_ext2() -> runtime_io::TestExternalities { + let mut r = system::GenesisConfig::::default() + .build_storage() + .unwrap(); + // balance +<<<<<<< HEAD + r.extend(balances::GenesisConfig:: { + balances: vec![(1, 1000), (2, 510), (3, 1000)], + transaction_base_fee: 0, + transaction_byte_fee: 0, + existential_deposit: 0, + transfer_fee: 0, + creation_fee: 0, + reclaim_rebate: 0, + }.build_storage().unwrap()); +======= + r.extend( + balances::GenesisConfig:: { + balances: vec![(1, 1000), (2, 510), (3, 1000)], + transaction_base_fee: 0, + transaction_byte_fee: 0, + existential_deposit: 0, + transfer_fee: 0, + creation_fee: 0, + reclaim_rebate: 0, + } + .build_storage() + .unwrap(), + ); +>>>>>>> develop + // 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); + +<<<<<<< HEAD + r.extend(GenesisConfig:: { + token_list: vec![ + (t, [(3, 100)].to_vec()), + (t2, [(3, 100)].to_vec()), + ], + transfer_token_fee: 10, + }.build_storage().unwrap()); +======= + r.extend( + GenesisConfig:: { + chainx_precision: 8, + token_list: vec![(t, [(3, 100)].to_vec()), (t2, [(3, 100)].to_vec())], + transfer_token_fee: 10, + } + .build_storage() + .unwrap(), + ); +>>>>>>> develop + r.into() +} diff --git a/xrml/xassets/assets/src/tests.rs b/xrml/xassets/assets/src/tests.rs new file mode 100644 index 0000000000000..7f738e30ac9e1 --- /dev/null +++ b/xrml/xassets/assets/src/tests.rs @@ -0,0 +1,729 @@ +// Copyright 2018 Chainpool. + +use super::*; +use mock::*; +use runtime_io::with_externalities; + +#[test] +fn test_genesis() { + with_externalities(&mut new_test_ext(), || { + // Check that GenesisBuilder works properly. + // check token_list + let btc_symbol = b"x-btc".to_vec(); + let eth_symbol = b"x-eth".to_vec(); + + assert_eq!( + TokenBalances::token_list(), + vec![ + Test::CHAINX_SYMBOL.to_vec(), + btc_symbol.clone(), + eth_symbol.clone(), + ] + ); + + assert_eq!( + TokenBalances::token_info(btc_symbol.clone()) + .unwrap() + .0 + .precision(), + 8 + ); + assert_eq!( + TokenBalances::token_info(eth_symbol.clone()) + .unwrap() + .0 + .precision(), + 4 + ); + + assert_eq!(TokenBalances::total_free_token(btc_symbol.clone()), 100); + assert_eq!(TokenBalances::total_reserved_token(btc_symbol.clone()), 0); + + // chainx symbol for every user + assert_eq!( + TokenBalances::token_list_of(&0), + [Test::CHAINX_SYMBOL.to_vec()].to_vec() + ); + }); +} + +#[test] +fn test_genesis_token_issue() { + with_externalities(&mut new_test_ext(), || { + let btc_symbol = b"x-btc".to_vec(); + let eth_symbol = b"x-eth".to_vec(); +<<<<<<< HEAD + assert_eq!(TokenBalances::free_token(&(3, Test::CHAINX_SYMBOL.to_vec())), 1000); + assert_eq!(TokenBalances::free_token(&(3, btc_symbol.clone())), 100); + assert_eq!(TokenBalances::free_token(&(3, eth_symbol.clone())), 100); + + assert_eq!(TokenBalances::token_list_of(&3), [Test::CHAINX_SYMBOL.to_vec(), btc_symbol, eth_symbol]); +======= + assert_eq!( + TokenBalances::free_token(&(3, Test::CHAINX_SYMBOL.to_vec())), + 1000 + ); + assert_eq!(TokenBalances::free_token(&(3, btc_symbol.clone())), 100); + assert_eq!(TokenBalances::free_token(&(3, eth_symbol.clone())), 100); + + assert_eq!( + TokenBalances::token_list_of(&3), + [Test::CHAINX_SYMBOL.to_vec(), btc_symbol, eth_symbol] + ); +>>>>>>> develop + }) +} + +#[test] +#[should_panic] +fn test_err_genesis() { + with_externalities(&mut err_test_ext(), || {}) +} + +#[test] +fn test_register() { + with_externalities(&mut new_test_ext(), || { + let t_sym: Symbol = b"x-eos".to_vec(); //slice_to_u8_8(b"x-eos"); + let t_desc: TokenDesc = b"eos token".to_vec(); //slice_to_u8_32(b"eos token"); + let precision = 4; + let t: Token = Token::new(t_sym.clone(), t_desc, precision); + assert_eq!(TokenBalances::register_token(t, 0, 0), Ok(())); + + assert_eq!(TokenBalances::token_list_len(), 4); + assert_eq!(TokenBalances::token_list_map(3), t_sym.clone()); + + let btc_symbol = b"x-btc".to_vec(); //b"x-btc".to_vec(); + let eth_symbol = b"x-eth".to_vec(); //slice_to_u8_8(b"x-eth"); + assert_eq!( + TokenBalances::token_list(), + vec![ + Test::CHAINX_SYMBOL.to_vec(), + btc_symbol.clone(), + eth_symbol.clone(), + t_sym.clone(), + ] + ); + + assert_eq!(TokenBalances::total_free_token(t_sym.clone()), 0); + assert_eq!( + TokenBalances::token_info(t_sym.clone()) + .unwrap() + .0 + .precision(), + 4 + ); + + // test err branch + let btc_t = Token::new(btc_symbol.clone(), b"btc token".to_vec(), 4); + assert_noop!( + TokenBalances::register_token(btc_t, 0, 0), + "already has this token symbol" + ); + assert_eq!(TokenBalances::token_list_len(), 4); + assert_eq!(TokenBalances::token_list_map(4), b"".to_vec()); + }) +} + +#[test] +fn test_remove() { + with_externalities(&mut new_test_ext(), || { + // register a new token + let t_sym: Symbol = b"x-eos".to_vec(); + let t_desc: TokenDesc = b"eos token".to_vec(); + let precision: Precision = 4; + let t: Token = Token::new(t_sym.clone(), t_desc, precision); + assert_eq!(TokenBalances::register_token(t.clone(), 0, 0), Ok(())); + assert_eq!(TokenBalances::token_list_map(3), t_sym.clone()); + + // remove it + assert_eq!(TokenBalances::cancel_token(&t_sym.clone()), Ok(())); + assert_eq!(TokenBalances::token_list_map(3), t_sym.clone()); + assert_eq!(TokenBalances::token_list_len(), 4); // length not modify + + // re-register, but must be failed + assert_noop!( + TokenBalances::register_token(t.clone(), 0, 0), + "already has this token symbol" + ); + + // create new token symbol + let t_new: Token = Token { + symbol: b"x-eos2".to_vec(), + ..t + }; + assert_noop!( + TokenBalances::cancel_token(&t_new.symbol), + "this token symbol dose not register yet or is invalid" + ); + assert_eq!(TokenBalances::register_token(t_new.clone(), 0, 0), Ok(())); + assert_eq!(TokenBalances::token_list_map(3), t_sym.clone()); + assert_eq!(TokenBalances::token_list_map(4), t_new.symbol); + assert_eq!(TokenBalances::token_list_len(), 5); + }) +} + +#[test] +fn test_total_balance() { + with_externalities(&mut new_test_ext(), || { + let btc_symbol = b"x-btc".to_vec(); + assert_eq!(TokenBalances::total_token(&btc_symbol.clone()), 100); + + TokenBalances::issue(&0, &btc_symbol, 100).unwrap(); + assert_eq!(TokenBalances::total_token(&btc_symbol.clone()), 200); + + TokenBalances::issue(&0, &btc_symbol, 50).unwrap(); + TokenBalances::reserve(&0, &btc_symbol, 50, Default::default()).unwrap(); + assert_eq!(TokenBalances::total_token(&btc_symbol.clone()), 250); + + TokenBalances::destroy(&0, &btc_symbol, 25, Default::default()).unwrap(); + assert_eq!(TokenBalances::total_token(&btc_symbol.clone()), 225); + }) +} + +#[test] +fn test_account_balance() { + with_externalities(&mut new_test_ext(), || { + let a: u64 = 1; // accountid + let btc_symbol = b"x-btc".to_vec(); + let key = (a, btc_symbol.clone()); + let reserved_key = (a, btc_symbol.clone(), Default::default()); + assert_eq!(TokenBalances::free_token(&key), 0); + assert_eq!(TokenBalances::reserved_token(&reserved_key), 0); + assert_eq!(TokenBalances::total_token_of(&a, &btc_symbol), 0); + + TokenBalances::issue(&a, &btc_symbol, 100).unwrap(); + assert_eq!(TokenBalances::free_token(&key), 100); + assert_eq!(TokenBalances::reserved_token(&reserved_key), 0); + assert_eq!(TokenBalances::total_token_of(&a, &btc_symbol.clone()), 100); + + TokenBalances::reserve(&a, &btc_symbol, 50, Default::default()).unwrap(); + TokenBalances::destroy(&a, &btc_symbol, 50, Default::default()).unwrap(); + assert_eq!(TokenBalances::total_token_of(&a, &btc_symbol.clone()), 50); + }) +} + +#[test] +fn test_normal_issue_and_destroy() { + with_externalities(&mut new_test_ext(), || { + let a: u64 = 1; // accountid + let btc_symbol = b"x-btc".to_vec(); + let key = (a, btc_symbol.clone()); + let reserved_key = (a, btc_symbol.clone(), Default::default()); + + // issue + TokenBalances::issue(&a, &btc_symbol.clone(), 50).unwrap(); + assert_eq!(TokenBalances::total_token_of(&a, &btc_symbol.clone()), 50); + assert_eq!(TokenBalances::total_token(&btc_symbol.clone()), 150); + + // reserve + TokenBalances::reserve(&a, &btc_symbol.clone(), 25, Default::default()).unwrap(); + assert_eq!(TokenBalances::reserved_token(&reserved_key), 25); + assert_eq!(TokenBalances::free_token(&key), 25); + assert_eq!(TokenBalances::total_token_of(&a, &btc_symbol.clone()), 50); + assert_eq!(TokenBalances::total_reserved_token(&btc_symbol.clone()), 25); + + // destroy + TokenBalances::destroy(&a, &btc_symbol.clone(), 25, Default::default()).unwrap(); + assert_eq!(TokenBalances::reserved_token(&reserved_key), 0); + assert_eq!(TokenBalances::free_token(&key), 25); + assert_eq!(TokenBalances::total_token_of(&a, &btc_symbol.clone()), 25); + assert_eq!(TokenBalances::total_reserved_token(&btc_symbol.clone()), 0); + assert_eq!(TokenBalances::total_token(&btc_symbol.clone()), 125); + }) +} + +#[test] +fn test_unlock_issue_and_destroy2() { + with_externalities(&mut new_test_ext(), || { + let a: u64 = 1; // accountid + let btc_symbol = b"x-btc".to_vec(); + let key = (a, btc_symbol.clone()); + let reserved_key = (a, btc_symbol.clone(), Default::default()); + + // issue + TokenBalances::issue(&a, &btc_symbol.clone(), 50).unwrap(); + assert_eq!(TokenBalances::total_token_of(&a, &btc_symbol.clone()), 50); + assert_eq!(TokenBalances::total_token(&btc_symbol.clone()), 150); + + // reserve + TokenBalances::reserve(&a, &btc_symbol.clone(), 25, Default::default()).unwrap(); + assert_eq!(TokenBalances::reserved_token(&reserved_key), 25); + assert_eq!(TokenBalances::free_token(&key), 25); + assert_eq!(TokenBalances::total_token_of(&a, &btc_symbol.clone()), 50); + assert_eq!(TokenBalances::total_reserved_token(&btc_symbol.clone()), 25); + + // unreserve + TokenBalances::unreserve(&a, &btc_symbol.clone(), 10, Default::default()).unwrap(); + assert_eq!(TokenBalances::reserved_token(&reserved_key), 15); + assert_eq!(TokenBalances::free_token(&key), 35); + assert_eq!(TokenBalances::total_token_of(&a, &btc_symbol.clone()), 50); + assert_eq!(TokenBalances::total_reserved_token(&btc_symbol.clone()), 15); + }) +} + +#[test] +fn test_error_issue_and_destroy1() { + with_externalities(&mut new_test_ext(), || { + let a: u64 = 1; // accountid + let btc_symbol = b"x-btc".to_vec(); + // issue + TokenBalances::issue(&a, &btc_symbol.clone(), 50).unwrap(); + assert_eq!(TokenBalances::total_token_of(&a, &btc_symbol.clone()), 50); + assert_eq!(TokenBalances::total_token(&btc_symbol.clone()), 150); + // destroy first + // destroy +<<<<<<< HEAD + assert_err!(TokenBalances::destroy(&a, &btc_symbol.clone(), 25, Default::default()), "reserved token too low to destroy"); + // reserve + assert_eq!(TokenBalances::total_free_token(&btc_symbol.clone()), 150); + assert_err!(TokenBalances::reserve(&a, &btc_symbol.clone(), 100, Default::default()), "free token too low to reserve"); + // lock first + assert_ok!(TokenBalances::reserve(&a, &btc_symbol.clone(), 25, Default::default())); + // destroy + assert_ok!(TokenBalances::destroy(&a, &btc_symbol.clone(), 25, Default::default())); +======= + assert_err!( + TokenBalances::destroy(&a, &btc_symbol.clone(), 25, Default::default()), + "reserved token too low to destroy" + ); + // reserve + assert_eq!(TokenBalances::total_free_token(&btc_symbol.clone()), 150); + assert_err!( + TokenBalances::reserve(&a, &btc_symbol.clone(), 100, Default::default()), + "free token too low to reserve" + ); + // lock first + assert_ok!(TokenBalances::reserve( + &a, + &btc_symbol.clone(), + 25, + Default::default() + )); + // destroy + assert_ok!(TokenBalances::destroy( + &a, + &btc_symbol.clone(), + 25, + Default::default() + )); +>>>>>>> develop + }) +} + +#[test] +fn test_error_issue_and_destroy2() { + with_externalities(&mut new_test_ext(), || { + let a: u64 = 1; // accountid + let btc_symbol = b"x-btc".to_vec(); + // issue + TokenBalances::issue(&a, &btc_symbol.clone(), 50).unwrap(); + assert_eq!(TokenBalances::total_token_of(&a, &btc_symbol), 50); + assert_eq!(TokenBalances::total_token(&btc_symbol.clone()), 150); + // overflow + let i: i32 = -1; +<<<<<<< HEAD + assert_err!(TokenBalances::reserve(&a, &btc_symbol.clone(), i as TokenBalance, Default::default()), "free token too low to reserve"); + assert_err!(TokenBalances::issue(&a, &btc_symbol.clone(), i as TokenBalance), "free token too high to issue"); +======= + assert_err!( + TokenBalances::reserve( + &a, + &btc_symbol.clone(), + i as TokenBalance, + Default::default() + ), + "free token too low to reserve" + ); + assert_err!( + TokenBalances::issue(&a, &btc_symbol.clone(), i as TokenBalance), + "free token too high to issue" + ); +>>>>>>> develop + }) +} + +#[test] +fn test_error_issue_and_destroy3() { + with_externalities(&mut new_test_ext(), || { + let a: u64 = 1; // accountid + let btc_symbol = b"x-btc".to_vec(); + // lock or destroy without init +<<<<<<< HEAD + assert_err!(TokenBalances::destroy(&a, &btc_symbol.clone(), 25, Default::default()), "not a existed token in this account token list"); + assert_err!(TokenBalances::reserve(&a, &btc_symbol.clone(), 25, Default::default()), "not a existed token in this account token list"); + TokenBalances::issue(&a, &btc_symbol.clone(), 0).unwrap(); + assert_err!(TokenBalances::destroy(&a, &btc_symbol.clone(), 25, Default::default()), "reserved token too low to destroy"); + assert_err!(TokenBalances::reserve(&a, &btc_symbol.clone(), 25, Default::default()), "free token too low to reserve"); + + TokenBalances::issue(&a, &btc_symbol.clone(), 100).unwrap(); + assert_ok!(TokenBalances::reserve(&a, &btc_symbol.clone(), 25, Default::default())); + assert_ok!(TokenBalances::destroy(&a, &btc_symbol.clone(), 25, Default::default())); +======= + assert_err!( + TokenBalances::destroy(&a, &btc_symbol.clone(), 25, Default::default()), + "not a existed token in this account token list" + ); + assert_err!( + TokenBalances::reserve(&a, &btc_symbol.clone(), 25, Default::default()), + "not a existed token in this account token list" + ); + TokenBalances::issue(&a, &btc_symbol.clone(), 0).unwrap(); + assert_err!( + TokenBalances::destroy(&a, &btc_symbol.clone(), 25, Default::default()), + "reserved token too low to destroy" + ); + assert_err!( + TokenBalances::reserve(&a, &btc_symbol.clone(), 25, Default::default()), + "free token too low to reserve" + ); + + TokenBalances::issue(&a, &btc_symbol.clone(), 100).unwrap(); + assert_ok!(TokenBalances::reserve( + &a, + &btc_symbol.clone(), + 25, + Default::default() + )); + assert_ok!(TokenBalances::destroy( + &a, + &btc_symbol.clone(), + 25, + Default::default() + )); +>>>>>>> develop + }) +} + +#[test] +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_ok!(TokenBalances::transfer( + Some(a).into(), + new_id.into(), + btc_symbol.clone(), + 25 + )); + assert_eq!(Balances::lookup_index(3), Some(new_id)); + assert_err!( + associations::Module::::init_account(Some(a).into(), new_id.into(),), + "this account is existing" + ); + 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 - 10 - 25 - 10 + ); + assert_eq!( + TokenBalances::free_token(&(new_id, Test::CHAINX_SYMBOL.to_vec())), + 25 + ); + }) +} + +#[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 + let btc_symbol = b"x-btc".to_vec(); + // issue 50 to account 1 + TokenBalances::issue(&a, &btc_symbol.clone(), 50).unwrap(); + // transfer + 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); + assert_eq!(TokenBalances::free_token(&(b, btc_symbol.clone())), 25); + assert_eq!(Balances::free_balance(&a), 990); + + assert_err!( + TokenBalances::transfer(Some(a).into(), b.into(), btc_symbol.clone(), 50), + "free token too low to send value" + ) + }) +} + +#[test] +fn test_transfer_to_self() { + with_externalities(&mut new_test_ext(), || { + let a: u64 = 1; // accountid + let btc_symbol = b"x-btc".to_vec(); + // issue 50 to account 1 + TokenBalances::issue(&a, &btc_symbol.clone(), 50).unwrap(); + // transfer + 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); + assert_eq!(Balances::free_balance(&a), 990); + }) +} + +#[test] +fn test_transfer_err() { + with_externalities(&mut new_test_ext(), || { + let a: u64 = 1; // accountid + let b: u64 = 2; // accountid + let btc_symbol = b"x-btc".to_vec(); + // issue 50 to account 2 + TokenBalances::issue(&b, &btc_symbol.clone(), 50).unwrap(); + // transfer + 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); + assert_eq!(TokenBalances::total_token_of(&a, &btc_symbol.clone()), 25); + assert_eq!(Balances::free_balance(&b), 500); + + assert_err!( + 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(), || { + let to: balances::Address = balances::address::Address::Id(2); + let origin = system::RawOrigin::Signed(1).into(); + let sym = b"".to_vec(); + assert_err!( + 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(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(origin, to.clone(), sym, 10), + "not a valid symbol char for number, capital/small letter or '-', '.', '|', '~'" + ); + + let t: Token = Token::new(b"x-btc2".to_vec(), b"btc token fdsfsdfasfasdfasdfasdfasdfasdfasdfjaskldfjalskdjflk;asjdfklasjkldfjalksdjfklasjflkdasjflkjkladsjfkrtewtewrtwertrjhjwretywertwertwerrtwerrtwerrtwertwelasjdfklsajdflkaj".to_vec(), 8); + assert_err!( + TokenBalances::register_token(t, 0, 0), + "token desc length too long" + ); + let t: Token = Token::new(b"x-btc?".to_vec(), b"btc token".to_vec(), 8); + assert_err!( + TokenBalances::register_token(t, 0, 0), + "not a valid symbol char for number, capital/small letter or '-', '.', '|', '~'" + ) + }) +} + +#[test] +fn test_chainx() { + with_externalities(&mut new_test_ext2(), || { + let a: u64 = 1; // accountid + let sym = Test::CHAINX_SYMBOL.to_vec(); + assert_err!( + TokenBalances::issue(&a, &sym, 100), + "can't issue chainx token" + ); + + assert_ok!(TokenBalances::reserve(&a, &sym, 100, Default::default())); + assert_eq!(Balances::free_balance(&a), 900); + assert_eq!(Balances::reserved_balance(&a), 100); +<<<<<<< HEAD + assert_eq!(TokenBalances::reserved_token(&(a, sym.clone(), Default::default())), 100); + + assert_ok!(TokenBalances::unreserve(&a, &sym, 50, Default::default())); + assert_eq!(Balances::free_balance(&a), 950); + assert_eq!(TokenBalances::reserved_token(&(a, sym.clone(), Default::default())), 50); + assert_eq!(Balances::reserved_balance(&a), 50); + assert_err!(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"); +======= + assert_eq!( + TokenBalances::reserved_token(&(a, sym.clone(), Default::default())), + 100 + ); + + assert_ok!(TokenBalances::unreserve(&a, &sym, 50, Default::default())); + assert_eq!(Balances::free_balance(&a), 950); + assert_eq!( + TokenBalances::reserved_token(&(a, sym.clone(), Default::default())), + 50 + ); + assert_eq!(Balances::reserved_balance(&a), 50); + assert_err!( + TokenBalances::destroy(&a, &sym, 50, Default::default()), + "can't destroy chainx token" + ); +>>>>>>> develop + }) +} + +#[test] +fn test_chainx_err() { + with_externalities(&mut new_test_ext2(), || { + let a: u64 = 1; // accountid + let sym = Test::CHAINX_SYMBOL.to_vec(); + +<<<<<<< HEAD + assert_err!(TokenBalances::reserve(&a, &sym, 2000, Default::default()), "chainx free token too low to reserve"); + assert_err!(TokenBalances::unreserve(&a, &sym, 10, Default::default()), "chainx reserved token too low to unreserve"); +======= + assert_err!( + TokenBalances::reserve(&a, &sym, 2000, Default::default()), + "chainx free token too low to reserve" + ); + assert_err!( + TokenBalances::unreserve(&a, &sym, 10, Default::default()), + "chainx reserved token too low to unreserve" + ); +>>>>>>> develop + + let i: i32 = -1; + let larger_balance: TokenBalance = (i as u64) as u128 + 2; + + assert_eq!(larger_balance, 18446744073709551617); + assert_eq!(larger_balance as u64, 1); + +<<<<<<< HEAD + assert_ok!(TokenBalances::reserve(&a, &sym, larger_balance, Default::default())); +======= + assert_ok!(TokenBalances::reserve( + &a, + &sym, + larger_balance, + Default::default() + )); +>>>>>>> develop + assert_eq!(Balances::free_balance(&a), 999); + + let i: i32 = -1; + let max_balance: TokenBalance = i as u128; + assert_eq!(max_balance as u64, 18446744073709551615); +<<<<<<< HEAD + assert_err!(TokenBalances::reserve(&a, &sym, max_balance, Default::default()), "chainx free token too low to reserve"); +======= + assert_err!( + TokenBalances::reserve(&a, &sym, max_balance, Default::default()), + "chainx free token too low to reserve" + ); +>>>>>>> develop + }) +} + +#[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); + }) +} diff --git a/xrml/xfee/manager/src/lib.rs b/xrml/xfee/manager/src/lib.rs index 15a21e13a1532..57a08c78aee26 100644 --- a/xrml/xfee/manager/src/lib.rs +++ b/xrml/xfee/manager/src/lib.rs @@ -22,24 +22,21 @@ pub trait MakePayment { } pub trait Trait: balances::Trait { - /// The overarching event type. - type Event: From> + Into<::Event>; + // /// The overarching event type. + // type Event: From> + Into<::Event>; } decl_module! { pub struct Module for enum Call where origin: T::Origin { - fn deposit_event() = default; +// fn deposit_event() = default; } } -decl_event!( - pub enum Event - where - B = ::Balance - { - Fee(B), - } -); +//decl_event!( +// pub enum Event where B = ::Balance { +// Fee(B), +// } +//); decl_storage! { trait Store for Module as XFeeManager { diff --git a/xrml/xsupport/Cargo.toml b/xrml/xsupport/Cargo.toml index 0a03cf827a214..ac8824b31be43 100644 --- a/xrml/xsupport/Cargo.toml +++ b/xrml/xsupport/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xrml-xsupport" -version = "0.3.0" +version = "0.4.0" authors = ["Chainpool "] [dependencies]