diff --git a/.maintain/ci/build_script.sh b/.maintain/ci/build_script.sh new file mode 100755 index 000000000..071af53e9 --- /dev/null +++ b/.maintain/ci/build_script.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -eux + +rustup default $RUST_TOOLCHAIN + +source ~/.cargo/env + +rustup --version +cargo --version +rustc --version + +case $TARGET in + # Without WASM + "native") + # There is some issue to build on ci server with SKIP_WASM_BUILD=1 + cargo build --release --all --locked "$@" + echo -e "\e[0;32m +-------------+ \n\e[0;32m | Native Pass | \n\e[0;32m +-------------+ \e[0m" + ;; + + # With WASM + "wasm") + WASM_BUILD_TYPE=release cargo build --locked "$@" + echo -e "\e[0;32m +-----------+ \n\e[0;32m | WASM Pass | \n\e[0;32m +-----------+ \e[0m" + ;; +esac diff --git a/.maintain/ci/darwinia_test_script.sh b/.maintain/ci/darwinia_test_script.sh new file mode 100755 index 000000000..dcd85e674 --- /dev/null +++ b/.maintain/ci/darwinia_test_script.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +echo -e "Test Darwinia ${1} ..." + +set -eux + +rustup default $RUST_TOOLCHAIN + +source ~/.cargo/env + +rustup --version +cargo --version +rustc --version + +case $TARGET in + # Without WASM + "native") + # There is some issue to build on ci server with SKIP_WASM_BUILD=1 + cargo test -p darwinia-${1} + echo -e "\e[0;32m +------------+ \n\e[0;32m | ${1} Pass | \n\e[0;32m +------------+ \e[0m" + ;; + + # With WASM + "wasm") + WASM_BUILD_TYPE=release cargo test -p darwinia-${1} + echo -e "\e[0;32m +------------+ \n\e[0;32m | ${1} Pass | \n\e[0;32m +------------+ \e[0m" + ;; +esac diff --git a/.maintain/ci/fmt_script.sh b/.maintain/ci/fmt_script.sh new file mode 100755 index 000000000..832a655c4 --- /dev/null +++ b/.maintain/ci/fmt_script.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -eux + +# rustfmt is check as stable rust +rustup default stable +rustup component add rustfmt + +source ~/.cargo/env + +rustup --version +cargo --version +rustc --version + +# clean target cache if any +rm -rf target + +cargo fmt --all +echo -e "\e[0;32m +-------------+ \n\e[0;32m | Format Pass | \n\e[0;32m +-------------+ \e[0m" diff --git a/.maintain/ci/script.sh b/.maintain/ci/script.sh deleted file mode 100755 index f5c08efd8..000000000 --- a/.maintain/ci/script.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash - -set -eux - -curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain=$RUST_TOOLCHAIN -y - -source ~/.cargo/env - -rustup --version -cargo --version -rustc --version - -case $TARGET in - # Format check - "rustfmt") - cargo fmt --all - ;; - - # Unit test - "native") - rustup target add wasm32-unknown-unknown - cargo test --release --all --locked "$@" - ;; - - # Build test - "wasm") - rustup target add wasm32-unknown-unknown - cargo build --locked "$@" - ;; -esac diff --git a/.maintain/ci/test_script.sh b/.maintain/ci/test_script.sh new file mode 100755 index 000000000..c8652fd1d --- /dev/null +++ b/.maintain/ci/test_script.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -eux + +rustup default $RUST_TOOLCHAIN + +source ~/.cargo/env + +rustup --version +cargo --version +rustc --version + +case $TARGET in + # Without WASM, build then test + "native") + # There is some issue to build on ci server with SKIP_WASM_BUILD=1 + cargo test --release --all --locked "$@" + echo -e "\e[0;32m +------------+ \n\e[0;32m | Release OK | \n\e[0;32m +------------+ \e[0m" + ;; + + # With WASM, build then test + "wasm") + WASM_BUILD_TYPE=release cargo test --locked "$@" + echo -e "\e[0;32m +------------+ \n\e[0;32m | Release OK | \n\e[0;32m +------------+ \e[0m" + ;; +esac diff --git a/.travis.yml b/.travis.yml index a4383709e..493b9fa0b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,11 @@ -# Request an environment that provides sudo (that goes with larger containers) -# and a minimal language environment. -sudo: true -language: minimal +language: rust +rust: + - nightly -cache: cargo +cache: + cargo: true + directories: + - target branches: only: @@ -13,17 +15,45 @@ branches: env: global: - RUST_BACKTRACE=1 - matrix: - - RUST_TOOLCHAIN=stable TARGET=rustfmt - - RUST_TOOLCHAIN=nightly TARGET=wasm - - RUST_TOOLCHAIN=nightly TARGET=native before_install: # Check how much space we've got on this machine. - df -h + # TODO: cache the toolchain + - rustup target add wasm32-unknown-unknown -script: - - .maintain/ci/script.sh +jobs: + include: + - stage: Check + script: .maintain/ci/fmt_script.sh + + - stage: Build + env: RUST_TOOLCHAIN=nightly TARGET=native + script: .maintain/ci/build_script.sh + + - stage: Build + env: RUST_TOOLCHAIN=nightly TARGET=wasm + script: .maintain/ci/build_script.sh + + - stage: Darwinia Test + env: RUST_TOOLCHAIN=nightly TARGET=native KTON + script: .maintain/ci/darwinia_test_script.sh kton + + - stage: Darwinia Test + env: RUST_TOOLCHAIN=nightly TARGET=native RING + script: .maintain/ci/darwinia_test_script.sh ring + + - stage: Darwinia Test + env: RUST_TOOLCHAIN=nightly TARGET=native STAKING + script: .maintain/ci/darwinia_test_script.sh staking + + - stage: Overall Test + env: RUST_TOOLCHAIN=nightly TARGET=native + script: .maintain/ci/test_script.sh + + # clean up cache + - stage: Cleanup + script: cargo clean after_script: # Check how much free disk space left after the build diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc new file mode 100644 index 000000000..1ecfb1c9d --- /dev/null +++ b/CONTRIBUTING.adoc @@ -0,0 +1,62 @@ += Contributing + +The `Darwinia` project is an **OPENISH Open Source Project** + +== What? + +Individuals making significant and valuable contributions are given commit-access to a project to contribute as they see fit. A project is more like an open wiki than a standard guarded open source project. + +== Rules + +There are a few basic ground-rules for contributors (including the maintainer(s) of the project): + +. **No `--force` pushes** or modifying the master branch history in any way. If you need to rebase, ensure you do it in your own repo. +. **Non-master branches**, prefixed with a short name moniker (e.g. `gav-my-feature`) must be used for ongoing work. +. **All modifications** must be made in a **pull-request** to solicit feedback from other contributors. +. A pull-request *must not be merged until CI* has finished successfully. +. Contributors should adhere to the https://wiki.parity.io/Substrate-Style-Guide[house coding style]. + + +== Merge Process + +Merging pull requests once CI is successful: + +. A PR needs to be reviewed and approved by project maintainers unless: + - it does not alter any logic (e.g. comments, dependencies, docs), then it may be tagged https://github.com/darwinia-network/darwinia/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+label%3AA2-insubstantial[`insubstantial`] and merged by its author once CI is complete. + - it is an urgent fix with no large change to logic, then it may be merged after a non-author contributor has approved the review once CI is complete. + +. Once a PR is ready for review please add the https://github.com/darwinia-network/darwinia/pulls?q=is%3Apr+is%3Aopen+label%3AA0-pleasereview[`pleasereview`] label. Generally PRs should sit with this label for 48 hours in order to garner feedback. It may be merged before if all relevant parties had a look at it. +. PRs that break the external API must be tagged with https://github.com/darwinia-network/darwinia/labels/B2-breaksapi[`breaksapi`], when it changes the SRML or consensus of running system with https://github.com/darwinia-network/darwinia/labels/B3-breaksconsensus[`breaksconsensus`] +. No PR should be merged until all reviews' comments are addressed. + +*Reviewing pull requests*: + +When reviewing a pull request, the end-goal is to suggest useful changes to the author. Reviews should finish with approval unless there are issues that would result in: + +. Buggy behavior. +. Undue maintenance burden. +. Breaking with house coding style. +. Pessimization (i.e. reduction of speed as measured in the projects benchmarks). +. Feature reduction (i.e. it removes some aspect of functionality that a significant minority of users rely on). +. Uselessness (i.e. it does not strictly add a feature or fix a known issue). + +*Reviews may not be used as an effective veto for a PR because*: + +. There exists a somewhat cleaner/better/faster way of accomplishing the same feature/fix. +. It does not fit well with some other contributors' longer-term vision for the project. + +== Helping out + +We use https://github.com/darwinia-network/darwinia/labels[labels] to manage PRs and issues and communicate state of a PR. Please familiarize yourself with them. Furthermore we are organizing issues in https://github.com/darwinia-network/darwinia/milestones[milestones]. Best way to get started is to a pick a ticket from the current milestone tagged https://github.com/darwinia-network/darwinia/issues?q=is%3Aissue+is%3Aopen+label%3AQ2-easy[`easy`] or https://github.com/darwinia-network/darwinia/issues?q=is%3Aissue+is%3Aopen+label%3AQ3-medium[`medium`] and get going or https://github.com/darwinia-network/darwinia/issues?q=is%3Aissue+is%3Aopen+label%3AX1-mentor[`mentor`] and get in contact with the mentor offering their support on that larger task. + +== Releases + +Declaring formal releases remains the prerogative of the project maintainer(s). + +== Changes to this arrangement + +This is an experiment and feedback is welcome! This document may also be subject to pull-requests or changes by contributors where you believe you have something valuable to add or change. + +== Heritage + +These contributing guidelines are modified from the "OPEN Open Source Project" guidelines for the Level project: https://github.com/Level/community/blob/master/CONTRIBUTING.md \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 74ceb5316..65bff5739 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -881,6 +881,7 @@ dependencies = [ name = "darwinia-kton" version = "0.3.0" dependencies = [ + "darwinia-ring", "darwinia-support", "frame-support", "frame-system", diff --git a/frame/balances/kton/Cargo.toml b/frame/balances/kton/Cargo.toml index c66763920..fd3b3a2c5 100644 --- a/frame/balances/kton/Cargo.toml +++ b/frame/balances/kton/Cargo.toml @@ -18,6 +18,7 @@ sp-std = { version = "2.0.0", default-features = false, git = "https://github.co # darwinia darwinia-support = { default-features = false, path = "../../support" } +darwinia-ring = { default-features = false, path = "../ring" } [dev-dependencies] sp-io = { version = "2.0.0", git = "https://github.com/paritytech/substrate.git", rev = "c2fccb36ffacd118fc3502aa93453580a07dc402" } @@ -39,4 +40,4 @@ std = [ "darwinia-support/std", ] # test -transfer-fee = ["std"] +with-fee = ["std"] diff --git a/frame/balances/kton/src/mock.rs b/frame/balances/kton/src/mock.rs index e74f68c9d..5c7288c8a 100644 --- a/frame/balances/kton/src/mock.rs +++ b/frame/balances/kton/src/mock.rs @@ -1,35 +1,70 @@ -use sr_primitives::{ +use std::cell::RefCell; + +use frame_support::{impl_outer_origin, parameter_types, weights::Weight}; +use sp_core::H256; +use sp_io; +use sp_runtime::{ testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - weights::Weight, + traits::{ + BlakeTwo256, + //ConvertInto, + IdentityLookup, + }, Perbill, }; -use substrate_primitives::H256; -use support::{impl_outer_origin, parameter_types}; use crate::*; +use darwinia_ring as ring; -/// The AccountId alias in this test module. pub type AccountId = u64; +pub type Balance = u128; pub type BlockNumber = u64; +pub type Index = u64; pub type Moment = u64; pub type System = system::Module; -pub type Timestamp = timestamp::Module; -#[cfg(feature = "transfer-fee")] pub type Ring = ring::Module; pub type Kton = Module; -pub const NANO: Balance = 1; -pub const MICRO: Balance = 1_000 * NANO; -pub const MILLI: Balance = 1_000 * MICRO; -pub const COIN: Balance = 1_000 * MILLI; - impl_outer_origin! { pub enum Origin for Test {} } +#[cfg(feature = "with-fee")] +thread_local! { + pub(crate) static EXISTENTIAL_DEPOSIT: RefCell = RefCell::new(1 * COIN); + static TRANSFER_FEE: RefCell = RefCell::new(1 * MILLI); + static CREATION_FEE: RefCell = RefCell::new(1 * MILLI); +} +#[cfg(not(feature = "with-fee"))] +thread_local! { + pub(crate) static EXISTENTIAL_DEPOSIT: RefCell = RefCell::new(0); + static TRANSFER_FEE: RefCell = RefCell::new(0); + static CREATION_FEE: RefCell = RefCell::new(0); +} + +pub struct ExistentialDeposit; +impl Get for ExistentialDeposit { + fn get() -> Balance { + EXISTENTIAL_DEPOSIT.with(|v| *v.borrow()) + } +} + +pub struct TransferFee; +impl Get for TransferFee { + fn get() -> Balance { + TRANSFER_FEE.with(|v| *v.borrow()) + } +} + +pub struct CreationFee; +impl Get for CreationFee { + fn get() -> Balance { + CREATION_FEE.with(|v| *v.borrow()) + } +} + // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, PartialEq, Eq, Debug)] pub struct Test; @@ -42,7 +77,7 @@ parameter_types! { impl system::Trait for Test { type Origin = Origin; type Call = (); - type Index = u64; + type Index = Index; type BlockNumber = BlockNumber; type Hash = H256; type Hashing = BlakeTwo256; @@ -55,24 +90,7 @@ impl system::Trait for Test { type MaximumBlockLength = MaximumBlockLength; type AvailableBlockRatio = AvailableBlockRatio; type Version = (); -} - -parameter_types! { - pub const MinimumPeriod: Moment = 5; -} -impl timestamp::Trait for Test { - type Moment = u64; - type OnTimestampSet = (); - type MinimumPeriod = MinimumPeriod; -} - -#[cfg(feature = "transfer-fee")] -parameter_types! { - pub const TransferFee: Balance = 1 * MICRO; -} -#[cfg(not(feature = "transfer-fee"))] -parameter_types! { - pub const TransferFee: Balance = 0; + type ModuleToIndex = (); } impl ring::Trait for Test { type Balance = Balance; @@ -81,62 +99,91 @@ impl ring::Trait for Test { type TransferPayment = (); type DustRemoval = (); type Event = (); - type ExistentialDeposit = (); + type ExistentialDeposit = ExistentialDeposit; type TransferFee = TransferFee; - type CreationFee = (); + type CreationFee = CreationFee; } - impl Trait for Test { + type Balance = Balance; type Event = (); + type RingCurrency = Ring; + type TransferPayment = Ring; + type ExistentialDeposit = (); + type TransferFee = (); } pub struct ExtBuilder { - balance_factor: Balance, + existential_deposit: Balance, + transfer_fee: Balance, + creation_fee: Balance, + monied: bool, vesting: bool, } - impl Default for ExtBuilder { fn default() -> Self { Self { - balance_factor: COIN, + existential_deposit: 0, + transfer_fee: 0, + creation_fee: 0, + monied: false, vesting: false, } } } - impl ExtBuilder { - pub fn balance_factor(mut self, balance_factor: Balance) -> Self { - self.balance_factor = balance_factor; + #[allow(dead_code)] + pub fn existential_deposit(mut self, existential_deposit: Balance) -> Self { + self.existential_deposit = existential_deposit; + self + } + #[allow(dead_code)] + pub fn transfer_fee(mut self, transfer_fee: Balance) -> Self { + self.transfer_fee = transfer_fee; + self + } + #[allow(dead_code)] + pub fn creation_fee(mut self, creation_fee: Balance) -> Self { + self.creation_fee = creation_fee; + self + } + #[allow(dead_code)] + pub fn monied(mut self, monied: bool) -> Self { + self.monied = monied; + if self.existential_deposit == 0 { + self.existential_deposit = 1; + } self } pub fn vesting(mut self, vesting: bool) -> Self { self.vesting = vesting; self } - pub fn build(self) -> runtime_io::TestExternalities { + pub fn set_associated_consts(&self) { + EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit); + TRANSFER_FEE.with(|v| *v.borrow_mut() = self.transfer_fee); + CREATION_FEE.with(|v| *v.borrow_mut() = self.creation_fee); + } + pub fn build(self) -> sp_io::TestExternalities { + self.set_associated_consts(); + let mut t = system::GenesisConfig::default().build_storage::().unwrap(); GenesisConfig:: { - balances: vec![ - (1, 10 * self.balance_factor), - (2, 20 * self.balance_factor), - (3, 300 * self.balance_factor), - (4, 400 * self.balance_factor), - (10, self.balance_factor), - (11, 1000 * self.balance_factor), - (20, self.balance_factor), - (21, 2000 * self.balance_factor), - (30, self.balance_factor), - (31, 2000 * self.balance_factor), - (40, self.balance_factor), - (41, 2000 * self.balance_factor), - (100, 2000 * self.balance_factor), - (101, 2000 * self.balance_factor), - ], - vesting: if self.vesting { + balances: if self.monied { vec![ - (1, 0, 10, 5 * self.balance_factor), + (1, 10 * self.existential_deposit), + (2, 20 * self.existential_deposit), + (3, 30 * self.existential_deposit), + (4, 40 * self.existential_deposit), + (12, 10 * self.existential_deposit), + ] + } else { + vec![] + }, + vesting: if self.vesting && self.monied { + vec![ + (1, 0, 10, 5 * self.existential_deposit), (2, 10, 20, 0), - (12, 10, 20, 5 * self.balance_factor), + (12, 10, 20, 5 * self.existential_deposit), ] } else { vec![] @@ -144,6 +191,7 @@ impl ExtBuilder { } .assimilate_storage(&mut t) .unwrap(); + t.into() } } diff --git a/frame/balances/kton/src/tests.rs b/frame/balances/kton/src/tests.rs index 6980abd76..b18e5f4de 100644 --- a/frame/balances/kton/src/tests.rs +++ b/frame/balances/kton/src/tests.rs @@ -1,4 +1,4 @@ -use support::{assert_err, assert_ok, traits::Currency}; +use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; use crate::{mock::*, *}; use darwinia_support::{LockIdentifier, NormalLock, WithdrawLock, WithdrawReasons}; @@ -7,7 +7,7 @@ const ID_1: LockIdentifier = *b"1 "; const ID_2: LockIdentifier = *b"2 "; const ID_3: LockIdentifier = *b"3 "; -#[cfg(feature = "transfer-fee")] +#[cfg(feature = "with-fee")] mod with_transfer_fee { use super::*; @@ -39,7 +39,7 @@ mod with_transfer_fee { } } -#[cfg(not(feature = "transfer-fee"))] +#[cfg(not(feature = "with-fee"))] mod without_transfer_fee { use super::*; @@ -60,51 +60,51 @@ mod without_transfer_fee { }); } - // TODO #[test] fn transfer_should_fail() { - ExtBuilder::default().vesting(true).build().execute_with(|| { - let _ = Kton::deposit_creating(&777, 1); - assert_err!( - Kton::transfer(Origin::signed(666), 777, 50), - "balance too low to send value", - ); + ExtBuilder::default() + .vesting(true) + .monied(true) + .build() + .execute_with(|| { + let _ = Kton::deposit_creating(&777, 1); + assert_noop!( + Kton::transfer(Origin::signed(666), 777, 50), + Error::::InsufficientBalance, + ); - let _ = Kton::deposit_creating(&666, Balance::max_value()); - assert_err!( - Kton::transfer(Origin::signed(777), 666, 1), - "destination balance too high to receive value", - ); + let _ = Kton::deposit_creating(&666, Balance::max_value()); + assert_noop!(Kton::transfer(Origin::signed(777), 666, 1), Error::::Overflow); - assert_err!( - Kton::transfer(Origin::signed(2), 777, Kton::vesting_balance(&2)), - "vesting balance too high to send value", - ); - Kton::set_lock( - ID_1, - &777, - WithdrawLock::Normal(NormalLock { - amount: Balance::max_value(), - until: Moment::max_value(), - }), - WithdrawReasons::all(), - ); - assert_err!( - Kton::transfer(Origin::signed(777), 1, 1), - "account liquidity restrictions prevent withdrawal", - ); - }); + assert_err!( + Kton::transfer(Origin::signed(2), 777, Kton::vesting_balance(&2)), + Error::::VestingBalance, + ); + + Kton::set_lock( + ID_1, + &777, + WithdrawLock::Normal(NormalLock { + amount: Balance::max_value(), + until: Moment::max_value(), + }), + WithdrawReasons::all(), + ); + assert_noop!( + Kton::transfer(Origin::signed(777), 1, 1), + Error::::LiquidityRestrictions, + ); + }); } #[test] fn set_lock_should_work() { - ExtBuilder::default().build().execute_with(|| { - let lock_ids = [[0; 8], [1; 8], [2; 8], [3; 8]]; - let balance_per_lock = Kton::free_balance(&1) / (lock_ids.len() as Balance); + ExtBuilder::default().monied(true).build().execute_with(|| { + let lock_ids = [[0; 8], [1; 8], [2; 8], [3; 8], [4; 8]]; - // account `1`'s vesting length - System::set_block_number(4); + let balance_per_lock = Kton::free_balance(&1) / (lock_ids.len() as Balance); + assert_eq!(balance_per_lock, 2); { let mut locks = vec![]; for lock_id in lock_ids.iter() { @@ -132,62 +132,67 @@ mod without_transfer_fee { for _ in 0..lock_ids.len() - 1 { assert_ok!(Kton::transfer(Origin::signed(1), 2, balance_per_lock)); } - assert_err!( + assert_noop!( Kton::transfer(Origin::signed(1), 2, balance_per_lock), - "account liquidity restrictions prevent withdrawal" + Error::::LiquidityRestrictions ); }); } + // TODO: The timestamp is removed, use block number to check this #[test] - fn remove_lock_should_work() { - ExtBuilder::default().build().execute_with(|| { - Timestamp::set_timestamp(0); - let ts: u64 = Timestamp::now().into(); + fn lock_release_then_remove_lock_then_lock_again_should_work() { + ExtBuilder::default().monied(true).build().execute_with(|| { + System::set_block_number(1); + // Lock 1 should released Kton::set_lock( ID_1, &2, WithdrawLock::Normal(NormalLock { amount: Balance::max_value(), - until: Moment::max_value(), + until: 2, }), WithdrawReasons::all(), ); assert_err!( Kton::transfer(Origin::signed(2), 1, 1), - "account liquidity restrictions prevent withdrawal" + Error::::LiquidityRestrictions ); + System::set_block_number(2); + assert_ok!(Kton::transfer(Origin::signed(2), 1, 1)); - // unexpired + // Lock 2 should be remove Kton::set_lock( ID_2, &2, WithdrawLock::Normal(NormalLock { amount: Balance::max_value(), - until: ts + 1, + until: 3, }), WithdrawReasons::all(), ); - Kton::remove_lock(ID_1, &2); - Timestamp::set_timestamp(ts); - assert_err!( + assert_noop!( Kton::transfer(Origin::signed(2), 1, 1), - "account liquidity restrictions prevent withdrawal" + Error::::LiquidityRestrictions ); Kton::remove_lock(ID_2, &2); assert_ok!(Kton::transfer(Origin::signed(2), 1, 1)); - // expired + System::set_block_number(3); + // Lock 3 should work after all lock released and removed Kton::set_lock( ID_3, &2, WithdrawLock::Normal(NormalLock { amount: Balance::max_value(), - until: ts, + until: 4, }), WithdrawReasons::all(), ); - assert_ok!(Kton::transfer(Origin::signed(2), 1, 1)); + assert_noop!( + Kton::transfer(Origin::signed(2), 1, 1), + Error::::LiquidityRestrictions + ); }); }