Skip to content

Commit

Permalink
Migration pallet
Browse files Browse the repository at this point in the history
  • Loading branch information
olegnn committed Sep 12, 2024
1 parent 725ecb5 commit a7f5a51
Show file tree
Hide file tree
Showing 11 changed files with 601 additions and 9 deletions.
26 changes: 26 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ resolver = "2"
members = [
"node",
"pallets/agreement",
"pallets/cheqd-migration",
"pallets/poa",
"pallets/poa/rpc",
"pallets/token-migration",
Expand Down
8 changes: 2 additions & 6 deletions pallets/agreement/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,8 @@ std = [
"frame-support/std",
"frame-system/std",
"sp-std/std",
"frame-benchmarking/std",
"sp-runtime/std",
]
test = ["std"]
runtime-benchmarks = [
"frame-system-benchmarking",
"frame-benchmarking",
"frame-system/runtime-benchmarks",
"frame-support/runtime-benchmarks",
]
runtime-benchmarks = ["frame-benchmarking"]
98 changes: 98 additions & 0 deletions pallets/cheqd-migration/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
[package]
name = "dock-cheqd-migration"
version = "0.1.0"
authors = ["Dock.io"]
edition = "2021"
license = "Apache-2.0"

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies.bech32]
version = "0.11.0"
default-features = false
features = ["alloc"]

[dev-dependencies.pallet-balances]
default-features = false
git = "https://github.com/paritytech/substrate.git"
branch = "polkadot-v0.9.29"

[dependencies.scale-info-derive]
git = "https://github.com/docknetwork/scale-info.git"
branch = "master"

[dependencies.scale-info]
version = "2.1.2"
default-features = false
features = ["derive"]

[dependencies.codec]
default-features = false
features = ["derive"]
package = "parity-scale-codec"
version = "3.1.5"

[dependencies.serde]
features = ["derive"]
optional = true
version = "1.0.119"

[dependencies.frame-support]
default-features = false
# version = "3.0.0"
git = "https://github.com/paritytech/substrate.git"
branch = "polkadot-v0.9.29"

[dependencies.frame-system]
default-features = false
# version = "3.0.0"
git = "https://github.com/paritytech/substrate.git"
branch = "polkadot-v0.9.29"

[dependencies.sp-std]
default-features = false
# version = "3.0.0"
git = "https://github.com/paritytech/substrate.git"
branch = "polkadot-v0.9.29"

[dependencies.frame-benchmarking]
optional = true
default-features = false
# version = "3.0.0"
git = "https://github.com/paritytech/substrate.git"
branch = "polkadot-v0.9.29"

[dev-dependencies.sp-io]
default-features = false
# version = "3.0.0"
git = "https://github.com/paritytech/substrate.git"
branch = "polkadot-v0.9.29"

[dev-dependencies.sp-core]
default-features = false
# version = "3.0.0"
git = "https://github.com/paritytech/substrate.git"
branch = "polkadot-v0.9.29"

[dependencies.sp-runtime]
default-features = false
#version = "3.0.0"
git = "https://github.com/paritytech/substrate.git"
branch = "polkadot-v0.9.29"

[features]
default = ["std"]
std = [
"codec/std",
"serde",
"bech32/std",
"frame-support/std",
"frame-system/std",
"pallet-balances/std",
"sp-std/std",
"frame-benchmarking/std",
"sp-runtime/std",
]
test = ["std"]
runtime-benchmarks = ["frame-benchmarking"]
50 changes: 50 additions & 0 deletions pallets/cheqd-migration/src/benchmarks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use super::*;
use frame_benchmarking::{benchmarks, whitelisted_caller};
use frame_support::traits::{Currency, IsType};
use frame_system::{Pallet as System, RawOrigin};
use scale_info::prelude::string::ToString;
use sp_runtime::{traits::Zero, DispatchError};

fn assert_event<T: Config>(expected_event: impl Into<<T as pallet::Config>::Event>) {
let events = System::<T>::events();
let expected_event = expected_event.into();

assert!(events
.iter()
.any(|event| &event.event == expected_event.into_ref()));
}

benchmarks! {
migrate {
let destination = "cheqd1fktkf9nsj625jkxz7r7gmryna6uy8y2pptang4".to_string();
let caller: T::AccountId = whitelisted_caller();
T::Currency::make_free_balance_be(&caller, 100_000_000u32.into());
let dock_amount = T::Currency::free_balance(&caller);

}: _(RawOrigin::Signed(caller.clone()), destination.clone())
verify {
assert_event::<T>(Event::<T>::Migrated {
sender: caller.clone(),
cheqd_recipient: CheqdAddress::new::<T>(destination).unwrap(),
dock_amount,
});
assert!(
T::Currency::free_balance(&caller).is_zero()
);
}

migrate_validation_failure {
let destination = "cosmos12zddgw36trnvwm4s3x0etjd86r4lgqdthrzjdk".to_string();
let caller: T::AccountId = whitelisted_caller();
let dock_amount = T::Currency::free_balance(&caller);

}: {
Pallet::<T>::migrate(RawOrigin::Signed(caller.clone()).into(), destination.clone()).unwrap_err();
Ok::<_, DispatchError>(())
}
verify {
assert_eq!(
T::Currency::free_balance(&caller), dock_amount
);
}
}
125 changes: 125 additions & 0 deletions pallets/cheqd-migration/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
//! A pallet that facilitates the smooth transfer of `DOCK` tokens from the `Dock` Chain to `CHEQD` tokens on the `Cheqd` Chain.
#![cfg_attr(not(feature = "std"), no_std)]

use scale_info::prelude::string::String;

#[cfg(feature = "runtime-benchmarks")]
pub mod benchmarks;
#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;
mod weights;

// Re-export pallet items so that they can be accessed from the crate namespace.
pub use pallet::*;

use weights::{SubstrateWeight, WeightInfo};

#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::{
dispatch::WithPostDispatchInfo,
pallet_prelude::*,
traits::{Currency, ExistenceRequirement::AllowDeath},
};
use frame_system::pallet_prelude::*;
use sp_runtime::traits::Zero;

type BalanceOf<T> =
<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;

/// Address of the recipient on the `cheqd` side.
#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
#[derive(scale_info_derive::TypeInfo)]
#[scale_info(omit_prefix)]
pub struct CheqdAddress(String);

impl CheqdAddress {
pub fn new<T>(value: String) -> Result<Self, Error<T>> {
let (prefix, addr) =
bech32::decode(&value).map_err(|_| Error::<T>::AddressMustBeValidBech32)?;
ensure!(
prefix.as_str() == "cheqd",
Error::<T>::AddressMustStartWithCheqd
);
ensure!(addr.len() == 20, Error::<T>::InvalidAddressLength);

Ok(Self(value))
}
}

#[pallet::config]
pub trait Config: frame_system::Config {
/// The overarching event type.
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
/// The currency to be burnt during migration.
type Currency: Currency<Self::AccountId>;
/// Id of the recipient account on the dock side to send burnt funds.
type BurnDestination: Get<Self::AccountId>;
}

#[pallet::error]
pub enum Error<T> {
/// `cheqd` address must start with `cheqd` prefix.
AddressMustStartWithCheqd,
/// Provided `cheqd` address is invalid because it has an incorrect length.
InvalidAddressLength,
/// `cheqd` address part coming after `cheqd` must be a valid bech-32 sequence.
AddressMustBeValidBech32,
/// Caller account's balance is zero.
BalanceIsZero,
}

#[pallet::pallet]
pub struct Pallet<T>(_);

#[pallet::call]
impl<T: Config> Pallet<T> {
/// Burns the free `DOCK` balance of the sender and emits an event containing the supplied recipient `cheqd` address.
/// By submitting this transaction, you agree to the Terms and Conditions.
#[pallet::weight(SubstrateWeight::<T::DbWeight>::migrate())]
pub fn migrate(origin: OriginFor<T>, cheqd_address: String) -> DispatchResultWithPostInfo {
let sender = ensure_signed(origin)?;

let cheqd_recipient = CheqdAddress::new::<T>(cheqd_address)
.map_err(DispatchError::from)
.map_err(|error| {
error.with_weight(SubstrateWeight::<T::DbWeight>::migrate_validation_failure())
})?;

let dock_amount = T::Currency::free_balance(&sender);
ensure!(!dock_amount.is_zero(), Error::<T>::BalanceIsZero);

let dest = T::BurnDestination::get();
T::Currency::transfer(&sender, &dest, dock_amount, AllowDeath)?;

Self::deposit_event(Event::Migrated {
sender,
cheqd_recipient,
dock_amount,
});

Ok(Pays::Yes.into())
}
}

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// The corresponding amount of `DOCK` tokens was burned on the `Dock` Chain side, and an equivalent amount of `CHEQD` tokens will be issued to the specified address on the `cheqd` Chain side.
/// Terms and conditions were accepted by the sender.
Migrated {
/// The account whose funds were burnt on the `Dock` side.
sender: T::AccountId,
/// Recipient address on the `cheqd` side.
cheqd_recipient: CheqdAddress,
/// Amount of the burnt DOCK tokens.
dock_amount: BalanceOf<T>,
},
}
}
Loading

0 comments on commit a7f5a51

Please sign in to comment.