mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-24 06:41:06 +00:00
c66ae375e6
Changes: - Change the fungible(s) logic to treat a self-transfer as No-OP (as long as all pre-checks pass). Note that the self-transfer case will not emit an event since no state was changed. --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
284 lines
7.7 KiB
Rust
284 lines
7.7 KiB
Rust
// This file is part of Substrate.
|
|
|
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
use codec::{Decode, Encode};
|
|
use frame_support::{
|
|
parameter_types,
|
|
traits::{
|
|
fungibles::{self, Dust},
|
|
tokens::{
|
|
self, DepositConsequence, Fortitude, Preservation, Provenance, WithdrawConsequence,
|
|
},
|
|
},
|
|
};
|
|
use scale_info::TypeInfo;
|
|
use sp_arithmetic::traits::Zero;
|
|
use sp_core::{Get, TypedGet};
|
|
use sp_runtime::{DispatchError, DispatchResult};
|
|
use sp_std::collections::btree_map::BTreeMap;
|
|
|
|
parameter_types! {
|
|
static TestAssetOf: BTreeMap<(u32, Vec<u8>), Vec<u8>> = Default::default();
|
|
static TestBalanceOf: BTreeMap<(u32, Vec<u8>, Vec<u8>), Vec<u8>> = Default::default();
|
|
static TestHoldOf: BTreeMap<(u32, Vec<u8>, Vec<u8>, Vec<u8>), Vec<u8>> = Default::default();
|
|
}
|
|
|
|
pub struct TestFungibles<Instance, AccountId, AssetId, MinimumBalance, HoldReason>(
|
|
core::marker::PhantomData<(Instance, AccountId, AssetId, MinimumBalance, HoldReason)>,
|
|
);
|
|
impl<
|
|
Instance: Get<u32>,
|
|
AccountId: Encode,
|
|
AssetId: tokens::AssetId + Copy,
|
|
MinimumBalance: TypedGet,
|
|
HoldReason,
|
|
> fungibles::Inspect<AccountId>
|
|
for TestFungibles<Instance, AccountId, AssetId, MinimumBalance, HoldReason>
|
|
where
|
|
MinimumBalance::Type: tokens::Balance,
|
|
{
|
|
type AssetId = AssetId;
|
|
type Balance = MinimumBalance::Type;
|
|
|
|
fn total_issuance(asset: Self::AssetId) -> Self::Balance {
|
|
TestAssetOf::get()
|
|
.get(&(Instance::get(), asset.encode()))
|
|
.and_then(|data| Decode::decode(&mut &data[..]).ok())
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
fn active_issuance(asset: Self::AssetId) -> Self::Balance {
|
|
Self::total_issuance(asset)
|
|
}
|
|
|
|
/// The minimum balance any single account may have.
|
|
fn minimum_balance(_asset: Self::AssetId) -> Self::Balance {
|
|
MinimumBalance::get()
|
|
}
|
|
|
|
fn total_balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance {
|
|
TestBalanceOf::get()
|
|
.get(&(Instance::get(), asset.encode(), who.encode()))
|
|
.and_then(|data| Decode::decode(&mut &data[..]).ok())
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
fn balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance {
|
|
Self::total_balance(asset, who)
|
|
}
|
|
|
|
fn reducible_balance(
|
|
asset: Self::AssetId,
|
|
who: &AccountId,
|
|
_preservation: Preservation,
|
|
_force: Fortitude,
|
|
) -> Self::Balance {
|
|
Self::total_balance(asset, who)
|
|
}
|
|
|
|
fn can_deposit(
|
|
asset: Self::AssetId,
|
|
who: &AccountId,
|
|
amount: Self::Balance,
|
|
_provenance: Provenance,
|
|
) -> DepositConsequence {
|
|
if !Self::asset_exists(asset) {
|
|
return DepositConsequence::UnknownAsset
|
|
}
|
|
if amount + Self::balance(asset, who) < Self::minimum_balance(asset) {
|
|
return DepositConsequence::BelowMinimum
|
|
}
|
|
DepositConsequence::Success
|
|
}
|
|
|
|
fn can_withdraw(
|
|
asset: Self::AssetId,
|
|
who: &AccountId,
|
|
amount: Self::Balance,
|
|
) -> WithdrawConsequence<Self::Balance> {
|
|
if Self::reducible_balance(asset, who, Preservation::Expendable, Fortitude::Polite) < amount
|
|
{
|
|
return WithdrawConsequence::BalanceLow
|
|
}
|
|
if Self::total_balance(asset, who) < Self::minimum_balance(asset) + amount {
|
|
return WithdrawConsequence::WouldDie
|
|
}
|
|
WithdrawConsequence::Success
|
|
}
|
|
|
|
fn asset_exists(asset: Self::AssetId) -> bool {
|
|
TestAssetOf::get().contains_key(&(Instance::get(), asset.encode()))
|
|
}
|
|
}
|
|
|
|
impl<
|
|
Instance: Get<u32>,
|
|
AccountId: Encode,
|
|
AssetId: tokens::AssetId + Copy,
|
|
MinimumBalance: TypedGet,
|
|
HoldReason,
|
|
> fungibles::Unbalanced<AccountId>
|
|
for TestFungibles<Instance, AccountId, AssetId, MinimumBalance, HoldReason>
|
|
where
|
|
MinimumBalance::Type: tokens::Balance,
|
|
{
|
|
fn handle_dust(_dust: Dust<AccountId, Self>) {}
|
|
|
|
fn write_balance(
|
|
asset: Self::AssetId,
|
|
who: &AccountId,
|
|
amount: Self::Balance,
|
|
) -> Result<Option<Self::Balance>, DispatchError> {
|
|
let mut tb = TestBalanceOf::get();
|
|
let maybe_dust = if amount < MinimumBalance::get() {
|
|
tb.remove(&(Instance::get(), asset.encode(), who.encode()));
|
|
if amount.is_zero() {
|
|
None
|
|
} else {
|
|
Some(amount)
|
|
}
|
|
} else {
|
|
tb.insert((Instance::get(), asset.encode(), who.encode()), amount.encode());
|
|
None
|
|
};
|
|
TestBalanceOf::set(tb);
|
|
Ok(maybe_dust)
|
|
}
|
|
|
|
fn set_total_issuance(asset: Self::AssetId, amount: Self::Balance) {
|
|
let mut ta = TestAssetOf::get();
|
|
ta.insert((Instance::get(), asset.encode()), amount.encode());
|
|
TestAssetOf::set(ta);
|
|
}
|
|
}
|
|
|
|
impl<
|
|
Instance: Get<u32>,
|
|
AccountId: Encode + Eq,
|
|
AssetId: tokens::AssetId + Copy,
|
|
MinimumBalance: TypedGet,
|
|
HoldReason,
|
|
> fungibles::Mutate<AccountId>
|
|
for TestFungibles<Instance, AccountId, AssetId, MinimumBalance, HoldReason>
|
|
where
|
|
MinimumBalance::Type: tokens::Balance,
|
|
{
|
|
}
|
|
|
|
impl<
|
|
Instance: Get<u32>,
|
|
AccountId: Encode,
|
|
AssetId: tokens::AssetId + Copy,
|
|
MinimumBalance: TypedGet,
|
|
HoldReason,
|
|
> fungibles::Balanced<AccountId>
|
|
for TestFungibles<Instance, AccountId, AssetId, MinimumBalance, HoldReason>
|
|
where
|
|
MinimumBalance::Type: tokens::Balance,
|
|
{
|
|
type OnDropCredit = fungibles::DecreaseIssuance<AccountId, Self>;
|
|
type OnDropDebt = fungibles::IncreaseIssuance<AccountId, Self>;
|
|
}
|
|
|
|
impl<
|
|
Instance: Get<u32>,
|
|
AccountId: Encode,
|
|
AssetId: tokens::AssetId + Copy,
|
|
MinimumBalance: TypedGet,
|
|
HoldReason: Encode + Decode + TypeInfo + 'static,
|
|
> fungibles::InspectHold<AccountId>
|
|
for TestFungibles<Instance, AccountId, AssetId, MinimumBalance, HoldReason>
|
|
where
|
|
MinimumBalance::Type: tokens::Balance,
|
|
{
|
|
type Reason = HoldReason;
|
|
|
|
fn total_balance_on_hold(asset: Self::AssetId, who: &AccountId) -> Self::Balance {
|
|
let asset = asset.encode();
|
|
let who = who.encode();
|
|
TestHoldOf::get()
|
|
.iter()
|
|
.filter(|(k, _)| k.0 == Instance::get() && k.1 == asset && k.2 == who)
|
|
.filter_map(|(_, b)| Self::Balance::decode(&mut &b[..]).ok())
|
|
.fold(Zero::zero(), |a, i| a + i)
|
|
}
|
|
|
|
fn balance_on_hold(
|
|
asset: Self::AssetId,
|
|
reason: &Self::Reason,
|
|
who: &AccountId,
|
|
) -> Self::Balance {
|
|
TestHoldOf::get()
|
|
.get(&(Instance::get(), asset.encode(), who.encode(), reason.encode()))
|
|
.and_then(|data| Decode::decode(&mut &data[..]).ok())
|
|
.unwrap_or_default()
|
|
}
|
|
}
|
|
|
|
impl<
|
|
Instance: Get<u32>,
|
|
AccountId: Encode,
|
|
AssetId: tokens::AssetId + Copy,
|
|
MinimumBalance: TypedGet,
|
|
HoldReason: Encode + Decode + TypeInfo + 'static,
|
|
> fungibles::UnbalancedHold<AccountId>
|
|
for TestFungibles<Instance, AccountId, AssetId, MinimumBalance, HoldReason>
|
|
where
|
|
MinimumBalance::Type: tokens::Balance,
|
|
{
|
|
fn set_balance_on_hold(
|
|
asset: Self::AssetId,
|
|
reason: &Self::Reason,
|
|
who: &AccountId,
|
|
amount: Self::Balance,
|
|
) -> DispatchResult {
|
|
let mut th = TestHoldOf::get();
|
|
th.insert(
|
|
(Instance::get(), asset.encode(), who.encode(), reason.encode()),
|
|
amount.encode(),
|
|
);
|
|
TestHoldOf::set(th);
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl<
|
|
Instance: Get<u32>,
|
|
AccountId: Encode,
|
|
AssetId: tokens::AssetId + Copy,
|
|
MinimumBalance: TypedGet,
|
|
HoldReason: Encode + Decode + TypeInfo + 'static,
|
|
> fungibles::MutateHold<AccountId>
|
|
for TestFungibles<Instance, AccountId, AssetId, MinimumBalance, HoldReason>
|
|
where
|
|
MinimumBalance::Type: tokens::Balance,
|
|
{
|
|
}
|
|
|
|
impl<
|
|
Instance: Get<u32>,
|
|
AccountId: Encode,
|
|
AssetId: tokens::AssetId + Copy,
|
|
MinimumBalance: TypedGet,
|
|
HoldReason: Encode + Decode + TypeInfo + 'static,
|
|
> fungibles::BalancedHold<AccountId>
|
|
for TestFungibles<Instance, AccountId, AssetId, MinimumBalance, HoldReason>
|
|
where
|
|
MinimumBalance::Type: tokens::Balance,
|
|
{
|
|
}
|