Decouple contract from balances (#2081)

* decouple contract from balance

* update impls and builds

* set fees in contract module

* builds
This commit is contained in:
thiolliere
2019-03-28 13:46:30 +01:00
committed by Gav Wood
parent ff4523cbec
commit 29001cb469
13 changed files with 91 additions and 67 deletions
+8
View File
@@ -150,6 +150,10 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
burn: Permill::from_percent(50),
}),
contract: Some(ContractConfig {
transaction_base_fee: 1 * CENTS,
transaction_byte_fee: 10 * MILLICENTS,
transfer_fee: 1 * CENTS,
creation_fee: 1 * CENTS,
contract_fee: 1 * CENTS,
call_base_fee: 1000,
create_base_fee: 1000,
@@ -303,6 +307,10 @@ pub fn testnet_genesis(
burn: Permill::from_percent(50),
}),
contract: Some(ContractConfig {
transaction_base_fee: 1,
transaction_byte_fee: 0,
transfer_fee: 0,
creation_fee: 0,
contract_fee: 21,
call_base_fee: 135,
create_base_fee: 175,
+2 -1
View File
@@ -59,7 +59,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
impl_name: create_runtime_str!("substrate-node"),
authoring_version: 10,
spec_version: 46,
impl_version: 46,
impl_version: 47,
apis: RUNTIME_API_VERSIONS,
};
@@ -167,6 +167,7 @@ impl treasury::Trait for Runtime {
}
impl contract::Trait for Runtime {
type Currency = balances::Module<Runtime>;
type Call = Call;
type Event = Event;
type Gas = u64;
-1
View File
@@ -2204,7 +2204,6 @@ dependencies = [
"sr-primitives 0.1.0",
"sr-sandbox 0.1.0",
"sr-std 0.1.0",
"srml-balances 0.1.0",
"srml-support 0.1.0",
"srml-system 0.1.0",
"srml-timestamp 0.1.0",
+1 -2
View File
@@ -17,7 +17,6 @@ rstd = { package = "sr-std", path = "../../core/sr-std", default-features = fals
sandbox = { package = "sr-sandbox", path = "../../core/sr-sandbox", default-features = false }
srml-support = { path = "../support", default-features = false }
system = { package = "srml-system", path = "../system", default-features = false }
balances = { package = "srml-balances", path = "../balances", default-features = false }
timestamp = { package = "srml-timestamp", path = "../timestamp", default-features = false }
[dev-dependencies]
@@ -25,6 +24,7 @@ wabt = "~0.7.4"
assert_matches = "1.1"
hex-literal = "0.1.0"
consensus = { package = "srml-consensus", path = "../consensus" }
balances = { package = "srml-balances", path = "../balances" }
[features]
default = ["std"]
@@ -36,7 +36,6 @@ std = [
"runtime-primitives/std",
"runtime-io/std",
"rstd/std",
"balances/std",
"sandbox/std",
"srml-support/std",
"system/std",
+9 -9
View File
@@ -16,8 +16,8 @@
//! Auxilliaries to help with managing partial changes to accounts state.
use super::{CodeHash, CodeHashOf, Trait, AccountInfo, TrieId, AccountInfoOf};
use {balances, system};
use super::{CodeHash, CodeHashOf, Trait, AccountInfo, TrieId, AccountInfoOf, BalanceOf};
use system;
use rstd::cell::RefCell;
use rstd::rc::Rc;
use rstd::collections::btree_map::{BTreeMap, Entry};
@@ -27,7 +27,7 @@ use srml_support::{StorageMap, traits::{UpdateBalanceOutcome,
SignedImbalance, Currency, Imbalance}, storage::child};
pub struct ChangeEntry<T: Trait> {
balance: Option<T::Balance>,
balance: Option<BalanceOf<T>>,
/// In the case the outer option is None, the code_hash remains untouched, while providing `Some(None)` signifies a removing of the code in question
code: Option<Option<CodeHash<T>>>,
storage: BTreeMap<Vec<u8>, Option<Vec<u8>>>,
@@ -91,7 +91,7 @@ pub trait AccountDb<T: Trait> {
fn get_or_create_trieid(&self, account: &T::AccountId) -> TrieId;
fn get_storage(&self, trie_id: &TrieId, location: &[u8]) -> Option<Vec<u8>>;
fn get_code(&self, account: &T::AccountId) -> Option<CodeHash<T>>;
fn get_balance(&self, account: &T::AccountId) -> T::Balance;
fn get_balance(&self, account: &T::AccountId) -> BalanceOf<T>;
fn commit(&mut self, change_set: ChangeSet<T>);
}
@@ -114,15 +114,15 @@ impl<T: Trait> AccountDb<T> for DirectAccountDb {
fn get_code(&self, account: &T::AccountId) -> Option<CodeHash<T>> {
<CodeHashOf<T>>::get(account)
}
fn get_balance(&self, account: &T::AccountId) -> T::Balance {
balances::Module::<T>::free_balance(account)
fn get_balance(&self, account: &T::AccountId) -> BalanceOf<T> {
T::Currency::free_balance(account)
}
fn commit(&mut self, s: ChangeSet<T>) {
let mut total_imbalance = SignedImbalance::zero();
for (address, changed) in s.into_iter() {
let trieid = <Self as AccountDb<T>>::get_or_create_trieid(&self, &address);
if let Some(balance) = changed.balance {
let (imbalance, outcome) = balances::Module::<T>::make_free_balance_be(&address, balance);
let (imbalance, outcome) = T::Currency::make_free_balance_be(&address, balance);
total_imbalance = total_imbalance.merge(imbalance);
if let UpdateBalanceOutcome::AccountKilled = outcome {
// Account killed. This will ultimately lead to calling `OnFreeBalanceZero` callback
@@ -206,7 +206,7 @@ impl<'a, T: Trait> OverlayAccountDb<'a, T> {
.or_insert(Default::default())
.code = Some(code);
}
pub fn set_balance(&mut self, account: &T::AccountId, balance: T::Balance) {
pub fn set_balance(&mut self, account: &T::AccountId, balance: BalanceOf<T>) {
self.local
.borrow_mut()
.entry(account.clone())
@@ -257,7 +257,7 @@ impl<'a, T: Trait> AccountDb<T> for OverlayAccountDb<'a, T> {
.and_then(|a| a.code.clone())
.unwrap_or_else(|| self.underlying.get_code(account))
}
fn get_balance(&self, account: &T::AccountId) -> T::Balance {
fn get_balance(&self, account: &T::AccountId) -> BalanceOf<T> {
self.local
.borrow()
.get(account)
+13 -14
View File
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use super::{CodeHash, Config, ContractAddressFor, Event, RawEvent, Trait, TrieId};
use super::{CodeHash, Config, ContractAddressFor, Event, RawEvent, Trait, TrieId, BalanceOf};
use crate::account_db::{AccountDb, DirectAccountDb, OverlayAccountDb, AccountTrieIdMapping};
use crate::gas::{GasMeter, Token, approx_gas_for_balance};
@@ -25,7 +25,6 @@ use runtime_primitives::traits::{CheckedAdd, CheckedSub, Zero};
use srml_support::traits::{WithdrawReason, Currency};
use timestamp;
pub type BalanceOf<T> = <T as balances::Trait>::Balance;
pub type AccountIdOf<T> = <T as system::Trait>::AccountId;
pub type CallOf<T> = <T as Trait>::Call;
pub type MomentOf<T> = <T as timestamp::Trait>::Moment;
@@ -281,7 +280,7 @@ where
pub fn call(
&mut self,
dest: T::AccountId,
value: T::Balance,
value: BalanceOf<T>,
gas_meter: &mut GasMeter<T>,
input_data: &[u8],
empty_output_buf: EmptyOutputBuf,
@@ -306,7 +305,7 @@ where
dest.clone()
);
if value > T::Balance::zero() {
if value > BalanceOf::<T>::zero() {
transfer(
gas_meter,
TransferCause::Call,
@@ -349,7 +348,7 @@ where
pub fn instantiate(
&mut self,
endowment: T::Balance,
endowment: BalanceOf<T>,
gas_meter: &mut GasMeter<T>,
code_hash: &CodeHash<T>,
input_data: &[u8],
@@ -439,7 +438,7 @@ pub struct TransferFeeToken<Balance> {
gas_price: Balance,
}
impl<T: Trait> Token<T> for TransferFeeToken<T::Balance> {
impl<T: Trait> Token<T> for TransferFeeToken<BalanceOf<T>> {
type Metadata = Config<T>;
#[inline]
@@ -468,7 +467,7 @@ enum TransferCause {
/// (transfering endowment) or because of a transfer via `call`. This
/// is specified using the `cause` parameter.
///
/// NOTE: that the fee is denominated in `T::Balance` units, but
/// NOTE: that the fee is denominated in `BalanceOf<T>` units, but
/// charged in `T::Gas` from the provided `gas_meter`. This means
/// that the actual amount charged might differ.
///
@@ -480,7 +479,7 @@ fn transfer<'a, T: Trait, V: Vm<T>, L: Loader<T>>(
cause: TransferCause,
transactor: &T::AccountId,
dest: &T::AccountId,
value: T::Balance,
value: BalanceOf<T>,
ctx: &mut ExecutionContext<'a, T, V, L>,
) -> Result<(), &'static str> {
use self::TransferCause::*;
@@ -528,7 +527,7 @@ fn transfer<'a, T: Trait, V: Vm<T>, L: Loader<T>>(
if would_create && value < ctx.config.existential_deposit {
return Err("value too low to create account");
}
<balances::Module<T>>::ensure_can_withdraw(transactor, value, WithdrawReason::Transfer, new_from_balance)?;
T::Currency::ensure_can_withdraw(transactor, value, WithdrawReason::Transfer, new_from_balance)?;
let new_to_balance = match to_balance.checked_add(&value) {
Some(b) => b,
@@ -548,7 +547,7 @@ fn transfer<'a, T: Trait, V: Vm<T>, L: Loader<T>>(
struct CallContext<'a, 'b: 'a, T: Trait + 'b, V: Vm<T> + 'b, L: Loader<T>> {
ctx: &'a mut ExecutionContext<'b, T, V, L>,
caller: T::AccountId,
value_transferred: T::Balance,
value_transferred: BalanceOf<T>,
timestamp: T::Moment,
random_seed: T::Hash,
}
@@ -574,7 +573,7 @@ where
fn instantiate(
&mut self,
code_hash: &CodeHash<T>,
endowment: T::Balance,
endowment: BalanceOf<T>,
gas_meter: &mut GasMeter<T>,
input_data: &[u8],
) -> Result<InstantiateReceipt<AccountIdOf<T>>, &'static str> {
@@ -584,7 +583,7 @@ where
fn call(
&mut self,
to: &T::AccountId,
value: T::Balance,
value: BalanceOf<T>,
gas_meter: &mut GasMeter<T>,
input_data: &[u8],
empty_output_buf: EmptyOutputBuf,
@@ -608,11 +607,11 @@ where
&self.caller
}
fn balance(&self) -> T::Balance {
fn balance(&self) -> BalanceOf<T> {
self.ctx.overlay.get_balance(&self.ctx.self_account)
}
fn value_transferred(&self) -> T::Balance {
fn value_transferred(&self) -> BalanceOf<T> {
self.value_transferred
}
+13 -14
View File
@@ -14,8 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use crate::{GasSpent, Module, Trait};
use balances;
use crate::{GasSpent, Module, Trait, BalanceOf, NegativeImbalanceOf};
use runtime_primitives::BLOCK_FULL;
use runtime_primitives::traits::{As, CheckedMul, CheckedSub, Zero};
use srml_support::{StorageValue, traits::{OnUnbalanced, ExistenceRequirement, WithdrawReason, Currency, Imbalance}};
@@ -83,14 +82,14 @@ pub struct GasMeter<T: Trait> {
limit: T::Gas,
/// Amount of gas left from initial gas limit. Can reach zero.
gas_left: T::Gas,
gas_price: T::Balance,
gas_price: BalanceOf<T>,
#[cfg(test)]
tokens: Vec<ErasedToken>,
}
impl<T: Trait> GasMeter<T> {
#[cfg(test)]
pub fn with_limit(gas_limit: T::Gas, gas_price: T::Balance) -> GasMeter<T> {
pub fn with_limit(gas_limit: T::Gas, gas_price: BalanceOf<T>) -> GasMeter<T> {
GasMeter {
limit: gas_limit,
gas_left: gas_limit,
@@ -175,7 +174,7 @@ impl<T: Trait> GasMeter<T> {
}
}
pub fn gas_price(&self) -> T::Balance {
pub fn gas_price(&self) -> BalanceOf<T> {
self.gas_price
}
@@ -202,7 +201,7 @@ impl<T: Trait> GasMeter<T> {
pub fn buy_gas<T: Trait>(
transactor: &T::AccountId,
gas_limit: T::Gas,
) -> Result<(GasMeter<T>, balances::NegativeImbalance<T>), &'static str> {
) -> Result<(GasMeter<T>, NegativeImbalanceOf<T>), &'static str> {
// Check if the specified amount of gas is available in the current block.
// This cannot underflow since `gas_spent` is never greater than `block_gas_limit`.
let gas_available = <Module<T>>::block_gas_limit() - <Module<T>>::gas_spent();
@@ -213,11 +212,11 @@ pub fn buy_gas<T: Trait>(
// Buy the specified amount of gas.
let gas_price = <Module<T>>::gas_price();
let cost = <T::Gas as As<T::Balance>>::as_(gas_limit.clone())
let cost = <T::Gas as As<BalanceOf<T>>>::as_(gas_limit.clone())
.checked_mul(&gas_price)
.ok_or("overflow multiplying gas limit by price")?;
let imbalance = <balances::Module<T>>::withdraw(
let imbalance = T::Currency::withdraw(
transactor,
cost,
WithdrawReason::Fee,
@@ -238,7 +237,7 @@ pub fn buy_gas<T: Trait>(
pub fn refund_unused_gas<T: Trait>(
transactor: &T::AccountId,
gas_meter: GasMeter<T>,
imbalance: balances::NegativeImbalance<T>,
imbalance: NegativeImbalanceOf<T>,
) {
let gas_spent = gas_meter.spent();
let gas_left = gas_meter.gas_left();
@@ -249,8 +248,8 @@ pub fn refund_unused_gas<T: Trait>(
<GasSpent<T>>::mutate(|block_gas_spent| *block_gas_spent += gas_spent);
// Refund gas left by the price it was bought.
let refund = <T::Gas as As<T::Balance>>::as_(gas_left) * gas_meter.gas_price;
let refund_imbalance = <balances::Module<T>>::deposit_creating(transactor, refund);
let refund = <T::Gas as As<BalanceOf<T>>>::as_(gas_left) * gas_meter.gas_price;
let refund_imbalance = T::Currency::deposit_creating(transactor, refund);
if let Ok(imbalance) = imbalance.offset(refund_imbalance) {
T::GasPayment::on_unbalanced(imbalance);
}
@@ -258,9 +257,9 @@ pub fn refund_unused_gas<T: Trait>(
/// A little handy utility for converting a value in balance units into approximitate value in gas units
/// at the given gas price.
pub fn approx_gas_for_balance<T: Trait>(gas_price: T::Balance, balance: T::Balance) -> T::Gas {
let amount_in_gas: T::Balance = balance / gas_price;
<T::Gas as As<T::Balance>>::sa(amount_in_gas)
pub fn approx_gas_for_balance<T: Trait>(gas_price: BalanceOf<T>, balance: BalanceOf<T>) -> T::Gas {
let amount_in_gas: BalanceOf<T> = balance / gas_price;
<T::Gas as As<BalanceOf<T>>>::sa(amount_in_gas)
}
/// A simple utility macro that helps to match against a
+36 -22
View File
@@ -74,7 +74,7 @@ use parity_codec::{Codec, Encode, Decode};
use runtime_primitives::traits::{Hash, As, SimpleArithmetic,Bounded, StaticLookup};
use srml_support::dispatch::{Result, Dispatchable};
use srml_support::{Parameter, StorageMap, StorageValue, decl_module, decl_event, decl_storage, storage::child};
use srml_support::traits::{OnFreeBalanceZero, OnUnbalanced};
use srml_support::traits::{OnFreeBalanceZero, OnUnbalanced, Currency};
use system::{ensure_signed, RawOrigin};
use timestamp;
@@ -133,7 +133,12 @@ where
}
}
pub trait Trait: balances::Trait + timestamp::Trait {
pub type BalanceOf<T> = <<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
pub type NegativeImbalanceOf<T> = <<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::NegativeImbalance;
pub trait Trait: timestamp::Trait {
type Currency: Currency<Self::AccountId>;
/// The outer call dispatch type.
type Call: Parameter + Dispatchable<Origin=<Self as system::Trait>::Origin>;
@@ -141,7 +146,7 @@ pub trait Trait: balances::Trait + timestamp::Trait {
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
// As<u32> is needed for wasm-utils
type Gas: Parameter + Default + Codec + SimpleArithmetic + Bounded + Copy + As<Self::Balance> + As<u64> + As<u32>;
type Gas: Parameter + Default + Codec + SimpleArithmetic + Bounded + Copy + As<BalanceOf<Self>> + As<u64> + As<u32>;
/// A function type to get the contract address given the creator.
type DetermineContractAddress: ContractAddressFor<CodeHash<Self>, Self::AccountId>;
@@ -150,12 +155,13 @@ pub trait Trait: balances::Trait + timestamp::Trait {
///
/// It is recommended (though not required) for this function to return a fee that would be taken
/// by executive module for regular dispatch.
type ComputeDispatchFee: ComputeDispatchFee<Self::Call, <Self as balances::Trait>::Balance>;
type ComputeDispatchFee: ComputeDispatchFee<Self::Call, BalanceOf<Self>>;
/// trieid id generator
type TrieIdGenerator: TrieIdGenerator<Self::AccountId>;
/// Handler for the unbalanced reduction when making a gas payment.
type GasPayment: OnUnbalanced<balances::NegativeImbalance<Self>>;
type GasPayment: OnUnbalanced<NegativeImbalanceOf<Self>>;
}
/// Simple contract address determintator.
@@ -184,12 +190,12 @@ where
/// The default dispatch fee computor computes the fee in the same way that
/// implementation of `MakePayment` for balances module does.
pub struct DefaultDispatchFeeComputor<T: Trait>(PhantomData<T>);
impl<T: Trait> ComputeDispatchFee<T::Call, T::Balance> for DefaultDispatchFeeComputor<T> {
fn compute_dispatch_fee(call: &T::Call) -> T::Balance {
impl<T: Trait> ComputeDispatchFee<T::Call, BalanceOf<T>> for DefaultDispatchFeeComputor<T> {
fn compute_dispatch_fee(call: &T::Call) -> BalanceOf<T> {
let encoded_len = call.using_encoded(|encoded| encoded.len());
let base_fee = <balances::Module<T>>::transaction_base_fee();
let byte_fee = <balances::Module<T>>::transaction_byte_fee();
base_fee + byte_fee * <T::Balance as As<u64>>::sa(encoded_len as u64)
let base_fee = <Module<T>>::transaction_base_fee();
let byte_fee = <Module<T>>::transaction_byte_fee();
base_fee + byte_fee * <BalanceOf<T> as As<u64>>::sa(encoded_len as u64)
}
}
@@ -237,7 +243,7 @@ decl_module! {
fn call(
origin,
dest: <T::Lookup as StaticLookup>::Source,
#[compact] value: T::Balance,
#[compact] value: BalanceOf<T>,
#[compact] gas_limit: T::Gas,
data: Vec<u8>
) -> Result {
@@ -291,7 +297,7 @@ decl_module! {
/// upon any message received by this account.
fn create(
origin,
#[compact] endowment: T::Balance,
#[compact] endowment: BalanceOf<T>,
#[compact] gas_limit: T::Gas,
code_hash: CodeHash<T>,
data: Vec<u8>
@@ -342,7 +348,7 @@ decl_module! {
decl_event! {
pub enum Event<T>
where
<T as balances::Trait>::Balance,
Balance = BalanceOf<T>,
<T as system::Trait>::AccountId,
<T as system::Trait>::Hash
{
@@ -366,14 +372,22 @@ decl_event! {
decl_storage! {
trait Store for Module<T: Trait> as Contract {
/// The fee required to make a transfer.
TransferFee get(transfer_fee) config(): BalanceOf<T>;
/// The fee required to create an account.
CreationFee get(creation_fee) config(): BalanceOf<T>;
/// The fee to be paid for making a transaction; the base.
TransactionBaseFee get(transaction_base_fee) config(): BalanceOf<T>;
/// The fee to be paid for making a transaction; the per-byte portion.
TransactionByteFee get(transaction_byte_fee) config(): BalanceOf<T>;
/// The fee required to create a contract.
ContractFee get(contract_fee) config(): T::Balance = T::Balance::sa(21);
ContractFee get(contract_fee) config(): BalanceOf<T> = BalanceOf::<T>::sa(21);
/// The fee charged for a call into a contract.
CallBaseFee get(call_base_fee) config(): T::Gas = T::Gas::sa(135);
/// The fee charged for a create of a contract.
CreateBaseFee get(create_base_fee) config(): T::Gas = T::Gas::sa(175);
/// The price of one unit of gas.
GasPrice get(gas_price) config(): T::Balance = T::Balance::sa(1);
GasPrice get(gas_price) config(): BalanceOf<T> = BalanceOf::<T>::sa(1);
/// The maximum nesting level of a call/create stack.
MaxDepth get(max_depth) config(): u32 = 100;
/// The maximum amount of gas that could be expended per block.
@@ -410,11 +424,11 @@ impl<T: Trait> OnFreeBalanceZero<T::AccountId> for Module<T> {
/// course of transaction execution.
pub struct Config<T: Trait> {
pub schedule: Schedule<T::Gas>,
pub existential_deposit: T::Balance,
pub existential_deposit: BalanceOf<T>,
pub max_depth: u32,
pub contract_account_instantiate_fee: T::Balance,
pub account_create_fee: T::Balance,
pub transfer_fee: T::Balance,
pub contract_account_instantiate_fee: BalanceOf<T>,
pub account_create_fee: BalanceOf<T>,
pub transfer_fee: BalanceOf<T>,
pub call_base_fee: T::Gas,
pub instantiate_base_fee: T::Gas,
}
@@ -423,11 +437,11 @@ impl<T: Trait> Config<T> {
fn preload() -> Config<T> {
Config {
schedule: <Module<T>>::current_schedule(),
existential_deposit: <balances::Module<T>>::existential_deposit(),
existential_deposit: T::Currency::minimum_balance(),
max_depth: <Module<T>>::max_depth(),
contract_account_instantiate_fee: <Module<T>>::contract_fee(),
account_create_fee: <balances::Module<T>>::creation_fee(),
transfer_fee: <balances::Module<T>>::transfer_fee(),
account_create_fee: <Module<T>>::creation_fee(),
transfer_fee: <Module<T>>::transfer_fee(),
call_base_fee: <Module<T>>::call_base_fee(),
instantiate_base_fee: <Module<T>>::create_base_fee(),
}
+5
View File
@@ -96,6 +96,7 @@ impl consensus::Trait for Test {
type InherentOfflineReport = ();
}
impl Trait for Test {
type Currency = Balances;
type Call = Call;
type Gas = u64;
type DetermineContractAddress = DummyContractAddressFor;
@@ -198,6 +199,10 @@ impl ExtBuilder {
);
t.extend(
GenesisConfig::<Test> {
transaction_base_fee: 0,
transaction_byte_fee: 0,
transfer_fee: self.transfer_fee,
creation_fee: self.creation_fee,
contract_fee: 21,
call_base_fee: 135,
create_base_fee: 175,
+2 -2
View File
@@ -16,8 +16,8 @@
//! Environment definition of the wasm smart-contract runtime.
use crate::{Schedule, Trait, CodeHash, ComputeDispatchFee};
use crate::exec::{Ext, BalanceOf, VmExecResult, OutputBuf, EmptyOutputBuf, CallReceipt, InstantiateReceipt};
use crate::{Schedule, Trait, CodeHash, ComputeDispatchFee, BalanceOf};
use crate::exec::{Ext, VmExecResult, OutputBuf, EmptyOutputBuf, CallReceipt, InstantiateReceipt};
use crate::gas::{GasMeter, Token, GasMeterResult, approx_gas_for_balance};
use sandbox;
use system;
+2 -2
View File
@@ -234,11 +234,11 @@ pub trait Currency<AccountId> {
/// The opaque token type for an imbalance. This is returned by unbalanced operations
/// and must be dealt with. It may be dropped but cannot be cloned.
type PositiveImbalance: Imbalance<Self::Balance>;
type PositiveImbalance: Imbalance<Self::Balance, Opposite=Self::NegativeImbalance>;
/// The opaque token type for an imbalance. This is returned by unbalanced operations
/// and must be dealt with. It may be dropped but cannot be cloned.
type NegativeImbalance: Imbalance<Self::Balance>;
type NegativeImbalance: Imbalance<Self::Balance, Opposite=Self::PositiveImbalance>;
// PUBLIC IMMUTABLES