Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LP Message with custom data format for serialization/deserialization #1889

Merged
merged 22 commits into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 40 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ hex = { version = "0.4.3", default-features = false }
smallvec = "1.11.0"
serde = { version = "1.0.195", default-features = false, features = ["derive"] }
serde_json = { version = "1.0.111" }
serde-big-array = { version = "0.5" }
bincode = { version = "2.0.0-rc.3", features-features = false, features = ["alloc", "serde"] }
parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] }
scale-info = { version = "2.10.0", default-features = false, features = ["derive"] }
log = { version = "0.4.20", default-features = false }
Expand Down
21 changes: 11 additions & 10 deletions libs/traits/src/liquidity_pools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,35 @@
// GNU General Public License for more details.

use frame_support::dispatch::{DispatchResult, DispatchResultWithPostInfo};
use parity_scale_codec::Input;
use sp_runtime::DispatchError;
use sp_std::vec::Vec;

/// An encoding & decoding trait for the purpose of meeting the
/// LiquidityPools General Message Passing Format
pub trait Codec: Sized {
pub trait LPEncoding: Sized {
fn serialize(&self) -> Vec<u8>;
fn deserialize<I: Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error>;
fn deserialize(input: &[u8]) -> Result<Self, DispatchError>;
}

#[cfg(any(test, feature = "std"))]
pub mod test_util {
use parity_scale_codec::{Decode, Encode, Input, MaxEncodedLen};
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;

use super::Codec;
use super::*;

#[derive(Debug, Eq, PartialEq, Clone, Encode, Decode, TypeInfo, MaxEncodedLen)]
pub struct Message;
impl Codec for Message {
impl LPEncoding for Message {
lemunozm marked this conversation as resolved.
Show resolved Hide resolved
fn serialize(&self) -> Vec<u8> {
vec![0x42]
}

fn deserialize<I: Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> {
match input.read_byte()? {
0x42 => Ok(Self),
_ => Err("unsupported message".into()),
fn deserialize(input: &[u8]) -> Result<Self, DispatchError> {
match input.first() {
Some(0x42) => Ok(Self),
lemunozm marked this conversation as resolved.
Show resolved Hide resolved
Some(_) => Err("unsupported message".into()),
None => Err("empty message".into()),
}
}
}
Expand Down
36 changes: 2 additions & 34 deletions libs/types/src/domain_address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,15 @@
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

use cfg_traits::liquidity_pools::Codec;
use cfg_utils::{decode_be_bytes, vec_to_fixed_array};
use cfg_utils::vec_to_fixed_array;
use frame_support::pallet_prelude::RuntimeDebug;
use parity_scale_codec::{Decode, Encode, Input, MaxEncodedLen};
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_runtime::traits::AccountIdConversion;
use sp_std::{vec, vec::Vec};

use crate::EVMChainId;

/// A Domain is a chain or network we can send a message to.
/// The domain indices need to match those used in the EVM contracts and these
/// need to pass the Centrifuge domain to send tranche tokens from the other
/// domain here. Therefore, DO NOT remove or move variants around.
#[derive(Encode, Decode, Clone, Eq, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)]
pub enum Domain {
/// Referring to the Centrifuge Parachain. Will be used for handling
Expand All @@ -36,33 +31,6 @@ pub enum Domain {
EVM(EVMChainId),
}

impl Codec for Domain {
fn serialize(&self) -> Vec<u8> {
match self {
Self::Centrifuge => vec![0; 9],
Self::EVM(chain_id) => {
let mut output: Vec<u8> = 1u8.encode();
output.append(&mut chain_id.to_be_bytes().to_vec());

output
}
}
}

fn deserialize<I: Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> {
let variant = input.read_byte()?;

match variant {
0 => Ok(Self::Centrifuge),
1 => {
let chain_id = decode_be_bytes::<8, _, _>(input)?;
Ok(Self::EVM(chain_id))
}
_ => Err(parity_scale_codec::Error::from("Unknown Domain variant")),
}
}
}

impl Domain {
pub fn into_account<AccountId: Encode + Decode>(&self) -> AccountId {
DomainLocator {
Expand Down
32 changes: 2 additions & 30 deletions libs/utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
// Ensure we're `no_std` when compiling for WebAssembly.
#![cfg_attr(not(feature = "std"), no_std)]

use parity_scale_codec::{Decode, Encode, Error, Input};
use sp_std::{cmp::min, vec::Vec};
use parity_scale_codec::Encode;
use sp_std::cmp::min;

/// Build a fixed-size array using as many elements from `src` as possible
/// without overflowing and ensuring that the array is 0 padded in the case
Expand All @@ -27,34 +27,6 @@ pub fn vec_to_fixed_array<const S: usize>(src: impl AsRef<[u8]>) -> [u8; S] {
dest
}

/// Encode a value in its big-endian representation of which all we know is that
/// it implements Encode. We use this for number types to make sure they are
/// encoded the way they are expected to be decoded on the Solidity side.
pub fn encode_be(x: impl Encode) -> Vec<u8> {
let mut output = x.encode();
output.reverse();
output
}

/// Decode a type O by reading S bytes from I. Those bytes are expected to be
/// encoded as big-endian and thus needs reversing to little-endian before
/// decoding to O.
pub fn decode_be_bytes<const S: usize, O: Decode, I: Input>(input: &mut I) -> Result<O, Error> {
let mut bytes = [0; S];
input.read(&mut bytes[..])?;
bytes.reverse();

O::decode(&mut bytes.as_slice())
}

/// Decode a type 0 by reading S bytes from I.
pub fn decode<const S: usize, O: Decode, I: Input>(input: &mut I) -> Result<O, Error> {
let mut bytes = [0; S];
input.read(&mut bytes[..])?;

O::decode(&mut bytes.as_slice())
}

/// Function that initializes the frame system & Aura, so a timestamp can be set
/// and pass validation
#[cfg(any(feature = "runtime-benchmarks", feature = "std"))]
Expand Down
4 changes: 2 additions & 2 deletions pallets/liquidity-pools-gateway/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
use core::fmt::Debug;

use cfg_traits::{
liquidity_pools::{Codec, InboundQueue, OutboundQueue, Router as DomainRouter},
liquidity_pools::{InboundQueue, LPEncoding, OutboundQueue, Router as DomainRouter},
TryConvert,
};
use cfg_types::domain_address::{Domain, DomainAddress};
Expand Down Expand Up @@ -122,7 +122,7 @@ pub mod pallet {
///
/// NOTE - this `Codec` trait is the Centrifuge trait for liquidity
/// pools' messages.
type Message: Codec + Clone + Debug + PartialEq + MaxEncodedLen + TypeInfo + FullCodec;
type Message: LPEncoding + Clone + Debug + PartialEq + MaxEncodedLen + TypeInfo + FullCodec;

/// The message router type that is stored for each domain.
type Router: DomainRouter<Sender = Self::AccountId>
Expand Down
2 changes: 1 addition & 1 deletion pallets/liquidity-pools-gateway/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use cfg_mocks::*;
use cfg_primitives::OutboundMessageNonce;
use cfg_traits::liquidity_pools::{test_util::Message, Codec, OutboundQueue};
use cfg_traits::liquidity_pools::{test_util::Message, LPEncoding, OutboundQueue};
use cfg_types::domain_address::*;
use frame_support::{
assert_noop, assert_ok,
Expand Down
5 changes: 5 additions & 0 deletions pallets/liquidity-pools/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ sp-core = { workspace = true }
sp-runtime = { workspace = true }
sp-std = { workspace = true }
staging-xcm = { workspace = true }
serde = { workspace = true }
serde-big-array = { workspace = true }
bincode = { workspace = true }

# Our custom pallets
cfg-primitives = { workspace = true }
Expand Down Expand Up @@ -50,6 +53,8 @@ std = [
"orml-traits/std",
"staging-xcm/std",
"scale-info/std",
"serde/std",
"bincode/std",
]
runtime-benchmarks = [
"orml-tokens/runtime-benchmarks",
Expand Down
36 changes: 18 additions & 18 deletions pallets/liquidity-pools/src/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use sp_core::Get;
use sp_runtime::{DispatchError, DispatchResult};
use sp_std::marker::PhantomData;

use crate::{pallet::Config, Message, MessageOf, Pallet};
use crate::{pallet::Config, Message, Pallet};

/// The hook struct which acts upon a finalized investment decrement.
pub struct DecreasedForeignInvestOrderHook<T>(PhantomData<T>);
Expand Down Expand Up @@ -59,13 +59,13 @@ where
Fortitude::Polite,
)?;

let message: MessageOf<T> = Message::ExecutedDecreaseInvestOrder {
pool_id: investment_id.of_pool(),
tranche_id: investment_id.of_tranche(),
let message = Message::ExecutedDecreaseInvestOrder {
pool_id: investment_id.of_pool().into(),
tranche_id: investment_id.of_tranche().into(),
investor: investor.into(),
currency,
currency_payout: status.amount_decreased,
remaining_invest_amount: status.amount_remaining,
currency_payout: status.amount_decreased.into(),
remaining_invest_amount: status.amount_remaining.into(),
};
T::OutboundQueue::submit(T::TreasuryAccount::get(), domain_address.domain(), message)?;

Expand Down Expand Up @@ -102,14 +102,14 @@ where
Fortitude::Polite,
)?;

let message: MessageOf<T> = Message::ExecutedCollectRedeem {
pool_id: investment_id.of_pool(),
tranche_id: investment_id.of_tranche(),
let message = Message::ExecutedCollectRedeem {
pool_id: investment_id.of_pool().into(),
tranche_id: investment_id.of_tranche().into(),
investor: investor.into(),
currency,
currency_payout: status.amount_currency_payout,
tranche_tokens_payout: status.amount_tranche_tokens_payout,
remaining_redeem_amount: status.amount_remaining,
currency_payout: status.amount_currency_payout.into(),
tranche_tokens_payout: status.amount_tranche_tokens_payout.into(),
remaining_redeem_amount: status.amount_remaining.into(),
};

T::OutboundQueue::submit(T::TreasuryAccount::get(), domain_address.domain(), message)?;
Expand Down Expand Up @@ -146,14 +146,14 @@ where
Preservation::Expendable,
)?;

let message: MessageOf<T> = Message::ExecutedCollectInvest {
pool_id: investment_id.of_pool(),
tranche_id: investment_id.of_tranche(),
let message = Message::ExecutedCollectInvest {
pool_id: investment_id.of_pool().into(),
tranche_id: investment_id.of_tranche().into(),
investor: investor.into(),
currency,
currency_payout: status.amount_currency_payout,
tranche_tokens_payout: status.amount_tranche_tokens_payout,
remaining_invest_amount: status.amount_remaining,
currency_payout: status.amount_currency_payout.into(),
tranche_tokens_payout: status.amount_tranche_tokens_payout.into(),
remaining_invest_amount: status.amount_remaining.into(),
};

T::OutboundQueue::submit(T::TreasuryAccount::get(), domain_address.domain(), message)?;
Expand Down
Loading
Loading