Skip to content

Commit

Permalink
Support all fractional places (#1049)
Browse files Browse the repository at this point in the history
* Create AlignedFractionalTransactAsset struct

* Implement adjusted deposit_asset

* Make compileable

* Allign fractional decimal places on Battery Station

* Implement tests

* Update runtime/zeitgeist/src/xcm_config/fees.rs

Co-authored-by: Chralt <[email protected]>

* Update runtime/zeitgeist/src/xcm_config/fees.rs

Co-authored-by: Chralt <[email protected]>

* Apply suggestions from code review

Co-authored-by: Chralt <[email protected]>

---------

Co-authored-by: Chralt <[email protected]>
  • Loading branch information
sea212 and Chralt98 authored Aug 3, 2023
1 parent 37e1a16 commit 41a2564
Show file tree
Hide file tree
Showing 9 changed files with 781 additions and 98 deletions.
17 changes: 17 additions & 0 deletions docs/changelog_for_devs.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,23 @@ https://keepachangelog.com/en/1.0.0/ and ⚠️ marks changes that might break
components which query the chain's storage, the extrinsics or the runtime
APIs/RPC interface.

## v0.3.11

[#1049]: https://github.com/zeitgeistpm/zeitgeist/pull/1049

### Changed

- ⚠️ All tokens now use 10 fractional decimal places.
- cross-consensus messages (XCM) assume the global canonical representation for token balances.
- The token metadata in the asset registry now assumes that the existential deposit and fee factor
are stored in base 10,000,000,000.

### Added

- Use pallet-asset-tx-payment for allowing to pay transaction fees in foreign
currencies ([#1022]). This requires each transaction to specify the fee
payment token with `asset_id` (`None` is ZTG).

## v0.3.10

[#1022]: https://github.com/zeitgeistpm/zeitgeist/pull/1022
Expand Down
68 changes: 48 additions & 20 deletions runtime/battery-station/src/integration_tests/xcm/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,41 @@ pub const PARA_ID_SIBLING: u32 = 3000;
pub const FOREIGN_ZTG_ID: Asset<u128> = CurrencyId::ForeignAsset(0);
pub const FOREIGN_PARENT_ID: Asset<u128> = CurrencyId::ForeignAsset(1);
pub const FOREIGN_SIBLING_ID: Asset<u128> = CurrencyId::ForeignAsset(2);
pub const BTC_ID: Asset<u128> = CurrencyId::ForeignAsset(3);

#[inline]
pub(super) const fn ztg(amount: Balance) -> Balance {
amount * dollar(10)
}

#[inline]
pub(super) const fn roc(amount: Balance) -> Balance {
foreign(amount, 12)
}

#[inline]
pub(super) const fn btc(amount: Balance) -> Balance {
foreign(amount, 8)
}

#[inline]
pub(super) const fn foreign(amount: Balance, decimals: u32) -> Balance {
amount * dollar(decimals)
}

#[inline]
pub(super) const fn dollar(decimals: u32) -> Balance {
10u128.saturating_pow(decimals)
}

#[inline]
pub(super) const fn adjusted_balance(foreign_base: Balance, amount: Balance) -> Balance {
if foreign_base > ztg(1) {
amount.saturating_div(foreign_base / ztg(1))
} else {
amount.saturating_mul(ztg(1) / foreign_base)
}
}

// Multilocations that are used to represent tokens from other chains
#[inline]
Expand Down Expand Up @@ -138,6 +173,19 @@ pub(super) fn register_foreign_ztg(additional_meta: Option<CustomMetadata>) {
assert_ok!(AssetRegistry::register_asset(RuntimeOrigin::root(), meta, Some(FOREIGN_ZTG_ID)));
}

pub(super) fn register_btc(additional_meta: Option<CustomMetadata>) {
let meta: AssetMetadata<Balance, CustomMetadata> = AssetMetadata {
decimals: 8,
name: "Bitcoin".into(),
symbol: "BTC".into(),
existential_deposit: ExistentialDeposit::get(),
location: Some(VersionedMultiLocation::V1(foreign_sibling_multilocation())),
additional: additional_meta.unwrap_or_default(),
};

assert_ok!(AssetRegistry::register_asset(RuntimeOrigin::root(), meta, Some(BTC_ID)));
}

pub(super) fn register_foreign_sibling(additional_meta: Option<CustomMetadata>) {
// Register native Sibling token as foreign asset.
let meta: AssetMetadata<Balance, CustomMetadata> = AssetMetadata {
Expand Down Expand Up @@ -170,26 +218,6 @@ pub(super) fn register_foreign_parent(additional_meta: Option<CustomMetadata>) {
assert_ok!(AssetRegistry::register_asset(RuntimeOrigin::root(), meta, Some(FOREIGN_PARENT_ID)));
}

#[inline]
pub(super) fn ztg(amount: Balance) -> Balance {
amount * dollar(10)
}

#[inline]
pub(super) fn roc(amount: Balance) -> Balance {
foreign(amount, 12)
}

#[inline]
pub(super) fn foreign(amount: Balance, decimals: u32) -> Balance {
amount * dollar(decimals)
}

#[inline]
pub(super) fn dollar(decimals: u32) -> Balance {
10u128.saturating_pow(decimals)
}

#[inline]
pub(super) fn sibling_parachain_account() -> AccountId {
parachain_account(PARA_ID_SIBLING)
Expand Down
145 changes: 134 additions & 11 deletions runtime/battery-station/src/integration_tests/xcm/tests/transfers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
use crate::{
integration_tests::xcm::{
setup::{
register_foreign_parent, register_foreign_ztg, roc, sibling_parachain_account,
zeitgeist_parachain_account, ztg, ALICE, BOB, FOREIGN_PARENT_ID, FOREIGN_ZTG_ID,
PARA_ID_SIBLING,
adjusted_balance, btc, register_btc, register_foreign_parent, register_foreign_ztg,
roc, sibling_parachain_account, zeitgeist_parachain_account, ztg, ALICE, BOB, BTC_ID,
FOREIGN_PARENT_ID, FOREIGN_ZTG_ID, PARA_ID_SIBLING,
},
test_net::{RococoNet, Sibling, TestNet, Zeitgeist},
},
Expand All @@ -33,7 +33,7 @@ use crate::{
use frame_support::assert_ok;
use orml_traits::MultiCurrency;
use xcm::latest::{Junction, Junction::*, Junctions::*, MultiLocation, NetworkId};
use xcm_emulator::TestExt;
use xcm_emulator::{Limited, TestExt};
use zeitgeist_primitives::{
constants::BalanceFractionalDecimals,
types::{CustomMetadata, XcmMetadata},
Expand Down Expand Up @@ -71,7 +71,7 @@ fn transfer_ztg_to_sibling() {
)
.into()
),
xcm_emulator::Limited(4_000_000_000),
Limited(4_000_000_000),
));

// Confirm that Alice's balance is initial_balance - amount_transferred
Expand Down Expand Up @@ -141,7 +141,7 @@ fn transfer_ztg_sibling_to_zeitgeist() {
)
.into()
),
xcm_emulator::Limited(4_000_000_000),
Limited(4_000_000_000),
));

// Confirm that Bobs's balance is initial balance - amount transferred
Expand Down Expand Up @@ -172,6 +172,121 @@ fn transfer_ztg_sibling_to_zeitgeist() {
});
}

#[test]
fn transfer_btc_sibling_to_zeitgeist() {
TestNet::reset();

let sibling_alice_initial_balance = ztg(10);
let zeitgeist_alice_initial_balance = btc(0);
let initial_sovereign_balance = btc(100);
let transfer_amount = btc(100);

Zeitgeist::execute_with(|| {
register_btc(None);

assert_eq!(Tokens::free_balance(BTC_ID, &ALICE), zeitgeist_alice_initial_balance,);
});

Sibling::execute_with(|| {
assert_eq!(Balances::free_balance(&ALICE), sibling_alice_initial_balance);
// Set the sovereign balance such that it is not subject to dust collection
assert_ok!(Balances::set_balance(
RuntimeOrigin::root(),
zeitgeist_parachain_account().into(),
initial_sovereign_balance,
0
));
assert_ok!(XTokens::transfer(
RuntimeOrigin::signed(ALICE),
// Target chain will interpret CurrencyId::Ztg as BTC in this context.
CurrencyId::Ztg,
transfer_amount,
Box::new(
MultiLocation::new(
1,
X2(
Parachain(battery_station::ID),
Junction::AccountId32 { network: NetworkId::Any, id: ALICE.into() }
)
)
.into()
),
Limited(4_000_000_000),
));

// Confirm that Alice's balance is initial_balance - amount_transferred
assert_eq!(Balances::free_balance(&ALICE), sibling_alice_initial_balance - transfer_amount);

// Verify that the amount transferred is now part of the zeitgeist account here
assert_eq!(
Balances::free_balance(zeitgeist_parachain_account()),
initial_sovereign_balance + transfer_amount
);
});

Zeitgeist::execute_with(|| {
let expected = transfer_amount - btc_fee();
let expected_adjusted = adjusted_balance(btc(1), expected);

// Verify that remote Alice now has initial balance + amount transferred - fee
assert_eq!(
Tokens::free_balance(BTC_ID, &ALICE),
zeitgeist_alice_initial_balance + expected_adjusted,
);
});
}

#[test]
fn transfer_btc_zeitgeist_to_sibling() {
TestNet::reset();

let transfer_amount = btc(100) - btc_fee();
let initial_sovereign_balance = 2 * btc(100);
let sibling_bob_initial_balance = btc(0);

transfer_btc_sibling_to_zeitgeist();

Sibling::execute_with(|| {
assert_eq!(Tokens::free_balance(BTC_ID, &BOB), sibling_bob_initial_balance,);
});

Zeitgeist::execute_with(|| {
assert_ok!(XTokens::transfer(
RuntimeOrigin::signed(ALICE),
BTC_ID,
transfer_amount,
Box::new(
MultiLocation::new(
1,
X2(
Parachain(PARA_ID_SIBLING),
Junction::AccountId32 { network: NetworkId::Any, id: BOB.into() }
)
)
.into()
),
Limited(4_000_000_000),
));

// Confirm that Alice's balance is initial_balance - amount_transferred
assert_eq!(Tokens::free_balance(BTC_ID, &ALICE), 0);
});

Sibling::execute_with(|| {
let fee_adjusted = adjusted_balance(btc(1), btc_fee());
let expected = transfer_amount - fee_adjusted;

// Verify that Bob now has initial balance + amount transferred - fee
assert_eq!(Balances::free_balance(&BOB), sibling_bob_initial_balance + expected,);

// Verify that the amount transferred is now subtracted from the zeitgeist account at sibling
assert_eq!(
Balances::free_balance(zeitgeist_parachain_account()),
initial_sovereign_balance - transfer_amount
);
});
}

#[test]
fn transfer_roc_from_relay_chain() {
TestNet::reset();
Expand All @@ -198,7 +313,9 @@ fn transfer_roc_from_relay_chain() {
});

Zeitgeist::execute_with(|| {
assert_eq!(Tokens::free_balance(FOREIGN_PARENT_ID, &BOB), transfer_amount - roc_fee());
let expected = transfer_amount - roc_fee();
let expected_adjusted = adjusted_balance(roc(1), expected);
assert_eq!(Tokens::free_balance(FOREIGN_PARENT_ID, &BOB), expected_adjusted);
});
}

Expand All @@ -207,6 +324,7 @@ fn transfer_roc_to_relay_chain() {
TestNet::reset();

let transfer_amount: Balance = roc(1);
let transfer_amount_local: Balance = adjusted_balance(roc(1), transfer_amount);
transfer_roc_from_relay_chain();

Zeitgeist::execute_with(|| {
Expand All @@ -224,12 +342,12 @@ fn transfer_roc_to_relay_chain() {
)
.into()
),
xcm_emulator::Limited(4_000_000_000)
Limited(4_000_000_000)
));

assert_eq!(
Tokens::free_balance(FOREIGN_PARENT_ID, &ALICE),
initial_balance - transfer_amount
initial_balance - transfer_amount_local
)
});

Expand Down Expand Up @@ -286,7 +404,7 @@ fn transfer_ztg_to_sibling_with_custom_fee() {
)
.into()
),
xcm_emulator::Limited(4_000_000_000),
Limited(4_000_000_000),
));

// Confirm that Alice's balance is initial_balance - amount_transferred
Expand Down Expand Up @@ -337,7 +455,12 @@ fn roc_fee() -> Balance {
}

#[inline]
fn calc_fee(fee_per_second: Balance) -> Balance {
fn btc_fee() -> Balance {
fee(8)
}

#[inline]
const fn calc_fee(fee_per_second: Balance) -> Balance {
// We divide the fee to align its unit and multiply by 8 as that seems to be the unit of
// time the tests take.
// NOTE: it is possible that in different machines this value may differ. We shall see.
Expand Down
Loading

0 comments on commit 41a2564

Please sign in to comment.