Skip to content

Commit

Permalink
Pallet for regulated assets support (#1044)
Browse files Browse the repository at this point in the history
  • Loading branch information
HaidarJbeily7 authored Jun 5, 2024
1 parent 6ac1313 commit c8780e1
Show file tree
Hide file tree
Showing 16 changed files with 1,230 additions and 3 deletions.
24 changes: 24 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 @@ -279,6 +279,7 @@ members = [
"pallets/kensetsu",
"pallets/band",
"pallets/qa-tools",
"pallets/regulated-assets",
"node/",
"utils/parse",
"utils/generate-bags",
Expand Down
4 changes: 2 additions & 2 deletions common/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,10 @@ macro_rules! mock_assets_config {
type GetBuyBackAccountId = GetBuyBackAccountId;
type GetBuyBackDexId = GetBuyBackDexId;
type BuyBackLiquidityProxy = ();
type Currency = currencies::Pallet<TestRuntime>;
type Currency = currencies::Pallet<$runtime>;
type GetTotalBalance = ();
type WeightInfo = ();
type AssetRegulator = permissions::Pallet<TestRuntime>;
type AssetRegulator = permissions::Pallet<$runtime>;
}
};
}
Expand Down
2 changes: 2 additions & 0 deletions common/src/permissions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ pub const UNLOCK_FROM_FARM: PermissionId = 13;
pub const CLAIM_FROM_FARM: PermissionId = 10;
pub const GET_FARM_INFO: PermissionId = 11;
pub const GET_FARMER_INFO: PermissionId = 12;
pub const ISSUE_SBT: PermissionId = 13;
pub const TRANSFER: PermissionId = 14;
12 changes: 12 additions & 0 deletions common/src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,12 @@ impl IsValid for AssetName {
}
}

impl MaxEncodedLen for AssetName {
fn max_encoded_len() -> usize {
ASSET_NAME_MAX_LENGTH
}
}

#[derive(
Encode,
Decode,
Expand Down Expand Up @@ -631,6 +637,12 @@ impl IsValid for Description {
}
}

impl MaxEncodedLen for Description {
fn max_encoded_len() -> usize {
ASSET_DESCRIPTION_MAX_LENGTH
}
}

#[derive(
Encode,
Decode,
Expand Down
1 change: 1 addition & 0 deletions common/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,7 @@ pub trait AssetManager<
+ MaybeSerializeDeserialize
+ Ord
+ Default
+ Clone
+ From<AssetId32<PredefinedAssetId>>
+ From<H256>
+ Into<H256>
Expand Down
3 changes: 2 additions & 1 deletion pallets/assets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ mod mock;
mod tests;

use codec::{Decode, Encode};
use common::permissions::{BURN, MINT};
use common::permissions::{BURN, MINT, TRANSFER};
use common::prelude::{Balance, SwapAmount};
use common::{
Amount, AssetInfoProvider, AssetManager, AssetName, AssetRegulator, AssetSymbol,
Expand Down Expand Up @@ -761,6 +761,7 @@ impl<T: Config> Pallet<T> {
to: &T::AccountId,
amount: Balance,
) -> DispatchResult {
T::AssetRegulator::check_permission(from, to, asset_id, &TRANSFER)?;
let r = T::Currency::transfer(*asset_id, from, to, amount);
if r.is_err() {
Self::ensure_asset_exists(asset_id)?;
Expand Down
4 changes: 4 additions & 0 deletions pallets/permissions/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
// TODO #167: fix clippy warnings
#![allow(clippy::all)]

use common::permissions::TRANSFER;
use common::{hash, AssetRegulator};
use frame_support::codec::{Decode, Encode};
use frame_support::sp_runtime::DispatchError;
Expand Down Expand Up @@ -382,6 +383,9 @@ impl<T: Config, AssetId: Encode> AssetRegulator<AccountIdOf<T>, AssetId> for Pal
if permission_id == &BURN && affected_account == issuer {
return Ok(());
}
if permission_id == &TRANSFER {
return Ok(());
}
Self::check_permission_with_scope(
issuer.clone(),
*permission_id,
Expand Down
64 changes: 64 additions & 0 deletions pallets/regulated-assets/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
[package]
authors = ["Polka Biome Ltd. <[email protected]>"]
license = "BSD-4-Clause"
homepage = "https://sora.org"
repository = "https://github.com/sora-xor/sora2-network"
edition = "2021"
name = "regulated-assets"
version = "1.0.0"

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

[dependencies]
codec = { package = "parity-scale-codec", version = "3", default-features = false, features = [
"derive",
] }
scale-info = { version = "2", default-features = false, features = ["derive"] }
frame-benchmarking = { git = "https://github.com/sora-xor/substrate.git", branch = "polkadot-v0.9.38", default-features = false, optional = true }
frame-support = { git = "https://github.com/sora-xor/substrate.git", branch = "polkadot-v0.9.38", default-features = false }
frame-system = { git = "https://github.com/sora-xor/substrate.git", branch = "polkadot-v0.9.38", default-features = false }
sp-std = { git = "https://github.com/sora-xor/substrate.git", branch = "polkadot-v0.9.38", default-features = false }
sp-core = { git = "https://github.com/sora-xor/substrate.git", branch = "polkadot-v0.9.38", default-features = false }
hex-literal = { version = "0.4.1", optional = true }

common = { path = "../../common", default-features = false }
permissions = { path = "../permissions", default-features = false }
technical = { path = "../technical", default-features = false }

[dev-dependencies]
sp-io = { git = "https://github.com/sora-xor/substrate.git", branch = "polkadot-v0.9.38", default-features = false }
sp-runtime = { git = "https://github.com/sora-xor/substrate.git", branch = "polkadot-v0.9.38", default-features = false }
pallet-balances = { git = "https://github.com/sora-xor/substrate.git", branch = "polkadot-v0.9.38" }
currencies = { git = "https://github.com/open-web3-stack/open-runtime-module-library.git", package = "orml-currencies" }
tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library.git", package = "orml-tokens", default-features = false }
hex-literal = { version = "0.4.1"}
common = { path = "../../common", features = ['test']}
assets = { path = "../assets" }
permissions = { path = "../permissions" }
technical = { path = "../technical" }

[features]
default = ["std"]

std = [
"scale-info/std",
"frame-support/std",
"frame-benchmarking/std",
"frame-system/std",
"sp-core/std",
"sp-std/std",
]

runtime-benchmarks = [
"frame-benchmarking",
"frame-system/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"hex-literal",
]

try-runtime = [
"frame-support/try-runtime",
]

wip = []
137 changes: 137 additions & 0 deletions pallets/regulated-assets/src/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// This file is part of the SORA network and Polkaswap app.

// Copyright (c) 2020, 2021, Polka Biome Ltd. All rights reserved.
// SPDX-License-Identifier: BSD-4-Clause

// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:

// Redistributions of source code must retain the above copyright notice, this list
// of conditions and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright notice, this
// list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// All advertising materials mentioning features or use of this software must display
// the following acknowledgement: This product includes software developed by Polka Biome
// Ltd., SORA, and Polkaswap.
//
// Neither the name of the Polka Biome Ltd. nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission.

// THIS SOFTWARE IS PROVIDED BY Polka Biome Ltd. AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Polka Biome Ltd. BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

//! Regulated Assets module benchmarking.
#![cfg(feature = "runtime-benchmarks")]
#![cfg(feature = "wip")] // DEFI-R

use codec::Decode;
use frame_benchmarking::benchmarks;
use frame_system::EventRecord;
use frame_system::RawOrigin;
use hex_literal::hex;
use sp_std::prelude::*;

use super::*;

use common::{AssetManager, AssetName, AssetSymbol, Balance, DEFAULT_BALANCE_PRECISION};

// Support Functions
fn asset_owner<T: Config>() -> T::AccountId {
let bytes = hex!("d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d");
T::AccountId::decode(&mut &bytes[..]).expect("Failed to decode account ID")
}

fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
let events = frame_system::Pallet::<T>::events();
let system_event: <T as frame_system::Config>::RuntimeEvent = generic_event.into();
// compare to the last event record
let EventRecord { event, .. } = &events[events.len() - 1];
assert_eq!(event, &system_event);
}

fn add_asset<T: Config>() -> AssetIdOf<T> {
let owner = asset_owner::<T>();
frame_system::Pallet::<T>::inc_providers(&owner);

T::AssetManager::register_from(
&owner,
AssetSymbol(b"TOKEN".to_vec()),
AssetName(b"TOKEN".to_vec()),
DEFAULT_BALANCE_PRECISION,
Balance::from(0u32),
true,
None,
None,
)
.expect("Failed to register asset")
}

fn assign_issue_sbt_permission<T: Config>(owner: T::AccountId, holder: T::AccountId) {
frame_system::Pallet::<T>::inc_providers(&owner);
permissions::Pallet::<T>::assign_permission(
owner,
&holder,
common::permissions::ISSUE_SBT,
permissions::Scope::Unlimited,
)
.unwrap();
}

benchmarks! {
regulate_asset {
let owner = asset_owner::<T>();
let owner_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(owner).into();
let asset_id = add_asset::<T>();
}: {
Pallet::<T>::regulate_asset(owner_origin, asset_id).unwrap();
}
verify{
assert_last_event::<T>(Event::AssetRegulated{
asset_id
}.into()
);
}

issue_sbt{
let owner = asset_owner::<T>();
assign_issue_sbt_permission::<T>(owner.clone(), owner.clone());
let owner_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(owner).into();
let asset_id = add_asset::<T>();
let asset_name = AssetName(b"Soulbound Token".to_vec());
let asset_symbol = AssetSymbol(b"SBT".to_vec());
let bounded_vec_assets = BoundedVec::try_from(vec![asset_id]).unwrap();
}: {
Pallet::<T>::issue_sbt(
owner_origin,
asset_symbol,
asset_name.clone(),
bounded_vec_assets.clone(),
None
).unwrap();
}
verify{
let sbts = Pallet::<T>::sbts_by_asset(asset_id);
let sbt_asset_id = sbts.first().ok_or("No SBT asset found").unwrap();

assert_last_event::<T>(Event::SoulboundTokenIssued {
asset_id: *sbt_asset_id,
owner: asset_owner::<T>(),
allowed_assets: vec![asset_id]
}.into()
);
}

impl_benchmark_test_suite!(
Pallet,
crate::mock::new_test_ext(),
crate::mock::TestRuntime
);
}
Loading

0 comments on commit c8780e1

Please sign in to comment.