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

New asset system - Separate asset types and add pallet-assets instances to runtime #1177

Merged
merged 14 commits into from
Dec 22, 2023
18 changes: 18 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 @@ -161,6 +161,7 @@ frame-system-benchmarking = { git = "https://github.com/paritytech/substrate", b
frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false }
frame-try-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false }
pallet-asset-tx-payment = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false }
pallet-assets = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false }
pallet-aura = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false }
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false }
pallet-bounties = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false }
Expand Down
21 changes: 21 additions & 0 deletions primitives/src/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ use scale_info::TypeInfo;
/// The `Asset` enum represents all types of assets available in the Zeitgeist
/// system.
///
/// **Deprecated:** Market and Pool assets are "lazy" migrated to pallet-assets
/// Do not create any new market or pool assets using this enumeration.
///
/// # Types
///
/// * `MI`: Market Id
Expand Down Expand Up @@ -53,6 +56,24 @@ pub enum Asset<MI: MaxEncodedLen> {
ParimutuelShare(MI, CategoryIndex),
}

/// The `MarketAsset` enum represents all types of assets available in the
/// Prediction Market protocol
sea212 marked this conversation as resolved.
Show resolved Hide resolved
///
/// # Types
///
/// * `MI`: Market Id
#[cfg_attr(feature = "std", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[derive(Clone, Copy, Debug, Decode, Default, Eq, Encode, MaxEncodedLen, PartialEq, TypeInfo)]
pub enum PredictionMarketAsset<MI: MaxEncodedLen> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub enum PredictionMarketAsset<MI: MaxEncodedLen> {
pub enum PredictionMarketAsset<MI> {

Not sure if that's a good idea, but I don't think we need this requirement here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it's for convenience?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will need that for MaxEncodedLen implementation for the Pool struct.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I think we can get rid of this after merging #1197

CategoricalOutcome(MI, CategoryIndex),
#[default]
CombinatorialOutcome,
maltekliemann marked this conversation as resolved.
Show resolved Hide resolved
ScalarOutcome(MI, ScalarPosition),
ParimutuelShare(MI, CategoryIndex),
PoolShare(PoolId),
}

/// In a scalar market, users can either choose a `Long` position,
/// meaning that they think the outcome will be closer to the upper bound
/// or a `Short` position meaning that they think the outcome will be closer
Expand Down
7 changes: 7 additions & 0 deletions primitives/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,15 @@ impl<'a> Arbitrary<'a> for MultiHash {
/// ORML adapter
pub type BasicCurrencyAdapter<R, B> = orml_currencies::BasicCurrencyAdapter<R, B, Amount, Balance>;

/// ID type for any asset class
pub type CurrencyId = Asset<MarketId>;

// ID type for asset classes that anyone can create
pub type AssetId = u128;

// ID type for the asset classes are used within the prediction market protocol
pub type MarketAsset = PredictionMarketAsset<MarketId>;
sea212 marked this conversation as resolved.
Show resolved Hide resolved

/// The asset id specifically used for pallet_assets_tx_payment for
/// paying transaction fees in different assets.
/// Since the polkadot extension and wallets can't handle custom asset ids other than just u32,
Expand Down
4 changes: 4 additions & 0 deletions runtime/battery-station/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ orml-currencies = { workspace = true }
orml-tokens = { workspace = true }
orml-traits = { workspace = true }
pallet-asset-tx-payment = { workspace = true }
pallet-assets = { workspace = true }
pallet-balances = { workspace = true }
pallet-bounties = { workspace = true }
pallet-collective = { workspace = true }
Expand Down Expand Up @@ -182,6 +183,7 @@ runtime-benchmarks = [
"orml-benchmarking",
"orml-tokens/runtime-benchmarks",
"orml-xtokens?/runtime-benchmarks",
"pallet-assets/runtime-benchmarks",
"pallet-author-inherent?/runtime-benchmarks",
"pallet-author-mapping?/runtime-benchmarks",
"pallet-author-slot-filter?/runtime-benchmarks",
Expand Down Expand Up @@ -231,6 +233,7 @@ std = [
"orml-currencies/std",
"orml-tokens/std",
"orml-traits/std",
"pallet-assets/std",
"pallet-asset-tx-payment/std",
"pallet-balances/std",
"pallet-bounties/std",
Expand Down Expand Up @@ -352,6 +355,7 @@ try-runtime = [
"pallet-preimage/try-runtime",

# Money runtime pallets
"pallet-assets/try-runtime",
"pallet-asset-tx-payment/try-runtime",
"pallet-balances/try-runtime",
"pallet-bounties/try-runtime",
Expand Down
12 changes: 8 additions & 4 deletions runtime/battery-station/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use common_runtime::{
};
pub use frame_system::{
Call as SystemCall, CheckEra, CheckGenesis, CheckNonZeroSender, CheckNonce, CheckSpecVersion,
CheckTxVersion, CheckWeight,
CheckTxVersion, CheckWeight, EnsureNever,
};
#[cfg(feature = "parachain")]
pub use pallet_author_slot_filter::EligibilityValue;
Expand All @@ -42,12 +42,16 @@ pub use crate::parachain_params::*;
pub use crate::parameters::*;
use alloc::vec;
use frame_support::{
traits::{ConstU32, Contains, EitherOfDiverse, EqualPrivilegeOnly, InstanceFilter},
traits::{
AsEnsureOriginWithArg, ConstU32, Contains, EitherOfDiverse, EqualPrivilegeOnly,
InstanceFilter,
},
weights::{constants::RocksDbWeight, ConstantMultiplier, IdentityFee, Weight},
};
use frame_system::{EnsureRoot, EnsureWithSuccess};
use frame_system::{EnsureRoot, EnsureSigned, EnsureWithSuccess};
use orml_currencies::Call::transfer;
use pallet_collective::{EnsureProportionAtLeast, PrimeDefaultVote};
use parity_scale_codec::Compact;
use sp_runtime::traits::{AccountIdConversion, AccountIdLookup, BlakeTwo256};
#[cfg(feature = "std")]
use sp_version::NativeVersion;
Expand All @@ -66,7 +70,7 @@ use zrml_swaps::Call::{
};
#[cfg(feature = "parachain")]
use {
frame_support::traits::{AsEnsureOriginWithArg, Everything, Nothing},
frame_support::traits::{Everything, Nothing},
xcm_builder::{EnsureXcmOrigin, FixedWeightBounds},
xcm_config::{
asset_registry::CustomAssetProcessor,
Expand Down
32 changes: 32 additions & 0 deletions runtime/battery-station/src/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,38 @@ parameter_types! {
}

parameter_types! {
// Assets (Campaign)
pub const CampaignAssetsAccountDeposit: Balance = deposit(1, 16);
pub const CampaignAssetsApprovalDeposit: Balance = ExistentialDeposit::get();
/// The amount of native currency that is frozen during the whole lifetime
/// if an asset class. Freezing happens at asset class creation.
/// Irrelevant - No origin can successfully call the associated dispatchable call..
sea212 marked this conversation as resolved.
Show resolved Hide resolved
pub const CampaignAssetsDeposit: Balance = BASE;
pub const CampaignAssetsStringLimit: u32 = 256;
pub const CampaignAssetsMetadataDepositBase: Balance = deposit(1, 68);
pub const CampaignAssetsMetadataDepositPerByte: Balance = deposit(0, 1);

// Assets (Custom)
pub const CustomAssetsAccountDeposit: Balance = deposit(1, 16);
pub const CustomAssetsApprovalDeposit: Balance = ExistentialDeposit::get();
/// The amount of native currency that is frozen during the whole lifetime
/// if an asset class. Freezing happens at asset class creation.
sea212 marked this conversation as resolved.
Show resolved Hide resolved
pub const CustomAssetsDeposit: Balance = BASE;
pub const CustomAssetsStringLimit: u32 = 50;
pub const CustomAssetsMetadataDepositBase: Balance = deposit(1, 68);
pub const CustomAssetsMetadataDepositPerByte: Balance = deposit(0, 1);

// Assets (Market)
pub const MarketAssetsAccountDeposit: Balance = deposit(1, 16);
pub const MarketAssetsApprovalDeposit: Balance = ExistentialDeposit::get();
/// The amount of native currency that is frozen during the whole lifetime
/// if an asset class. Freezing happens at asset class creation.
sea212 marked this conversation as resolved.
Show resolved Hide resolved
/// Irrelevant - No origin can successfully call the associated dispatchable call.
pub const MarketAssetsDeposit: Balance = BASE;
pub const MarketAssetsStringLimit: u32 = 50;
pub const MarketAssetsMetadataDepositBase: Balance = deposit(1, 68);
pub const MarketAssetsMetadataDepositPerByte: Balance = deposit(0, 1);

// Authorized
pub const AuthorizedPalletId: PalletId = AUTHORIZED_PALLET_ID;
pub const CorrectionPeriod: BlockNumber = BLOCKS_PER_DAY;
Expand Down
2 changes: 2 additions & 0 deletions runtime/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ frame-system = { workspace = true }
orml-currencies = { workspace = true }
orml-tokens = { workspace = true }
pallet-asset-tx-payment = { workspace = true }
pallet-assets = { workspace = true }
pallet-author-inherent = { workspace = true, optional = true }
pallet-author-mapping = { workspace = true, optional = true }
pallet-author-slot-filter = { workspace = true, optional = true }
Expand Down Expand Up @@ -49,6 +50,7 @@ std = [
"frame-support/std",
"orml-currencies/std",
"orml-tokens/std",
"pallet-assets/std",
"pallet-asset-tx-payment/std",
"pallet-author-inherent?/std",
"pallet-author-mapping?/std",
Expand Down
114 changes: 114 additions & 0 deletions runtime/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ macro_rules! decl_common_types {
pub type UncheckedExtrinsic =
generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;

// Asset instances
type CustomAssetsInstance = pallet_assets::Instance1;
type CampaignAssetsInstance = pallet_assets::Instance2;
type MarketAssetsInstance = pallet_assets::Instance3;

// Governance
type AdvisoryCommitteeInstance = pallet_collective::Instance1;
type AdvisoryCommitteeMembershipInstance = pallet_membership::Instance1;
Expand Down Expand Up @@ -284,6 +289,9 @@ macro_rules! create_runtime {
Multisig: pallet_multisig::{Call, Event<T>, Pallet, Storage} = 14,
Bounties: pallet_bounties::{Call, Event<T>, Pallet, Storage} = 15,
AssetTxPayment: pallet_asset_tx_payment::{Event<T>, Pallet} = 16,
Assets: pallet_assets::<Instance1>::{Call, Pallet, Storage, Event<T>} = 17,
CampaignAssets: pallet_assets::<Instance2>::{Call, Pallet, Storage, Event<T>} = 18,
MarketAssets: pallet_assets::<Instance3>::{Call, Pallet, Storage, Event<T>} = 19,

// Governance
Democracy: pallet_democracy::{Pallet, Call, Storage, Config<T>, Event<T>} = 20,
sea212 marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -625,6 +633,110 @@ macro_rules! impl_config_traits {
type XcmExecutor = xcm_executor::XcmExecutor<XcmConfig>;
}

// Required for runtime benchmarks
pallet_assets::runtime_benchmarks_enabled! {
pub struct CustomAssetsBenchmarkHelper;

impl<AssetIdParameter> pallet_assets::BenchmarkHelper<AssetIdParameter>
for CustomAssetsBenchmarkHelper
where
AssetIdParameter: From<u128>,
{
fn create_asset_id_parameter(id: u32) -> AssetIdParameter {
(id as u128).into()
}
}
}

impl pallet_assets::Config<CustomAssetsInstance> for Runtime {
type ApprovalDeposit = CustomAssetsApprovalDeposit;
type AssetAccountDeposit = CustomAssetsAccountDeposit;
type AssetDeposit = CustomAssetsDeposit;
type AssetId = AssetId;
type AssetIdParameter = Compact<AssetId>;
type Balance = Balance;
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper = CustomAssetsBenchmarkHelper;
type CallbackHandle = ();
type CreateOrigin = AsEnsureOriginWithArg<EnsureSigned<AccountId>>;
type Currency = Balances;
type Extra = ();
type ForceOrigin = EnsureRootOrTwoThirdsTechnicalCommittee;
type Freezer = ();
type MetadataDepositBase = CustomAssetsMetadataDepositBase;
type MetadataDepositPerByte = CustomAssetsMetadataDepositPerByte;
// TODO(#1176): Figure out sensible number after benchmark on reference machine
type RemoveItemsLimit = ConstU32<{ 50 }>;
type RuntimeEvent = RuntimeEvent;
type StringLimit = CustomAssetsStringLimit;
type WeightInfo = weights::pallet_assets::WeightInfo<Runtime>;
}

impl pallet_assets::Config<CampaignAssetsInstance> for Runtime {
type ApprovalDeposit = CampaignAssetsApprovalDeposit;
type AssetAccountDeposit = CampaignAssetsAccountDeposit;
type AssetDeposit = CampaignAssetsDeposit;
type AssetId = AssetId;
type AssetIdParameter = Compact<AssetId>;
type Balance = Balance;
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper = CustomAssetsBenchmarkHelper;
type CallbackHandle = ();
type CreateOrigin = AsEnsureOriginWithArg<EnsureNever<AccountId>>;
type Currency = Balances;
type Extra = ();
type ForceOrigin = EitherOfDiverse<
EnsureRootOrTwoThirdsCouncil,
EnsureRootOrAllTechnicalCommittee,
>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should use the same ForceOrigin for all pallets. The distinction between Council and Tech Comm isn't there right now anyways.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree for the following reasons:

  1. The CampaignAsset class is much more powerful, as it allows to spawn assets that can be used to pay transaction fees. Thus it should require at least higher privileges than other asset classes to be created.
  2. There are distinctions:
    a. While other asset classes use the ForceOrigin solely to technically correct faults, the CampaignAsset class uses the ForceOrigin to realize business decisions (pushing into directions by utilizing campaigns)
    b. The Council is different from the Technical Committee (TC), even on Zeitgeist. In contrast to the TC, the Council contains all members of the executive. Currently the Council consists of 5 members, with an required agreement from the Council of at least 2/3 to spawn campaign assets, at least two members of the executive have to agree, thus also mapping agreement within the executive of Zeitgeist to move forward with campaigns.

I decided to add the TC to allow assistance in regards to technical aspects, such as cleaning up campaign assets after a campaign is over. However, I think granting the (complete) TC the ForceOrigin power invalidates my second argument. I am leaning towards removing the TC completely from the ForceOrigin of the CampaignAsset class. What's your opinion?

This makes me think about point 1. though. The MarketAssets have the ForceOrigin TwoThirdsOrTechnicalCommittee. Obviously MarketAssets have an even more tangible value. MarketAssets should never be managed directly as the pallets control the whole lifecycle of market assets such as outcome tokens or pool shares. I added this because I wanted to give the TC the opportunity to hotfix some inconsistent states introduced by pallets. Thinking more about it though, I think the TC should not have the power to manage market assets. What's your opinion?

Makes me also question right now if it makes sense at all to add the TC to any ForceOrigin, including CustomAssets. After all, with the help of the Council the TC is capable of spawning a referendum with a short period until dispatch.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm okay with all of these options. As long as there are no elections, I don't see any difference between the Council and TC. In the long run (assuming elections take place), I'd prefer if the TC did not have control over market assets. This is based on the assumption that until then, all bugs will have been fixed or can be fixed by governance rather than TC intervention.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make more sense like this: a86c36a

Idea: Still convinced about at least 2/3 Council for CampaignAssets, full tech committee for MarketAssets (due to the potential impact) and 2/3 technical committee for CustomAssets.

type Freezer = ();
type MetadataDepositBase = CampaignAssetsMetadataDepositBase;
type MetadataDepositPerByte = CampaignAssetsMetadataDepositPerByte;
// TODO(#1176): Figure out sensible number after benchmark on reference machine
type RemoveItemsLimit = ConstU32<{ 50 }>;
type RuntimeEvent = RuntimeEvent;
type StringLimit = CampaignAssetsStringLimit;
type WeightInfo = weights::pallet_assets::WeightInfo<Runtime>;
}

// Required for runtime benchmarks
pallet_assets::runtime_benchmarks_enabled! {
pub struct MarketAssetsBenchmarkHelper;

impl pallet_assets::BenchmarkHelper<MarketAsset>
for MarketAssetsBenchmarkHelper
{
fn create_asset_id_parameter(id: u32) -> MarketAsset {
MarketAsset::CategoricalOutcome(0, id as CategoryIndex)
}
}
}

impl pallet_assets::Config<MarketAssetsInstance> for Runtime {
type ApprovalDeposit = MarketAssetsApprovalDeposit;
type AssetAccountDeposit = MarketAssetsAccountDeposit;
type AssetDeposit = MarketAssetsDeposit;
type AssetId = MarketAsset;
type AssetIdParameter = MarketAsset;
type Balance = Balance;
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper = MarketAssetsBenchmarkHelper;
type CallbackHandle = ();
type CreateOrigin = AsEnsureOriginWithArg<EnsureNever<AccountId>>;
type Currency = Balances;
type Extra = ();
type ForceOrigin = EnsureRootOrTwoThirdsTechnicalCommittee;
type Freezer = ();
type MetadataDepositBase = MarketAssetsMetadataDepositBase;
type MetadataDepositPerByte = MarketAssetsMetadataDepositPerByte;
// TODO(#1176): Figure out sensible number after benchmark on reference machine
type RemoveItemsLimit = ConstU32<{ 50 }>;
sea212 marked this conversation as resolved.
Show resolved Hide resolved
type RuntimeEvent = RuntimeEvent;
type StringLimit = MarketAssetsStringLimit;
type WeightInfo = weights::pallet_assets::WeightInfo<Runtime>;
}


impl pallet_balances::Config for Runtime {
type AccountStore = System;
type Balance = Balance;
Expand Down Expand Up @@ -1372,6 +1484,7 @@ macro_rules! create_runtime_api {
list_benchmark!(list, extra, frame_system, SystemBench::<Runtime>);
orml_list_benchmark!(list, extra, orml_currencies, crate::benchmarks::currencies);
orml_list_benchmark!(list, extra, orml_tokens, crate::benchmarks::tokens);
list_benchmark!(list, extra, pallet_assets, Assets);
list_benchmark!(list, extra, pallet_balances, Balances);
list_benchmark!(list, extra, pallet_bounties, Bounties);
list_benchmark!(list, extra, pallet_collective, AdvisoryCommittee);
Expand Down Expand Up @@ -1476,6 +1589,7 @@ macro_rules! create_runtime_api {
add_benchmark!(params, batches, frame_system, SystemBench::<Runtime>);
orml_add_benchmark!(params, batches, orml_currencies, crate::benchmarks::currencies);
orml_add_benchmark!(params, batches, orml_tokens, crate::benchmarks::tokens);
add_benchmark!(params, batches, pallet_assets, Assets);
add_benchmark!(params, batches, pallet_balances, Balances);
add_benchmark!(params, batches, pallet_bounties, Bounties);
add_benchmark!(params, batches, pallet_collective, AdvisoryCommittee);
Expand Down
1 change: 1 addition & 0 deletions runtime/common/src/weights/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ cfg_if::cfg_if! {
pub mod frame_system;
pub mod orml_currencies;
pub mod orml_tokens;
pub mod pallet_assets;
pub mod pallet_balances;
pub mod pallet_bounties;
pub mod pallet_collective;
Expand Down
Loading
Loading