-
Notifications
You must be signed in to change notification settings - Fork 68
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* initial commit * save * add a couple of tests * add events everywhere * Fix updating of penalty * Add test for linear_decay * remove unused variables * add rescind_timelocked_mit and set_timelock_duration * add tests for transfer_to and accept_transfer * more tests and a fix * enable todo in do_transfer_to * avoid burning the full balance * introduce tuple in scope instead of indexing * fixup * Split account into sub_accounts * Fix do_transfer_to test by checking if the correct Event was emitted * Fix timelocked_mint tests * Fix issue where any user could remove IncomingTransactions belonging to any other account * More mosaic docs * introduce `TransactionType` and `SubAccount` to split incoming/ougoing accounts Users were having their incoming/outgoing funds merged together into a single sub_account within the pallet. Which would allow a bug to impact all the funds. By splitting them, they are isolated. * use tuple deconstruction instead of indexing * format tests * use `AssetId` instead of `CurrencyId` for consistency in tests * implements more tests & fix some types used by mocking (accountId too small) * Group transfer_to tests * Add more test todos * set_relayer tests * rotate_relayer tests * set_network tests * more budget tests * more mosaic tests * mosaic timelocked_mint tests * more mosaic timelocked_mint tests * add a couple of tests * Fix updating of penalty * add tests for transfer_to and accept_transfer * more tests and a fix * Split account into sub_accounts * Fix timelocked_mint tests * More mosaic docs * introduce `TransactionType` and `SubAccount` to split incoming/ougoing accounts Users were having their incoming/outgoing funds merged together into a single sub_account within the pallet. Which would allow a bug to impact all the funds. By splitting them, they are isolated. * format tests * use `AssetId` instead of `CurrencyId` for consistency in tests * implements more tests & fix some types used by mocking (accountId too small) * Group transfer_to tests * Add more test todos * more mosaic tests * mosaic timelocked_mint tests * mosaic test claim_to * convert first mosaic test to proptest * proptest with unique AccountIds * add prop_assert_err and prop_assert_noop * use prop_assert_err and prop_assert_noop in mosaic tests * rename decay types * test decay of budget penalties for mints * cargo fmt * cargo fmt nightly * forbid impossible state by avoiding default instance for RelayerConfig We were using Default + ValueQuery for RelayerConfig. It was fine because RelayerConfig was containing an `Option<AccountId>` but this would allow inconsistent states such as None for RelayerConfig.current & None for RelayerConfig.next. By removing the option within RelayerConfig and using an OptionQuery for the storage, we it's more clear that a Relayer can be Set/Unset. And if set, an AcccountId must be present. * better naming * fmt * update test-helpers edition * remove rust-version from mosaic * refactor for consistency * remove unused newline * better naming * more comments on decayer * reflect the partial/complete nature of a transfer via the event * rebase on main * fiix difffd * bump spec version for simnode * fmt Co-authored-by: kaiserkarel <k.l.kubat@gmail.com> Co-authored-by: Hussein Ait Lahcen <hussein.aitlahcen@gmail.com> Co-authored-by: Seun Lanlege <seunlanlege@gmail.com>
- Loading branch information
1 parent
089aeba
commit bf8adbf
Showing
17 changed files
with
2,625 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
[package] | ||
name = "pallet-mosaic" | ||
version = "0.1.0" | ||
authors = ["Composable Developers"] | ||
homepage = "https://composable.finance" | ||
edition = "2021" | ||
|
||
[[bin]] | ||
name = "plot" | ||
path = "src/plots.rs" | ||
|
||
[package.metadata.docs.rs] | ||
targets = ["x86_64-unknown-linux-gnu"] | ||
|
||
[package.metadata.cargo-udeps.ignore] | ||
development = ["pallet-balances"] | ||
|
||
# alias "parity-scale-code" to "codec" | ||
[dependencies.codec] | ||
default-features = false | ||
features = ["derive"] | ||
package = "parity-scale-codec" | ||
version = "2.0.0" | ||
|
||
[dependencies] | ||
composable-traits = { path = "../composable-traits", default-features = false } | ||
frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.13" } | ||
frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } | ||
frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } | ||
|
||
sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } | ||
sp-io = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } | ||
sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } | ||
sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } | ||
xcm = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.13", default-features = false } | ||
|
||
log = { version = "0.4.14", default-features = false } | ||
scale-info = { version = "1.0", default-features = false, features = ["derive"] } | ||
num-traits = "0.2.14" | ||
plotters = {version = "0.3.1", optional = true} | ||
|
||
[dev-dependencies] | ||
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } | ||
proptest = "0.9.6" | ||
orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "17a791edf431d7d7aee1ea3dfaeeb7bc21944301" } | ||
orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "17a791edf431d7d7aee1ea3dfaeeb7bc21944301", default-features = false } | ||
composable-tests-helpers = { version = "0.0.1", path = "../composable-tests-helpers", default-features = false } | ||
|
||
|
||
[features] | ||
default = ["std"] | ||
std = [ | ||
"codec/std", | ||
"log/std", | ||
"composable-traits/std", | ||
"scale-info/std", | ||
"frame-support/std", | ||
"frame-system/std", | ||
"sp-runtime/std", | ||
"sp-io/std", | ||
"sp-core/std", | ||
"sp-std/std", | ||
"xcm/std", | ||
] | ||
|
||
runtime-benchmarks = [ | ||
'frame-benchmarking', | ||
'frame-support/runtime-benchmarks', | ||
'frame-system/runtime-benchmarks', | ||
] | ||
|
||
visualization = ["plotters"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Mosaic | ||
|
||
Pallet implementing an interface for the Mosaic Relayer. As opposed to the EVM-EVM bridge, this pallet takes a different approach and uses `mint` and `burn` operations. | ||
Because of that it also limits the mintable amount by the relayer using a decaying penalty. | ||
|
||
## Decaying Penalty | ||
|
||
At moment N, the relayer has a maximum budget `budget`. Minting a token adds a penalty `penalty` to the relayer. The penalty decreases each block according to decay function `decayer`, | ||
which depends on the penalty, current_block, and last_decay_block. The current maximum amount that the relayer can mint is given by `budget - decayer(penalty, current_block, last_decay_block)`. | ||
The new penalty is the decayed previous penalty plus the minted amount. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Seeds for failure cases proptest has generated in the past. It is | ||
# automatically read and these particular cases re-run before any | ||
# novel cases are generated. | ||
# | ||
# It is recommended to check this file in to source control so that | ||
# everyone who runs the test benefits from these saved cases. | ||
cc 622d5f60d70240f7b19156918e818b27925f88f0440f60e4e5975def08a99b84 # shrinks to amount = 10000 | ||
cc 1e4de59b29da912d7745cbfdc8d9893eb2d492cb817275ae19c38e6387c46a35 # shrinks to amount = 1, account_a = 1, lock_time = 1, early = 3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
use frame_support::pallet_prelude::*; | ||
use num_traits::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, One, Saturating, Zero}; | ||
|
||
pub trait Decayer<Balance, BlockNumber> { | ||
/// Decay the `amount` proportionally to the time elapsed `current_block - last_decay_block` | ||
/// Returns `None` if an input value is invalid | ||
fn checked_decay( | ||
&self, | ||
amount: Balance, | ||
current_block: BlockNumber, | ||
last_decay_block: BlockNumber, | ||
) -> Option<Balance>; | ||
|
||
/// Determine how many blocks are required to pass until the `amount` fully recover from this | ||
/// decayer. Returns `None` if the recovery period cannot be computed. | ||
fn full_recovery_period(&self, amount: Balance) -> Option<BlockNumber>; | ||
} | ||
|
||
/// Recommend type for storing the decay function of a penalty. | ||
#[derive(Decode, Encode, TypeInfo, Debug, PartialEq, Clone)] | ||
pub enum BudgetPenaltyDecayer<Balance, BlockNumber> { | ||
/// Linear variant of the decay function, which decreases every block. | ||
Linear(LinearDecay<Balance, BlockNumber>), | ||
} | ||
|
||
impl<Balance, BlockNumber> BudgetPenaltyDecayer<Balance, BlockNumber> { | ||
#[allow(dead_code)] | ||
pub fn linear(n: Balance) -> BudgetPenaltyDecayer<Balance, BlockNumber> { | ||
BudgetPenaltyDecayer::Linear(LinearDecay { factor: n, _marker: PhantomData }) | ||
} | ||
} | ||
|
||
impl<Balance, BlockNumber> Decayer<Balance, BlockNumber> | ||
for BudgetPenaltyDecayer<Balance, BlockNumber> | ||
where | ||
BlockNumber: CheckedSub + Saturating + Into<Balance> + TryFrom<Balance> + One + CheckedAdd, | ||
Balance: CheckedMul + CheckedDiv + Saturating + Zero, | ||
{ | ||
fn checked_decay( | ||
&self, | ||
amount: Balance, | ||
current: BlockNumber, | ||
last: BlockNumber, | ||
) -> Option<Balance> { | ||
match self { | ||
BudgetPenaltyDecayer::Linear(lin) => lin.checked_decay(amount, current, last), | ||
} | ||
} | ||
|
||
fn full_recovery_period(&self, amount: Balance) -> Option<BlockNumber> { | ||
match self { | ||
BudgetPenaltyDecayer::Linear(lin) => lin.full_recovery_period(amount), | ||
} | ||
} | ||
} | ||
|
||
#[derive(Decode, Encode, TypeInfo, Default, Debug, PartialEq, Clone)] | ||
pub struct LinearDecay<Balance, BlockNumber> { | ||
/// Factor by which we decay every block. | ||
factor: Balance, | ||
_marker: core::marker::PhantomData<BlockNumber>, | ||
} | ||
|
||
impl<Balance, BlockNumber> Decayer<Balance, BlockNumber> for LinearDecay<Balance, BlockNumber> | ||
where | ||
BlockNumber: CheckedSub + Saturating + Into<Balance> + TryFrom<Balance> + One + CheckedAdd, | ||
Balance: CheckedMul + CheckedDiv + Saturating + Zero, | ||
{ | ||
fn checked_decay( | ||
&self, | ||
amount: Balance, | ||
current: BlockNumber, | ||
last: BlockNumber, | ||
) -> Option<Balance> { | ||
let diff = current.saturating_sub(last); | ||
let reduction = diff.into().checked_mul(&self.factor)?; | ||
Some(amount.saturating_sub(reduction)) | ||
} | ||
|
||
fn full_recovery_period(&self, amount: Balance) -> Option<BlockNumber> { | ||
let full_period = amount.checked_div(&self.factor)?; | ||
let block_full_period: BlockNumber = TryFrom::<Balance>::try_from(full_period).ok()?; | ||
let block_full_period_plus_one: BlockNumber = block_full_period.checked_add(&One::one())?; | ||
Some(block_full_period_plus_one) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn test_linear_decrease() { | ||
let mut penalty = 1000; | ||
let prev = penalty.clone(); | ||
let penalty_decayer = BudgetPenaltyDecayer::linear(10); | ||
|
||
(0..=100).for_each(|x| { | ||
penalty = penalty_decayer.checked_decay(penalty, x, x - 1).unwrap(); | ||
assert!(prev > penalty); | ||
}); | ||
} | ||
} |
Oops, something went wrong.