Skip to content

Commit

Permalink
Merge pull request #221 from InvArch/francisco-docs_rings
Browse files Browse the repository at this point in the history
Rings documentation
  • Loading branch information
arrudagates authored Mar 4, 2024
2 parents 8abce80 + a953a5f commit 8f24d1d
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 0 deletions.
76 changes: 76 additions & 0 deletions pallet-rings/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Rings Pallet

## Overview

The Rings pallet provides a cross-consensus message (XCM) abstraction layer for INV4 Cores, enabling them to manage assets effortlessly across multiple chains. It abstracts XCM complexities, facilitating easier handling of cross-chain transactions.

## Key Features

- **Maintenance Mode**: Chains can be put under maintenance, restricting certain operations to ensure system integrity during upgrades or when issues are detected.
- **Cross-chain Calls**: Enables sending XCM calls to other chains, allowing for a wide range of interactions.
- **Asset Transfers**: Supports transferring fungible assets between accounts across different chains.
- **Asset Bridging**: Facilitates the bridging of assets between chains, enhancing liquidity and asset interoperability.

## Traits Overview

The pallet utilizes traits to abstract chain and asset locations:

- [`ChainList`]: Provides an interface for referencing chains and retrieving their [`MultiLocation`] or main asset.
- [`ChainAssetsList`]: Offers an interface for referencing chain assets and obtaining their [`MultiLocation`] or parent chain.

## Dispatchable Functions

### `set_maintenance_status`

Sets the maintenance status of a chain. Requires `MaintenanceOrigin` authorization.

- `chain`: The chain to modify.
- `under_maintenance`: The desired maintenance status.

### `send_call`

Allows sending a XCM call to another chain. Can be initiated by a core.

- `destination`: The target chain.
- `weight`: The call's weight.
- `fee_asset`: The asset used for fee payment.
- `fee`: The fee amount.
- `call`: The call data.

### `transfer_assets`

Allows transfers of fungible assets to another account in the destination chain.
**Requires asset and fee_asset to be located in the same chain**.

- `asset`: The asset to transfer.
- `amount`: The amount to transfer.
- `to`: The recipient account.
- `fee_asset`: The asset used for fee payment.
- `fee`: The fee amount.

### `bridge_assets`

Allows bridging of assets to another chain, with either the core account or a third-party account as the beneficiary.

- `asset`: The asset to bridge and it's origin chain.
- `destination`: The destination chain.
- `fee`: The bridging fee.
- `amount`: The amount to bridge.
- `to`: Optional beneficiary account on the destination chain. (Defaults to the core account)

## Events

- `CallSent`: Emitted when a XCM call is sent to another chain.
- `AssetsTransferred`: Emitted when assets are transferred to another account on a different chain.
- `AssetsBridged`: Emitted when assets are bridged to another chain.
- `ChainMaintenanceStatusChanged`: Indicates a change in a chain's maintenance status.

## Errors

- `SendingFailed`: Emitted when sending a XCM message fails.
- `WeightTooHigh`: Emitted when the call's weight exceeds the maximum allowed.
- `FailedToCalculateXcmFee`: Emitted when calculating the XCM fee fails.
- `FailedToReanchorAsset`, `FailedToInvertLocation`: Errors related to asset reanchoring or location inversion.
- `DifferentChains`, `ChainUnderMaintenance`: Indicate issues with the target chain or maintenance status.

This pallet serves as a foundational component for building cross-chain solutions within the InvArch ecosystem, streamlining asset management and interoperability across diverse blockchain environments.
76 changes: 76 additions & 0 deletions pallet-rings/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
//! # Rings Pallet
//!
//! - [`Config`]
//! - [`Call`]
//! - [`Pallet`]
//!
//! ## Overview
//! This pallet provides a XCM abstraction layer for INV4 Cores, allowing them to manage assets easily across multiple chains.
//!
//! The module [`traits`] contains traits that provide an abstraction on top of XCM [`MultiLocation`] and has to be correctly implemented in the runtime.
//!
//! ## Dispatchable Functions
//!
//! - `set_maintenance_status` - Sets the maintenance status of a chain, requires the origin to be authorized as a `MaintenanceOrigin`.
//! - `send_call` - Allows a core to send a XCM call to a destination chain.
//! - `transfer_assets` - Allows a core to transfer fungible assets to another account in the destination chain.
//! - `bridge_assets` - Allows a core to bridge fungible assets to another chain having either a third party account or
//! the core account as beneficiary in the destination chain.

#![cfg_attr(not(feature = "std"), no_std)]

use frame_support::traits::Get;
Expand Down Expand Up @@ -33,43 +52,58 @@ pub mod pallet {

#[pallet::config]
pub trait Config: frame_system::Config + pallet_inv4::Config + pallet_xcm::Config {
/// The overarching event type.
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;

/// Higher level type providing an abstraction over a chain's asset and location.
type Chains: ChainList;

/// Max length of an XCM call.
#[pallet::constant]
type MaxXCMCallLength: Get<u32>;

/// Origin that can set maintenance status.
type MaintenanceOrigin: EnsureOrigin<<Self as frame_system::Config>::RuntimeOrigin>;

/// Weight information for extrinsics in this pallet.
type WeightInfo: WeightInfo;
}

/// Maps chain's and their maintenance status.
#[pallet::storage]
#[pallet::getter(fn is_under_maintenance)]
pub type ChainsUnderMaintenance<T: Config> =
StorageMap<_, Blake2_128Concat, MultiLocation, bool>;

#[pallet::error]
pub enum Error<T> {
/// Failed to send XCM.
SendingFailed,
/// Weight exceeds `MaxXCMCallLength`.
WeightTooHigh,
/// Failed to calculate XCM fee.
FailedToCalculateXcmFee,
/// Failed to reanchor asset.
FailedToReanchorAsset,
/// Failed to invert location.
FailedToInvertLocation,
/// Asset is not supported in the destination chain.
DifferentChains,
/// Chain is under maintenance.
ChainUnderMaintenance,
}

#[pallet::event]
#[pallet::generate_deposit(fn deposit_event)]
pub enum Event<T: Config> {
/// A XCM call was sent.
CallSent {
sender: <T as pallet_inv4::Config>::CoreId,
destination: <T as pallet::Config>::Chains,
call: Vec<u8>,
},

/// Assets were transferred.
AssetsTransferred {
chain: <<<T as pallet::Config>::Chains as ChainList>::ChainAssets as ChainAssetsList>::Chains,
asset: <<T as pallet::Config>::Chains as ChainList>::ChainAssets,
Expand All @@ -78,13 +112,15 @@ pub mod pallet {
to: <T as frame_system::Config>::AccountId,
},

/// Assets were bridged.
AssetsBridged {
origin_chain_asset: <<T as pallet::Config>::Chains as ChainList>::ChainAssets,
amount: u128,
from: <T as pallet_inv4::Config>::CoreId,
to: <T as frame_system::Config>::AccountId,
},

/// A Chain's maintenance status changed.
ChainMaintenanceStatusChanged {
chain: <T as Config>::Chains,
under_maintenance: bool,
Expand All @@ -102,6 +138,12 @@ pub mod pallet {
[u8; 32]: From<<T as frame_system::Config>::AccountId>,
T::AccountId: From<[u8; 32]>,
{
/// Set the maintenance status of a chain.
///
/// The origin has to be `MaintenanceOrigin`.
///
/// - `chain`: referred chain.
/// - `under_maintenance`: maintenance status.
#[pallet::call_index(0)]
#[pallet::weight((<T as Config>::WeightInfo::set_maintenance_status(), Pays::No))]
pub fn set_maintenance_status(
Expand All @@ -121,6 +163,15 @@ pub mod pallet {
Ok(())
}

/// Send a XCM call to a destination chain.
///
/// The origin has to be a core.
///
/// - `destination`: destination chain.
/// - `weight`: weight of the call.
/// - `fee_asset`: asset used to pay the fee.
/// - `fee`: fee amount.
/// - `call`: XCM call.
#[pallet::call_index(1)]
#[pallet::weight(
<T as Config>::WeightInfo::send_call(call.len() as u32)
Expand Down Expand Up @@ -193,6 +244,17 @@ pub mod pallet {
Ok(())
}

/// Transfer fungible assets to another account in the destination chain.
///
/// Both asset and fee_asset have to be in the same chain.
///
/// The origin has to be a core.
///
/// - `asset`: asset to transfer.
/// - `amount`: amount to transfer.
/// - `to`: account receiving the asset.
/// - `fee_asset`: asset used to pay the fee.
/// - `fee`: fee amount.
#[pallet::call_index(2)]
#[pallet::weight(<T as Config>::WeightInfo::transfer_assets())]
pub fn transfer_assets(
Expand Down Expand Up @@ -283,6 +345,15 @@ pub mod pallet {
Ok(())
}

/// Bridge fungible assets to another chain.
///
/// The origin has to be a core.
///
/// - `asset`: asset to bridge and the chain to bridge from.
/// - `destination`: destination chain.
/// - `fee`: fee amount.
/// - `amount`: amount to bridge.
/// - `to`: account receiving the asset, None defaults to core account.
#[pallet::call_index(3)]
#[pallet::weight(<T as Config>::WeightInfo::bridge_assets())]
pub fn bridge_assets(
Expand Down Expand Up @@ -369,9 +440,11 @@ pub mod pallet {
None => core_multilocation,
};

// If the asset originates from the destination chain, we need to reverse the reserve-transfer.
let message = if asset_location.starts_with(&dest) {
Xcm(vec![
WithdrawAsset(vec![fee_multiasset.clone(), multiasset.clone()].into()),
// Core pays for the execution fee incurred on sending the XCM.
Instruction::BuyExecution {
fees: fee_multiasset,
weight_limit: WeightLimit::Unlimited,
Expand All @@ -380,6 +453,7 @@ pub mod pallet {
assets: multiasset.into(),
reserve: inverted_destination,
xcm: Xcm(vec![
// the beneficiary buys execution fee in the destination chain for the deposit.
Instruction::BuyExecution {
fees: reanchored_multiasset,
weight_limit: WeightLimit::Unlimited,
Expand All @@ -389,13 +463,15 @@ pub mod pallet {
beneficiary,
},
Instruction::RefundSurplus,
// Refunds the beneficiary the surplus of the execution fees in the destination chain.
Instruction::DepositAsset {
assets: All.into(),
beneficiary,
},
]),
},
Instruction::RefundSurplus,
// Refunds the core the surplus of the execution fees incurred on sending the XCM.
Instruction::DepositAsset {
assets: All.into(),
beneficiary: core_multilocation,
Expand Down
28 changes: 28 additions & 0 deletions pallet-rings/src/traits.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,51 @@
//! Provides supporting traits for the rings pallet.
//!
//! ## Overview
//!
//! This module contains the traits responsible for creating an abstraction layer on top of XCM [`MultiLocation`] and allows
//! easier handling of cross-chain transactions through XCM.
//!
//! The traits contained in this pallet require an appropriate runtime implementation.
//!
//! ## Traits overview:
//!
//! - [`ChainList`] - Trait used to opaquely refer to a chain, provides an interface to get the chain `MultiLocation` or the chain's main asset as `ChainAssetsList`.
//! - [`ChainAssetsList`] - Trait used to opaquely refer to a chain's asset, provides an interface to get the chain asset `MultiLocation` or the chain as `ChainList`.

use codec::MaxEncodedLen;
use frame_support::Parameter;
use xcm::latest::MultiLocation;

/// A chain [`MultiLocation`] abstraction trait.
///
/// It provides an interface for easily getting a chain's [`MultiLocation`] and to go back and forth between the chain and its assets.
///
/// This should be implemented properly in the runtime.
pub trait ChainList: Parameter + MaxEncodedLen {
type Balance: Into<u128>;
type ChainAssets: ChainAssetsList;

/// Returns the chain's [`MultiLocation`].
fn get_location(&self) -> MultiLocation;

/// Returns the chain's main asset as `ChainAssetsList`.
fn get_main_asset(&self) -> Self::ChainAssets;

#[cfg(feature = "runtime-benchmarks")]
fn benchmark_mock() -> Self;
}

/// A chain asset [`MultiLocation`] abstraction trait.
///
/// It provides an interface for easily getting a chain's asset [`MultiLocation`] and to go back and forth between the asset and its parent chain.
///
/// This should be implemented properly in the runtime.
pub trait ChainAssetsList: Parameter + MaxEncodedLen {
type Chains: ChainList;

/// Returns the asset's parent chain.
fn get_chain(&self) -> Self::Chains;

/// Returns the asset's [`MultiLocation`].
fn get_asset_location(&self) -> MultiLocation;
}

0 comments on commit 8f24d1d

Please sign in to comment.