From df5d1d9b396a531063698fe3704baaf27e7d48e9 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 29 Aug 2024 13:46:47 +0800 Subject: [PATCH 001/215] temp: temporary stash submit --- pallets/collab-ai/aiusd-convertor/Cargo.toml | 45 + pallets/collab-ai/aiusd-convertor/src/lib.rs | 101 ++ .../collab-ai/candidate-preimage/Cargo.toml | 0 .../collab-ai/candidate-preimage/src/lib.rs | 0 pallets/collab-ai/curator/Cargo.toml | 51 + pallets/collab-ai/curator/src/lib.rs | 1610 +++++++++++++++++ 6 files changed, 1807 insertions(+) create mode 100644 pallets/collab-ai/aiusd-convertor/Cargo.toml create mode 100644 pallets/collab-ai/aiusd-convertor/src/lib.rs create mode 100644 pallets/collab-ai/candidate-preimage/Cargo.toml create mode 100644 pallets/collab-ai/candidate-preimage/src/lib.rs create mode 100644 pallets/collab-ai/curator/Cargo.toml create mode 100644 pallets/collab-ai/curator/src/lib.rs diff --git a/pallets/collab-ai/aiusd-convertor/Cargo.toml b/pallets/collab-ai/aiusd-convertor/Cargo.toml new file mode 100644 index 0000000000..c061e8823e --- /dev/null +++ b/pallets/collab-ai/aiusd-convertor/Cargo.toml @@ -0,0 +1,45 @@ +[package] +authors = ['Trust Computing GmbH '] +description = 'Pallet for converting among AIUSD and other stable token' +edition = '2021' +homepage = 'https://litentry.com/' +license = 'GPL-3.0' +name = 'pallet-aiusd-convertor' +repository = 'https://github.com/litentry/litentry-parachain' +version = '0.1.0' + +[dependencies] +hex-literal = { workspace = true } +parity-scale-codec = { workspace = true } +scale-info = { workspace = true } + +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-assets = { workspace = true } +pallet-balances = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +[features] +default = ["std"] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", +] +std = [ + "parity-scale-codec/std", + "scale-info/std", + "sp-std/std", + "sp-runtime/std", + "sp-io/std", + "sp-core/std", + "frame-support/std", + "frame-system/std", + "pallet-assets/std", + "pallet-balances/std", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/collab-ai/aiusd-convertor/src/lib.rs b/pallets/collab-ai/aiusd-convertor/src/lib.rs new file mode 100644 index 0000000000..58a7b94b22 --- /dev/null +++ b/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -0,0 +1,101 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +//! Pallet for converting among AIUSD and other stable token. +//! +#![cfg_attr(not(feature = "std"), no_std)] + + + + +#[frame_support::pallet] +pub mod pallet { + use super::*; + type AssetId = ::AssetId; + + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + pallet_assets::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + // This is not a treasury account + // Balance of all types in this account will be distributed to user + // who help even the distribution of stable token + type ConvertingFeeAccount = Get; + + // Declare the asset id of AIUSD + type AIUSDAssetId = Get; + } + + #[pallet::storage] + #[pallet::getter(fn reward_pools)] + pub type CumulatedFee = + StorageMap<_, Blake2_128Concat, T::EVMId, T::AccountId, OptionQuery>; + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(W{195_000_000})] + pub fn switch_token( + origin: OriginFor, + consumed_asset_id: AssetId, + target_asset_id: AssetId, + ) -> DispatchResultWithPostInfo { + let _ = T::IncConsumerOrigin::ensure_origin(origin)?; + for i in &who { + frame_system::Pallet::::inc_consumers(i)?; + } + Ok(()) + } + + /// Enable a specific type of token available for switching + #[pallet::call_index(1)] + #[pallet::weight({195_000_000})] + pub fn enable_token( + origin: OriginFor, + + ) -> DispatchResultWithPostInfo { + + } + + /// pause the switch of a specific type of token + #[pallet::call_index(2)] + #[pallet::weight({195_000_000})] + pub fn pause_token( + origin: OriginFor, + + ) -> DispatchResultWithPostInfo { + + } + + /// unpause the switch of a specific type of token + #[pallet::call_index(3)] + #[pallet::weight({195_000_000})] + pub fn unpause_token( + origin: OriginFor, + + ) -> DispatchResultWithPostInfo { + + } + } +} diff --git a/pallets/collab-ai/candidate-preimage/Cargo.toml b/pallets/collab-ai/candidate-preimage/Cargo.toml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pallets/collab-ai/candidate-preimage/src/lib.rs b/pallets/collab-ai/candidate-preimage/src/lib.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pallets/collab-ai/curator/Cargo.toml b/pallets/collab-ai/curator/Cargo.toml new file mode 100644 index 0000000000..a0b37e8fc0 --- /dev/null +++ b/pallets/collab-ai/curator/Cargo.toml @@ -0,0 +1,51 @@ +[package] +authors = ['Litentry Dev'] +description = 'Pallet for managing Curator and pool proposal' +edition = '2021' +homepage = 'https://litentry.com/' +license = 'GPL-3.0' +name = 'pallet-evm-address' +repository = 'https://github.com/litentry/litentry-parachain' +version = '0.1.0' + +[dependencies] +parity-scale-codec = { workspace = true } +scale-info = { workspace = true } + +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +[dev-dependencies] +hex-literal = { workspace = true } +sp-core = { workspace = true, features = ["std"] } +sp-io = { workspace = true, features = ["std"] } +pallet-balances = { workspace = true, features = ["std"] } +pallet-timestamp = { workspace = true, features = ["std"] } + +[features] +default = ["std"] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-ethereum/runtime-benchmarks", +] +std = [ + "parity-scale-codec/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-std/std", + "sp-io/std", + "sp-core/std", + "sp-runtime/std", + "frame-support/std", + "frame-system/std", + "pallet-balances/std", + "pallet-timestamp/std", + "pallet-ethereum/std", + "pallet-evm/std", + "fp-evm/std", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/collab-ai/curator/src/lib.rs b/pallets/collab-ai/curator/src/lib.rs new file mode 100644 index 0000000000..d46030b609 --- /dev/null +++ b/pallets/collab-ai/curator/src/lib.rs @@ -0,0 +1,1610 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . +// +//! # Curator Pallet +//! +//! - [`Config`] +//! - [`Call`] +//! +//! ## Overview +//! +//! The Curator pallet handles the administration of general curator and proposed staking pool. +//! +//! +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::{Decode, Encode}; +use frame_support::{ + ensure, + error::BadOrigin, + traits::{ + defensive_prelude::*, + schedule::{v3::Named as ScheduleNamed, DispatchTime}, + Bounded, Currency, EnsureOrigin, Get, Hash as PreimageHash, LockIdentifier, + LockableCurrency, OnUnbalanced, QueryPreimage, ReservableCurrency, StorePreimage, + WithdrawReasons, + }, + weights::Weight, +}; +use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; + +pub use pallet::*; + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + +type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; +type NegativeImbalanceOf = <::Currency as Currency< + ::AccountId, +>>::NegativeImbalance; +pub type CallOf = ::RuntimeCall; +pub type BoundedCallOf = Bounded>; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + +#[frame_support::pallet] +pub mod pallet { + use super::{DispatchResult, *}; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + use sp_core::H256; + + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + Sized { + type WeightInfo: WeightInfo; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The Scheduler. + type Scheduler: ScheduleNamed, CallOf, Self::PalletsOrigin>; + + /// The Legal file storage + type FileStorage: QueryPreimage + StorePreimage; + + /// Currency type for this pallet. + type Currency: ReservableCurrency + + LockableCurrency>; + + /// The period between a proposal being approved and enacted. + /// + /// It should generally be a little more than the unstake period to ensure that + /// voting stakers have an opportunity to remove themselves from the system in the case + /// where they are on the losing side of a vote. + #[pallet::constant] + type EnactmentPeriod: Get>; + + /// How often (in blocks) new public referenda are launched. + #[pallet::constant] + type LaunchPeriod: Get>; + + /// How often (in blocks) to check for new votes. + #[pallet::constant] + type VotingPeriod: Get>; + + /// The minimum period of vote locking. + /// + /// It should be no shorter than enactment period to ensure that in the case of an approval, + /// those successful voters are locked into the consequences that their votes entail. + #[pallet::constant] + type VoteLockingPeriod: Get>; + + /// The minimum amount to be used as a deposit for a public referendum proposal. + #[pallet::constant] + type MinimumDeposit: Get>; + + /// Indicator for whether an emergency origin is even allowed to happen. Some chains may + /// want to set this permanently to `false`, others may want to condition it on things such + /// as an upgrade having happened recently. + #[pallet::constant] + type InstantAllowed: Get; + + /// Minimum voting period allowed for a fast-track referendum. + #[pallet::constant] + type FastTrackVotingPeriod: Get>; + + /// Period in blocks where an external proposal may not be re-submitted after being vetoed. + #[pallet::constant] + type CooloffPeriod: Get>; + + /// The maximum number of votes for an account. + /// + /// Also used to compute weight, an overly big value can + /// lead to extrinsic with very big weight: see `delegate` for instance. + #[pallet::constant] + type MaxVotes: Get; + + /// The maximum number of public proposals that can exist at any time. + #[pallet::constant] + type MaxProposals: Get; + + /// The maximum number of deposits a public proposal may have at any time. + #[pallet::constant] + type MaxDeposits: Get; + + /// The maximum number of items which can be blacklisted. + #[pallet::constant] + type MaxBlacklisted: Get; + + /// Origin from which the next tabled referendum may be forced. This is a normal + /// "super-majority-required" referendum. + type ExternalOrigin: EnsureOrigin; + + /// Origin from which the next tabled referendum may be forced; this allows for the tabling + /// of a majority-carries referendum. + type ExternalMajorityOrigin: EnsureOrigin; + + /// Origin from which the next tabled referendum may be forced; this allows for the tabling + /// of a negative-turnout-bias (default-carries) referendum. + type ExternalDefaultOrigin: EnsureOrigin; + + /// Origin from which the new proposal can be made. + /// + /// The success variant is the account id of the depositor. + type SubmitOrigin: EnsureOrigin; + + /// Origin from which the next majority-carries (or more permissive) referendum may be + /// tabled to vote according to the `FastTrackVotingPeriod` asynchronously in a similar + /// manner to the emergency origin. It retains its threshold method. + type FastTrackOrigin: EnsureOrigin; + + /// Origin from which the next majority-carries (or more permissive) referendum may be + /// tabled to vote immediately and asynchronously in a similar manner to the emergency + /// origin. It retains its threshold method. + type InstantOrigin: EnsureOrigin; + + /// Origin from which any referendum may be cancelled in an emergency. + type CancellationOrigin: EnsureOrigin; + + /// Origin from which proposals may be blacklisted. + type BlacklistOrigin: EnsureOrigin; + + /// Origin from which a proposal may be cancelled and its backers slashed. + type CancelProposalOrigin: EnsureOrigin; + + /// Origin for anyone able to veto proposals. + type VetoOrigin: EnsureOrigin; + + /// Overarching type of all pallets origins. + type PalletsOrigin: From>; + + /// Handler for the unbalanced reduction when slashing a preimage deposit. + type Slash: OnUnbalanced>; + } + + /// The number of (public) proposals that have been made so far. + #[pallet::storage] + #[pallet::getter(fn public_prop_count)] + pub type PublicPropCount = StorageValue<_, PropIndex, ValueQuery>; + + /// The public proposals. Unsorted. The second item is the proposal. + #[pallet::storage] + #[pallet::getter(fn public_props)] + pub type PublicProps = StorageValue< + _, + BoundedVec<(PropIndex, BoundedCallOf, T::AccountId), T::MaxProposals>, + ValueQuery, + >; + + /// Those who have locked a deposit. + /// + /// TWOX-NOTE: Safe, as increasing integer keys are safe. + #[pallet::storage] + #[pallet::getter(fn deposit_of)] + pub type DepositOf = StorageMap< + _, + Twox64Concat, + PropIndex, + (BoundedVec, BalanceOf), + >; + + /// The next free referendum index, aka the number of referenda started so far. + #[pallet::storage] + #[pallet::getter(fn referendum_count)] + pub type ReferendumCount = StorageValue<_, ReferendumIndex, ValueQuery>; + + /// The lowest referendum index representing an unbaked referendum. Equal to + /// `ReferendumCount` if there isn't a unbaked referendum. + #[pallet::storage] + #[pallet::getter(fn lowest_unbaked)] + pub type LowestUnbaked = StorageValue<_, ReferendumIndex, ValueQuery>; + + /// Information concerning any given referendum. + /// + /// TWOX-NOTE: SAFE as indexes are not under an attacker’s control. + #[pallet::storage] + #[pallet::getter(fn referendum_info)] + pub type ReferendumInfoOf = StorageMap< + _, + Twox64Concat, + ReferendumIndex, + ReferendumInfo, BoundedCallOf, BalanceOf>, + >; + + /// All votes for a particular voter. We store the balance for the number of votes that we + /// have recorded. The second item is the total amount of delegations, that will be added. + /// + /// TWOX-NOTE: SAFE as `AccountId`s are crypto hashes anyway. + #[pallet::storage] + pub type VotingOf = StorageMap< + _, + Twox64Concat, + T::AccountId, + Voting, T::AccountId, BlockNumberFor, T::MaxVotes>, + ValueQuery, + >; + + /// True if the last referendum tabled was submitted externally. False if it was a public + /// proposal. + #[pallet::storage] + pub type LastTabledWasExternal = StorageValue<_, bool, ValueQuery>; + + /// The referendum to be tabled whenever it would be valid to table an external proposal. + /// This happens when a referendum needs to be tabled and one of two conditions are met: + /// - `LastTabledWasExternal` is `false`; or + /// - `PublicProps` is empty. + #[pallet::storage] + pub type NextExternal = StorageValue<_, (BoundedCallOf, VoteThreshold)>; + + /// A record of who vetoed what. Maps proposal hash to a possible existent block number + /// (until when it may not be resubmitted) and who vetoed it. + #[pallet::storage] + pub type Blacklist = StorageMap< + _, + Identity, + H256, + (BlockNumberFor, BoundedVec), + >; + + /// Record of all proposals that have been subject to emergency cancellation. + #[pallet::storage] + pub type Cancellations = StorageMap<_, Identity, H256, bool, ValueQuery>; + + /// General information concerning any proposal or referendum. + /// The `PreimageHash` refers to the preimage of the `Preimages` provider which can be a JSON + /// dump or IPFS hash of a JSON file. + /// + /// Consider a garbage collection for a metadata of finished referendums to `unrequest` (remove) + /// large preimages. + #[pallet::storage] + pub type MetadataOf = StorageMap<_, Blake2_128Concat, MetadataOwner, PreimageHash>; + + #[pallet::genesis_config] + #[derive(frame_support::DefaultNoBound)] + pub struct GenesisConfig { + #[serde(skip)] + _config: sp_std::marker::PhantomData, + } + + #[pallet::genesis_build] + impl BuildGenesisConfig for GenesisConfig { + fn build(&self) { + PublicPropCount::::put(0 as PropIndex); + ReferendumCount::::put(0 as ReferendumIndex); + LowestUnbaked::::put(0 as ReferendumIndex); + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A motion has been proposed by a public account. + Proposed { proposal_index: PropIndex, deposit: BalanceOf }, + /// A public proposal has been tabled for referendum vote. + Tabled { proposal_index: PropIndex, deposit: BalanceOf }, + /// An external proposal has been tabled. + ExternalTabled, + /// A referendum has begun. + Started { ref_index: ReferendumIndex, threshold: VoteThreshold }, + /// A proposal has been approved by referendum. + Passed { ref_index: ReferendumIndex }, + /// A proposal has been rejected by referendum. + NotPassed { ref_index: ReferendumIndex }, + /// A referendum has been cancelled. + Cancelled { ref_index: ReferendumIndex }, + /// An account has delegated their vote to another account. + Delegated { who: T::AccountId, target: T::AccountId }, + /// An account has cancelled a previous delegation operation. + Undelegated { account: T::AccountId }, + /// An external proposal has been vetoed. + Vetoed { who: T::AccountId, proposal_hash: H256, until: BlockNumberFor }, + /// A proposal_hash has been blacklisted permanently. + Blacklisted { proposal_hash: H256 }, + /// An account has voted in a referendum + Voted { voter: T::AccountId, ref_index: ReferendumIndex, vote: AccountVote> }, + /// An account has secconded a proposal + Seconded { seconder: T::AccountId, prop_index: PropIndex }, + /// A proposal got canceled. + ProposalCanceled { prop_index: PropIndex }, + /// Metadata for a proposal or a referendum has been set. + MetadataSet { + /// Metadata owner. + owner: MetadataOwner, + /// Preimage hash. + hash: PreimageHash, + }, + /// Metadata for a proposal or a referendum has been cleared. + MetadataCleared { + /// Metadata owner. + owner: MetadataOwner, + /// Preimage hash. + hash: PreimageHash, + }, + /// Metadata has been transferred to new owner. + MetadataTransferred { + /// Previous metadata owner. + prev_owner: MetadataOwner, + /// New metadata owner. + owner: MetadataOwner, + /// Preimage hash. + hash: PreimageHash, + }, + } + + #[pallet::error] + pub enum Error { + /// Value too low + ValueLow, + /// Proposal does not exist + ProposalMissing, + /// Cannot cancel the same proposal twice + AlreadyCanceled, + /// Proposal already made + DuplicateProposal, + /// Proposal still blacklisted + ProposalBlacklisted, + /// Next external proposal not simple majority + NotSimpleMajority, + /// Invalid hash + InvalidHash, + /// No external proposal + NoProposal, + /// Identity may not veto a proposal twice + AlreadyVetoed, + /// Vote given for invalid referendum + ReferendumInvalid, + /// No proposals waiting + NoneWaiting, + /// The given account did not vote on the referendum. + NotVoter, + /// The actor has no permission to conduct the action. + NoPermission, + /// The account is already delegating. + AlreadyDelegating, + /// Too high a balance was provided that the account cannot afford. + InsufficientFunds, + /// The account is not currently delegating. + NotDelegating, + /// The account currently has votes attached to it and the operation cannot succeed until + /// these are removed, either through `unvote` or `reap_vote`. + VotesExist, + /// The instant referendum origin is currently disallowed. + InstantNotAllowed, + /// Delegation to oneself makes no sense. + Nonsense, + /// Invalid upper bound. + WrongUpperBound, + /// Maximum number of votes reached. + MaxVotesReached, + /// Maximum number of items reached. + TooMany, + /// Voting period too low + VotingPeriodLow, + /// The preimage does not exist. + PreimageNotExist, + } + + #[pallet::hooks] + impl Hooks> for Pallet { + /// Weight: see `begin_block` + fn on_initialize(n: BlockNumberFor) -> Weight { + Self::begin_block(n) + } + } + + #[pallet::call] + impl Pallet { + /// Propose a sensitive action to be taken. + /// + /// The dispatch origin of this call must be _Signed_ and the sender must + /// have funds to cover the deposit. + /// + /// - `proposal_hash`: The hash of the proposal preimage. + /// - `value`: The amount of deposit (must be at least `MinimumDeposit`). + /// + /// Emits `Proposed`. + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::propose())] + pub fn propose( + origin: OriginFor, + proposal: BoundedCallOf, + #[pallet::compact] value: BalanceOf, + ) -> DispatchResult { + let who = T::SubmitOrigin::ensure_origin(origin)?; + ensure!(value >= T::MinimumDeposit::get(), Error::::ValueLow); + + let index = Self::public_prop_count(); + let real_prop_count = PublicProps::::decode_len().unwrap_or(0) as u32; + let max_proposals = T::MaxProposals::get(); + ensure!(real_prop_count < max_proposals, Error::::TooMany); + let proposal_hash = proposal.hash(); + + if let Some((until, _)) = >::get(proposal_hash) { + ensure!( + >::block_number() >= until, + Error::::ProposalBlacklisted, + ); + } + + T::Currency::reserve(&who, value)?; + + let depositors = BoundedVec::<_, T::MaxDeposits>::truncate_from(vec![who.clone()]); + DepositOf::::insert(index, (depositors, value)); + + PublicPropCount::::put(index + 1); + + PublicProps::::try_append((index, proposal, who)) + .map_err(|_| Error::::TooMany)?; + + Self::deposit_event(Event::::Proposed { proposal_index: index, deposit: value }); + Ok(()) + } + + /// Signals agreement with a particular proposal. + /// + /// The dispatch origin of this call must be _Signed_ and the sender + /// must have funds to cover the deposit, equal to the original deposit. + /// + /// - `proposal`: The index of the proposal to second. + #[pallet::call_index(1)] + #[pallet::weight(T::WeightInfo::second())] + pub fn second( + origin: OriginFor, + #[pallet::compact] proposal: PropIndex, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + let seconds = Self::len_of_deposit_of(proposal).ok_or(Error::::ProposalMissing)?; + ensure!(seconds < T::MaxDeposits::get(), Error::::TooMany); + let mut deposit = Self::deposit_of(proposal).ok_or(Error::::ProposalMissing)?; + T::Currency::reserve(&who, deposit.1)?; + let ok = deposit.0.try_push(who.clone()).is_ok(); + debug_assert!(ok, "`seconds` is below static limit; `try_insert` should succeed; qed"); + >::insert(proposal, deposit); + Self::deposit_event(Event::::Seconded { seconder: who, prop_index: proposal }); + Ok(()) + } + + /// Vote in a referendum. If `vote.is_aye()`, the vote is to enact the proposal; + /// otherwise it is a vote to keep the status quo. + /// + /// The dispatch origin of this call must be _Signed_. + /// + /// - `ref_index`: The index of the referendum to vote for. + /// - `vote`: The vote configuration. + #[pallet::call_index(2)] + #[pallet::weight(T::WeightInfo::vote_new().max(T::WeightInfo::vote_existing()))] + pub fn vote( + origin: OriginFor, + #[pallet::compact] ref_index: ReferendumIndex, + vote: AccountVote>, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + Self::try_vote(&who, ref_index, vote) + } + + /// Schedule an emergency cancellation of a referendum. Cannot happen twice to the same + /// referendum. + /// + /// The dispatch origin of this call must be `CancellationOrigin`. + /// + /// -`ref_index`: The index of the referendum to cancel. + /// + /// Weight: `O(1)`. + #[pallet::call_index(3)] + #[pallet::weight((T::WeightInfo::emergency_cancel(), DispatchClass::Operational))] + pub fn emergency_cancel( + origin: OriginFor, + ref_index: ReferendumIndex, + ) -> DispatchResult { + T::CancellationOrigin::ensure_origin(origin)?; + + let status = Self::referendum_status(ref_index)?; + let h = status.proposal.hash(); + ensure!(!>::contains_key(h), Error::::AlreadyCanceled); + + >::insert(h, true); + Self::internal_cancel_referendum(ref_index); + Ok(()) + } + + /// Schedule a referendum to be tabled once it is legal to schedule an external + /// referendum. + /// + /// The dispatch origin of this call must be `ExternalOrigin`. + /// + /// - `proposal_hash`: The preimage hash of the proposal. + #[pallet::call_index(4)] + #[pallet::weight(T::WeightInfo::external_propose())] + pub fn external_propose( + origin: OriginFor, + proposal: BoundedCallOf, + ) -> DispatchResult { + T::ExternalOrigin::ensure_origin(origin)?; + ensure!(!>::exists(), Error::::DuplicateProposal); + if let Some((until, _)) = >::get(proposal.hash()) { + ensure!( + >::block_number() >= until, + Error::::ProposalBlacklisted, + ); + } + >::put((proposal, VoteThreshold::SuperMajorityApprove)); + Ok(()) + } + + /// Schedule a majority-carries referendum to be tabled next once it is legal to schedule + /// an external referendum. + /// + /// The dispatch of this call must be `ExternalMajorityOrigin`. + /// + /// - `proposal_hash`: The preimage hash of the proposal. + /// + /// Unlike `external_propose`, blacklisting has no effect on this and it may replace a + /// pre-scheduled `external_propose` call. + /// + /// Weight: `O(1)` + #[pallet::call_index(5)] + #[pallet::weight(T::WeightInfo::external_propose_majority())] + pub fn external_propose_majority( + origin: OriginFor, + proposal: BoundedCallOf, + ) -> DispatchResult { + T::ExternalMajorityOrigin::ensure_origin(origin)?; + >::put((proposal, VoteThreshold::SimpleMajority)); + Ok(()) + } + + /// Schedule a negative-turnout-bias referendum to be tabled next once it is legal to + /// schedule an external referendum. + /// + /// The dispatch of this call must be `ExternalDefaultOrigin`. + /// + /// - `proposal_hash`: The preimage hash of the proposal. + /// + /// Unlike `external_propose`, blacklisting has no effect on this and it may replace a + /// pre-scheduled `external_propose` call. + /// + /// Weight: `O(1)` + #[pallet::call_index(6)] + #[pallet::weight(T::WeightInfo::external_propose_default())] + pub fn external_propose_default( + origin: OriginFor, + proposal: BoundedCallOf, + ) -> DispatchResult { + T::ExternalDefaultOrigin::ensure_origin(origin)?; + >::put((proposal, VoteThreshold::SuperMajorityAgainst)); + Ok(()) + } + + /// Schedule the currently externally-proposed majority-carries referendum to be tabled + /// immediately. If there is no externally-proposed referendum currently, or if there is one + /// but it is not a majority-carries referendum then it fails. + /// + /// The dispatch of this call must be `FastTrackOrigin`. + /// + /// - `proposal_hash`: The hash of the current external proposal. + /// - `voting_period`: The period that is allowed for voting on this proposal. Increased to + /// Must be always greater than zero. + /// For `FastTrackOrigin` must be equal or greater than `FastTrackVotingPeriod`. + /// - `delay`: The number of block after voting has ended in approval and this should be + /// enacted. This doesn't have a minimum amount. + /// + /// Emits `Started`. + /// + /// Weight: `O(1)` + #[pallet::call_index(7)] + #[pallet::weight(T::WeightInfo::fast_track())] + pub fn fast_track( + origin: OriginFor, + proposal_hash: H256, + voting_period: BlockNumberFor, + delay: BlockNumberFor, + ) -> DispatchResult { + // Rather complicated bit of code to ensure that either: + // - `voting_period` is at least `FastTrackVotingPeriod` and `origin` is + // `FastTrackOrigin`; or + // - `InstantAllowed` is `true` and `origin` is `InstantOrigin`. + let maybe_ensure_instant = if voting_period < T::FastTrackVotingPeriod::get() { + Some(origin) + } else if let Err(origin) = T::FastTrackOrigin::try_origin(origin) { + Some(origin) + } else { + None + }; + if let Some(ensure_instant) = maybe_ensure_instant { + T::InstantOrigin::ensure_origin(ensure_instant)?; + ensure!(T::InstantAllowed::get(), Error::::InstantNotAllowed); + } + + ensure!(voting_period > Zero::zero(), Error::::VotingPeriodLow); + let (ext_proposal, threshold) = + >::get().ok_or(Error::::ProposalMissing)?; + ensure!( + threshold != VoteThreshold::SuperMajorityApprove, + Error::::NotSimpleMajority, + ); + ensure!(proposal_hash == ext_proposal.hash(), Error::::InvalidHash); + + >::kill(); + let now = >::block_number(); + let ref_index = Self::inject_referendum( + now.saturating_add(voting_period), + ext_proposal, + threshold, + delay, + ); + Self::transfer_metadata(MetadataOwner::External, MetadataOwner::Referendum(ref_index)); + Ok(()) + } + + /// Veto and blacklist the external proposal hash. + /// + /// The dispatch origin of this call must be `VetoOrigin`. + /// + /// - `proposal_hash`: The preimage hash of the proposal to veto and blacklist. + /// + /// Emits `Vetoed`. + /// + /// Weight: `O(V + log(V))` where V is number of `existing vetoers` + #[pallet::call_index(8)] + #[pallet::weight(T::WeightInfo::veto_external())] + pub fn veto_external(origin: OriginFor, proposal_hash: H256) -> DispatchResult { + let who = T::VetoOrigin::ensure_origin(origin)?; + + if let Some((ext_proposal, _)) = NextExternal::::get() { + ensure!(proposal_hash == ext_proposal.hash(), Error::::ProposalMissing); + } else { + return Err(Error::::NoProposal.into()) + } + + let mut existing_vetoers = + >::get(&proposal_hash).map(|pair| pair.1).unwrap_or_default(); + let insert_position = + existing_vetoers.binary_search(&who).err().ok_or(Error::::AlreadyVetoed)?; + existing_vetoers + .try_insert(insert_position, who.clone()) + .map_err(|_| Error::::TooMany)?; + + let until = + >::block_number().saturating_add(T::CooloffPeriod::get()); + >::insert(&proposal_hash, (until, existing_vetoers)); + + Self::deposit_event(Event::::Vetoed { who, proposal_hash, until }); + >::kill(); + Self::clear_metadata(MetadataOwner::External); + Ok(()) + } + + /// Remove a referendum. + /// + /// The dispatch origin of this call must be _Root_. + /// + /// - `ref_index`: The index of the referendum to cancel. + /// + /// # Weight: `O(1)`. + #[pallet::call_index(9)] + #[pallet::weight(T::WeightInfo::cancel_referendum())] + pub fn cancel_referendum( + origin: OriginFor, + #[pallet::compact] ref_index: ReferendumIndex, + ) -> DispatchResult { + ensure_root(origin)?; + Self::internal_cancel_referendum(ref_index); + Ok(()) + } + + /// Delegate the voting power (with some given conviction) of the sending account. + /// + /// The balance delegated is locked for as long as it's delegated, and thereafter for the + /// time appropriate for the conviction's lock period. + /// + /// The dispatch origin of this call must be _Signed_, and the signing account must either: + /// - be delegating already; or + /// - have no voting activity (if there is, then it will need to be removed/consolidated + /// through `reap_vote` or `unvote`). + /// + /// - `to`: The account whose voting the `target` account's voting power will follow. + /// - `conviction`: The conviction that will be attached to the delegated votes. When the + /// account is undelegated, the funds will be locked for the corresponding period. + /// - `balance`: The amount of the account's balance to be used in delegating. This must not + /// be more than the account's current balance. + /// + /// Emits `Delegated`. + /// + /// Weight: `O(R)` where R is the number of referendums the voter delegating to has + /// voted on. Weight is charged as if maximum votes. + // NOTE: weight must cover an incorrect voting of origin with max votes, this is ensure + // because a valid delegation cover decoding a direct voting with max votes. + #[pallet::call_index(10)] + #[pallet::weight(T::WeightInfo::delegate(T::MaxVotes::get()))] + pub fn delegate( + origin: OriginFor, + to: AccountIdLookupOf, + conviction: Conviction, + balance: BalanceOf, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + let to = T::Lookup::lookup(to)?; + let votes = Self::try_delegate(who, to, conviction, balance)?; + + Ok(Some(T::WeightInfo::delegate(votes)).into()) + } + + /// Undelegate the voting power of the sending account. + /// + /// Tokens may be unlocked following once an amount of time consistent with the lock period + /// of the conviction with which the delegation was issued. + /// + /// The dispatch origin of this call must be _Signed_ and the signing account must be + /// currently delegating. + /// + /// Emits `Undelegated`. + /// + /// Weight: `O(R)` where R is the number of referendums the voter delegating to has + /// voted on. Weight is charged as if maximum votes. + // NOTE: weight must cover an incorrect voting of origin with max votes, this is ensure + // because a valid delegation cover decoding a direct voting with max votes. + #[pallet::call_index(11)] + #[pallet::weight(T::WeightInfo::undelegate(T::MaxVotes::get()))] + pub fn undelegate(origin: OriginFor) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + let votes = Self::try_undelegate(who)?; + Ok(Some(T::WeightInfo::undelegate(votes)).into()) + } + + /// Clears all public proposals. + /// + /// The dispatch origin of this call must be _Root_. + /// + /// Weight: `O(1)`. + #[pallet::call_index(12)] + #[pallet::weight(T::WeightInfo::clear_public_proposals())] + pub fn clear_public_proposals(origin: OriginFor) -> DispatchResult { + ensure_root(origin)?; + >::kill(); + Ok(()) + } + + /// Unlock tokens that have an expired lock. + /// + /// The dispatch origin of this call must be _Signed_. + /// + /// - `target`: The account to remove the lock on. + /// + /// Weight: `O(R)` with R number of vote of target. + #[pallet::call_index(13)] + #[pallet::weight(T::WeightInfo::unlock_set(T::MaxVotes::get()).max(T::WeightInfo::unlock_remove(T::MaxVotes::get())))] + pub fn unlock(origin: OriginFor, target: AccountIdLookupOf) -> DispatchResult { + ensure_signed(origin)?; + let target = T::Lookup::lookup(target)?; + Self::update_lock(&target); + Ok(()) + } + + /// Remove a vote for a referendum. + /// + /// If: + /// - the referendum was cancelled, or + /// - the referendum is ongoing, or + /// - the referendum has ended such that + /// - the vote of the account was in opposition to the result; or + /// - there was no conviction to the account's vote; or + /// - the account made a split vote + /// ...then the vote is removed cleanly and a following call to `unlock` may result in more + /// funds being available. + /// + /// If, however, the referendum has ended and: + /// - it finished corresponding to the vote of the account, and + /// - the account made a standard vote with conviction, and + /// - the lock period of the conviction is not over + /// ...then the lock will be aggregated into the overall account's lock, which may involve + /// *overlocking* (where the two locks are combined into a single lock that is the maximum + /// of both the amount locked and the time is it locked for). + /// + /// The dispatch origin of this call must be _Signed_, and the signer must have a vote + /// registered for referendum `index`. + /// + /// - `index`: The index of referendum of the vote to be removed. + /// + /// Weight: `O(R + log R)` where R is the number of referenda that `target` has voted on. + /// Weight is calculated for the maximum number of vote. + #[pallet::call_index(14)] + #[pallet::weight(T::WeightInfo::remove_vote(T::MaxVotes::get()))] + pub fn remove_vote(origin: OriginFor, index: ReferendumIndex) -> DispatchResult { + let who = ensure_signed(origin)?; + Self::try_remove_vote(&who, index, UnvoteScope::Any) + } + + /// Remove a vote for a referendum. + /// + /// If the `target` is equal to the signer, then this function is exactly equivalent to + /// `remove_vote`. If not equal to the signer, then the vote must have expired, + /// either because the referendum was cancelled, because the voter lost the referendum or + /// because the conviction period is over. + /// + /// The dispatch origin of this call must be _Signed_. + /// + /// - `target`: The account of the vote to be removed; this account must have voted for + /// referendum `index`. + /// - `index`: The index of referendum of the vote to be removed. + /// + /// Weight: `O(R + log R)` where R is the number of referenda that `target` has voted on. + /// Weight is calculated for the maximum number of vote. + #[pallet::call_index(15)] + #[pallet::weight(T::WeightInfo::remove_other_vote(T::MaxVotes::get()))] + pub fn remove_other_vote( + origin: OriginFor, + target: AccountIdLookupOf, + index: ReferendumIndex, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + let target = T::Lookup::lookup(target)?; + let scope = if target == who { UnvoteScope::Any } else { UnvoteScope::OnlyExpired }; + Self::try_remove_vote(&target, index, scope)?; + Ok(()) + } + + /// Permanently place a proposal into the blacklist. This prevents it from ever being + /// proposed again. + /// + /// If called on a queued public or external proposal, then this will result in it being + /// removed. If the `ref_index` supplied is an active referendum with the proposal hash, + /// then it will be cancelled. + /// + /// The dispatch origin of this call must be `BlacklistOrigin`. + /// + /// - `proposal_hash`: The proposal hash to blacklist permanently. + /// - `ref_index`: An ongoing referendum whose hash is `proposal_hash`, which will be + /// cancelled. + /// + /// Weight: `O(p)` (though as this is an high-privilege dispatch, we assume it has a + /// reasonable value). + #[pallet::call_index(16)] + #[pallet::weight((T::WeightInfo::blacklist(), DispatchClass::Operational))] + pub fn blacklist( + origin: OriginFor, + proposal_hash: H256, + maybe_ref_index: Option, + ) -> DispatchResult { + T::BlacklistOrigin::ensure_origin(origin)?; + + // Insert the proposal into the blacklist. + let permanent = + (BlockNumberFor::::max_value(), BoundedVec::::default()); + Blacklist::::insert(&proposal_hash, permanent); + + // Remove the queued proposal, if it's there. + PublicProps::::mutate(|props| { + if let Some(index) = props.iter().position(|p| p.1.hash() == proposal_hash) { + let (prop_index, ..) = props.remove(index); + if let Some((whos, amount)) = DepositOf::::take(prop_index) { + for who in whos.into_iter() { + T::Slash::on_unbalanced(T::Currency::slash_reserved(&who, amount).0); + } + } + Self::clear_metadata(MetadataOwner::Proposal(prop_index)); + } + }); + + // Remove the external queued referendum, if it's there. + if matches!(NextExternal::::get(), Some((p, ..)) if p.hash() == proposal_hash) { + NextExternal::::kill(); + Self::clear_metadata(MetadataOwner::External); + } + + // Remove the referendum, if it's there. + if let Some(ref_index) = maybe_ref_index { + if let Ok(status) = Self::referendum_status(ref_index) { + if status.proposal.hash() == proposal_hash { + Self::internal_cancel_referendum(ref_index); + } + } + } + + Self::deposit_event(Event::::Blacklisted { proposal_hash }); + Ok(()) + } + + /// Remove a proposal. + /// + /// The dispatch origin of this call must be `CancelProposalOrigin`. + /// + /// - `prop_index`: The index of the proposal to cancel. + /// + /// Weight: `O(p)` where `p = PublicProps::::decode_len()` + #[pallet::call_index(17)] + #[pallet::weight(T::WeightInfo::cancel_proposal())] + pub fn cancel_proposal( + origin: OriginFor, + #[pallet::compact] prop_index: PropIndex, + ) -> DispatchResult { + T::CancelProposalOrigin::ensure_origin(origin)?; + + PublicProps::::mutate(|props| props.retain(|p| p.0 != prop_index)); + if let Some((whos, amount)) = DepositOf::::take(prop_index) { + for who in whos.into_iter() { + T::Slash::on_unbalanced(T::Currency::slash_reserved(&who, amount).0); + } + } + Self::deposit_event(Event::::ProposalCanceled { prop_index }); + Self::clear_metadata(MetadataOwner::Proposal(prop_index)); + Ok(()) + } + + /// Set or clear a metadata of a proposal or a referendum. + /// + /// Parameters: + /// - `origin`: Must correspond to the `MetadataOwner`. + /// - `ExternalOrigin` for an external proposal with the `SuperMajorityApprove` + /// threshold. + /// - `ExternalDefaultOrigin` for an external proposal with the `SuperMajorityAgainst` + /// threshold. + /// - `ExternalMajorityOrigin` for an external proposal with the `SimpleMajority` + /// threshold. + /// - `Signed` by a creator for a public proposal. + /// - `Signed` to clear a metadata for a finished referendum. + /// - `Root` to set a metadata for an ongoing referendum. + /// - `owner`: an identifier of a metadata owner. + /// - `maybe_hash`: The hash of an on-chain stored preimage. `None` to clear a metadata. + #[pallet::call_index(18)] + #[pallet::weight( + match (owner, maybe_hash) { + (MetadataOwner::External, Some(_)) => T::WeightInfo::set_external_metadata(), + (MetadataOwner::External, None) => T::WeightInfo::clear_external_metadata(), + (MetadataOwner::Proposal(_), Some(_)) => T::WeightInfo::set_proposal_metadata(), + (MetadataOwner::Proposal(_), None) => T::WeightInfo::clear_proposal_metadata(), + (MetadataOwner::Referendum(_), Some(_)) => T::WeightInfo::set_referendum_metadata(), + (MetadataOwner::Referendum(_), None) => T::WeightInfo::clear_referendum_metadata(), + } + )] + pub fn set_metadata( + origin: OriginFor, + owner: MetadataOwner, + maybe_hash: Option, + ) -> DispatchResult { + match owner { + MetadataOwner::External => { + let (_, threshold) = >::get().ok_or(Error::::NoProposal)?; + Self::ensure_external_origin(threshold, origin)?; + }, + MetadataOwner::Proposal(index) => { + let who = ensure_signed(origin)?; + let (_, _, proposer) = Self::proposal(index)?; + ensure!(proposer == who, Error::::NoPermission); + }, + MetadataOwner::Referendum(index) => { + let is_root = ensure_signed_or_root(origin)?.is_none(); + ensure!(is_root || maybe_hash.is_none(), Error::::NoPermission); + ensure!( + is_root || Self::referendum_status(index).is_err(), + Error::::NoPermission + ); + }, + } + if let Some(hash) = maybe_hash { + ensure!(T::Preimages::len(&hash).is_some(), Error::::PreimageNotExist); + MetadataOf::::insert(owner.clone(), hash); + Self::deposit_event(Event::::MetadataSet { owner, hash }); + } else { + Self::clear_metadata(owner); + } + Ok(()) + } + } +} + +pub trait EncodeInto: Encode { + fn encode_into + Default>(&self) -> T { + let mut t = T::default(); + self.using_encoded(|data| { + if data.len() <= t.as_mut().len() { + t.as_mut()[0..data.len()].copy_from_slice(data); + } else { + // encoded self is too big to fit into a T. hash it and use the first bytes of that + // instead. + let hash = sp_io::hashing::blake2_256(data); + let l = t.as_mut().len().min(hash.len()); + t.as_mut()[0..l].copy_from_slice(&hash[0..l]); + } + }); + t + } +} +impl EncodeInto for T {} + +impl Pallet { + // exposed immutables. + + /// Get the amount locked in support of `proposal`; `None` if proposal isn't a valid proposal + /// index. + pub fn backing_for(proposal: PropIndex) -> Option> { + Self::deposit_of(proposal).map(|(l, d)| d.saturating_mul((l.len() as u32).into())) + } + + /// Get all referenda ready for tally at block `n`. + pub fn maturing_referenda_at( + n: BlockNumberFor, + ) -> Vec<(ReferendumIndex, ReferendumStatus, BoundedCallOf, BalanceOf>)> + { + let next = Self::lowest_unbaked(); + let last = Self::referendum_count(); + Self::maturing_referenda_at_inner(n, next..last) + } + + fn maturing_referenda_at_inner( + n: BlockNumberFor, + range: core::ops::Range, + ) -> Vec<(ReferendumIndex, ReferendumStatus, BoundedCallOf, BalanceOf>)> + { + range + .into_iter() + .map(|i| (i, Self::referendum_info(i))) + .filter_map(|(i, maybe_info)| match maybe_info { + Some(ReferendumInfo::Ongoing(status)) => Some((i, status)), + _ => None, + }) + .filter(|(_, status)| status.end == n) + .collect() + } + + // Exposed mutables. + + /// Start a referendum. + pub fn internal_start_referendum( + proposal: BoundedCallOf, + threshold: VoteThreshold, + delay: BlockNumberFor, + ) -> ReferendumIndex { + >::inject_referendum( + >::block_number().saturating_add(T::VotingPeriod::get()), + proposal, + threshold, + delay, + ) + } + + /// Remove a referendum. + pub fn internal_cancel_referendum(ref_index: ReferendumIndex) { + Self::deposit_event(Event::::Cancelled { ref_index }); + ReferendumInfoOf::::remove(ref_index); + Self::clear_metadata(MetadataOwner::Referendum(ref_index)); + } + + // private. + + /// Ok if the given referendum is active, Err otherwise + fn ensure_ongoing( + r: ReferendumInfo, BoundedCallOf, BalanceOf>, + ) -> Result, BoundedCallOf, BalanceOf>, DispatchError> + { + match r { + ReferendumInfo::Ongoing(s) => Ok(s), + _ => Err(Error::::ReferendumInvalid.into()), + } + } + + fn referendum_status( + ref_index: ReferendumIndex, + ) -> Result, BoundedCallOf, BalanceOf>, DispatchError> + { + let info = ReferendumInfoOf::::get(ref_index).ok_or(Error::::ReferendumInvalid)?; + Self::ensure_ongoing(info) + } + + /// Actually enact a vote, if legit. + fn try_vote( + who: &T::AccountId, + ref_index: ReferendumIndex, + vote: AccountVote>, + ) -> DispatchResult { + let mut status = Self::referendum_status(ref_index)?; + ensure!(vote.balance() <= T::Currency::free_balance(who), Error::::InsufficientFunds); + VotingOf::::try_mutate(who, |voting| -> DispatchResult { + if let Voting::Direct { ref mut votes, delegations, .. } = voting { + match votes.binary_search_by_key(&ref_index, |i| i.0) { + Ok(i) => { + // Shouldn't be possible to fail, but we handle it gracefully. + status.tally.remove(votes[i].1).ok_or(ArithmeticError::Underflow)?; + if let Some(approve) = votes[i].1.as_standard() { + status.tally.reduce(approve, *delegations); + } + votes[i].1 = vote; + }, + Err(i) => { + votes + .try_insert(i, (ref_index, vote)) + .map_err(|_| Error::::MaxVotesReached)?; + }, + } + Self::deposit_event(Event::::Voted { voter: who.clone(), ref_index, vote }); + // Shouldn't be possible to fail, but we handle it gracefully. + status.tally.add(vote).ok_or(ArithmeticError::Overflow)?; + if let Some(approve) = vote.as_standard() { + status.tally.increase(approve, *delegations); + } + Ok(()) + } else { + Err(Error::::AlreadyDelegating.into()) + } + })?; + // Extend the lock to `balance` (rather than setting it) since we don't know what other + // votes are in place. + T::Currency::extend_lock( + DEMOCRACY_ID, + who, + vote.balance(), + WithdrawReasons::except(WithdrawReasons::RESERVE), + ); + ReferendumInfoOf::::insert(ref_index, ReferendumInfo::Ongoing(status)); + Ok(()) + } + + /// Remove the account's vote for the given referendum if possible. This is possible when: + /// - The referendum has not finished. + /// - The referendum has finished and the voter lost their direction. + /// - The referendum has finished and the voter's lock period is up. + /// + /// This will generally be combined with a call to `unlock`. + fn try_remove_vote( + who: &T::AccountId, + ref_index: ReferendumIndex, + scope: UnvoteScope, + ) -> DispatchResult { + let info = ReferendumInfoOf::::get(ref_index); + VotingOf::::try_mutate(who, |voting| -> DispatchResult { + if let Voting::Direct { ref mut votes, delegations, ref mut prior } = voting { + let i = votes + .binary_search_by_key(&ref_index, |i| i.0) + .map_err(|_| Error::::NotVoter)?; + match info { + Some(ReferendumInfo::Ongoing(mut status)) => { + ensure!(matches!(scope, UnvoteScope::Any), Error::::NoPermission); + // Shouldn't be possible to fail, but we handle it gracefully. + status.tally.remove(votes[i].1).ok_or(ArithmeticError::Underflow)?; + if let Some(approve) = votes[i].1.as_standard() { + status.tally.reduce(approve, *delegations); + } + ReferendumInfoOf::::insert(ref_index, ReferendumInfo::Ongoing(status)); + }, + Some(ReferendumInfo::Finished { end, approved }) => { + if let Some((lock_periods, balance)) = votes[i].1.locked_if(approved) { + let unlock_at = end.saturating_add( + T::VoteLockingPeriod::get().saturating_mul(lock_periods.into()), + ); + let now = frame_system::Pallet::::block_number(); + if now < unlock_at { + ensure!( + matches!(scope, UnvoteScope::Any), + Error::::NoPermission + ); + prior.accumulate(unlock_at, balance) + } + } + }, + None => {}, // Referendum was cancelled. + } + votes.remove(i); + } + Ok(()) + })?; + Ok(()) + } + + /// Return the number of votes for `who` + fn increase_upstream_delegation(who: &T::AccountId, amount: Delegations>) -> u32 { + VotingOf::::mutate(who, |voting| match voting { + Voting::Delegating { delegations, .. } => { + // We don't support second level delegating, so we don't need to do anything more. + *delegations = delegations.saturating_add(amount); + 1 + }, + Voting::Direct { votes, delegations, .. } => { + *delegations = delegations.saturating_add(amount); + for &(ref_index, account_vote) in votes.iter() { + if let AccountVote::Standard { vote, .. } = account_vote { + ReferendumInfoOf::::mutate(ref_index, |maybe_info| { + if let Some(ReferendumInfo::Ongoing(ref mut status)) = maybe_info { + status.tally.increase(vote.aye, amount); + } + }); + } + } + votes.len() as u32 + }, + }) + } + + /// Return the number of votes for `who` + fn reduce_upstream_delegation(who: &T::AccountId, amount: Delegations>) -> u32 { + VotingOf::::mutate(who, |voting| match voting { + Voting::Delegating { delegations, .. } => { + // We don't support second level delegating, so we don't need to do anything more. + *delegations = delegations.saturating_sub(amount); + 1 + }, + Voting::Direct { votes, delegations, .. } => { + *delegations = delegations.saturating_sub(amount); + for &(ref_index, account_vote) in votes.iter() { + if let AccountVote::Standard { vote, .. } = account_vote { + ReferendumInfoOf::::mutate(ref_index, |maybe_info| { + if let Some(ReferendumInfo::Ongoing(ref mut status)) = maybe_info { + status.tally.reduce(vote.aye, amount); + } + }); + } + } + votes.len() as u32 + }, + }) + } + + /// Attempt to delegate `balance` times `conviction` of voting power from `who` to `target`. + /// + /// Return the upstream number of votes. + fn try_delegate( + who: T::AccountId, + target: T::AccountId, + conviction: Conviction, + balance: BalanceOf, + ) -> Result { + ensure!(who != target, Error::::Nonsense); + ensure!(balance <= T::Currency::free_balance(&who), Error::::InsufficientFunds); + let votes = VotingOf::::try_mutate(&who, |voting| -> Result { + let mut old = Voting::Delegating { + balance, + target: target.clone(), + conviction, + delegations: Default::default(), + prior: Default::default(), + }; + sp_std::mem::swap(&mut old, voting); + match old { + Voting::Delegating { + balance, target, conviction, delegations, mut prior, .. + } => { + // remove any delegation votes to our current target. + Self::reduce_upstream_delegation(&target, conviction.votes(balance)); + let now = frame_system::Pallet::::block_number(); + let lock_periods = conviction.lock_periods().into(); + let unlock_block = now + .saturating_add(T::VoteLockingPeriod::get().saturating_mul(lock_periods)); + prior.accumulate(unlock_block, balance); + voting.set_common(delegations, prior); + }, + Voting::Direct { votes, delegations, prior } => { + // here we just ensure that we're currently idling with no votes recorded. + ensure!(votes.is_empty(), Error::::VotesExist); + voting.set_common(delegations, prior); + }, + } + let votes = Self::increase_upstream_delegation(&target, conviction.votes(balance)); + // Extend the lock to `balance` (rather than setting it) since we don't know what other + // votes are in place. + T::Currency::extend_lock( + DEMOCRACY_ID, + &who, + balance, + WithdrawReasons::except(WithdrawReasons::RESERVE), + ); + Ok(votes) + })?; + Self::deposit_event(Event::::Delegated { who, target }); + Ok(votes) + } + + /// Attempt to end the current delegation. + /// + /// Return the number of votes of upstream. + fn try_undelegate(who: T::AccountId) -> Result { + let votes = VotingOf::::try_mutate(&who, |voting| -> Result { + let mut old = Voting::default(); + sp_std::mem::swap(&mut old, voting); + match old { + Voting::Delegating { balance, target, conviction, delegations, mut prior } => { + // remove any delegation votes to our current target. + let votes = + Self::reduce_upstream_delegation(&target, conviction.votes(balance)); + let now = frame_system::Pallet::::block_number(); + let lock_periods = conviction.lock_periods().into(); + let unlock_block = now + .saturating_add(T::VoteLockingPeriod::get().saturating_mul(lock_periods)); + prior.accumulate(unlock_block, balance); + voting.set_common(delegations, prior); + + Ok(votes) + }, + Voting::Direct { .. } => Err(Error::::NotDelegating.into()), + } + })?; + Self::deposit_event(Event::::Undelegated { account: who }); + Ok(votes) + } + + /// Rejig the lock on an account. It will never get more stringent (since that would indicate + /// a security hole) but may be reduced from what they are currently. + fn update_lock(who: &T::AccountId) { + let lock_needed = VotingOf::::mutate(who, |voting| { + voting.rejig(frame_system::Pallet::::block_number()); + voting.locked_balance() + }); + if lock_needed.is_zero() { + T::Currency::remove_lock(DEMOCRACY_ID, who); + } else { + T::Currency::set_lock( + DEMOCRACY_ID, + who, + lock_needed, + WithdrawReasons::except(WithdrawReasons::RESERVE), + ); + } + } + + /// Start a referendum + fn inject_referendum( + end: BlockNumberFor, + proposal: BoundedCallOf, + threshold: VoteThreshold, + delay: BlockNumberFor, + ) -> ReferendumIndex { + let ref_index = Self::referendum_count(); + ReferendumCount::::put(ref_index + 1); + let status = + ReferendumStatus { end, proposal, threshold, delay, tally: Default::default() }; + let item = ReferendumInfo::Ongoing(status); + >::insert(ref_index, item); + Self::deposit_event(Event::::Started { ref_index, threshold }); + ref_index + } + + /// Table the next waiting proposal for a vote. + fn launch_next(now: BlockNumberFor) -> DispatchResult { + if LastTabledWasExternal::::take() { + Self::launch_public(now).or_else(|_| Self::launch_external(now)) + } else { + Self::launch_external(now).or_else(|_| Self::launch_public(now)) + } + .map_err(|_| Error::::NoneWaiting.into()) + } + + /// Table the waiting external proposal for a vote, if there is one. + fn launch_external(now: BlockNumberFor) -> DispatchResult { + if let Some((proposal, threshold)) = >::take() { + LastTabledWasExternal::::put(true); + Self::deposit_event(Event::::ExternalTabled); + let ref_index = Self::inject_referendum( + now.saturating_add(T::VotingPeriod::get()), + proposal, + threshold, + T::EnactmentPeriod::get(), + ); + Self::transfer_metadata(MetadataOwner::External, MetadataOwner::Referendum(ref_index)); + Ok(()) + } else { + return Err(Error::::NoneWaiting.into()) + } + } + + /// Table the waiting public proposal with the highest backing for a vote. + fn launch_public(now: BlockNumberFor) -> DispatchResult { + let mut public_props = Self::public_props(); + if let Some((winner_index, _)) = public_props.iter().enumerate().max_by_key( + // defensive only: All current public proposals have an amount locked + |x| Self::backing_for((x.1).0).defensive_unwrap_or_else(Zero::zero), + ) { + let (prop_index, proposal, _) = public_props.swap_remove(winner_index); + >::put(public_props); + + if let Some((depositors, deposit)) = >::take(prop_index) { + // refund depositors + for d in depositors.iter() { + T::Currency::unreserve(d, deposit); + } + Self::deposit_event(Event::::Tabled { proposal_index: prop_index, deposit }); + let ref_index = Self::inject_referendum( + now.saturating_add(T::VotingPeriod::get()), + proposal, + VoteThreshold::SuperMajorityApprove, + T::EnactmentPeriod::get(), + ); + Self::transfer_metadata( + MetadataOwner::Proposal(prop_index), + MetadataOwner::Referendum(ref_index), + ) + } + Ok(()) + } else { + return Err(Error::::NoneWaiting.into()) + } + } + + fn bake_referendum( + now: BlockNumberFor, + index: ReferendumIndex, + status: ReferendumStatus, BoundedCallOf, BalanceOf>, + ) -> bool { + let total_issuance = T::Currency::total_issuance(); + let approved = status.threshold.approved(status.tally, total_issuance); + + if approved { + Self::deposit_event(Event::::Passed { ref_index: index }); + + // Earliest it can be scheduled for is next block. + let when = now.saturating_add(status.delay.max(One::one())); + if T::Scheduler::schedule_named( + (DEMOCRACY_ID, index).encode_into(), + DispatchTime::At(when), + None, + 63, + frame_system::RawOrigin::Root.into(), + status.proposal, + ) + .is_err() + { + frame_support::print("LOGIC ERROR: bake_referendum/schedule_named failed"); + } + } else { + Self::deposit_event(Event::::NotPassed { ref_index: index }); + } + + approved + } + + /// Current era is ending; we should finish up any proposals. + /// + /// + /// ## Complexity: + /// If a referendum is launched or maturing, this will take full block weight if queue is not + /// empty. Otherwise, `O(R)` where `R` is the number of unbaked referenda. + fn begin_block(now: BlockNumberFor) -> Weight { + let max_block_weight = T::BlockWeights::get().max_block; + let mut weight = Weight::zero(); + + let next = Self::lowest_unbaked(); + let last = Self::referendum_count(); + let r = last.saturating_sub(next); + + // pick out another public referendum if it's time. + if (now % T::LaunchPeriod::get()).is_zero() { + // Errors come from the queue being empty. If the queue is not empty, it will take + // full block weight. + if Self::launch_next(now).is_ok() { + weight = max_block_weight; + } else { + weight.saturating_accrue(T::WeightInfo::on_initialize_base_with_launch_period(r)); + } + } else { + weight.saturating_accrue(T::WeightInfo::on_initialize_base(r)); + } + + // tally up votes for any expiring referenda. + for (index, info) in Self::maturing_referenda_at_inner(now, next..last).into_iter() { + let approved = Self::bake_referendum(now, index, info); + ReferendumInfoOf::::insert(index, ReferendumInfo::Finished { end: now, approved }); + weight = max_block_weight; + } + + // Notes: + // * We don't consider the lowest unbaked to be the last maturing in case some referenda + // have a longer voting period than others. + // * The iteration here shouldn't trigger any storage read that are not in cache, due to + // `maturing_referenda_at_inner` having already read them. + // * We shouldn't iterate more than `LaunchPeriod/VotingPeriod + 1` times because the number + // of unbaked referendum is bounded by this number. In case those number have changed in a + // runtime upgrade the formula should be adjusted but the bound should still be sensible. + >::mutate(|ref_index| { + while *ref_index < last && + Self::referendum_info(*ref_index) + .map_or(true, |info| matches!(info, ReferendumInfo::Finished { .. })) + { + *ref_index += 1 + } + }); + + weight + } + + /// Reads the length of account in DepositOf without getting the complete value in the runtime. + /// + /// Return 0 if no deposit for this proposal. + fn len_of_deposit_of(proposal: PropIndex) -> Option { + // DepositOf first tuple element is a vec, decoding its len is equivalent to decode a + // `Compact`. + decode_compact_u32_at(&>::hashed_key_for(proposal)) + } + + /// Return a proposal of an index. + fn proposal(index: PropIndex) -> Result<(PropIndex, BoundedCallOf, T::AccountId), Error> { + PublicProps::::get() + .into_iter() + .find(|(prop_index, _, _)| prop_index == &index) + .ok_or(Error::::ProposalMissing) + } + + /// Clear metadata if exist for a given owner. + fn clear_metadata(owner: MetadataOwner) { + if let Some(hash) = MetadataOf::::take(&owner) { + Self::deposit_event(Event::::MetadataCleared { owner, hash }); + } + } + + /// Transfer the metadata of an `owner` to a `new_owner`. + fn transfer_metadata(owner: MetadataOwner, new_owner: MetadataOwner) { + if let Some(hash) = MetadataOf::::take(&owner) { + MetadataOf::::insert(&new_owner, hash); + Self::deposit_event(Event::::MetadataTransferred { + prev_owner: owner, + owner: new_owner, + hash, + }); + } + } + + /// Ensure external origin for corresponding vote threshold. + fn ensure_external_origin( + threshold: VoteThreshold, + origin: OriginFor, + ) -> Result<(), BadOrigin> { + match threshold { + VoteThreshold::SuperMajorityApprove => { + let _ = T::ExternalOrigin::ensure_origin(origin)?; + }, + VoteThreshold::SuperMajorityAgainst => { + let _ = T::ExternalDefaultOrigin::ensure_origin(origin)?; + }, + VoteThreshold::SimpleMajority => { + let _ = T::ExternalMajorityOrigin::ensure_origin(origin)?; + }, + }; + Ok(()) + } +} + +/// Decode `Compact` from the trie at given key. +fn decode_compact_u32_at(key: &[u8]) -> Option { + // `Compact` takes at most 5 bytes. + let mut buf = [0u8; 5]; + let bytes = sp_io::storage::read(key, &mut buf, 0)?; + // The value may be smaller than 5 bytes. + let mut input = &buf[0..buf.len().min(bytes as usize)]; + match codec::Compact::::decode(&mut input) { + Ok(c) => Some(c.0), + Err(_) => { + sp_runtime::print("Failed to decode compact u32 at:"); + sp_runtime::print(key); + None + }, + } +} From 6cea2e64eb9d7daa36f7555812a5e7b57e59173c Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 30 Aug 2024 16:58:29 +0800 Subject: [PATCH 002/215] temp: stash submit --- pallets/collab-ai/aiusd-convertor/src/lib.rs | 136 +++++++++++++++---- 1 file changed, 106 insertions(+), 30 deletions(-) diff --git a/pallets/collab-ai/aiusd-convertor/src/lib.rs b/pallets/collab-ai/aiusd-convertor/src/lib.rs index 58a7b94b22..710a709ed6 100644 --- a/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -17,14 +17,29 @@ //! Pallet for converting among AIUSD and other stable token. //! #![cfg_attr(not(feature = "std"), no_std)] - +use frame_support::{ + pallet_prelude::*, + traits::{ + tokens::{ + fungibles::{Inspect as FsInspect, Mutate as FsMutate}, + Fortitude, Precision, + }, + StorageVersion, + }, +}; #[frame_support::pallet] pub mod pallet { use super::*; - type AssetId = ::AssetId; + /// Balance type alias for balances of assets that implement the `fungibles` trait. + pub(crate) type InspectFungibles = pallet_assets::Pallet as FsInspect::AccountId>; + pub(crate) type AssetBalanceOf = + InspectFungibles::Balance; + /// Type alias for Asset IDs. + pub(crate) type AssetIdOf = + InspectFungibles::AssetId; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -39,61 +54,122 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; // This is not a treasury account - // Balance of all types in this account will be distributed to user - // who help even the distribution of stable token - type ConvertingFeeAccount = Get; + // Balance of all types in this account record the + // available stable coin for AIUSD to switch back + type ConvertingFeeAccount: Get; - // Declare the asset id of AIUSD - type AIUSDAssetId = Get; + // Declare the asset id of AIUSD + type AIUSDAssetId: Get>; } + // Asset Id => ratio of system exchange rate for AIUSD to other token in 10^18 + // e.g. + // (1 USDT) = 10^6 in system + // (1 AIUSD) = 10^18 in system + // Value of StorageMap n = 10^(-12) * 10^(18) = 10^(6), + // which means (1 AIUSD) * n = (10^18) * (1 USDT) in system balance when converting. #[pallet::storage] - #[pallet::getter(fn reward_pools)] - pub type CumulatedFee = - StorageMap<_, Blake2_128Concat, T::EVMId, T::AccountId, OptionQuery>; + #[pallet::getter(fn enabled_tokens)] + pub type EnabledTokens = + StorageMap<_, Twox64Concat, AssetIdOf, AssetBalanceOf, OptionQuery>; + + #[pallet::error] + pub enum Error { + InvalidAssetId, + AssetNotEnabled, + CannotPayAsFee, + ReachMaximumSupply, + Overflow, + } + + #[pallet::event] + #[pallet::generate_deposit(pub (crate) fn deposit_event)] + pub enum Event { + /// AIUSD minted with other eligible stable token locked + AIUSDCreated { + beneficiary: T::AccountId, + asset_id: AssetIdOf, + amount: AssetBalanceOf, + }, + /// AIUSD burned with other eligible stable token released + AIUSDDestroyed { + beneficiary: T::AccountId, + asset_id: AssetIdOf, + amount: AssetBalanceOf, + }, + } #[pallet::call] impl Pallet { + + // Lock target_asset_id token and mint AIUSD #[pallet::call_index(0)] #[pallet::weight(W{195_000_000})] - pub fn switch_token( + pub fn mint_aiusd( origin: OriginFor, - consumed_asset_id: AssetId, - target_asset_id: AssetId, + target_asset_id: AssetIdOf, + amount: AssetBalanceOf, ) -> DispatchResultWithPostInfo { - let _ = T::IncConsumerOrigin::ensure_origin(origin)?; - for i in &who { - frame_system::Pallet::::inc_consumers(i)?; - } + let beneficiary = T::IncConsumerOrigin::ensure_origin(origin)?; + ensure!(EnabledTokens::::contains_key(&target_asset_id), Error::::AssetNotEnabled); + let aiusd_id = AIUSDAssetId::get(); + ensure!(InspectFungibles::asset_exists(&aiusd_id) && InspectFungibles::asset_exists(&target_asset_id), Error::::InvalidAssetId); + // It will fail if insufficient fund + let actual_amount: AssetBalanceOf = InspectFungibles::transfer(target_asset_id, beneficiary, ConvertingFeeAccount::get(), amount, Expendable)?; + + + let minted_amount: AssetBalanceOf = InspectFungibles::mint_into(aiusd_id, beneficiary, actual_amount)?; + + Self::deposit_event(Event::AIUSDCreated { beneficiary, asset_id: target_asset_id, amount }); + Ok(()) } - /// Enable a specific type of token available for switching - #[pallet::call_index(1)] - #[pallet::weight({195_000_000})] - pub fn enable_token( + // Burn aiusd and get target_asset_id token released + // Failed if pool does not have enough token of one type + #[pallet::call_index(0)] + #[pallet::weight(W{195_000_000})] + pub fn burn_aiusd( origin: OriginFor, - + target_asset_id: AssetIdOf, + amount: AssetBalanceOf, ) -> DispatchResultWithPostInfo { + let beneficiary = T::IncConsumerOrigin::ensure_origin(origin)?; + if let Some(ratio) = EnabledTokens::::get(&target_asset_id) { + let aiusd_id = AIUSDAssetId::get(); + ensure!(InspectFungibles::asset_exists(&aiusd_id) && InspectFungibles::asset_exists(&target_asset_id), Error::::InvalidAssetId); + // It will fail if insufficient fund + let actual_amount: AssetBalanceOf = InspectFungibles::transfer(aiusd_id, beneficiary, ConvertingFeeAccount::get(), amount, Expendable)?; + + // Maybe it is better to save decimal of AIUSD somewhere + let minted_amount: AssetBalanceOf = InspectFungibles::mint_into(target_asset_id, beneficiary, actual_amount * ratio / 10^18)?; + + Self::deposit_event(Event::AIUSDDestroyed { beneficiary, asset_id: target_asset_id, amount }); + Ok(()) + } else { + Err(Error::::AssetNotEnabled.into()) + } } - /// pause the switch of a specific type of token - #[pallet::call_index(2)] + + + /// Enable a specific type of token available for switching + #[pallet::call_index(1)] #[pallet::weight({195_000_000})] - pub fn pause_token( + pub fn enable_token( origin: OriginFor, - + target_asset_id: AssetId, ) -> DispatchResultWithPostInfo { } - /// unpause the switch of a specific type of token - #[pallet::call_index(3)] + /// disable a specific type of token available for switching + #[pallet::call_index(2)] #[pallet::weight({195_000_000})] - pub fn unpause_token( + pub fn disable_token( origin: OriginFor, - + target_asset_id: AssetId, ) -> DispatchResultWithPostInfo { } From 3da51dbec06441b1607676a8b7a31d7c3ee1334e Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 2 Sep 2024 11:37:44 +0800 Subject: [PATCH 003/215] feat: aiusd-convertor impl --- Cargo.toml | 5 + pallets/collab-ai/aiusd-convertor/src/lib.rs | 145 +++++++++++++------ 2 files changed, 105 insertions(+), 45 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index be1d357ec4..de6f738a35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ 'pallets/bridge/chain-bridge', 'pallets/bridge/bridge-transfer', 'pallets/bridge/common', + 'pallets/collab-ai/aiusd-convertor', 'pallets/extrinsic-filter', 'pallets/evm-address', 'pallets/evm-assertions', @@ -271,6 +272,10 @@ pallet-evm-precompile-parachain-staking = { path = "precompiles/parachain-stakin pallet-evm-precompile-score-staking = { path = "precompiles/score-staking", default-features = false } pallet-evm-assertions = { path = "pallets/evm-assertions", default-features = false } +# CollabAI local +pallet-aiusd-convertor = { path = "pallets/collab-ai/aiusd-convertor", default-features = false } + + [patch.crates-io] ring = { git = "https://github.com/betrusted-io/ring-xous", branch = "0.16.20-cleanup" } diff --git a/pallets/collab-ai/aiusd-convertor/src/lib.rs b/pallets/collab-ai/aiusd-convertor/src/lib.rs index 710a709ed6..0b61acce51 100644 --- a/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -15,31 +15,29 @@ // along with Litentry. If not, see . //! Pallet for converting among AIUSD and other stable token. -//! +//! #![cfg_attr(not(feature = "std"), no_std)] use frame_support::{ pallet_prelude::*, traits::{ tokens::{ fungibles::{Inspect as FsInspect, Mutate as FsMutate}, - Fortitude, Precision, + Fortitude, Precision, Preservation, }, StorageVersion, }, }; - - #[frame_support::pallet] pub mod pallet { use super::*; + pub(crate) type InspectFungibles = pallet_assets::Pallet; /// Balance type alias for balances of assets that implement the `fungibles` trait. - pub(crate) type InspectFungibles = pallet_assets::Pallet as FsInspect::AccountId>; pub(crate) type AssetBalanceOf = - InspectFungibles::Balance; + as FsInspect<::AccountId>>::Balance; /// Type alias for Asset IDs. pub(crate) type AssetIdOf = - InspectFungibles::AssetId; + as FsInspect<::AccountId>>::AssetId; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -51,24 +49,27 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config + pallet_assets::Config { - type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; - // This is not a treasury account - // Balance of all types in this account record the + // This is not a treasury account + // Balance of all types in this account record the // available stable coin for AIUSD to switch back - type ConvertingFeeAccount: Get; + type ConvertingFeeAccount: Get; // Declare the asset id of AIUSD - type AIUSDAssetId: Get>; + type AIUSDAssetId: Get>; + + /// The privileged origin to enable/disable AIUSD switch + type ManagerOrigin: EnsureOrigin; } // Asset Id => ratio of system exchange rate for AIUSD to other token in 10^18 // e.g. // (1 USDT) = 10^6 in system // (1 AIUSD) = 10^18 in system - // Value of StorageMap n = 10^(-12) * 10^(18) = 10^(6), + // Value of StorageMap n = 10^(-12) * 10^(18) = 10^(6), // which means (1 AIUSD) * n = (10^18) * (1 USDT) in system balance when converting. - #[pallet::storage] + #[pallet::storage] #[pallet::getter(fn enabled_tokens)] pub type EnabledTokens = StorageMap<_, Twox64Concat, AssetIdOf, AssetBalanceOf, OptionQuery>; @@ -88,41 +89,71 @@ pub mod pallet { /// AIUSD minted with other eligible stable token locked AIUSDCreated { beneficiary: T::AccountId, + aiusd_amount: AssetBalanceOf, asset_id: AssetIdOf, - amount: AssetBalanceOf, + asset_amount: AssetBalanceOf, }, /// AIUSD burned with other eligible stable token released AIUSDDestroyed { beneficiary: T::AccountId, + aiusd_amount: AssetBalanceOf, + asset_id: AssetIdOf, + asset_amount: AssetBalanceOf, + }, + AssetEnabled { + asset_id: AssetIdOf, + decimal_ratio: AssetBalanceOf, + }, + AssetDisabled { asset_id: AssetIdOf, - amount: AssetBalanceOf, }, } #[pallet::call] impl Pallet { - // Lock target_asset_id token and mint AIUSD #[pallet::call_index(0)] #[pallet::weight(W{195_000_000})] pub fn mint_aiusd( origin: OriginFor, - target_asset_id: AssetIdOf, - amount: AssetBalanceOf, + target_asset_id: AssetIdOf, + aiusd_amount: AssetBalanceOf, ) -> DispatchResultWithPostInfo { let beneficiary = T::IncConsumerOrigin::ensure_origin(origin)?; - ensure!(EnabledTokens::::contains_key(&target_asset_id), Error::::AssetNotEnabled); - let aiusd_id = AIUSDAssetId::get(); - ensure!(InspectFungibles::asset_exists(&aiusd_id) && InspectFungibles::asset_exists(&target_asset_id), Error::::InvalidAssetId); - // It will fail if insufficient fund - let actual_amount: AssetBalanceOf = InspectFungibles::transfer(target_asset_id, beneficiary, ConvertingFeeAccount::get(), amount, Expendable)?; - - - let minted_amount: AssetBalanceOf = InspectFungibles::mint_into(aiusd_id, beneficiary, actual_amount)?; - - Self::deposit_event(Event::AIUSDCreated { beneficiary, asset_id: target_asset_id, amount }); - - Ok(()) + if let Some(ratio) = EnabledTokens::::get(&target_asset_id) { + ensure!( + EnabledTokens::::contains_key(&target_asset_id), + Error::::AssetNotEnabled + ); + let aiusd_id = AIUSDAssetId::get(); + ensure!(InspectFungibles::asset_exists(&aiusd_id) && InspectFungibles::asset_exists(&target_asset_id), Error::::InvalidAssetId); + // It will fail if insufficient fund + let aiusd_minted_amount: AssetBalanceOf = + >::mint_into(aiusd_id, beneficiary, aiusd_amount)?; + + // Maybe it is better to save decimal of AIUSD somewhere + let aseet_target_transfer_amount = + aiusd_minted_amount.checked_mul(ratio)?.checked_div(10 ^ 18)?; + let asset_actual_transfer_amount: AssetBalanceOf = + >::transfer( + target_asset_id, + beneficiary, + ConvertingFeeAccount::get(), + aseet_target_mint_amount, + Preservation::Expendable, + )?; + + Self::deposit_event(Event::AIUSDCreated { + beneficiary, + aiusd_amount: aiusd_minted_amount, + asset_id: target_asset_id, + asset_amount: asset_actual_transfer_amount, + }); + + Ok(()) + } else { + Err(Error::::AssetNotEnabled.into()) + } } // Burn aiusd and get target_asset_id token released @@ -131,37 +162,58 @@ pub mod pallet { #[pallet::weight(W{195_000_000})] pub fn burn_aiusd( origin: OriginFor, - target_asset_id: AssetIdOf, - amount: AssetBalanceOf, + target_asset_id: AssetIdOf, + aiusd_amount: AssetBalanceOf, ) -> DispatchResultWithPostInfo { let beneficiary = T::IncConsumerOrigin::ensure_origin(origin)?; if let Some(ratio) = EnabledTokens::::get(&target_asset_id) { let aiusd_id = AIUSDAssetId::get(); ensure!(InspectFungibles::asset_exists(&aiusd_id) && InspectFungibles::asset_exists(&target_asset_id), Error::::InvalidAssetId); // It will fail if insufficient fund - let actual_amount: AssetBalanceOf = InspectFungibles::transfer(aiusd_id, beneficiary, ConvertingFeeAccount::get(), amount, Expendable)?; - - - // Maybe it is better to save decimal of AIUSD somewhere - let minted_amount: AssetBalanceOf = InspectFungibles::mint_into(target_asset_id, beneficiary, actual_amount * ratio / 10^18)?; + let aiusd_destroyed_amount: AssetBalanceOf = >::burn_from( + aiusd_id, + beneficiary, + aiusd_amount, + Precision::Exact, + Fortitude::Polite, + )?; - Self::deposit_event(Event::AIUSDDestroyed { beneficiary, asset_id: target_asset_id, amount }); + // Maybe it is better to save decimal of AIUSD somewhere + let aseet_target_transfer_amount = + aiusd_destroyed_amount.checked_mul(ratio)?.checked_div(10 ^ 18)?; + let asset_actual_transfer_amount: AssetBalanceOf = + >::transfer( + target_asset_id, + ConvertingFeeAccount::get(), + beneficiary, + aseet_target_transfer_amount, + Preservation::Expendable, + )?; + + Self::deposit_event(Event::AIUSDDestroyed { + beneficiary, + aiusd_amount: aiusd_destroyed_amount, + asset_id: target_asset_id, + asset_amount: asset_actual_transfer_amount, + }); Ok(()) } else { Err(Error::::AssetNotEnabled.into()) } } - - - /// Enable a specific type of token available for switching - #[pallet::call_index(1)] + /// Enable a specific type of token available for switching + #[pallet::call_index(1)] #[pallet::weight({195_000_000})] pub fn enable_token( origin: OriginFor, target_asset_id: AssetId, + decimal_ratio: AssetBalanceOf, ) -> DispatchResultWithPostInfo { - + T::ManagerOrigin::ensure_origin(origin)?; + EnabledTokens::::insert(&target_asset_id, decimal_ratio); + Self::deposit_event(Event::AssetEnabled { asset_id: target_asset_id, decimal_ratio }); + Ok(Pays::No.into()) } /// disable a specific type of token available for switching @@ -171,7 +223,10 @@ pub mod pallet { origin: OriginFor, target_asset_id: AssetId, ) -> DispatchResultWithPostInfo { - + T::ManagerOrigin::ensure_origin(origin)?; + EnabledTokens::::remove(&target_asset_id); + Self::deposit_event(Event::AssetDisabled { asset_id: target_asset_id }); + Ok(Pays::No.into()) } } } From 702d4e6069f5f82cab848e6275e84c7da2dfd4b1 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 2 Sep 2024 17:57:05 +0800 Subject: [PATCH 004/215] feat: half stash commit of pallet curator impl --- Cargo.lock | 17 + Cargo.toml | 2 + pallets/collab-ai/aiusd-convertor/src/lib.rs | 5 +- pallets/collab-ai/common/Cargo.toml | 27 + pallets/collab-ai/common/src/lib.rs | 51 + pallets/collab-ai/curator/Cargo.toml | 21 +- pallets/collab-ai/curator/src/lib.rs | 1310 ++---------------- 7 files changed, 185 insertions(+), 1248 deletions(-) create mode 100644 pallets/collab-ai/common/Cargo.toml create mode 100644 pallets/collab-ai/common/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 72cdab3888..e720b08abb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6815,6 +6815,23 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-aiusd-convertor" +version = "0.1.0" +dependencies = [ + "frame-support", + "frame-system", + "hex-literal", + "pallet-assets", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-asset-manager" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index de6f738a35..3790c2e701 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -274,6 +274,8 @@ pallet-evm-assertions = { path = "pallets/evm-assertions", default-features = fa # CollabAI local pallet-aiusd-convertor = { path = "pallets/collab-ai/aiusd-convertor", default-features = false } +pallet-collab-ai-common = { path = "pallets/collab-ai/common", default-features = false } +pallet-curator = { path = "pallets/collab-ai/curator", default-features = false } [patch.crates-io] diff --git a/pallets/collab-ai/aiusd-convertor/src/lib.rs b/pallets/collab-ai/aiusd-convertor/src/lib.rs index 0b61acce51..9e02056cfe 100644 --- a/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -20,10 +20,7 @@ use frame_support::{ pallet_prelude::*, traits::{ - tokens::{ - fungibles::{Inspect as FsInspect, Mutate as FsMutate}, - Fortitude, Precision, Preservation, - }, + tokens::{fungibles::Inspect as FsInspect, Fortitude, Precision, Preservation}, StorageVersion, }, }; diff --git a/pallets/collab-ai/common/Cargo.toml b/pallets/collab-ai/common/Cargo.toml new file mode 100644 index 0000000000..e32dc05c4a --- /dev/null +++ b/pallets/collab-ai/common/Cargo.toml @@ -0,0 +1,27 @@ +[package] +authors = ['Trust Computing GmbH '] +edition = '2021' +homepage = 'https://litentry.com' +name = 'pallet-collab-ai-common' +repository = 'https://github.com/litentry/litentry-parachain' +version = '0.1.0' + +[dependencies] +parity-scale-codec = { workspace = true } +scale-info = { workspace = true } + +frame-support = { workspace = true, optional = true } +sp-runtime = { workspace = true } + +[features] +default = ["std"] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +std = [ + "scale-info/std", + "parity-scale-codec/std", + "frame-support?/std", + "sp-runtime/std", +] diff --git a/pallets/collab-ai/common/src/lib.rs b/pallets/collab-ai/common/src/lib.rs new file mode 100644 index 0000000000..f65c8d2c4f --- /dev/null +++ b/pallets/collab-ai/common/src/lib.rs @@ -0,0 +1,51 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +#![cfg_attr(not(feature = "std"), no_std)] +use parity_scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_runtime::DispatchError; + +#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] +pub struct PoolSetting { + // The start time of staking pool + pub start_time: BlockNumber, + // How many epoch will staking pool last, n > 0, valid epoch index :[0..n) + pub epoch: u128, + // How many blocks each epoch consist + pub epoch_range: BlockNumber, + // The number of block regarding setup for purchasing hardware which deliver no non-native + // token reward + pub setup_time: BlockNumber, + // Max staked amount of pool + pub pool_cap: Balance, + // Minimum amount of token required for pool starting + pub minimum_cap: Balance, +} + +#[derive(PartialEq, Eq, Clone, Copy, Default, Encode, Decode, Debug, TypeInfo)] +pub enum CandidateStatus { + /// Initial status of legal file + #[default] + #[codec(index = 0)] + Unverified, + /// Checked and authorized status of legal file + #[codec(index = 1)] + Verified, + /// Legal file suspicious and banned + #[codec(index = 2)] + Banned, +} diff --git a/pallets/collab-ai/curator/Cargo.toml b/pallets/collab-ai/curator/Cargo.toml index a0b37e8fc0..94dddabc71 100644 --- a/pallets/collab-ai/curator/Cargo.toml +++ b/pallets/collab-ai/curator/Cargo.toml @@ -4,7 +4,7 @@ description = 'Pallet for managing Curator and pool proposal' edition = '2021' homepage = 'https://litentry.com/' license = 'GPL-3.0' -name = 'pallet-evm-address' +name = 'pallet-curator' repository = 'https://github.com/litentry/litentry-parachain' version = '0.1.0' @@ -17,35 +17,22 @@ frame-system = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } -[dev-dependencies] -hex-literal = { workspace = true } -sp-core = { workspace = true, features = ["std"] } -sp-io = { workspace = true, features = ["std"] } -pallet-balances = { workspace = true, features = ["std"] } -pallet-timestamp = { workspace = true, features = ["std"] } +pallet-collab-ai-common = { workspace = true } [features] default = ["std"] runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", - "pallet-ethereum/runtime-benchmarks", + "pallet-collab-ai-common/runtime-benchmarks", ] std = [ "parity-scale-codec/std", "scale-info/std", - "sp-core/std", - "sp-io/std", "sp-std/std", - "sp-io/std", - "sp-core/std", "sp-runtime/std", "frame-support/std", "frame-system/std", - "pallet-balances/std", - "pallet-timestamp/std", - "pallet-ethereum/std", - "pallet-evm/std", - "fp-evm/std", + "pallet-collab-ai-common/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/collab-ai/curator/src/lib.rs b/pallets/collab-ai/curator/src/lib.rs index d46030b609..ddfca4db79 100644 --- a/pallets/collab-ai/curator/src/lib.rs +++ b/pallets/collab-ai/curator/src/lib.rs @@ -40,7 +40,7 @@ use frame_support::{ weights::Weight, }; use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; - +use sp_core::H256; pub use pallet::*; #[cfg(test)] @@ -60,12 +60,23 @@ pub type CallOf = ::RuntimeCall; pub type BoundedCallOf = Bounded>; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; +pub type InfoHash = H256; +pub type CuratorIndex = u128; +pub type PoolProposalIndex = u128; + +#[derive(Clone, Encode, Decode, Eq, PartialEq, Default, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub struct PoolMetadata { + /// The user friendly name of this staking pool. Limited in length by `PoolStringLimit`. + pub name: BoundedString, + /// The short description for this staking pool. Limited in length by `PoolStringLimit`. + pub description: BoundedString, +} + #[frame_support::pallet] pub mod pallet { use super::{DispatchResult, *}; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - use sp_core::H256; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -76,7 +87,6 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config + Sized { - type WeightInfo: WeightInfo; type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The Scheduler. @@ -130,16 +140,9 @@ pub mod pallet { #[pallet::constant] type CooloffPeriod: Get>; - /// The maximum number of votes for an account. - /// - /// Also used to compute weight, an overly big value can - /// lead to extrinsic with very big weight: see `delegate` for instance. - #[pallet::constant] - type MaxVotes: Get; - /// The maximum number of public proposals that can exist at any time. #[pallet::constant] - type MaxProposals: Get; + type MaxCurators: Get; /// The maximum number of deposits a public proposal may have at any time. #[pallet::constant] @@ -195,119 +198,62 @@ pub mod pallet { type Slash: OnUnbalanced>; } - /// The number of (public) proposals that have been made so far. + /// The number of (public) curator that have been made so far. #[pallet::storage] - #[pallet::getter(fn public_prop_count)] - pub type PublicPropCount = StorageValue<_, PropIndex, ValueQuery>; + #[pallet::getter(fn public_curator_count)] + pub type PublicCuratorCount = StorageValue<_, CuratorIndex, ValueQuery>; - /// The public proposals. Unsorted. The second item is the proposal. + /// The public Curator. The second item is current using curator legal file hash. #[pallet::storage] - #[pallet::getter(fn public_props)] - pub type PublicProps = StorageValue< + #[pallet::getter(fn public_curators)] + pub type PublicCurators = StorageMap< _, - BoundedVec<(PropIndex, BoundedCallOf, T::AccountId), T::MaxProposals>, - ValueQuery, + Twox64Concat, + T::AccountId, + (CuratorIndex, InfoHash), + OptionQuery, >; - /// Those who have locked a deposit. - /// - /// TWOX-NOTE: Safe, as increasing integer keys are safe. + // Storing all history curator info hash with updated time + // We all record the user who update the hash in the first place #[pallet::storage] - #[pallet::getter(fn deposit_of)] - pub type DepositOf = StorageMap< + #[pallet::getter(fn curator_info_hash)] + pub type CuratorInfoHash = StorageMap< _, Twox64Concat, - PropIndex, - (BoundedVec, BalanceOf), + InfoHash, + (BlockNumberFor, T::AccountId, CandidateStatus), + OptionQuery, >; /// The next free referendum index, aka the number of referenda started so far. #[pallet::storage] - #[pallet::getter(fn referendum_count)] - pub type ReferendumCount = StorageValue<_, ReferendumIndex, ValueQuery>; - - /// The lowest referendum index representing an unbaked referendum. Equal to - /// `ReferendumCount` if there isn't a unbaked referendum. - #[pallet::storage] - #[pallet::getter(fn lowest_unbaked)] - pub type LowestUnbaked = StorageValue<_, ReferendumIndex, ValueQuery>; + #[pallet::getter(fn pool_proposal_count)] + pub type PoolProposalCount = StorageValue<_, PoolProposalIndex, ValueQuery>; - /// Information concerning any given referendum. + /// Those who have a reserve for his pool proposal. /// - /// TWOX-NOTE: SAFE as indexes are not under an attacker’s control. + /// TWOX-NOTE: Safe, as increasing integer keys are safe. #[pallet::storage] - #[pallet::getter(fn referendum_info)] - pub type ReferendumInfoOf = StorageMap< + #[pallet::getter(fn pool_deposit_of)] + pub type PoolDepositOf = StorageMap< _, Twox64Concat, - ReferendumIndex, - ReferendumInfo, BoundedCallOf, BalanceOf>, + CuratorIndex, + BoundedVec<(PoolProposalIndex, BalanceOf), T::MaxDeposits>, >; - /// All votes for a particular voter. We store the balance for the number of votes that we - /// have recorded. The second item is the total amount of delegations, that will be added. - /// - /// TWOX-NOTE: SAFE as `AccountId`s are crypto hashes anyway. + // Metadata of staking pools #[pallet::storage] - pub type VotingOf = StorageMap< + #[pallet::getter(fn staking_pool_metadata)] + pub type StakingPoolMetadata = StorageMap< _, Twox64Concat, - T::AccountId, - Voting, T::AccountId, BlockNumberFor, T::MaxVotes>, - ValueQuery, + PoolProposalIndex, + PoolMetadata>, + OptionQuery, >; - /// True if the last referendum tabled was submitted externally. False if it was a public - /// proposal. - #[pallet::storage] - pub type LastTabledWasExternal = StorageValue<_, bool, ValueQuery>; - - /// The referendum to be tabled whenever it would be valid to table an external proposal. - /// This happens when a referendum needs to be tabled and one of two conditions are met: - /// - `LastTabledWasExternal` is `false`; or - /// - `PublicProps` is empty. - #[pallet::storage] - pub type NextExternal = StorageValue<_, (BoundedCallOf, VoteThreshold)>; - - /// A record of who vetoed what. Maps proposal hash to a possible existent block number - /// (until when it may not be resubmitted) and who vetoed it. - #[pallet::storage] - pub type Blacklist = StorageMap< - _, - Identity, - H256, - (BlockNumberFor, BoundedVec), - >; - - /// Record of all proposals that have been subject to emergency cancellation. - #[pallet::storage] - pub type Cancellations = StorageMap<_, Identity, H256, bool, ValueQuery>; - - /// General information concerning any proposal or referendum. - /// The `PreimageHash` refers to the preimage of the `Preimages` provider which can be a JSON - /// dump or IPFS hash of a JSON file. - /// - /// Consider a garbage collection for a metadata of finished referendums to `unrequest` (remove) - /// large preimages. - #[pallet::storage] - pub type MetadataOf = StorageMap<_, Blake2_128Concat, MetadataOwner, PreimageHash>; - - #[pallet::genesis_config] - #[derive(frame_support::DefaultNoBound)] - pub struct GenesisConfig { - #[serde(skip)] - _config: sp_std::marker::PhantomData, - } - - #[pallet::genesis_build] - impl BuildGenesisConfig for GenesisConfig { - fn build(&self) { - PublicPropCount::::put(0 as PropIndex); - ReferendumCount::::put(0 as ReferendumIndex); - LowestUnbaked::::put(0 as ReferendumIndex); - } - } - #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -401,20 +347,6 @@ pub mod pallet { /// The account currently has votes attached to it and the operation cannot succeed until /// these are removed, either through `unvote` or `reap_vote`. VotesExist, - /// The instant referendum origin is currently disallowed. - InstantNotAllowed, - /// Delegation to oneself makes no sense. - Nonsense, - /// Invalid upper bound. - WrongUpperBound, - /// Maximum number of votes reached. - MaxVotesReached, - /// Maximum number of items reached. - TooMany, - /// Voting period too low - VotingPeriodLow, - /// The preimage does not exist. - PreimageNotExist, } #[pallet::hooks] @@ -427,7 +359,35 @@ pub mod pallet { #[pallet::call] impl Pallet { - /// Propose a sensitive action to be taken. + /// Registing a curator legal info + #[pallet::call_index(0)] + #[pallet::weight(W{195_000_000})] + pub fn regist_curator( + origin: OriginFor, + info_hash: Option, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + // Ensure curator not existing yet + + + } + + /// Updating a curator legal info + #[pallet::call_index(0)] + #[pallet::weight(W{195_000_000})] + pub fn update_curator( + origin: OriginFor, + info_hash: Option, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + // Ensure existing + } + + + + /// Curator propose a staking pool /// /// The dispatch origin of this call must be _Signed_ and the sender must /// have funds to cover the deposit. @@ -437,13 +397,18 @@ pub mod pallet { /// /// Emits `Proposed`. #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::propose())] - pub fn propose( + #[pallet::weight(W{195_000_000})] + pub fn propose_staking_pool( origin: OriginFor, - proposal: BoundedCallOf, + pool_setup: PoolSetting, BalanceOf>, #[pallet::compact] value: BalanceOf, ) -> DispatchResult { - let who = T::SubmitOrigin::ensure_origin(origin)?; + let who = ensure_signed(origin)?; + + + + + ensure!(value >= T::MinimumDeposit::get(), Error::::ValueLow); let index = Self::public_prop_count(); @@ -497,1114 +462,5 @@ pub mod pallet { Self::deposit_event(Event::::Seconded { seconder: who, prop_index: proposal }); Ok(()) } - - /// Vote in a referendum. If `vote.is_aye()`, the vote is to enact the proposal; - /// otherwise it is a vote to keep the status quo. - /// - /// The dispatch origin of this call must be _Signed_. - /// - /// - `ref_index`: The index of the referendum to vote for. - /// - `vote`: The vote configuration. - #[pallet::call_index(2)] - #[pallet::weight(T::WeightInfo::vote_new().max(T::WeightInfo::vote_existing()))] - pub fn vote( - origin: OriginFor, - #[pallet::compact] ref_index: ReferendumIndex, - vote: AccountVote>, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - Self::try_vote(&who, ref_index, vote) - } - - /// Schedule an emergency cancellation of a referendum. Cannot happen twice to the same - /// referendum. - /// - /// The dispatch origin of this call must be `CancellationOrigin`. - /// - /// -`ref_index`: The index of the referendum to cancel. - /// - /// Weight: `O(1)`. - #[pallet::call_index(3)] - #[pallet::weight((T::WeightInfo::emergency_cancel(), DispatchClass::Operational))] - pub fn emergency_cancel( - origin: OriginFor, - ref_index: ReferendumIndex, - ) -> DispatchResult { - T::CancellationOrigin::ensure_origin(origin)?; - - let status = Self::referendum_status(ref_index)?; - let h = status.proposal.hash(); - ensure!(!>::contains_key(h), Error::::AlreadyCanceled); - - >::insert(h, true); - Self::internal_cancel_referendum(ref_index); - Ok(()) - } - - /// Schedule a referendum to be tabled once it is legal to schedule an external - /// referendum. - /// - /// The dispatch origin of this call must be `ExternalOrigin`. - /// - /// - `proposal_hash`: The preimage hash of the proposal. - #[pallet::call_index(4)] - #[pallet::weight(T::WeightInfo::external_propose())] - pub fn external_propose( - origin: OriginFor, - proposal: BoundedCallOf, - ) -> DispatchResult { - T::ExternalOrigin::ensure_origin(origin)?; - ensure!(!>::exists(), Error::::DuplicateProposal); - if let Some((until, _)) = >::get(proposal.hash()) { - ensure!( - >::block_number() >= until, - Error::::ProposalBlacklisted, - ); - } - >::put((proposal, VoteThreshold::SuperMajorityApprove)); - Ok(()) - } - - /// Schedule a majority-carries referendum to be tabled next once it is legal to schedule - /// an external referendum. - /// - /// The dispatch of this call must be `ExternalMajorityOrigin`. - /// - /// - `proposal_hash`: The preimage hash of the proposal. - /// - /// Unlike `external_propose`, blacklisting has no effect on this and it may replace a - /// pre-scheduled `external_propose` call. - /// - /// Weight: `O(1)` - #[pallet::call_index(5)] - #[pallet::weight(T::WeightInfo::external_propose_majority())] - pub fn external_propose_majority( - origin: OriginFor, - proposal: BoundedCallOf, - ) -> DispatchResult { - T::ExternalMajorityOrigin::ensure_origin(origin)?; - >::put((proposal, VoteThreshold::SimpleMajority)); - Ok(()) - } - - /// Schedule a negative-turnout-bias referendum to be tabled next once it is legal to - /// schedule an external referendum. - /// - /// The dispatch of this call must be `ExternalDefaultOrigin`. - /// - /// - `proposal_hash`: The preimage hash of the proposal. - /// - /// Unlike `external_propose`, blacklisting has no effect on this and it may replace a - /// pre-scheduled `external_propose` call. - /// - /// Weight: `O(1)` - #[pallet::call_index(6)] - #[pallet::weight(T::WeightInfo::external_propose_default())] - pub fn external_propose_default( - origin: OriginFor, - proposal: BoundedCallOf, - ) -> DispatchResult { - T::ExternalDefaultOrigin::ensure_origin(origin)?; - >::put((proposal, VoteThreshold::SuperMajorityAgainst)); - Ok(()) - } - - /// Schedule the currently externally-proposed majority-carries referendum to be tabled - /// immediately. If there is no externally-proposed referendum currently, or if there is one - /// but it is not a majority-carries referendum then it fails. - /// - /// The dispatch of this call must be `FastTrackOrigin`. - /// - /// - `proposal_hash`: The hash of the current external proposal. - /// - `voting_period`: The period that is allowed for voting on this proposal. Increased to - /// Must be always greater than zero. - /// For `FastTrackOrigin` must be equal or greater than `FastTrackVotingPeriod`. - /// - `delay`: The number of block after voting has ended in approval and this should be - /// enacted. This doesn't have a minimum amount. - /// - /// Emits `Started`. - /// - /// Weight: `O(1)` - #[pallet::call_index(7)] - #[pallet::weight(T::WeightInfo::fast_track())] - pub fn fast_track( - origin: OriginFor, - proposal_hash: H256, - voting_period: BlockNumberFor, - delay: BlockNumberFor, - ) -> DispatchResult { - // Rather complicated bit of code to ensure that either: - // - `voting_period` is at least `FastTrackVotingPeriod` and `origin` is - // `FastTrackOrigin`; or - // - `InstantAllowed` is `true` and `origin` is `InstantOrigin`. - let maybe_ensure_instant = if voting_period < T::FastTrackVotingPeriod::get() { - Some(origin) - } else if let Err(origin) = T::FastTrackOrigin::try_origin(origin) { - Some(origin) - } else { - None - }; - if let Some(ensure_instant) = maybe_ensure_instant { - T::InstantOrigin::ensure_origin(ensure_instant)?; - ensure!(T::InstantAllowed::get(), Error::::InstantNotAllowed); - } - - ensure!(voting_period > Zero::zero(), Error::::VotingPeriodLow); - let (ext_proposal, threshold) = - >::get().ok_or(Error::::ProposalMissing)?; - ensure!( - threshold != VoteThreshold::SuperMajorityApprove, - Error::::NotSimpleMajority, - ); - ensure!(proposal_hash == ext_proposal.hash(), Error::::InvalidHash); - - >::kill(); - let now = >::block_number(); - let ref_index = Self::inject_referendum( - now.saturating_add(voting_period), - ext_proposal, - threshold, - delay, - ); - Self::transfer_metadata(MetadataOwner::External, MetadataOwner::Referendum(ref_index)); - Ok(()) - } - - /// Veto and blacklist the external proposal hash. - /// - /// The dispatch origin of this call must be `VetoOrigin`. - /// - /// - `proposal_hash`: The preimage hash of the proposal to veto and blacklist. - /// - /// Emits `Vetoed`. - /// - /// Weight: `O(V + log(V))` where V is number of `existing vetoers` - #[pallet::call_index(8)] - #[pallet::weight(T::WeightInfo::veto_external())] - pub fn veto_external(origin: OriginFor, proposal_hash: H256) -> DispatchResult { - let who = T::VetoOrigin::ensure_origin(origin)?; - - if let Some((ext_proposal, _)) = NextExternal::::get() { - ensure!(proposal_hash == ext_proposal.hash(), Error::::ProposalMissing); - } else { - return Err(Error::::NoProposal.into()) - } - - let mut existing_vetoers = - >::get(&proposal_hash).map(|pair| pair.1).unwrap_or_default(); - let insert_position = - existing_vetoers.binary_search(&who).err().ok_or(Error::::AlreadyVetoed)?; - existing_vetoers - .try_insert(insert_position, who.clone()) - .map_err(|_| Error::::TooMany)?; - - let until = - >::block_number().saturating_add(T::CooloffPeriod::get()); - >::insert(&proposal_hash, (until, existing_vetoers)); - - Self::deposit_event(Event::::Vetoed { who, proposal_hash, until }); - >::kill(); - Self::clear_metadata(MetadataOwner::External); - Ok(()) - } - - /// Remove a referendum. - /// - /// The dispatch origin of this call must be _Root_. - /// - /// - `ref_index`: The index of the referendum to cancel. - /// - /// # Weight: `O(1)`. - #[pallet::call_index(9)] - #[pallet::weight(T::WeightInfo::cancel_referendum())] - pub fn cancel_referendum( - origin: OriginFor, - #[pallet::compact] ref_index: ReferendumIndex, - ) -> DispatchResult { - ensure_root(origin)?; - Self::internal_cancel_referendum(ref_index); - Ok(()) - } - - /// Delegate the voting power (with some given conviction) of the sending account. - /// - /// The balance delegated is locked for as long as it's delegated, and thereafter for the - /// time appropriate for the conviction's lock period. - /// - /// The dispatch origin of this call must be _Signed_, and the signing account must either: - /// - be delegating already; or - /// - have no voting activity (if there is, then it will need to be removed/consolidated - /// through `reap_vote` or `unvote`). - /// - /// - `to`: The account whose voting the `target` account's voting power will follow. - /// - `conviction`: The conviction that will be attached to the delegated votes. When the - /// account is undelegated, the funds will be locked for the corresponding period. - /// - `balance`: The amount of the account's balance to be used in delegating. This must not - /// be more than the account's current balance. - /// - /// Emits `Delegated`. - /// - /// Weight: `O(R)` where R is the number of referendums the voter delegating to has - /// voted on. Weight is charged as if maximum votes. - // NOTE: weight must cover an incorrect voting of origin with max votes, this is ensure - // because a valid delegation cover decoding a direct voting with max votes. - #[pallet::call_index(10)] - #[pallet::weight(T::WeightInfo::delegate(T::MaxVotes::get()))] - pub fn delegate( - origin: OriginFor, - to: AccountIdLookupOf, - conviction: Conviction, - balance: BalanceOf, - ) -> DispatchResultWithPostInfo { - let who = ensure_signed(origin)?; - let to = T::Lookup::lookup(to)?; - let votes = Self::try_delegate(who, to, conviction, balance)?; - - Ok(Some(T::WeightInfo::delegate(votes)).into()) - } - - /// Undelegate the voting power of the sending account. - /// - /// Tokens may be unlocked following once an amount of time consistent with the lock period - /// of the conviction with which the delegation was issued. - /// - /// The dispatch origin of this call must be _Signed_ and the signing account must be - /// currently delegating. - /// - /// Emits `Undelegated`. - /// - /// Weight: `O(R)` where R is the number of referendums the voter delegating to has - /// voted on. Weight is charged as if maximum votes. - // NOTE: weight must cover an incorrect voting of origin with max votes, this is ensure - // because a valid delegation cover decoding a direct voting with max votes. - #[pallet::call_index(11)] - #[pallet::weight(T::WeightInfo::undelegate(T::MaxVotes::get()))] - pub fn undelegate(origin: OriginFor) -> DispatchResultWithPostInfo { - let who = ensure_signed(origin)?; - let votes = Self::try_undelegate(who)?; - Ok(Some(T::WeightInfo::undelegate(votes)).into()) - } - - /// Clears all public proposals. - /// - /// The dispatch origin of this call must be _Root_. - /// - /// Weight: `O(1)`. - #[pallet::call_index(12)] - #[pallet::weight(T::WeightInfo::clear_public_proposals())] - pub fn clear_public_proposals(origin: OriginFor) -> DispatchResult { - ensure_root(origin)?; - >::kill(); - Ok(()) - } - - /// Unlock tokens that have an expired lock. - /// - /// The dispatch origin of this call must be _Signed_. - /// - /// - `target`: The account to remove the lock on. - /// - /// Weight: `O(R)` with R number of vote of target. - #[pallet::call_index(13)] - #[pallet::weight(T::WeightInfo::unlock_set(T::MaxVotes::get()).max(T::WeightInfo::unlock_remove(T::MaxVotes::get())))] - pub fn unlock(origin: OriginFor, target: AccountIdLookupOf) -> DispatchResult { - ensure_signed(origin)?; - let target = T::Lookup::lookup(target)?; - Self::update_lock(&target); - Ok(()) - } - - /// Remove a vote for a referendum. - /// - /// If: - /// - the referendum was cancelled, or - /// - the referendum is ongoing, or - /// - the referendum has ended such that - /// - the vote of the account was in opposition to the result; or - /// - there was no conviction to the account's vote; or - /// - the account made a split vote - /// ...then the vote is removed cleanly and a following call to `unlock` may result in more - /// funds being available. - /// - /// If, however, the referendum has ended and: - /// - it finished corresponding to the vote of the account, and - /// - the account made a standard vote with conviction, and - /// - the lock period of the conviction is not over - /// ...then the lock will be aggregated into the overall account's lock, which may involve - /// *overlocking* (where the two locks are combined into a single lock that is the maximum - /// of both the amount locked and the time is it locked for). - /// - /// The dispatch origin of this call must be _Signed_, and the signer must have a vote - /// registered for referendum `index`. - /// - /// - `index`: The index of referendum of the vote to be removed. - /// - /// Weight: `O(R + log R)` where R is the number of referenda that `target` has voted on. - /// Weight is calculated for the maximum number of vote. - #[pallet::call_index(14)] - #[pallet::weight(T::WeightInfo::remove_vote(T::MaxVotes::get()))] - pub fn remove_vote(origin: OriginFor, index: ReferendumIndex) -> DispatchResult { - let who = ensure_signed(origin)?; - Self::try_remove_vote(&who, index, UnvoteScope::Any) - } - - /// Remove a vote for a referendum. - /// - /// If the `target` is equal to the signer, then this function is exactly equivalent to - /// `remove_vote`. If not equal to the signer, then the vote must have expired, - /// either because the referendum was cancelled, because the voter lost the referendum or - /// because the conviction period is over. - /// - /// The dispatch origin of this call must be _Signed_. - /// - /// - `target`: The account of the vote to be removed; this account must have voted for - /// referendum `index`. - /// - `index`: The index of referendum of the vote to be removed. - /// - /// Weight: `O(R + log R)` where R is the number of referenda that `target` has voted on. - /// Weight is calculated for the maximum number of vote. - #[pallet::call_index(15)] - #[pallet::weight(T::WeightInfo::remove_other_vote(T::MaxVotes::get()))] - pub fn remove_other_vote( - origin: OriginFor, - target: AccountIdLookupOf, - index: ReferendumIndex, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - let target = T::Lookup::lookup(target)?; - let scope = if target == who { UnvoteScope::Any } else { UnvoteScope::OnlyExpired }; - Self::try_remove_vote(&target, index, scope)?; - Ok(()) - } - - /// Permanently place a proposal into the blacklist. This prevents it from ever being - /// proposed again. - /// - /// If called on a queued public or external proposal, then this will result in it being - /// removed. If the `ref_index` supplied is an active referendum with the proposal hash, - /// then it will be cancelled. - /// - /// The dispatch origin of this call must be `BlacklistOrigin`. - /// - /// - `proposal_hash`: The proposal hash to blacklist permanently. - /// - `ref_index`: An ongoing referendum whose hash is `proposal_hash`, which will be - /// cancelled. - /// - /// Weight: `O(p)` (though as this is an high-privilege dispatch, we assume it has a - /// reasonable value). - #[pallet::call_index(16)] - #[pallet::weight((T::WeightInfo::blacklist(), DispatchClass::Operational))] - pub fn blacklist( - origin: OriginFor, - proposal_hash: H256, - maybe_ref_index: Option, - ) -> DispatchResult { - T::BlacklistOrigin::ensure_origin(origin)?; - - // Insert the proposal into the blacklist. - let permanent = - (BlockNumberFor::::max_value(), BoundedVec::::default()); - Blacklist::::insert(&proposal_hash, permanent); - - // Remove the queued proposal, if it's there. - PublicProps::::mutate(|props| { - if let Some(index) = props.iter().position(|p| p.1.hash() == proposal_hash) { - let (prop_index, ..) = props.remove(index); - if let Some((whos, amount)) = DepositOf::::take(prop_index) { - for who in whos.into_iter() { - T::Slash::on_unbalanced(T::Currency::slash_reserved(&who, amount).0); - } - } - Self::clear_metadata(MetadataOwner::Proposal(prop_index)); - } - }); - - // Remove the external queued referendum, if it's there. - if matches!(NextExternal::::get(), Some((p, ..)) if p.hash() == proposal_hash) { - NextExternal::::kill(); - Self::clear_metadata(MetadataOwner::External); - } - - // Remove the referendum, if it's there. - if let Some(ref_index) = maybe_ref_index { - if let Ok(status) = Self::referendum_status(ref_index) { - if status.proposal.hash() == proposal_hash { - Self::internal_cancel_referendum(ref_index); - } - } - } - - Self::deposit_event(Event::::Blacklisted { proposal_hash }); - Ok(()) - } - - /// Remove a proposal. - /// - /// The dispatch origin of this call must be `CancelProposalOrigin`. - /// - /// - `prop_index`: The index of the proposal to cancel. - /// - /// Weight: `O(p)` where `p = PublicProps::::decode_len()` - #[pallet::call_index(17)] - #[pallet::weight(T::WeightInfo::cancel_proposal())] - pub fn cancel_proposal( - origin: OriginFor, - #[pallet::compact] prop_index: PropIndex, - ) -> DispatchResult { - T::CancelProposalOrigin::ensure_origin(origin)?; - - PublicProps::::mutate(|props| props.retain(|p| p.0 != prop_index)); - if let Some((whos, amount)) = DepositOf::::take(prop_index) { - for who in whos.into_iter() { - T::Slash::on_unbalanced(T::Currency::slash_reserved(&who, amount).0); - } - } - Self::deposit_event(Event::::ProposalCanceled { prop_index }); - Self::clear_metadata(MetadataOwner::Proposal(prop_index)); - Ok(()) - } - - /// Set or clear a metadata of a proposal or a referendum. - /// - /// Parameters: - /// - `origin`: Must correspond to the `MetadataOwner`. - /// - `ExternalOrigin` for an external proposal with the `SuperMajorityApprove` - /// threshold. - /// - `ExternalDefaultOrigin` for an external proposal with the `SuperMajorityAgainst` - /// threshold. - /// - `ExternalMajorityOrigin` for an external proposal with the `SimpleMajority` - /// threshold. - /// - `Signed` by a creator for a public proposal. - /// - `Signed` to clear a metadata for a finished referendum. - /// - `Root` to set a metadata for an ongoing referendum. - /// - `owner`: an identifier of a metadata owner. - /// - `maybe_hash`: The hash of an on-chain stored preimage. `None` to clear a metadata. - #[pallet::call_index(18)] - #[pallet::weight( - match (owner, maybe_hash) { - (MetadataOwner::External, Some(_)) => T::WeightInfo::set_external_metadata(), - (MetadataOwner::External, None) => T::WeightInfo::clear_external_metadata(), - (MetadataOwner::Proposal(_), Some(_)) => T::WeightInfo::set_proposal_metadata(), - (MetadataOwner::Proposal(_), None) => T::WeightInfo::clear_proposal_metadata(), - (MetadataOwner::Referendum(_), Some(_)) => T::WeightInfo::set_referendum_metadata(), - (MetadataOwner::Referendum(_), None) => T::WeightInfo::clear_referendum_metadata(), - } - )] - pub fn set_metadata( - origin: OriginFor, - owner: MetadataOwner, - maybe_hash: Option, - ) -> DispatchResult { - match owner { - MetadataOwner::External => { - let (_, threshold) = >::get().ok_or(Error::::NoProposal)?; - Self::ensure_external_origin(threshold, origin)?; - }, - MetadataOwner::Proposal(index) => { - let who = ensure_signed(origin)?; - let (_, _, proposer) = Self::proposal(index)?; - ensure!(proposer == who, Error::::NoPermission); - }, - MetadataOwner::Referendum(index) => { - let is_root = ensure_signed_or_root(origin)?.is_none(); - ensure!(is_root || maybe_hash.is_none(), Error::::NoPermission); - ensure!( - is_root || Self::referendum_status(index).is_err(), - Error::::NoPermission - ); - }, - } - if let Some(hash) = maybe_hash { - ensure!(T::Preimages::len(&hash).is_some(), Error::::PreimageNotExist); - MetadataOf::::insert(owner.clone(), hash); - Self::deposit_event(Event::::MetadataSet { owner, hash }); - } else { - Self::clear_metadata(owner); - } - Ok(()) - } - } -} - -pub trait EncodeInto: Encode { - fn encode_into + Default>(&self) -> T { - let mut t = T::default(); - self.using_encoded(|data| { - if data.len() <= t.as_mut().len() { - t.as_mut()[0..data.len()].copy_from_slice(data); - } else { - // encoded self is too big to fit into a T. hash it and use the first bytes of that - // instead. - let hash = sp_io::hashing::blake2_256(data); - let l = t.as_mut().len().min(hash.len()); - t.as_mut()[0..l].copy_from_slice(&hash[0..l]); - } - }); - t - } -} -impl EncodeInto for T {} - -impl Pallet { - // exposed immutables. - - /// Get the amount locked in support of `proposal`; `None` if proposal isn't a valid proposal - /// index. - pub fn backing_for(proposal: PropIndex) -> Option> { - Self::deposit_of(proposal).map(|(l, d)| d.saturating_mul((l.len() as u32).into())) - } - - /// Get all referenda ready for tally at block `n`. - pub fn maturing_referenda_at( - n: BlockNumberFor, - ) -> Vec<(ReferendumIndex, ReferendumStatus, BoundedCallOf, BalanceOf>)> - { - let next = Self::lowest_unbaked(); - let last = Self::referendum_count(); - Self::maturing_referenda_at_inner(n, next..last) - } - - fn maturing_referenda_at_inner( - n: BlockNumberFor, - range: core::ops::Range, - ) -> Vec<(ReferendumIndex, ReferendumStatus, BoundedCallOf, BalanceOf>)> - { - range - .into_iter() - .map(|i| (i, Self::referendum_info(i))) - .filter_map(|(i, maybe_info)| match maybe_info { - Some(ReferendumInfo::Ongoing(status)) => Some((i, status)), - _ => None, - }) - .filter(|(_, status)| status.end == n) - .collect() - } - - // Exposed mutables. - - /// Start a referendum. - pub fn internal_start_referendum( - proposal: BoundedCallOf, - threshold: VoteThreshold, - delay: BlockNumberFor, - ) -> ReferendumIndex { - >::inject_referendum( - >::block_number().saturating_add(T::VotingPeriod::get()), - proposal, - threshold, - delay, - ) - } - - /// Remove a referendum. - pub fn internal_cancel_referendum(ref_index: ReferendumIndex) { - Self::deposit_event(Event::::Cancelled { ref_index }); - ReferendumInfoOf::::remove(ref_index); - Self::clear_metadata(MetadataOwner::Referendum(ref_index)); - } - - // private. - - /// Ok if the given referendum is active, Err otherwise - fn ensure_ongoing( - r: ReferendumInfo, BoundedCallOf, BalanceOf>, - ) -> Result, BoundedCallOf, BalanceOf>, DispatchError> - { - match r { - ReferendumInfo::Ongoing(s) => Ok(s), - _ => Err(Error::::ReferendumInvalid.into()), - } - } - - fn referendum_status( - ref_index: ReferendumIndex, - ) -> Result, BoundedCallOf, BalanceOf>, DispatchError> - { - let info = ReferendumInfoOf::::get(ref_index).ok_or(Error::::ReferendumInvalid)?; - Self::ensure_ongoing(info) - } - - /// Actually enact a vote, if legit. - fn try_vote( - who: &T::AccountId, - ref_index: ReferendumIndex, - vote: AccountVote>, - ) -> DispatchResult { - let mut status = Self::referendum_status(ref_index)?; - ensure!(vote.balance() <= T::Currency::free_balance(who), Error::::InsufficientFunds); - VotingOf::::try_mutate(who, |voting| -> DispatchResult { - if let Voting::Direct { ref mut votes, delegations, .. } = voting { - match votes.binary_search_by_key(&ref_index, |i| i.0) { - Ok(i) => { - // Shouldn't be possible to fail, but we handle it gracefully. - status.tally.remove(votes[i].1).ok_or(ArithmeticError::Underflow)?; - if let Some(approve) = votes[i].1.as_standard() { - status.tally.reduce(approve, *delegations); - } - votes[i].1 = vote; - }, - Err(i) => { - votes - .try_insert(i, (ref_index, vote)) - .map_err(|_| Error::::MaxVotesReached)?; - }, - } - Self::deposit_event(Event::::Voted { voter: who.clone(), ref_index, vote }); - // Shouldn't be possible to fail, but we handle it gracefully. - status.tally.add(vote).ok_or(ArithmeticError::Overflow)?; - if let Some(approve) = vote.as_standard() { - status.tally.increase(approve, *delegations); - } - Ok(()) - } else { - Err(Error::::AlreadyDelegating.into()) - } - })?; - // Extend the lock to `balance` (rather than setting it) since we don't know what other - // votes are in place. - T::Currency::extend_lock( - DEMOCRACY_ID, - who, - vote.balance(), - WithdrawReasons::except(WithdrawReasons::RESERVE), - ); - ReferendumInfoOf::::insert(ref_index, ReferendumInfo::Ongoing(status)); - Ok(()) - } - - /// Remove the account's vote for the given referendum if possible. This is possible when: - /// - The referendum has not finished. - /// - The referendum has finished and the voter lost their direction. - /// - The referendum has finished and the voter's lock period is up. - /// - /// This will generally be combined with a call to `unlock`. - fn try_remove_vote( - who: &T::AccountId, - ref_index: ReferendumIndex, - scope: UnvoteScope, - ) -> DispatchResult { - let info = ReferendumInfoOf::::get(ref_index); - VotingOf::::try_mutate(who, |voting| -> DispatchResult { - if let Voting::Direct { ref mut votes, delegations, ref mut prior } = voting { - let i = votes - .binary_search_by_key(&ref_index, |i| i.0) - .map_err(|_| Error::::NotVoter)?; - match info { - Some(ReferendumInfo::Ongoing(mut status)) => { - ensure!(matches!(scope, UnvoteScope::Any), Error::::NoPermission); - // Shouldn't be possible to fail, but we handle it gracefully. - status.tally.remove(votes[i].1).ok_or(ArithmeticError::Underflow)?; - if let Some(approve) = votes[i].1.as_standard() { - status.tally.reduce(approve, *delegations); - } - ReferendumInfoOf::::insert(ref_index, ReferendumInfo::Ongoing(status)); - }, - Some(ReferendumInfo::Finished { end, approved }) => { - if let Some((lock_periods, balance)) = votes[i].1.locked_if(approved) { - let unlock_at = end.saturating_add( - T::VoteLockingPeriod::get().saturating_mul(lock_periods.into()), - ); - let now = frame_system::Pallet::::block_number(); - if now < unlock_at { - ensure!( - matches!(scope, UnvoteScope::Any), - Error::::NoPermission - ); - prior.accumulate(unlock_at, balance) - } - } - }, - None => {}, // Referendum was cancelled. - } - votes.remove(i); - } - Ok(()) - })?; - Ok(()) - } - - /// Return the number of votes for `who` - fn increase_upstream_delegation(who: &T::AccountId, amount: Delegations>) -> u32 { - VotingOf::::mutate(who, |voting| match voting { - Voting::Delegating { delegations, .. } => { - // We don't support second level delegating, so we don't need to do anything more. - *delegations = delegations.saturating_add(amount); - 1 - }, - Voting::Direct { votes, delegations, .. } => { - *delegations = delegations.saturating_add(amount); - for &(ref_index, account_vote) in votes.iter() { - if let AccountVote::Standard { vote, .. } = account_vote { - ReferendumInfoOf::::mutate(ref_index, |maybe_info| { - if let Some(ReferendumInfo::Ongoing(ref mut status)) = maybe_info { - status.tally.increase(vote.aye, amount); - } - }); - } - } - votes.len() as u32 - }, - }) - } - - /// Return the number of votes for `who` - fn reduce_upstream_delegation(who: &T::AccountId, amount: Delegations>) -> u32 { - VotingOf::::mutate(who, |voting| match voting { - Voting::Delegating { delegations, .. } => { - // We don't support second level delegating, so we don't need to do anything more. - *delegations = delegations.saturating_sub(amount); - 1 - }, - Voting::Direct { votes, delegations, .. } => { - *delegations = delegations.saturating_sub(amount); - for &(ref_index, account_vote) in votes.iter() { - if let AccountVote::Standard { vote, .. } = account_vote { - ReferendumInfoOf::::mutate(ref_index, |maybe_info| { - if let Some(ReferendumInfo::Ongoing(ref mut status)) = maybe_info { - status.tally.reduce(vote.aye, amount); - } - }); - } - } - votes.len() as u32 - }, - }) - } - - /// Attempt to delegate `balance` times `conviction` of voting power from `who` to `target`. - /// - /// Return the upstream number of votes. - fn try_delegate( - who: T::AccountId, - target: T::AccountId, - conviction: Conviction, - balance: BalanceOf, - ) -> Result { - ensure!(who != target, Error::::Nonsense); - ensure!(balance <= T::Currency::free_balance(&who), Error::::InsufficientFunds); - let votes = VotingOf::::try_mutate(&who, |voting| -> Result { - let mut old = Voting::Delegating { - balance, - target: target.clone(), - conviction, - delegations: Default::default(), - prior: Default::default(), - }; - sp_std::mem::swap(&mut old, voting); - match old { - Voting::Delegating { - balance, target, conviction, delegations, mut prior, .. - } => { - // remove any delegation votes to our current target. - Self::reduce_upstream_delegation(&target, conviction.votes(balance)); - let now = frame_system::Pallet::::block_number(); - let lock_periods = conviction.lock_periods().into(); - let unlock_block = now - .saturating_add(T::VoteLockingPeriod::get().saturating_mul(lock_periods)); - prior.accumulate(unlock_block, balance); - voting.set_common(delegations, prior); - }, - Voting::Direct { votes, delegations, prior } => { - // here we just ensure that we're currently idling with no votes recorded. - ensure!(votes.is_empty(), Error::::VotesExist); - voting.set_common(delegations, prior); - }, - } - let votes = Self::increase_upstream_delegation(&target, conviction.votes(balance)); - // Extend the lock to `balance` (rather than setting it) since we don't know what other - // votes are in place. - T::Currency::extend_lock( - DEMOCRACY_ID, - &who, - balance, - WithdrawReasons::except(WithdrawReasons::RESERVE), - ); - Ok(votes) - })?; - Self::deposit_event(Event::::Delegated { who, target }); - Ok(votes) - } - - /// Attempt to end the current delegation. - /// - /// Return the number of votes of upstream. - fn try_undelegate(who: T::AccountId) -> Result { - let votes = VotingOf::::try_mutate(&who, |voting| -> Result { - let mut old = Voting::default(); - sp_std::mem::swap(&mut old, voting); - match old { - Voting::Delegating { balance, target, conviction, delegations, mut prior } => { - // remove any delegation votes to our current target. - let votes = - Self::reduce_upstream_delegation(&target, conviction.votes(balance)); - let now = frame_system::Pallet::::block_number(); - let lock_periods = conviction.lock_periods().into(); - let unlock_block = now - .saturating_add(T::VoteLockingPeriod::get().saturating_mul(lock_periods)); - prior.accumulate(unlock_block, balance); - voting.set_common(delegations, prior); - - Ok(votes) - }, - Voting::Direct { .. } => Err(Error::::NotDelegating.into()), - } - })?; - Self::deposit_event(Event::::Undelegated { account: who }); - Ok(votes) - } - - /// Rejig the lock on an account. It will never get more stringent (since that would indicate - /// a security hole) but may be reduced from what they are currently. - fn update_lock(who: &T::AccountId) { - let lock_needed = VotingOf::::mutate(who, |voting| { - voting.rejig(frame_system::Pallet::::block_number()); - voting.locked_balance() - }); - if lock_needed.is_zero() { - T::Currency::remove_lock(DEMOCRACY_ID, who); - } else { - T::Currency::set_lock( - DEMOCRACY_ID, - who, - lock_needed, - WithdrawReasons::except(WithdrawReasons::RESERVE), - ); - } - } - - /// Start a referendum - fn inject_referendum( - end: BlockNumberFor, - proposal: BoundedCallOf, - threshold: VoteThreshold, - delay: BlockNumberFor, - ) -> ReferendumIndex { - let ref_index = Self::referendum_count(); - ReferendumCount::::put(ref_index + 1); - let status = - ReferendumStatus { end, proposal, threshold, delay, tally: Default::default() }; - let item = ReferendumInfo::Ongoing(status); - >::insert(ref_index, item); - Self::deposit_event(Event::::Started { ref_index, threshold }); - ref_index - } - - /// Table the next waiting proposal for a vote. - fn launch_next(now: BlockNumberFor) -> DispatchResult { - if LastTabledWasExternal::::take() { - Self::launch_public(now).or_else(|_| Self::launch_external(now)) - } else { - Self::launch_external(now).or_else(|_| Self::launch_public(now)) - } - .map_err(|_| Error::::NoneWaiting.into()) - } - - /// Table the waiting external proposal for a vote, if there is one. - fn launch_external(now: BlockNumberFor) -> DispatchResult { - if let Some((proposal, threshold)) = >::take() { - LastTabledWasExternal::::put(true); - Self::deposit_event(Event::::ExternalTabled); - let ref_index = Self::inject_referendum( - now.saturating_add(T::VotingPeriod::get()), - proposal, - threshold, - T::EnactmentPeriod::get(), - ); - Self::transfer_metadata(MetadataOwner::External, MetadataOwner::Referendum(ref_index)); - Ok(()) - } else { - return Err(Error::::NoneWaiting.into()) - } - } - - /// Table the waiting public proposal with the highest backing for a vote. - fn launch_public(now: BlockNumberFor) -> DispatchResult { - let mut public_props = Self::public_props(); - if let Some((winner_index, _)) = public_props.iter().enumerate().max_by_key( - // defensive only: All current public proposals have an amount locked - |x| Self::backing_for((x.1).0).defensive_unwrap_or_else(Zero::zero), - ) { - let (prop_index, proposal, _) = public_props.swap_remove(winner_index); - >::put(public_props); - - if let Some((depositors, deposit)) = >::take(prop_index) { - // refund depositors - for d in depositors.iter() { - T::Currency::unreserve(d, deposit); - } - Self::deposit_event(Event::::Tabled { proposal_index: prop_index, deposit }); - let ref_index = Self::inject_referendum( - now.saturating_add(T::VotingPeriod::get()), - proposal, - VoteThreshold::SuperMajorityApprove, - T::EnactmentPeriod::get(), - ); - Self::transfer_metadata( - MetadataOwner::Proposal(prop_index), - MetadataOwner::Referendum(ref_index), - ) - } - Ok(()) - } else { - return Err(Error::::NoneWaiting.into()) - } - } - - fn bake_referendum( - now: BlockNumberFor, - index: ReferendumIndex, - status: ReferendumStatus, BoundedCallOf, BalanceOf>, - ) -> bool { - let total_issuance = T::Currency::total_issuance(); - let approved = status.threshold.approved(status.tally, total_issuance); - - if approved { - Self::deposit_event(Event::::Passed { ref_index: index }); - - // Earliest it can be scheduled for is next block. - let when = now.saturating_add(status.delay.max(One::one())); - if T::Scheduler::schedule_named( - (DEMOCRACY_ID, index).encode_into(), - DispatchTime::At(when), - None, - 63, - frame_system::RawOrigin::Root.into(), - status.proposal, - ) - .is_err() - { - frame_support::print("LOGIC ERROR: bake_referendum/schedule_named failed"); - } - } else { - Self::deposit_event(Event::::NotPassed { ref_index: index }); - } - - approved - } - - /// Current era is ending; we should finish up any proposals. - /// - /// - /// ## Complexity: - /// If a referendum is launched or maturing, this will take full block weight if queue is not - /// empty. Otherwise, `O(R)` where `R` is the number of unbaked referenda. - fn begin_block(now: BlockNumberFor) -> Weight { - let max_block_weight = T::BlockWeights::get().max_block; - let mut weight = Weight::zero(); - - let next = Self::lowest_unbaked(); - let last = Self::referendum_count(); - let r = last.saturating_sub(next); - - // pick out another public referendum if it's time. - if (now % T::LaunchPeriod::get()).is_zero() { - // Errors come from the queue being empty. If the queue is not empty, it will take - // full block weight. - if Self::launch_next(now).is_ok() { - weight = max_block_weight; - } else { - weight.saturating_accrue(T::WeightInfo::on_initialize_base_with_launch_period(r)); - } - } else { - weight.saturating_accrue(T::WeightInfo::on_initialize_base(r)); - } - - // tally up votes for any expiring referenda. - for (index, info) in Self::maturing_referenda_at_inner(now, next..last).into_iter() { - let approved = Self::bake_referendum(now, index, info); - ReferendumInfoOf::::insert(index, ReferendumInfo::Finished { end: now, approved }); - weight = max_block_weight; - } - - // Notes: - // * We don't consider the lowest unbaked to be the last maturing in case some referenda - // have a longer voting period than others. - // * The iteration here shouldn't trigger any storage read that are not in cache, due to - // `maturing_referenda_at_inner` having already read them. - // * We shouldn't iterate more than `LaunchPeriod/VotingPeriod + 1` times because the number - // of unbaked referendum is bounded by this number. In case those number have changed in a - // runtime upgrade the formula should be adjusted but the bound should still be sensible. - >::mutate(|ref_index| { - while *ref_index < last && - Self::referendum_info(*ref_index) - .map_or(true, |info| matches!(info, ReferendumInfo::Finished { .. })) - { - *ref_index += 1 - } - }); - - weight - } - - /// Reads the length of account in DepositOf without getting the complete value in the runtime. - /// - /// Return 0 if no deposit for this proposal. - fn len_of_deposit_of(proposal: PropIndex) -> Option { - // DepositOf first tuple element is a vec, decoding its len is equivalent to decode a - // `Compact`. - decode_compact_u32_at(&>::hashed_key_for(proposal)) - } - - /// Return a proposal of an index. - fn proposal(index: PropIndex) -> Result<(PropIndex, BoundedCallOf, T::AccountId), Error> { - PublicProps::::get() - .into_iter() - .find(|(prop_index, _, _)| prop_index == &index) - .ok_or(Error::::ProposalMissing) - } - - /// Clear metadata if exist for a given owner. - fn clear_metadata(owner: MetadataOwner) { - if let Some(hash) = MetadataOf::::take(&owner) { - Self::deposit_event(Event::::MetadataCleared { owner, hash }); - } - } - - /// Transfer the metadata of an `owner` to a `new_owner`. - fn transfer_metadata(owner: MetadataOwner, new_owner: MetadataOwner) { - if let Some(hash) = MetadataOf::::take(&owner) { - MetadataOf::::insert(&new_owner, hash); - Self::deposit_event(Event::::MetadataTransferred { - prev_owner: owner, - owner: new_owner, - hash, - }); - } - } - - /// Ensure external origin for corresponding vote threshold. - fn ensure_external_origin( - threshold: VoteThreshold, - origin: OriginFor, - ) -> Result<(), BadOrigin> { - match threshold { - VoteThreshold::SuperMajorityApprove => { - let _ = T::ExternalOrigin::ensure_origin(origin)?; - }, - VoteThreshold::SuperMajorityAgainst => { - let _ = T::ExternalDefaultOrigin::ensure_origin(origin)?; - }, - VoteThreshold::SimpleMajority => { - let _ = T::ExternalMajorityOrigin::ensure_origin(origin)?; - }, - }; - Ok(()) - } -} - -/// Decode `Compact` from the trie at given key. -fn decode_compact_u32_at(key: &[u8]) -> Option { - // `Compact` takes at most 5 bytes. - let mut buf = [0u8; 5]; - let bytes = sp_io::storage::read(key, &mut buf, 0)?; - // The value may be smaller than 5 bytes. - let mut input = &buf[0..buf.len().min(bytes as usize)]; - match codec::Compact::::decode(&mut input) { - Ok(c) => Some(c.0), - Err(_) => { - sp_runtime::print("Failed to decode compact u32 at:"); - sp_runtime::print(key); - None - }, } } From 03899aea458af363560c541d903ab6858faee5bb Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Tue, 3 Sep 2024 17:54:55 +0800 Subject: [PATCH 005/215] temp: stash commit of curator impl --- Cargo.toml | 1 + pallets/collab-ai/curator/Cargo.toml | 1 + pallets/collab-ai/curator/src/lib.rs | 407 ++++++++++----------------- 3 files changed, 153 insertions(+), 256 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3790c2e701..538fa55887 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,7 @@ assert_matches = { version = "1.3.0" } blake2-rfc = { version = "0.2.18", default-features = false } base58 = { version = "0.2", default-features = false } base64 = { version = "0.13", default-features = false, features = ["alloc"] } +bitflags = { version = "1.3.2" } chrono = { version = "0.4", default-features = false, features = ["serde"] } clap = { version = "4.4", features = ["derive"] } der = { version = "0.6.0", default-features = false } diff --git a/pallets/collab-ai/curator/Cargo.toml b/pallets/collab-ai/curator/Cargo.toml index 94dddabc71..601787ea00 100644 --- a/pallets/collab-ai/curator/Cargo.toml +++ b/pallets/collab-ai/curator/Cargo.toml @@ -11,6 +11,7 @@ version = '0.1.0' [dependencies] parity-scale-codec = { workspace = true } scale-info = { workspace = true } +bitflags = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } diff --git a/pallets/collab-ai/curator/src/lib.rs b/pallets/collab-ai/curator/src/lib.rs index ddfca4db79..138cc6740f 100644 --- a/pallets/collab-ai/curator/src/lib.rs +++ b/pallets/collab-ai/curator/src/lib.rs @@ -25,7 +25,7 @@ //! //! #![cfg_attr(not(feature = "std"), no_std)] - +use bitflags::bitflags; use codec::{Decode, Encode}; use frame_support::{ ensure, @@ -72,11 +72,42 @@ pub struct PoolMetadata { pub description: BoundedString, } +bitflags! { + /// Flags used to record the status of pool proposal + pub struct ProposalStatusFlags: u32 { + /// Whether the minimum staked amount proposed by curator is satisfied. + /// + /// # Note + /// + /// Once a pool is satisfied this requirement, all staked amount can no longer be withdrawed + /// unless the pool is later denied passing by voting or until the end of pool maturity. + /// + /// Otherwise, the pool will be refunded. + const MINIMUM_STAKE_PASSED = 0b0000_0001; + /// Whether the pool proposal passing the committee voting. + /// + /// # Note + /// + /// A valid pool must passing committee's audit procedure regarding legal files and other pool parameters. + const COMMITTEE_VOTE_PASSED = 0b0000_0010; + /// Whether the pool proposal passing the global democracy voting. + /// + /// # Note + /// + /// A valid pool must passing committee's audit procedure regarding legal files and other pool parameters. + const DEMOCRACY_VOTE_PASSED = 0b0000_0100; + /// Whether the pool guardian has been selected + /// + /// # Note + /// + /// A valid pool must have guardian or a default one will be used (committee) + const GUARDIAN_SELECTED = 0b0000_1000; + } +} + #[frame_support::pallet] pub mod pallet { - use super::{DispatchResult, *}; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; + use super::*; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -99,103 +130,13 @@ pub mod pallet { type Currency: ReservableCurrency + LockableCurrency>; - /// The period between a proposal being approved and enacted. - /// - /// It should generally be a little more than the unstake period to ensure that - /// voting stakers have an opportunity to remove themselves from the system in the case - /// where they are on the losing side of a vote. - #[pallet::constant] - type EnactmentPeriod: Get>; - - /// How often (in blocks) new public referenda are launched. + /// The minimum amount to be used as a deposit for a curator #[pallet::constant] - type LaunchPeriod: Get>; + type MinimumCuratorDeposit: Get>; - /// How often (in blocks) to check for new votes. - #[pallet::constant] - type VotingPeriod: Get>; + /// Origin from curator legal file verified by + type CuratorJudgeOrigin: EnsureOrigin; - /// The minimum period of vote locking. - /// - /// It should be no shorter than enactment period to ensure that in the case of an approval, - /// those successful voters are locked into the consequences that their votes entail. - #[pallet::constant] - type VoteLockingPeriod: Get>; - - /// The minimum amount to be used as a deposit for a public referendum proposal. - #[pallet::constant] - type MinimumDeposit: Get>; - - /// Indicator for whether an emergency origin is even allowed to happen. Some chains may - /// want to set this permanently to `false`, others may want to condition it on things such - /// as an upgrade having happened recently. - #[pallet::constant] - type InstantAllowed: Get; - - /// Minimum voting period allowed for a fast-track referendum. - #[pallet::constant] - type FastTrackVotingPeriod: Get>; - - /// Period in blocks where an external proposal may not be re-submitted after being vetoed. - #[pallet::constant] - type CooloffPeriod: Get>; - - /// The maximum number of public proposals that can exist at any time. - #[pallet::constant] - type MaxCurators: Get; - - /// The maximum number of deposits a public proposal may have at any time. - #[pallet::constant] - type MaxDeposits: Get; - - /// The maximum number of items which can be blacklisted. - #[pallet::constant] - type MaxBlacklisted: Get; - - /// Origin from which the next tabled referendum may be forced. This is a normal - /// "super-majority-required" referendum. - type ExternalOrigin: EnsureOrigin; - - /// Origin from which the next tabled referendum may be forced; this allows for the tabling - /// of a majority-carries referendum. - type ExternalMajorityOrigin: EnsureOrigin; - - /// Origin from which the next tabled referendum may be forced; this allows for the tabling - /// of a negative-turnout-bias (default-carries) referendum. - type ExternalDefaultOrigin: EnsureOrigin; - - /// Origin from which the new proposal can be made. - /// - /// The success variant is the account id of the depositor. - type SubmitOrigin: EnsureOrigin; - - /// Origin from which the next majority-carries (or more permissive) referendum may be - /// tabled to vote according to the `FastTrackVotingPeriod` asynchronously in a similar - /// manner to the emergency origin. It retains its threshold method. - type FastTrackOrigin: EnsureOrigin; - - /// Origin from which the next majority-carries (or more permissive) referendum may be - /// tabled to vote immediately and asynchronously in a similar manner to the emergency - /// origin. It retains its threshold method. - type InstantOrigin: EnsureOrigin; - - /// Origin from which any referendum may be cancelled in an emergency. - type CancellationOrigin: EnsureOrigin; - - /// Origin from which proposals may be blacklisted. - type BlacklistOrigin: EnsureOrigin; - - /// Origin from which a proposal may be cancelled and its backers slashed. - type CancelProposalOrigin: EnsureOrigin; - - /// Origin for anyone able to veto proposals. - type VetoOrigin: EnsureOrigin; - - /// Overarching type of all pallets origins. - type PalletsOrigin: From>; - - /// Handler for the unbalanced reduction when slashing a preimage deposit. - type Slash: OnUnbalanced>; } /// The number of (public) curator that have been made so far. @@ -203,30 +144,29 @@ pub mod pallet { #[pallet::getter(fn public_curator_count)] pub type PublicCuratorCount = StorageValue<_, CuratorIndex, ValueQuery>; - /// The public Curator. The second item is current using curator legal file hash. + /// The public curator to index #[pallet::storage] - #[pallet::getter(fn public_curators)] - pub type PublicCurators = StorageMap< + #[pallet::getter(fn public_curator_to_index)] + pub type PublicCuratorToIndex = StorageMap< _, Twox64Concat, T::AccountId, - (CuratorIndex, InfoHash), + CuratorIndex, OptionQuery, >; - // Storing all history curator info hash with updated time - // We all record the user who update the hash in the first place + /// Curator index to hash and update time. Info Hash is current used curator legal file hash. #[pallet::storage] - #[pallet::getter(fn curator_info_hash)] - pub type CuratorInfoHash = StorageMap< + #[pallet::getter(fn curator_index_to_info)] + pub type CuratorIndexToInfo = StorageMap< _, Twox64Concat, - InfoHash, - (BlockNumberFor, T::AccountId, CandidateStatus), + CuratorIndex, + (InfoHash, BlockNumberFor, T::AccountId, CandidateStatus), OptionQuery, >; - /// The next free referendum index, aka the number of referenda started so far. + /// The next free Pool Proposal index, aka the number of pool proposed so far. #[pallet::storage] #[pallet::getter(fn pool_proposal_count)] pub type PoolProposalCount = StorageValue<_, PoolProposalIndex, ValueQuery>; @@ -243,6 +183,17 @@ pub mod pallet { BoundedVec<(PoolProposalIndex, BalanceOf), T::MaxDeposits>, >; + // Metadata of staking pools + #[pallet::storage] + #[pallet::getter(fn staking_pool_metadata)] + pub type StakingPoolStatus = StorageMap< + _, + Twox64Concat, + PoolProposalIndex, + (InfoHash), + OptionQuery, + >; + // Metadata of staking pools #[pallet::storage] #[pallet::getter(fn staking_pool_metadata)] @@ -257,96 +208,35 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// A motion has been proposed by a public account. - Proposed { proposal_index: PropIndex, deposit: BalanceOf }, - /// A public proposal has been tabled for referendum vote. - Tabled { proposal_index: PropIndex, deposit: BalanceOf }, - /// An external proposal has been tabled. - ExternalTabled, - /// A referendum has begun. - Started { ref_index: ReferendumIndex, threshold: VoteThreshold }, - /// A proposal has been approved by referendum. - Passed { ref_index: ReferendumIndex }, - /// A proposal has been rejected by referendum. - NotPassed { ref_index: ReferendumIndex }, - /// A referendum has been cancelled. - Cancelled { ref_index: ReferendumIndex }, - /// An account has delegated their vote to another account. - Delegated { who: T::AccountId, target: T::AccountId }, - /// An account has cancelled a previous delegation operation. - Undelegated { account: T::AccountId }, - /// An external proposal has been vetoed. - Vetoed { who: T::AccountId, proposal_hash: H256, until: BlockNumberFor }, - /// A proposal_hash has been blacklisted permanently. - Blacklisted { proposal_hash: H256 }, - /// An account has voted in a referendum - Voted { voter: T::AccountId, ref_index: ReferendumIndex, vote: AccountVote> }, - /// An account has secconded a proposal - Seconded { seconder: T::AccountId, prop_index: PropIndex }, - /// A proposal got canceled. - ProposalCanceled { prop_index: PropIndex }, - /// Metadata for a proposal or a referendum has been set. - MetadataSet { - /// Metadata owner. - owner: MetadataOwner, - /// Preimage hash. - hash: PreimageHash, + + CuratorRegisted { + curator: T::AccountId, + curator_index: CuratorIndex, + info_hash: InfoHash, }, - /// Metadata for a proposal or a referendum has been cleared. - MetadataCleared { - /// Metadata owner. - owner: MetadataOwner, - /// Preimage hash. - hash: PreimageHash, + CuratorUpdated { + curator: T::AccountId, + curator_index: CuratorIndex, + info_hash: InfoHash, }, - /// Metadata has been transferred to new owner. - MetadataTransferred { - /// Previous metadata owner. - prev_owner: MetadataOwner, - /// New metadata owner. - owner: MetadataOwner, - /// Preimage hash. - hash: PreimageHash, + CuratorCleaned { + curator: T::AccountId, + curator_index: CuratorIndex, }, + CuratorStatusUpdated { + curator: T::AccountId, + curator_index: CuratorIndex, + status: CandidateStatus, + } + /// A motion has been proposed by a public account. + Proposed { proposal_index: PropIndex, deposit: BalanceOf }, } #[pallet::error] pub enum Error { - /// Value too low - ValueLow, - /// Proposal does not exist - ProposalMissing, - /// Cannot cancel the same proposal twice - AlreadyCanceled, - /// Proposal already made - DuplicateProposal, - /// Proposal still blacklisted - ProposalBlacklisted, - /// Next external proposal not simple majority - NotSimpleMajority, - /// Invalid hash - InvalidHash, - /// No external proposal - NoProposal, - /// Identity may not veto a proposal twice - AlreadyVetoed, - /// Vote given for invalid referendum - ReferendumInvalid, - /// No proposals waiting - NoneWaiting, - /// The given account did not vote on the referendum. - NotVoter, - /// The actor has no permission to conduct the action. - NoPermission, - /// The account is already delegating. - AlreadyDelegating, - /// Too high a balance was provided that the account cannot afford. - InsufficientFunds, - /// The account is not currently delegating. - NotDelegating, - /// The account currently has votes attached to it and the operation cannot succeed until - /// these are removed, either through `unvote` or `reap_vote`. - VotesExist, + CuratorAlreadyRegistered, + CuratorNotRegistered, + CuratorIndexNotExist, } #[pallet::hooks] @@ -364,103 +254,108 @@ pub mod pallet { #[pallet::weight(W{195_000_000})] pub fn regist_curator( origin: OriginFor, - info_hash: Option, + info_hash: InfoHash, ) -> DispatchResult { let who = ensure_signed(origin)?; // Ensure curator not existing yet - - + ensure!(!PublicCuratorToIndex::::contains_key(&who), Error::::CuratorAlreadyRegistered); + // New registed curator need to make a balance reserve + T::Currency::reserve(&who, MinimumCuratorDeposit::get())?; + Self::update_curator(who, Some(info_hash)) } /// Updating a curator legal info - #[pallet::call_index(0)] + #[pallet::call_index(1)] #[pallet::weight(W{195_000_000})] pub fn update_curator( origin: OriginFor, - info_hash: Option, + info_hash: InfoHash, ) -> DispatchResult { let who = ensure_signed(origin)?; // Ensure existing - } - + ensure!(PublicCuratorToIndex::::contains_key(&who), Error::::CuratorNotRegistered); + Self::update_curator(who, Some(info_hash)) + } - /// Curator propose a staking pool - /// - /// The dispatch origin of this call must be _Signed_ and the sender must - /// have funds to cover the deposit. - /// - /// - `proposal_hash`: The hash of the proposal preimage. - /// - `value`: The amount of deposit (must be at least `MinimumDeposit`). - /// - /// Emits `Proposed`. - #[pallet::call_index(0)] + /// Clean a curator legal info + /// Impossible when there is a staking pool proposal ongoing + #[pallet::call_index(2)] #[pallet::weight(W{195_000_000})] - pub fn propose_staking_pool( + pub fn clean_curator( origin: OriginFor, - pool_setup: PoolSetting, BalanceOf>, - #[pallet::compact] value: BalanceOf, ) -> DispatchResult { let who = ensure_signed(origin)?; + // Ensure existing + ensure!(PublicCuratorToIndex::::contains_key(&who), Error::::CuratorNotRegistered); + // New registed curator need to make a balance reserve + T::Currency::unreserve(&who, MinimumCuratorDeposit::get())?; + Self::update_curator(who, None) + } + #[pallet::call_index(3)] + #[pallet::weight(W{195_000_000})] + pub fn judge_curator_status( + origin: OriginFor, + curator: T::AccountId, + status: CandidateStatus, + ) -> DispatchResult { + T::CuratorJudgeOrigin::ensure_origin(origin)?; + let curator_index = PublicCuratorToIndex::::get(curator).ok_or(Error::::CuratorNotRegistered)?; + CuratorIndexToInfo::::try_mutate_exists(curator_index, |maybe_info| -> Result<(), DispatchError> { + let mut info = maybe_info.as_mut().ok_or(Error::::CuratorIndexNotExist)?; + // Update block number + info.1 = frame_system::Pallet::::block_number(); + // Update status + info.3 = status; + Self::deposit_event(Event::CuratorStatusUpdated { + curator, + curator_index, + status, + }); + })?; + } - ensure!(value >= T::MinimumDeposit::get(), Error::::ValueLow); - - let index = Self::public_prop_count(); - let real_prop_count = PublicProps::::decode_len().unwrap_or(0) as u32; - let max_proposals = T::MaxProposals::get(); - ensure!(real_prop_count < max_proposals, Error::::TooMany); - let proposal_hash = proposal.hash(); - - if let Some((until, _)) = >::get(proposal_hash) { - ensure!( - >::block_number() >= until, - Error::::ProposalBlacklisted, - ); - } - - T::Currency::reserve(&who, value)?; - - let depositors = BoundedVec::<_, T::MaxDeposits>::truncate_from(vec![who.clone()]); - DepositOf::::insert(index, (depositors, value)); - - PublicPropCount::::put(index + 1); - PublicProps::::try_append((index, proposal, who)) - .map_err(|_| Error::::TooMany)?; - Self::deposit_event(Event::::Proposed { proposal_index: index, deposit: value }); - Ok(()) - } - /// Signals agreement with a particular proposal. - /// - /// The dispatch origin of this call must be _Signed_ and the sender - /// must have funds to cover the deposit, equal to the original deposit. + /// Curator propose a staking pool /// - /// - `proposal`: The index of the proposal to second. - #[pallet::call_index(1)] - #[pallet::weight(T::WeightInfo::second())] - pub fn second( + + #[pallet::call_index(0)] + #[pallet::weight(W{195_000_000})] + pub fn propose_staking_pool( origin: OriginFor, - #[pallet::compact] proposal: PropIndex, + pool_setup: PoolSetting, BalanceOf>, + #[pallet::compact] value: BalanceOf, ) -> DispatchResult { let who = ensure_signed(origin)?; - let seconds = Self::len_of_deposit_of(proposal).ok_or(Error::::ProposalMissing)?; - ensure!(seconds < T::MaxDeposits::get(), Error::::TooMany); - let mut deposit = Self::deposit_of(proposal).ok_or(Error::::ProposalMissing)?; - T::Currency::reserve(&who, deposit.1)?; - let ok = deposit.0.try_push(who.clone()).is_ok(); - debug_assert!(ok, "`seconds` is below static limit; `try_insert` should succeed; qed"); - >::insert(proposal, deposit); - Self::deposit_event(Event::::Seconded { seconder: who, prop_index: proposal }); - Ok(()) + + } + } +} + +impl Pallet { + pub fn update_curator(who: T::AccountId, info_hash: Option) -> DispatchResult { + if Some(hash) = info_hash { + let current_block = frame_system::Pallet::::block_number(); + let next_curator_index = PublicCuratorCount::::get(); + + PublicCuratorToIndex::::insert(&who, next_curator_index); + CuratorIndexToInfo::::insert(&next_curator_index, (info_hash, current_block, who.clone(), CandidateStatus::Unverified)); + + PublicCuratorCount::::put(next_curator_index.checked_add(1u32.into())?); + } else { + // i.e. info_hash == None + let index = PublicCuratorToIndex::::take(&who); + CuratorIndexToInfo::::remove(&index); } + Ok(()) } } From 158fc7a15ade0331a55ec6ab99ba08f5c75056f6 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 4 Sep 2024 16:26:23 +0800 Subject: [PATCH 006/215] feat: pallet curator rough impl --- Cargo.toml | 1 + pallets/collab-ai/common/Cargo.toml | 3 + pallets/collab-ai/common/src/lib.rs | 13 ++ pallets/collab-ai/curator/Cargo.toml | 3 +- pallets/collab-ai/curator/src/lib.rs | 218 ++++--------------- pallets/collab-ai/pool-proposal/Cargo.toml | 39 ++++ pallets/collab-ai/pool-proposal/src/lib.rs | 239 +++++++++++++++++++++ 7 files changed, 341 insertions(+), 175 deletions(-) create mode 100644 pallets/collab-ai/pool-proposal/Cargo.toml create mode 100644 pallets/collab-ai/pool-proposal/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 538fa55887..52ef9679b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ members = [ 'pallets/bridge/bridge-transfer', 'pallets/bridge/common', 'pallets/collab-ai/aiusd-convertor', + 'pallets/collab-ai/curator', 'pallets/extrinsic-filter', 'pallets/evm-address', 'pallets/evm-assertions', diff --git a/pallets/collab-ai/common/Cargo.toml b/pallets/collab-ai/common/Cargo.toml index e32dc05c4a..b74d46cd2e 100644 --- a/pallets/collab-ai/common/Cargo.toml +++ b/pallets/collab-ai/common/Cargo.toml @@ -12,6 +12,7 @@ scale-info = { workspace = true } frame-support = { workspace = true, optional = true } sp-runtime = { workspace = true } +sp-core = { workspace = true } [features] default = ["std"] @@ -24,4 +25,6 @@ std = [ "parity-scale-codec/std", "frame-support?/std", "sp-runtime/std", + "sp-core/std", ] +try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/collab-ai/common/src/lib.rs b/pallets/collab-ai/common/src/lib.rs index f65c8d2c4f..6d80034762 100644 --- a/pallets/collab-ai/common/src/lib.rs +++ b/pallets/collab-ai/common/src/lib.rs @@ -17,8 +17,13 @@ #![cfg_attr(not(feature = "std"), no_std)] use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; +use sp_core::H256; use sp_runtime::DispatchError; +pub type InfoHash = H256; +pub type CuratorIndex = u128; +pub type PoolProposalIndex = u128; + #[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] pub struct PoolSetting { // The start time of staking pool @@ -36,6 +41,14 @@ pub struct PoolSetting { pub minimum_cap: Balance, } +#[derive(Clone, Encode, Decode, Eq, PartialEq, Default, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub struct PoolMetadata { + /// The user friendly name of this staking pool. Limited in length by `PoolStringLimit`. + pub name: BoundedString, + /// The short description for this staking pool. Limited in length by `PoolStringLimit`. + pub description: BoundedString, +} + #[derive(PartialEq, Eq, Clone, Copy, Default, Encode, Decode, Debug, TypeInfo)] pub enum CandidateStatus { /// Initial status of legal file diff --git a/pallets/collab-ai/curator/Cargo.toml b/pallets/collab-ai/curator/Cargo.toml index 601787ea00..a9f4fa7114 100644 --- a/pallets/collab-ai/curator/Cargo.toml +++ b/pallets/collab-ai/curator/Cargo.toml @@ -1,6 +1,6 @@ [package] authors = ['Litentry Dev'] -description = 'Pallet for managing Curator and pool proposal' +description = 'Pallet for managing curator' edition = '2021' homepage = 'https://litentry.com/' license = 'GPL-3.0' @@ -11,7 +11,6 @@ version = '0.1.0' [dependencies] parity-scale-codec = { workspace = true } scale-info = { workspace = true } -bitflags = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } diff --git a/pallets/collab-ai/curator/src/lib.rs b/pallets/collab-ai/curator/src/lib.rs index 138cc6740f..33a577f945 100644 --- a/pallets/collab-ai/curator/src/lib.rs +++ b/pallets/collab-ai/curator/src/lib.rs @@ -23,87 +23,21 @@ //! //! The Curator pallet handles the administration of general curator and proposed staking pool. //! -//! +//! #![cfg_attr(not(feature = "std"), no_std)] use bitflags::bitflags; use codec::{Decode, Encode}; use frame_support::{ ensure, - error::BadOrigin, - traits::{ - defensive_prelude::*, - schedule::{v3::Named as ScheduleNamed, DispatchTime}, - Bounded, Currency, EnsureOrigin, Get, Hash as PreimageHash, LockIdentifier, - LockableCurrency, OnUnbalanced, QueryPreimage, ReservableCurrency, StorePreimage, - WithdrawReasons, - }, + traits::{Currency, EnsureOrigin, Get, LockableCurrency, ReservableCurrency}, weights::Weight, }; use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; -use sp_core::H256; pub use pallet::*; - -#[cfg(test)] -mod mock; -#[cfg(test)] -mod tests; - -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmarking; +use pallet_collab_ai_common::*; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; -type NegativeImbalanceOf = <::Currency as Currency< - ::AccountId, ->>::NegativeImbalance; -pub type CallOf = ::RuntimeCall; -pub type BoundedCallOf = Bounded>; -type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; - -pub type InfoHash = H256; -pub type CuratorIndex = u128; -pub type PoolProposalIndex = u128; - -#[derive(Clone, Encode, Decode, Eq, PartialEq, Default, RuntimeDebug, MaxEncodedLen, TypeInfo)] -pub struct PoolMetadata { - /// The user friendly name of this staking pool. Limited in length by `PoolStringLimit`. - pub name: BoundedString, - /// The short description for this staking pool. Limited in length by `PoolStringLimit`. - pub description: BoundedString, -} - -bitflags! { - /// Flags used to record the status of pool proposal - pub struct ProposalStatusFlags: u32 { - /// Whether the minimum staked amount proposed by curator is satisfied. - /// - /// # Note - /// - /// Once a pool is satisfied this requirement, all staked amount can no longer be withdrawed - /// unless the pool is later denied passing by voting or until the end of pool maturity. - /// - /// Otherwise, the pool will be refunded. - const MINIMUM_STAKE_PASSED = 0b0000_0001; - /// Whether the pool proposal passing the committee voting. - /// - /// # Note - /// - /// A valid pool must passing committee's audit procedure regarding legal files and other pool parameters. - const COMMITTEE_VOTE_PASSED = 0b0000_0010; - /// Whether the pool proposal passing the global democracy voting. - /// - /// # Note - /// - /// A valid pool must passing committee's audit procedure regarding legal files and other pool parameters. - const DEMOCRACY_VOTE_PASSED = 0b0000_0100; - /// Whether the pool guardian has been selected - /// - /// # Note - /// - /// A valid pool must have guardian or a default one will be used (committee) - const GUARDIAN_SELECTED = 0b0000_1000; - } -} #[frame_support::pallet] pub mod pallet { @@ -120,9 +54,6 @@ pub mod pallet { pub trait Config: frame_system::Config + Sized { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// The Scheduler. - type Scheduler: ScheduleNamed, CallOf, Self::PalletsOrigin>; - /// The Legal file storage type FileStorage: QueryPreimage + StorePreimage; @@ -136,7 +67,6 @@ pub mod pallet { /// Origin from curator legal file verified by type CuratorJudgeOrigin: EnsureOrigin; - } /// The number of (public) curator that have been made so far. @@ -147,13 +77,8 @@ pub mod pallet { /// The public curator to index #[pallet::storage] #[pallet::getter(fn public_curator_to_index)] - pub type PublicCuratorToIndex = StorageMap< - _, - Twox64Concat, - T::AccountId, - CuratorIndex, - OptionQuery, - >; + pub type PublicCuratorToIndex = + StorageMap<_, Twox64Concat, T::AccountId, CuratorIndex, OptionQuery>; /// Curator index to hash and update time. Info Hash is current used curator legal file hash. #[pallet::storage] @@ -166,58 +91,18 @@ pub mod pallet { OptionQuery, >; - /// The next free Pool Proposal index, aka the number of pool proposed so far. - #[pallet::storage] - #[pallet::getter(fn pool_proposal_count)] - pub type PoolProposalCount = StorageValue<_, PoolProposalIndex, ValueQuery>; - - /// Those who have a reserve for his pool proposal. - /// - /// TWOX-NOTE: Safe, as increasing integer keys are safe. - #[pallet::storage] - #[pallet::getter(fn pool_deposit_of)] - pub type PoolDepositOf = StorageMap< - _, - Twox64Concat, - CuratorIndex, - BoundedVec<(PoolProposalIndex, BalanceOf), T::MaxDeposits>, - >; - - // Metadata of staking pools - #[pallet::storage] - #[pallet::getter(fn staking_pool_metadata)] - pub type StakingPoolStatus = StorageMap< - _, - Twox64Concat, - PoolProposalIndex, - (InfoHash), - OptionQuery, - >; - - // Metadata of staking pools - #[pallet::storage] - #[pallet::getter(fn staking_pool_metadata)] - pub type StakingPoolMetadata = StorageMap< - _, - Twox64Concat, - PoolProposalIndex, - PoolMetadata>, - OptionQuery, - >; - #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - CuratorRegisted { curator: T::AccountId, curator_index: CuratorIndex, - info_hash: InfoHash, + info_hash: InfoHash, }, CuratorUpdated { curator: T::AccountId, curator_index: CuratorIndex, - info_hash: InfoHash, + info_hash: InfoHash, }, CuratorCleaned { curator: T::AccountId, @@ -227,9 +112,7 @@ pub mod pallet { curator: T::AccountId, curator_index: CuratorIndex, status: CandidateStatus, - } - /// A motion has been proposed by a public account. - Proposed { proposal_index: PropIndex, deposit: BalanceOf }, + }, } #[pallet::error] @@ -252,14 +135,14 @@ pub mod pallet { /// Registing a curator legal info #[pallet::call_index(0)] #[pallet::weight(W{195_000_000})] - pub fn regist_curator( - origin: OriginFor, - info_hash: InfoHash, - ) -> DispatchResult { + pub fn regist_curator(origin: OriginFor, info_hash: InfoHash) -> DispatchResult { let who = ensure_signed(origin)?; // Ensure curator not existing yet - ensure!(!PublicCuratorToIndex::::contains_key(&who), Error::::CuratorAlreadyRegistered); + ensure!( + !PublicCuratorToIndex::::contains_key(&who), + Error::::CuratorAlreadyRegistered + ); // New registed curator need to make a balance reserve T::Currency::reserve(&who, MinimumCuratorDeposit::get())?; Self::update_curator(who, Some(info_hash)) @@ -268,14 +151,14 @@ pub mod pallet { /// Updating a curator legal info #[pallet::call_index(1)] #[pallet::weight(W{195_000_000})] - pub fn update_curator( - origin: OriginFor, - info_hash: InfoHash, - ) -> DispatchResult { + pub fn update_curator(origin: OriginFor, info_hash: InfoHash) -> DispatchResult { let who = ensure_signed(origin)?; // Ensure existing - ensure!(PublicCuratorToIndex::::contains_key(&who), Error::::CuratorNotRegistered); + ensure!( + PublicCuratorToIndex::::contains_key(&who), + Error::::CuratorNotRegistered + ); Self::update_curator(who, Some(info_hash)) } @@ -284,13 +167,14 @@ pub mod pallet { /// Impossible when there is a staking pool proposal ongoing #[pallet::call_index(2)] #[pallet::weight(W{195_000_000})] - pub fn clean_curator( - origin: OriginFor, - ) -> DispatchResult { + pub fn clean_curator(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; // Ensure existing - ensure!(PublicCuratorToIndex::::contains_key(&who), Error::::CuratorNotRegistered); + ensure!( + PublicCuratorToIndex::::contains_key(&who), + Error::::CuratorNotRegistered + ); // New registed curator need to make a balance reserve T::Currency::unreserve(&who, MinimumCuratorDeposit::get())?; @@ -305,38 +189,23 @@ pub mod pallet { status: CandidateStatus, ) -> DispatchResult { T::CuratorJudgeOrigin::ensure_origin(origin)?; - let curator_index = PublicCuratorToIndex::::get(curator).ok_or(Error::::CuratorNotRegistered)?; - CuratorIndexToInfo::::try_mutate_exists(curator_index, |maybe_info| -> Result<(), DispatchError> { - let mut info = maybe_info.as_mut().ok_or(Error::::CuratorIndexNotExist)?; - // Update block number - info.1 = frame_system::Pallet::::block_number(); - // Update status - info.3 = status; - Self::deposit_event(Event::CuratorStatusUpdated { - curator, - curator_index, - status, - }); - })?; - } - - - - - - /// Curator propose a staking pool - /// - - #[pallet::call_index(0)] - #[pallet::weight(W{195_000_000})] - pub fn propose_staking_pool( - origin: OriginFor, - pool_setup: PoolSetting, BalanceOf>, - #[pallet::compact] value: BalanceOf, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - - + let curator_index = + PublicCuratorToIndex::::get(curator).ok_or(Error::::CuratorNotRegistered)?; + CuratorIndexToInfo::::try_mutate_exists( + curator_index, + |maybe_info| -> Result<(), DispatchError> { + let mut info = maybe_info.as_mut().ok_or(Error::::CuratorIndexNotExist)?; + // Update block number + info.1 = frame_system::Pallet::::block_number(); + // Update status + info.3 = status; + Self::deposit_event(Event::CuratorStatusUpdated { + curator, + curator_index, + status, + }); + }, + )?; } } } @@ -348,8 +217,11 @@ impl Pallet { let next_curator_index = PublicCuratorCount::::get(); PublicCuratorToIndex::::insert(&who, next_curator_index); - CuratorIndexToInfo::::insert(&next_curator_index, (info_hash, current_block, who.clone(), CandidateStatus::Unverified)); - + CuratorIndexToInfo::::insert( + &next_curator_index, + (info_hash, current_block, who.clone(), CandidateStatus::Unverified), + ); + PublicCuratorCount::::put(next_curator_index.checked_add(1u32.into())?); } else { // i.e. info_hash == None diff --git a/pallets/collab-ai/pool-proposal/Cargo.toml b/pallets/collab-ai/pool-proposal/Cargo.toml new file mode 100644 index 0000000000..a2d4117768 --- /dev/null +++ b/pallets/collab-ai/pool-proposal/Cargo.toml @@ -0,0 +1,39 @@ +[package] +authors = ['Litentry Dev'] +description = 'Pallet for managing pool proposal' +edition = '2021' +homepage = 'https://litentry.com/' +license = 'GPL-3.0' +name = 'pallet-pool-proposal' +repository = 'https://github.com/litentry/litentry-parachain' +version = '0.1.0' + +[dependencies] +parity-scale-codec = { workspace = true } +scale-info = { workspace = true } +bitflags = { workspace = true } + +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +pallet-collab-ai-common = { workspace = true } + +[features] +default = ["std"] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-collab-ai-common/runtime-benchmarks", +] +std = [ + "parity-scale-codec/std", + "scale-info/std", + "sp-std/std", + "sp-runtime/std", + "frame-support/std", + "frame-system/std", + "pallet-collab-ai-common/std", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/collab-ai/pool-proposal/src/lib.rs b/pallets/collab-ai/pool-proposal/src/lib.rs new file mode 100644 index 0000000000..4844f28594 --- /dev/null +++ b/pallets/collab-ai/pool-proposal/src/lib.rs @@ -0,0 +1,239 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . +// +//! # Curator Pallet +//! +//! - [`Config`] +//! - [`Call`] +//! +//! ## Overview +//! +//! The Curator pallet handles the administration of general curator and proposed staking pool. +//! +//! +#![cfg_attr(not(feature = "std"), no_std)] +use bitflags::bitflags; +use codec::{Decode, Encode}; +use frame_support::{ + ensure, + error::BadOrigin, + traits::{ + defensive_prelude::*, + schedule::{v3::Named as ScheduleNamed, DispatchTime}, + Bounded, Currency, EnsureOrigin, Get, Hash as PreimageHash, LockIdentifier, + LockableCurrency, OnUnbalanced, QueryPreimage, ReservableCurrency, StorePreimage, + WithdrawReasons, + }, + weights::Weight, +}; +use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; +use pallet_collab_ai_common::*; +pub use pallet::*; + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + +type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; +type NegativeImbalanceOf = <::Currency as Currency< + ::AccountId, +>>::NegativeImbalance; +pub type CallOf = ::RuntimeCall; +pub type BoundedCallOf = Bounded>; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + +#[derive(Clone, Encode, Decode, Eq, PartialEq, Default, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub struct PoolMetadata { + /// The user friendly name of this staking pool. Limited in length by `PoolStringLimit`. + pub name: BoundedString, + /// The short description for this staking pool. Limited in length by `PoolStringLimit`. + pub description: BoundedString, +} + +bitflags! { + /// Flags used to record the status of pool proposal + pub struct ProposalStatusFlags: u32 { + /// Whether the minimum staked amount proposed by curator is satisfied. + /// + /// # Note + /// + /// Once a pool is satisfied this requirement, all staked amount can no longer be withdrawed + /// unless the pool is later denied passing by voting or until the end of pool maturity. + /// + /// Otherwise, the pool will be refunded. + const MINIMUM_STAKE_PASSED = 0b0000_0001; + /// Whether the pool proposal passing the committee voting. + /// + /// # Note + /// + /// A valid pool must passing committee's audit procedure regarding legal files and other pool parameters. + const COMMITTEE_VOTE_PASSED = 0b0000_0010; + /// Whether the pool proposal passing the global democracy voting. + /// + /// # Note + /// + /// A valid pool must passing committee's audit procedure regarding legal files and other pool parameters. + const DEMOCRACY_VOTE_PASSED = 0b0000_0100; + /// Whether the pool guardian has been selected + /// + /// # Note + /// + /// A valid pool must have guardian or a default one will be used (committee) + const GUARDIAN_SELECTED = 0b0000_1000; + } +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + Sized { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The Scheduler. + type Scheduler: ScheduleNamed, CallOf, Self::PalletsOrigin>; + + /// The Legal file storage + type FileStorage: QueryPreimage + StorePreimage; + + /// Currency type for this pallet. + type Currency: ReservableCurrency + + LockableCurrency>; + + /// The minimum amount to be used as a deposit for a curator + #[pallet::constant] + type MinimumCuratorDeposit: Get>; + + /// Origin from curator legal file verified by + type CuratorJudgeOrigin: EnsureOrigin; + + } + + /// The next free Pool Proposal index, aka the number of pool proposed so far. + #[pallet::storage] + #[pallet::getter(fn pool_proposal_count)] + pub type PoolProposalCount = StorageValue<_, PoolProposalIndex, ValueQuery>; + + /// Those who have a reserve for his pool proposal. + /// + /// TWOX-NOTE: Safe, as increasing integer keys are safe. + #[pallet::storage] + #[pallet::getter(fn pool_deposit_of)] + pub type PoolDepositOf = StorageMap< + _, + Twox64Concat, + CuratorIndex, + BoundedVec<(PoolProposalIndex, BalanceOf), T::MaxDeposits>, + >; + + // Metadata of staking pools + #[pallet::storage] + #[pallet::getter(fn staking_pool_metadata)] + pub type StakingPoolStatus = StorageMap< + _, + Twox64Concat, + PoolProposalIndex, + (InfoHash), + OptionQuery, + >; + + // Metadata of staking pools + #[pallet::storage] + #[pallet::getter(fn staking_pool_metadata)] + pub type StakingPoolMetadata = StorageMap< + _, + Twox64Concat, + PoolProposalIndex, + PoolMetadata>, + OptionQuery, + >; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A motion has been proposed by a public account. + Proposed { proposal_index: PropIndex, deposit: BalanceOf }, + } + + #[pallet::error] + pub enum Error { + CuratorAlreadyRegistered, + CuratorNotRegistered, + CuratorIndexNotExist, + } + + #[pallet::hooks] + impl Hooks> for Pallet { + /// Weight: see `begin_block` + fn on_initialize(n: BlockNumberFor) -> Weight { + Self::begin_block(n) + } + } + + #[pallet::call] + impl Pallet { + /// Curator propose a staking pool + /// + /// pool_setup: Including pool details + /// proposal_end_time: All ProposalStatusFlags must be satisfied before this date + /// estimated_epoch_reward: This number is only for displaying purpose without any techinical meaning + /// + #[pallet::call_index(0)] + #[pallet::weight(W{195_000_000})] + pub fn propose_staking_pool( + origin: OriginFor, + pool_setup: PoolSetting, BalanceOf>, + proposal_end_time: BlockNumberFor, + estimated_epoch_reward: BalanceOf, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + + } + } +} + +impl Pallet { + pub fn update_curator(who: T::AccountId, info_hash: Option) -> DispatchResult { + if Some(hash) = info_hash { + let current_block = frame_system::Pallet::::block_number(); + let next_curator_index = PublicCuratorCount::::get(); + + PublicCuratorToIndex::::insert(&who, next_curator_index); + CuratorIndexToInfo::::insert(&next_curator_index, (info_hash, current_block, who.clone(), CandidateStatus::Unverified)); + + PublicCuratorCount::::put(next_curator_index.checked_add(1u32.into())?); + } else { + // i.e. info_hash == None + let index = PublicCuratorToIndex::::take(&who); + CuratorIndexToInfo::::remove(&index); + } + Ok(()) + } +} From 24bbe4f02936646d76b01d1d8a807061b3cd2e33 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 5 Sep 2024 17:45:43 +0800 Subject: [PATCH 007/215] temp: stash commit --- Cargo.lock | 24 +++++ Cargo.toml | 1 + pallets/collab-ai/common/src/lib.rs | 36 +++++++ pallets/collab-ai/curator/src/lib.rs | 119 ++++++++++++++------- pallets/collab-ai/pool-proposal/Cargo.toml | 2 + pallets/collab-ai/pool-proposal/src/lib.rs | 99 ++++++++--------- 6 files changed, 192 insertions(+), 89 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e720b08abb..3943ca1a08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7143,6 +7143,17 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-collab-ai-common" +version = "0.1.0" +dependencies = [ + "frame-support", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", +] + [[package]] name = "pallet-collective" version = "4.0.0-dev" @@ -7177,6 +7188,19 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-curator" +version = "0.1.0" +dependencies = [ + "frame-support", + "frame-system", + "pallet-collab-ai-common", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-democracy" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 52ef9679b3..e0cb5e7e05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -236,6 +236,7 @@ parachain-info = { git = "https://github.com/paritytech/polkadot-sdk", branch = substrate-fixed = { git = "https://github.com/encointer/substrate-fixed", default-features = false } orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v1.1.0", default-features = false } +orml-utilities = { git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v1.1.0", default-features = false } orml-xtokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v1.1.0", default-features = false } # benchmarking diff --git a/pallets/collab-ai/common/src/lib.rs b/pallets/collab-ai/common/src/lib.rs index 6d80034762..a187beddaa 100644 --- a/pallets/collab-ai/common/src/lib.rs +++ b/pallets/collab-ai/common/src/lib.rs @@ -62,3 +62,39 @@ pub enum CandidateStatus { #[codec(index = 2)] Banned, } + +/// Some sort of check on the account is from some group. +pub trait EnsureCurator { + /// All curator but banned ones + fn is_curator(account: AccountId) -> bool; + + /// Only verified one + fn is_verified_curator(account: AccountId) -> bool; +} + +pub struct EnsureSignedAndCurator(sp_std::marker::PhantomData<(AccountId, EC)>); +impl, O>> + From>, AccountId: Decode> + EnsureOrigin for EnsureSignedAndCurator +where + EC: EnsureCurator, +{ + type Success = AccountId; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + RawOrigin::Signed(who) => { + if EC::is_curator() { + Ok(who) + } else { + Err(O::from(r)) + } + }, + r => Err(O::from(r)), + }) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + // No promised successful_origin + Err(()) + } +} diff --git a/pallets/collab-ai/curator/src/lib.rs b/pallets/collab-ai/curator/src/lib.rs index 33a577f945..19b77b4791 100644 --- a/pallets/collab-ai/curator/src/lib.rs +++ b/pallets/collab-ai/curator/src/lib.rs @@ -54,9 +54,6 @@ pub mod pallet { pub trait Config: frame_system::Config + Sized { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// The Legal file storage - type FileStorage: QueryPreimage + StorePreimage; - /// Currency type for this pallet. type Currency: ReservableCurrency + LockableCurrency>; @@ -122,14 +119,6 @@ pub mod pallet { CuratorIndexNotExist, } - #[pallet::hooks] - impl Hooks> for Pallet { - /// Weight: see `begin_block` - fn on_initialize(n: BlockNumberFor) -> Weight { - Self::begin_block(n) - } - } - #[pallet::call] impl Pallet { /// Registing a curator legal info @@ -145,7 +134,20 @@ pub mod pallet { ); // New registed curator need to make a balance reserve T::Currency::reserve(&who, MinimumCuratorDeposit::get())?; - Self::update_curator(who, Some(info_hash)) + + // Update curator + let current_block = frame_system::Pallet::::block_number(); + let next_curator_index = PublicCuratorCount::::get(); + + PublicCuratorToIndex::::insert(&who, next_curator_index); + CuratorIndexToInfo::::insert( + &next_curator_index, + (info_hash, current_block, who, CandidateStatus::Unverified), + ); + PublicCuratorCount::::put(next_curator_index.checked_add(1u32.into())?); + + Self::deposit_event(Event::CuratorRegisted { curator: who, curator_index, info_hash }); + Ok(()) } /// Updating a curator legal info @@ -155,12 +157,33 @@ pub mod pallet { let who = ensure_signed(origin)?; // Ensure existing - ensure!( - PublicCuratorToIndex::::contains_key(&who), - Error::::CuratorNotRegistered - ); + let curator_index = + PublicCuratorToIndex::::get(curator).ok_or(Error::::CuratorNotRegistered)?; - Self::update_curator(who, Some(info_hash)) + // Update curator + // But if banned, then require extra reserve + CuratorIndexToInfo::::try_mutate_exists( + curator_index, + |maybe_info| -> Result<(), DispatchError> { + let mut info = maybe_info.as_mut().ok_or(Error::::CuratorIndexNotExist)?; + + if (info.3 == CandidateStatus::Banned) { + T::Currency::reserve(&who, MinimumCuratorDeposit::get())?; + } + + // Update hash + info.0 = info_hash; + // Update block number + info.1 = frame_system::Pallet::::block_number(); + Self::deposit_event(Event::CuratorUpdated { + curator, + curator_index, + info_hash, + }); + Ok(()) + }, + )?; + Ok(()) } /// Clean a curator legal info @@ -176,9 +199,26 @@ pub mod pallet { Error::::CuratorNotRegistered ); - // New registed curator need to make a balance reserve - T::Currency::unreserve(&who, MinimumCuratorDeposit::get())?; - Self::update_curator(who, None) + let curator_index = PublicCuratorToIndex::::take(&who); + + // Update curator + // But if banned, then require extra reserve + CuratorIndexToInfo::::try_mutate_exists( + curator_index, + |maybe_info| -> Result<(), DispatchError> { + let info = maybe_info.ok_or(Error::::CuratorIndexNotExist)?; + + if (info.3 != CandidateStatus::Banned) { + T::Currency::unreserve(&who, MinimumCuratorDeposit::get())?; + } + + // Delete item + maybe_info = None; + Self::deposit_event(Event::CuratorCleaned { curator, curator_index }); + Ok(()) + }, + )?; + Ok(()) } #[pallet::call_index(3)] @@ -199,35 +239,42 @@ pub mod pallet { info.1 = frame_system::Pallet::::block_number(); // Update status info.3 = status; + Self::deposit_event(Event::CuratorStatusUpdated { curator, curator_index, status, }); + Ok(()) }, )?; } } } -impl Pallet { - pub fn update_curator(who: T::AccountId, info_hash: Option) -> DispatchResult { - if Some(hash) = info_hash { - let current_block = frame_system::Pallet::::block_number(); - let next_curator_index = PublicCuratorCount::::get(); +/// Some sort of check on the origin is from curator. +impl EnsureCurator for Pallet { + fn is_curator(account: T::AccountId) -> bool { + if let some(curator_index) = PublicCuratorToIndex::::get(account) { + if let some(info) = CuratorIndexToInfo::::get(curator_index) { + if (info.3 != CandidateStatus::Banned) { + return true; + } + } + } - PublicCuratorToIndex::::insert(&who, next_curator_index); - CuratorIndexToInfo::::insert( - &next_curator_index, - (info_hash, current_block, who.clone(), CandidateStatus::Unverified), - ); + false + } - PublicCuratorCount::::put(next_curator_index.checked_add(1u32.into())?); - } else { - // i.e. info_hash == None - let index = PublicCuratorToIndex::::take(&who); - CuratorIndexToInfo::::remove(&index); + fn is_verified_curator(account: T::AccountId) -> bool { + if let some(curator_index) = PublicCuratorToIndex::::get(account) { + if let some(info) = CuratorIndexToInfo::::get(curator_index) { + if (info.3 == CandidateStatus::Verified) { + return true; + } + } } - Ok(()) + + false } } diff --git a/pallets/collab-ai/pool-proposal/Cargo.toml b/pallets/collab-ai/pool-proposal/Cargo.toml index a2d4117768..c488eec5c2 100644 --- a/pallets/collab-ai/pool-proposal/Cargo.toml +++ b/pallets/collab-ai/pool-proposal/Cargo.toml @@ -17,6 +17,7 @@ frame-support = { workspace = true } frame-system = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } +orml-utilities = { workspace = true } pallet-collab-ai-common = { workspace = true } @@ -34,6 +35,7 @@ std = [ "sp-runtime/std", "frame-support/std", "frame-system/std", + "orml-utilities/std", "pallet-collab-ai-common/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/collab-ai/pool-proposal/src/lib.rs b/pallets/collab-ai/pool-proposal/src/lib.rs index 4844f28594..093bcf53aa 100644 --- a/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/pallets/collab-ai/pool-proposal/src/lib.rs @@ -40,6 +40,7 @@ use frame_support::{ weights::Weight, }; use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; +use orml_utilities::OrderedSet; use pallet_collab_ai_common::*; pub use pallet::*; @@ -60,18 +61,16 @@ pub type CallOf = ::RuntimeCall; pub type BoundedCallOf = Bounded>; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; -#[derive(Clone, Encode, Decode, Eq, PartialEq, Default, RuntimeDebug, MaxEncodedLen, TypeInfo)] -pub struct PoolMetadata { - /// The user friendly name of this staking pool. Limited in length by `PoolStringLimit`. - pub name: BoundedString, - /// The short description for this staking pool. Limited in length by `PoolStringLimit`. - pub description: BoundedString, -} - bitflags! { /// Flags used to record the status of pool proposal pub struct ProposalStatusFlags: u32 { - /// Whether the minimum staked amount proposed by curator is satisfied. + /// Whether the pool proposal passing the committee voting. + /// + /// # Note + /// + /// A valid pool must passing committee's audit procedure regarding legal files and other pool parameters. + const COMMITTEE_VOTE_PASSED = 0b0000_0001; + /// Whether the minimum staked amount proposed by curator is satisfied. /// /// # Note /// @@ -79,13 +78,7 @@ bitflags! { /// unless the pool is later denied passing by voting or until the end of pool maturity. /// /// Otherwise, the pool will be refunded. - const MINIMUM_STAKE_PASSED = 0b0000_0001; - /// Whether the pool proposal passing the committee voting. - /// - /// # Note - /// - /// A valid pool must passing committee's audit procedure regarding legal files and other pool parameters. - const COMMITTEE_VOTE_PASSED = 0b0000_0010; + const MINIMUM_STAKE_PASSED = 0b0000_0010; /// Whether the pool proposal passing the global democracy voting. /// /// # Note @@ -101,6 +94,24 @@ bitflags! { } } +#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] +pub struct PoolProposalStatus { + pub pool_status_flags: ProposalStatusFlags, + pub proposal_expire_time: BlockNumber, +} + +#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] +pub struct PoolProposalPreStake { + pub amount: Balance, + pub owner: AccountId, +} + +#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] +pub struct PoolProposalPreStaking> { + pub total_pre_staked_amount: Balance, + pub pre_staking: OrderedSet, S>, +} + #[frame_support::pallet] pub mod pallet { use super::*; @@ -119,19 +130,16 @@ pub mod pallet { /// The Scheduler. type Scheduler: ScheduleNamed, CallOf, Self::PalletsOrigin>; - /// The Legal file storage - type FileStorage: QueryPreimage + StorePreimage; - /// Currency type for this pallet. type Currency: ReservableCurrency + LockableCurrency>; - /// The minimum amount to be used as a deposit for a curator + /// The minimum amount to be used as a deposit for creating a pool curator #[pallet::constant] - type MinimumCuratorDeposit: Get>; + type MinimumPoolDeposit: Get>; - /// Origin from curator legal file verified by - type CuratorJudgeOrigin: EnsureOrigin; + /// Origin who can make a pool proposal + type ProposalOrigin: EnsureOrigin; } @@ -144,18 +152,18 @@ pub mod pallet { /// /// TWOX-NOTE: Safe, as increasing integer keys are safe. #[pallet::storage] - #[pallet::getter(fn pool_deposit_of)] - pub type PoolDepositOf = StorageMap< + #[pallet::getter(fn pool_proposal_deposit_of)] + pub type PoolProposalDepositOf = StorageMap< _, Twox64Concat, - CuratorIndex, + T::AccountId, BoundedVec<(PoolProposalIndex, BalanceOf), T::MaxDeposits>, >; // Metadata of staking pools #[pallet::storage] - #[pallet::getter(fn staking_pool_metadata)] - pub type StakingPoolStatus = StorageMap< + #[pallet::getter(fn pool_proposal_status)] + pub type PoolProposalStatus = StorageMap< _, Twox64Concat, PoolProposalIndex, @@ -183,9 +191,6 @@ pub mod pallet { #[pallet::error] pub enum Error { - CuratorAlreadyRegistered, - CuratorNotRegistered, - CuratorIndexNotExist, } #[pallet::hooks] @@ -200,17 +205,23 @@ pub mod pallet { impl Pallet { /// Curator propose a staking pool /// - /// pool_setup: Including pool details - /// proposal_end_time: All ProposalStatusFlags must be satisfied before this date + /// max_pool_size: At most this amount of raised money curator/staking pool willing to take + /// min_pool_size: At least this amount of raised money require for curator willing to fulfill contract + /// proposal_end_time: All ProposalStatusFlags must be satisfied before this date, this is also the approximate + /// date when pool begins. + /// pool_last_time: How long does the staking pool last if passed /// estimated_epoch_reward: This number is only for displaying purpose without any techinical meaning - /// + /// pool_info_hash: Hash of pool info for including pool details #[pallet::call_index(0)] #[pallet::weight(W{195_000_000})] pub fn propose_staking_pool( origin: OriginFor, - pool_setup: PoolSetting, BalanceOf>, + max_pool_size: BalanceOf, + min_pool_size: BalanceOf, proposal_end_time: BlockNumberFor, + pool_last_time: BlockNumberFor, estimated_epoch_reward: BalanceOf, + pool_info_hash: InfoHash, ) -> DispatchResult { let who = ensure_signed(origin)?; @@ -219,21 +230,3 @@ pub mod pallet { } } -impl Pallet { - pub fn update_curator(who: T::AccountId, info_hash: Option) -> DispatchResult { - if Some(hash) = info_hash { - let current_block = frame_system::Pallet::::block_number(); - let next_curator_index = PublicCuratorCount::::get(); - - PublicCuratorToIndex::::insert(&who, next_curator_index); - CuratorIndexToInfo::::insert(&next_curator_index, (info_hash, current_block, who.clone(), CandidateStatus::Unverified)); - - PublicCuratorCount::::put(next_curator_index.checked_add(1u32.into())?); - } else { - // i.e. info_hash == None - let index = PublicCuratorToIndex::::take(&who); - CuratorIndexToInfo::::remove(&index); - } - Ok(()) - } -} From af406cc5aa9d6baaa818fcf1d647337b2def133f Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 8 Sep 2024 20:46:01 +0800 Subject: [PATCH 008/215] temp: stash commit of pool proposal --- Cargo.toml | 3 +- .../Cargo.toml | 0 .../src/lib.rs | 0 pallets/collab-ai/pool-proposal/src/lib.rs | 102 +++++++++++------- 4 files changed, 65 insertions(+), 40 deletions(-) rename pallets/collab-ai/{candidate-preimage => guardian}/Cargo.toml (100%) rename pallets/collab-ai/{candidate-preimage => guardian}/src/lib.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index e0cb5e7e05..0939a46908 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ members = [ 'pallets/bridge/common', 'pallets/collab-ai/aiusd-convertor', 'pallets/collab-ai/curator', + 'pallets/collab-ai/pool-proposal', 'pallets/extrinsic-filter', 'pallets/evm-address', 'pallets/evm-assertions', @@ -279,7 +280,7 @@ pallet-evm-assertions = { path = "pallets/evm-assertions", default-features = fa pallet-aiusd-convertor = { path = "pallets/collab-ai/aiusd-convertor", default-features = false } pallet-collab-ai-common = { path = "pallets/collab-ai/common", default-features = false } pallet-curator = { path = "pallets/collab-ai/curator", default-features = false } - +pallet-pool-proposal = { path = "pallets/collab-ai/pool-proposal", default-features = false } [patch.crates-io] ring = { git = "https://github.com/betrusted-io/ring-xous", branch = "0.16.20-cleanup" } diff --git a/pallets/collab-ai/candidate-preimage/Cargo.toml b/pallets/collab-ai/guardian/Cargo.toml similarity index 100% rename from pallets/collab-ai/candidate-preimage/Cargo.toml rename to pallets/collab-ai/guardian/Cargo.toml diff --git a/pallets/collab-ai/candidate-preimage/src/lib.rs b/pallets/collab-ai/guardian/src/lib.rs similarity index 100% rename from pallets/collab-ai/candidate-preimage/src/lib.rs rename to pallets/collab-ai/guardian/src/lib.rs diff --git a/pallets/collab-ai/pool-proposal/src/lib.rs b/pallets/collab-ai/pool-proposal/src/lib.rs index 093bcf53aa..ab354866e7 100644 --- a/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/pallets/collab-ai/pool-proposal/src/lib.rs @@ -23,34 +23,25 @@ //! //! The Curator pallet handles the administration of general curator and proposed staking pool. //! -//! +//! #![cfg_attr(not(feature = "std"), no_std)] use bitflags::bitflags; use codec::{Decode, Encode}; use frame_support::{ ensure, error::BadOrigin, - traits::{ - defensive_prelude::*, - schedule::{v3::Named as ScheduleNamed, DispatchTime}, - Bounded, Currency, EnsureOrigin, Get, Hash as PreimageHash, LockIdentifier, - LockableCurrency, OnUnbalanced, QueryPreimage, ReservableCurrency, StorePreimage, - WithdrawReasons, - }, + traits::{Currency, EnsureOrigin, Get, LockIdentifier, LockableCurrency, ReservableCurrency}, weights::Weight, + BoundedVec, }; use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; use orml_utilities::OrderedSet; -use pallet_collab_ai_common::*; pub use pallet::*; +use pallet_collab_ai_common::*; +use sp_std::collections::vec_deque::VecDeque; -#[cfg(test)] -mod mock; -#[cfg(test)] -mod tests; - -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmarking; +pub(crate) const POOL_DEMOCRACY_ID: LockIdentifier = *b"spdemocy"; +pub(crate) const POOL_COMMITTEE_ID: LockIdentifier = *b"spcomtte"; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -76,7 +67,7 @@ bitflags! { /// /// Once a pool is satisfied this requirement, all staked amount can no longer be withdrawed /// unless the pool is later denied passing by voting or until the end of pool maturity. - /// + /// /// Otherwise, the pool will be refunded. const MINIMUM_STAKE_PASSED = 0b0000_0010; /// Whether the pool proposal passing the global democracy voting. @@ -95,13 +86,31 @@ bitflags! { } #[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] -pub struct PoolProposalStatus { +pub struct PoolProposalStatus { + pub pool_proposal_index: PoolProposalIndex, pub pool_status_flags: ProposalStatusFlags, pub proposal_expire_time: BlockNumber, } #[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] -pub struct PoolProposalPreStake { +pub struct PoolProposalInfo { + // Proposer/Curator + pub proposer: AccountId, + // Hash of pool info like legal files etc. + pub pool_info_hash: InfoHash, + // The maximum staking amount that the pool can handle + pub max_pool_size: Balance, + // The minimum staking amount that pool must satisfied in order for curator willing to operating + pub min_pool_size: Balance, + // If proposal passed, when the staking pool will be ended + pub pool_last_time: BlockNumber, + // estimated APR, but in percentage form + // i.e. 100 => 100% + pub estimated_epoch_reward: Balance, +} + +#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] +pub struct PoolStaking { pub amount: Balance, pub owner: AccountId, } @@ -109,7 +118,7 @@ pub struct PoolProposalPreStake { #[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] pub struct PoolProposalPreStaking> { pub total_pre_staked_amount: Balance, - pub pre_staking: OrderedSet, S>, + pub pre_staking: OrderedSet, S>, } #[frame_support::pallet] @@ -138,9 +147,12 @@ pub mod pallet { #[pallet::constant] type MinimumPoolDeposit: Get>; - /// Origin who can make a pool proposal - type ProposalOrigin: EnsureOrigin; + /// The maximum amount of allowed pool proposed by a single curator + #[pallet::constant] + type MaximumPoolProposed: Get; + /// Origin who can make a pool proposal + type ProposalOrigin: EnsureOrigin; } /// The next free Pool Proposal index, aka the number of pool proposed so far. @@ -149,8 +161,6 @@ pub mod pallet { pub type PoolProposalCount = StorageValue<_, PoolProposalIndex, ValueQuery>; /// Those who have a reserve for his pool proposal. - /// - /// TWOX-NOTE: Safe, as increasing integer keys are safe. #[pallet::storage] #[pallet::getter(fn pool_proposal_deposit_of)] pub type PoolProposalDepositOf = StorageMap< @@ -160,25 +170,33 @@ pub mod pallet { BoundedVec<(PoolProposalIndex, BalanceOf), T::MaxDeposits>, >; - // Metadata of staking pools + // Pending pool proposal status of staking pools #[pallet::storage] - #[pallet::getter(fn pool_proposal_status)] - pub type PoolProposalStatus = StorageMap< + #[pallet::getter(fn pending_pool_proposal_status)] + pub type PendingPoolProposalStatus = + StorageValue<_, VecDeque>>, ValueQuery>; + + // Pool proposal content + // This storage is not allowed to update once any ProposalStatusFlags passed + // Yet root is allowed to do that + #[pallet::storage] + #[pallet::getter(fn pool_proposal)] + pub type PoolProposal = StorageMap< _, Twox64Concat, PoolProposalIndex, - (InfoHash), + PoolProposalInfo, BlockNumberFor, T::AccountId>, OptionQuery, >; - // Metadata of staking pools + // Prestaking of pool proposal #[pallet::storage] - #[pallet::getter(fn staking_pool_metadata)] - pub type StakingPoolMetadata = StorageMap< + #[pallet::getter(fn staking_pool_pre_stakings)] + pub type StakingPoolPrestakings = StorageMap< _, Twox64Concat, PoolProposalIndex, - PoolMetadata>, + PoolProposalPreStaking, T::MaximumPoolProposed>, OptionQuery, >; @@ -190,8 +208,7 @@ pub mod pallet { } #[pallet::error] - pub enum Error { - } + pub enum Error {} #[pallet::hooks] impl Hooks> for Pallet { @@ -204,10 +221,10 @@ pub mod pallet { #[pallet::call] impl Pallet { /// Curator propose a staking pool - /// + /// /// max_pool_size: At most this amount of raised money curator/staking pool willing to take - /// min_pool_size: At least this amount of raised money require for curator willing to fulfill contract - /// proposal_end_time: All ProposalStatusFlags must be satisfied before this date, this is also the approximate + /// min_pool_size: At least this amount of raised money require for curator willing to fulfill contract + /// proposal_end_time: All ProposalStatusFlags must be satisfied before this date, this is also the approximate /// date when pool begins. /// pool_last_time: How long does the staking pool last if passed /// estimated_epoch_reward: This number is only for displaying purpose without any techinical meaning @@ -224,9 +241,16 @@ pub mod pallet { pool_info_hash: InfoHash, ) -> DispatchResult { let who = ensure_signed(origin)?; + } - + #[pallet::call_index(1)] + #[pallet::weight(W{195_000_000})] + pub fn vote_staking_pool( + origin: OriginFor, + pool_proposal_index: PoolProposalIndex, + vote: AccountVote>, + ) -> DispatchResult { + let who = ensure_signed(origin)?; } } } - From cc9d6b96aa338eb5b7812479f796764d356a9e7d Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 23 Sep 2024 16:27:49 +0800 Subject: [PATCH 009/215] tmp: rough commit for pre-staking --- Cargo.lock | 15 + pallets/collab-ai/pool-proposal/src/lib.rs | 440 +++++++++++++++---- pallets/collab-ai/pool-proposal/src/types.rs | 323 ++++++++++++++ 3 files changed, 689 insertions(+), 89 deletions(-) create mode 100644 pallets/collab-ai/pool-proposal/src/types.rs diff --git a/Cargo.lock b/Cargo.lock index 3943ca1a08..c577297828 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7869,6 +7869,21 @@ dependencies = [ "substrate-fixed", ] +[[package]] +name = "pallet-pool-proposal" +version = "0.1.0" +dependencies = [ + "bitflags 1.3.2", + "frame-support", + "frame-system", + "orml-utilities", + "pallet-collab-ai-common", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-preimage" version = "4.0.0-dev" diff --git a/pallets/collab-ai/pool-proposal/src/lib.rs b/pallets/collab-ai/pool-proposal/src/lib.rs index ab354866e7..30767bf288 100644 --- a/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/pallets/collab-ai/pool-proposal/src/lib.rs @@ -14,17 +14,18 @@ // You should have received a copy of the GNU General Public License // along with Litentry. If not, see . // -//! # Curator Pallet +//! # Pool Proposal Pallet //! //! - [`Config`] //! - [`Call`] //! //! ## Overview //! -//! The Curator pallet handles the administration of general curator and proposed staking pool. -//! -//! +//! The Pool Proposal handles the administration of proposed staking pool and pre-staking. #![cfg_attr(not(feature = "std"), no_std)] + +pub mod types; + use bitflags::bitflags; use codec::{Decode, Encode}; use frame_support::{ @@ -38,7 +39,10 @@ use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; use orml_utilities::OrderedSet; pub use pallet::*; use pallet_collab_ai_common::*; -use sp_std::collections::vec_deque::VecDeque; +use sp_runtime::traits::CheckedAdd; +use sp_std::{cmp::Ordering, collections::vec_deque::VecDeque}; + +pub use types::*; pub(crate) const POOL_DEMOCRACY_ID: LockIdentifier = *b"spdemocy"; pub(crate) const POOL_COMMITTEE_ID: LockIdentifier = *b"spcomtte"; @@ -52,77 +56,19 @@ pub type CallOf = ::RuntimeCall; pub type BoundedCallOf = Bounded>; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; -bitflags! { - /// Flags used to record the status of pool proposal - pub struct ProposalStatusFlags: u32 { - /// Whether the pool proposal passing the committee voting. - /// - /// # Note - /// - /// A valid pool must passing committee's audit procedure regarding legal files and other pool parameters. - const COMMITTEE_VOTE_PASSED = 0b0000_0001; - /// Whether the minimum staked amount proposed by curator is satisfied. - /// - /// # Note - /// - /// Once a pool is satisfied this requirement, all staked amount can no longer be withdrawed - /// unless the pool is later denied passing by voting or until the end of pool maturity. - /// - /// Otherwise, the pool will be refunded. - const MINIMUM_STAKE_PASSED = 0b0000_0010; - /// Whether the pool proposal passing the global democracy voting. - /// - /// # Note - /// - /// A valid pool must passing committee's audit procedure regarding legal files and other pool parameters. - const DEMOCRACY_VOTE_PASSED = 0b0000_0100; - /// Whether the pool guardian has been selected - /// - /// # Note - /// - /// A valid pool must have guardian or a default one will be used (committee) - const GUARDIAN_SELECTED = 0b0000_1000; - } -} - -#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] -pub struct PoolProposalStatus { - pub pool_proposal_index: PoolProposalIndex, - pub pool_status_flags: ProposalStatusFlags, - pub proposal_expire_time: BlockNumber, -} - -#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] -pub struct PoolProposalInfo { - // Proposer/Curator - pub proposer: AccountId, - // Hash of pool info like legal files etc. - pub pool_info_hash: InfoHash, - // The maximum staking amount that the pool can handle - pub max_pool_size: Balance, - // The minimum staking amount that pool must satisfied in order for curator willing to operating - pub min_pool_size: Balance, - // If proposal passed, when the staking pool will be ended - pub pool_last_time: BlockNumber, - // estimated APR, but in percentage form - // i.e. 100 => 100% - pub estimated_epoch_reward: Balance, -} - -#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] -pub struct PoolStaking { - pub amount: Balance, - pub owner: AccountId, -} - -#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] -pub struct PoolProposalPreStaking> { - pub total_pre_staked_amount: Balance, - pub pre_staking: OrderedSet, S>, -} +pub(crate) type InspectFungibles = pallet_assets::Pallet; +/// Balance type alias for balances of assets that implement the `fungibles` trait. +pub(crate) type AssetBalanceOf = + as FsInspect<::AccountId>>::Balance; +/// Type alias for Asset IDs. +pub(crate) type AssetIdOf = + as FsInspect<::AccountId>>::AssetId; #[frame_support::pallet] pub mod pallet { + use frame_support::{dispatch::DispatchResult, pallet_prelude::OptionQuery}; + use orml_utilities::ordered_set; + use super::*; /// The current storage version. @@ -133,7 +79,7 @@ pub mod pallet { pub struct Pallet(_); #[pallet::config] - pub trait Config: frame_system::Config + Sized { + pub trait Config: frame_system::Config + pallet_assets::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The Scheduler. @@ -143,6 +89,17 @@ pub mod pallet { type Currency: ReservableCurrency + LockableCurrency>; + // Declare the asset id of AIUSD + type AIUSDAssetId: Get>; + + /// Period of time between proposal ended and pool start + #[pallet::constant] + type OfficialGapPeriod: Get>; + + /// Minimum period of time for proposal voting end/expired + #[pallet::constant] + type MinimumProposalLastTime: Get>; + /// The minimum amount to be used as a deposit for creating a pool curator #[pallet::constant] type MinimumPoolDeposit: Get>; @@ -152,7 +109,13 @@ pub mod pallet { type MaximumPoolProposed: Get; /// Origin who can make a pool proposal - type ProposalOrigin: EnsureOrigin; + type ProposalOrigin: EnsureOrigin; + + /// Origin who can make a pool proposal pass public vote check + type PublicVotingOrigin: EnsureOrigin; + + /// System Account holding pre-staking assets + type PreStakingPool: Get; } /// The next free Pool Proposal index, aka the number of pool proposed so far. @@ -167,10 +130,12 @@ pub mod pallet { _, Twox64Concat, T::AccountId, - BoundedVec<(PoolProposalIndex, BalanceOf), T::MaxDeposits>, + OrderedSet>, T::MaxDeposits>, + OptionQuery, >; // Pending pool proposal status of staking pools + // Ordered by expired time #[pallet::storage] #[pallet::getter(fn pending_pool_proposal_status)] pub type PendingPoolProposalStatus = @@ -185,18 +150,24 @@ pub mod pallet { _, Twox64Concat, PoolProposalIndex, - PoolProposalInfo, BlockNumberFor, T::AccountId>, + PoolProposalInfo, BlockNumberFor, T::AccountId>, OptionQuery, >; // Prestaking of pool proposal + // This storage will be modified/delete correspondingly when solving pending pool #[pallet::storage] #[pallet::getter(fn staking_pool_pre_stakings)] pub type StakingPoolPrestakings = StorageMap< _, Twox64Concat, PoolProposalIndex, - PoolProposalPreStaking, T::MaximumPoolProposed>, + PoolProposalPreStaking< + T::AccountId, + AssetBalanceOf, + BlockNumberFor, + T::MaximumPoolProposed, + >, OptionQuery, >; @@ -204,11 +175,45 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// A motion has been proposed by a public account. - Proposed { proposal_index: PropIndex, deposit: BalanceOf }, + PoolProposed { proposer: T::AccountId, pool_proposal_index: PoolProposalIndex }, + /// A pre staking becomes valid + PoolPreStaked { + user: T::AccountId, + pool_proposal_index: PoolProposalIndex, + amount: AssetBalanceOf, + }, + /// A pre staking queued + PoolPreStakeQueued { + user: T::AccountId, + pool_proposal_index: PoolProposalIndex, + amount: AssetBalanceOf, + }, + /// A queued pre staking becomes a valid pre staking + PoolQueuedStaked { + user: T::AccountId, + pool_proposal_index: PoolProposalIndex, + amount: AssetBalanceOf, + }, + /// Some amount of pre staking regardless of queue or pre staked, withdrawed (Withdraw queue ones first) + PoolWithdrawed { + user: T::AccountId, + pool_proposal_index: PoolProposalIndex, + amount: AssetBalanceOf, + }, + /// A public vote result of proposal get passed + ProposalPublicVoted { pool_proposal_index: PoolProposalIndex, vote_result: bool }, } #[pallet::error] - pub enum Error {} + pub enum Error { + PreStakingOverflow, + ProposalExpired, + ProposalPreStakingLocked, + ProposalPublicTimeTooShort, + ProposalNotExist, + StakingPoolOversized, + InsufficientPreStaking, + } #[pallet::hooks] impl Hooks> for Pallet { @@ -224,33 +229,290 @@ pub mod pallet { /// /// max_pool_size: At most this amount of raised money curator/staking pool willing to take /// min_pool_size: At least this amount of raised money require for curator willing to fulfill contract - /// proposal_end_time: All ProposalStatusFlags must be satisfied before this date, this is also the approximate - /// date when pool begins. + /// proposal_last_time: How does the proposal lasts for voting/prestaking. + /// All ProposalStatusFlags must be satisfied after this period passed, which is also + /// the approximate date when pool begins. /// pool_last_time: How long does the staking pool last if passed /// estimated_epoch_reward: This number is only for displaying purpose without any techinical meaning /// pool_info_hash: Hash of pool info for including pool details #[pallet::call_index(0)] #[pallet::weight(W{195_000_000})] + #[transactional] pub fn propose_staking_pool( origin: OriginFor, - max_pool_size: BalanceOf, - min_pool_size: BalanceOf, - proposal_end_time: BlockNumberFor, + max_pool_size: AssetBalanceOf, + proposal_last_time: BlockNumberFor, pool_last_time: BlockNumberFor, - estimated_epoch_reward: BalanceOf, + estimated_epoch_reward: AssetBalanceOf, pool_info_hash: InfoHash, ) -> DispatchResult { - let who = ensure_signed(origin)?; + let who = T::ProposalOrigin::ensure_origin(origin)?; + + let current_block = frame_system::Pallet::::block_number(); + ensure!( + proposal_last_time >= MinimumProposalLastTime::get(), + Error::::ProposalPublicTimeTooShort + ); + + let proposal_end_time = + current_block.checked_add(proposal_last_time).ok_or(ArithmeticError::Overflow)?; + + let pool_start_time = proposal_end_time + .checked_add(OfficialGapPeriod::get()) + .ok_or(ArithmeticError::Overflow)?; + + let new_proposal_info = PoolProposalInfo { + proposer: who, + pool_info_hash, + max_pool_size, + pool_start_time, + pool_end_time: pool_start_time + .checked_add(pool_last_time) + .ok_or(ArithmeticError::Overflow)?, + estimated_epoch_reward, + proposal_status_flags: ProposalStatusFlags::empty(), + }; + + let next_proposal_index = PoolProposalCount::::get(); + PoolProposal::::insert(next_proposal_index, new_proposal_info); + PublicCuratorToIndex::::insert(&who, next_curator_index); + PoolProposalDepositOf::::try_mutate_exists( + &who, + |maybe_ordered_set| -> Result<(), DispatchError> { + let reserved_amount = MinimumPoolDeposit::get(); + let _ = T::Currency::reserve(&who, reserved_amount)?; + // We should not care about duplicating since the proposal index is auto-increment + match maybe_ordered_set.as_mut() { + Some(ordered_set) => { + ordered_set.insert(Bond { + owner: next_proposal_index, + value: reserved_amount, + }); + }, + None => { + let new_ordered_set = OrderedSet::new().insert(Bond { + owner: next_proposal_index, + value: reserved_amount, + }); + *maybe_ordered_set = Some(new_ordered_set) + }, + } + }, + ); + >::mutate(|pending_porposals| { + let new_proposal_status = PoolProposalStatus { + pool_proposal_index: next_proposal_index, + proposal_expire_time: proposal_end_time, + }; + pending_porposals.push_back(new_proposal_status); + // Make sure the first element has earlies effective time + pending_porposals + .make_contiguous() + .sort_by(|a, b| a.proposal_expire_time.cmp(&b.proposal_expire_time)); + }); + PoolProposalCount::::put( + next_proposal_index.checked_add(1u32.into()).ok_or(ArithmeticError::Overflow)?, + ); + Self::deposit_event(Event::PoolProposed { + proposer: who, + pool_proposal_index: next_proposal_index, + }); + Ok(()) } #[pallet::call_index(1)] #[pallet::weight(W{195_000_000})] - pub fn vote_staking_pool( + #[transactional] + pub fn pre_stake_proposal( + origin: OriginFor, + pool_proposal_index: PoolProposalIndex, + amount: AssetBalanceOf, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + let asset_actual_transfer_amount: AssetBalanceOf = >::transfer( + AIUSDAssetId::get(), + who, + PreStakingPool::get(), + amount, + Preservation::Expendable, + )?; + + let mut pool_proposal_pre_staking = + >::take(pool_proposal_index) + .unwrap_or(PoolProposalPreStaking::new()); + + // Check pool maximum size limit and make pool size limit flag change accordingly + let mut pool_proposal = + PoolProposal::get(pool_proposal_index).ok_or(Error::::ProposalNotExist)?; + // Proposal not expired + ensure!( + !pool_proposal + .proposal_status_flags + .contains(ProposalStatusFlags::PROPOSAL_EXPIRED), + Error::::ProposalExpired + ); + // If proposal is fully pre-staked or partial oversized after this stake + + // Check BoundedVec limit + ensure!( + !pool_proposal_pre_staking.pre_stakings.is_full + && !pool_proposal_pre_staking.queued_pre_stakings.is_full, + Error::::StakingPoolOversized + ); + + let target_pre_staked_amount = pool_proposal_pre_staking + .total_pre_staked_amount + .checked_add(asset_actual_transfer_amount) + .ok_or(ArithmeticError::Overflow)?; + if (target_pre_staked_amount <= pool_proposal.max_pool_size) { + // take all pre-staking into valid pre-staking line + pool_proposal_pre_staking + .add_pre_staking::(who, asset_actual_transfer_amount)?; + + // Emit event only + Self::deposit_event(Event::PoolPreStaked { + user: who, + pool_proposal_index, + amount: asset_actual_transfer_amount, + }); + // Flag proposal status if pool is just fully staked + if (target_pre_staked_amount == pool_proposal.max_pool_size) { + pool_proposal.proposal_status_flags = pool_proposal.proposal_status_flags + | ProposalStatusFlags::STAKE_AMOUNT_PASSED; + PoolProposal::put(pool_proposal_index, pool_proposal); + } + } else { + // Partially + let queued_pre_staked_amount = target_pre_staked_amount + .checked_sub(pool_proposal.max_pool_size) + .ok_or(ArithmeticError::Overflow)?; + pool_proposal_pre_staking.add_queued_staking::( + who, + queued_pre_staked_amount, + frame_system::Pallet::::block_number(), + )?; + + // If pool not already full, flag proposal status + if (asset_actual_transfer_amount > queued_pre_staked_amount) { + let actual_pre_staked_amount = asset_actual_transfer_amount + .checked_sub(queued_pre_staked_amount) + .ok_or(ArithmeticError::Overflow)?; + pool_proposal_pre_staking + .add_pre_staking::(who, actual_pre_staked_amount)?; + + Self::deposit_event(Event::PoolPreStaked { + user: who, + pool_proposal_index, + amount: actual_pre_staked_amount, + }); + + pool_proposal.proposal_status_flags = pool_proposal.proposal_status_flags + | ProposalStatusFlags::STAKE_AMOUNT_PASSED; + PoolProposal::put(pool_proposal_index, pool_proposal); + } + + // Emit events + Self::deposit_event(Event::PoolPreStakeQueued { + user: who, + pool_proposal_index, + amount: queued_pre_staked_amount, + }); + } + + >::put(pool_proposal_index, pool_proposal_pre_staking); + } + + // Withdraw is not allowed when proposal has STAKE_AMOUNT_PASSED flag + // unless there is queued amount pending + #[pallet::call_index(2)] + #[pallet::weight(W{195_000_000})] + #[transactional] + pub fn withdraw_pre_staking( origin: OriginFor, pool_proposal_index: PoolProposalIndex, - vote: AccountVote>, + amount: AssetBalanceOf, ) -> DispatchResult { let who = ensure_signed(origin)?; + + let mut pool_proposal_pre_staking = + >::take(pool_proposal_index) + .unwrap_or(PoolProposalPreStaking::new()); + + // Either staking pool has not locked yet, + // Or queued amount is enough to replace the withdrawal + ensure!( + !pool_proposal + .proposal_status_flags + .contains(ProposalStatusFlags::STAKE_AMOUNT_PASSED) + || (pool_proposal_pre_staking.total_queued_amount >= amount), + Error::::ProposalPreStakingLocked + ); + + let _ = pool_proposal_pre_staking.withdraw::(who, amount)?; + Self::deposit_event(Event::PoolWithdrawed { user: who, pool_proposal_index, amount }); + + let mut pool_proposal = + PoolProposal::get(pool_proposal_index).ok_or(Error::::ProposalNotExist)?; + // Make queued amount fill the missing staked amount if pool staked flag ever reached + if ((pool_proposal_pre_staking.total_pre_staked_amount < pool_proposal.max_pool_size) + && (pool_proposal + .proposal_status_flags + .contains(ProposalStatusFlags::STAKE_AMOUNT_PASSED))) + { + let moved_bonds = pool_proposal_pre_staking + .move_queued_to_pre_staking_until::(pool_proposal.max_pool_size)?; + for i in moved_bonds.iter() { + // Emit events + Self::deposit_event(Event::PoolQueuedStaked { + user: i.owner, + pool_proposal_index, + amount: i.amount, + }); + } + } + + // Return funds + let asset_actual_transfer_amount: AssetBalanceOf = >::transfer( + AIUSDAssetId::get(), + PreStakingPool::get(), + who, + amount, + Preservation::Expendable, + )?; + + >::put(pool_proposal_index, pool_proposal_pre_staking); + + Ok(()) + } + + // This is democracy/committe passing check for staking pool proposal + // TODO: Related logic with "pallet-conviction-voting" + #[pallet::call_index(3)] + #[pallet::weight(W{195_000_000})] + pub fn public_vote_proposal( + origin: OriginFor, + pool_proposal_index: PoolProposalIndex, + vote: bool, + ) -> DispatchResult { + T::PublicVotingOrigin::ensure_origin(origin)?; + let mut pool_proposal = + PoolProposal::get(pool_proposal_index).ok_or(Error::::ProposalNotExist)?; + + if vote { + pool_proposal.proposal_status_flags = + pool_proposal.proposal_status_flags | ProposalStatusFlags::PUBLIC_VOTE_PASSED; + } else { + pool_proposal.proposal_status_flags = + pool_proposal.proposal_status_flags & !ProposalStatusFlags::PUBLIC_VOTE_PASSED; + } + PoolProposal::put(pool_proposal_index, pool_proposal); + + Self::deposit_event(Event::ProposalPublicVoted { + pool_proposal_index, + vote_result: vote, + }); + Ok(()) } } } diff --git a/pallets/collab-ai/pool-proposal/src/types.rs b/pallets/collab-ai/pool-proposal/src/types.rs new file mode 100644 index 0000000000..63fb03f960 --- /dev/null +++ b/pallets/collab-ai/pool-proposal/src/types.rs @@ -0,0 +1,323 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +bitflags! { + /// Flags used to record the status of pool proposal + #[derive(Encode, Decode, MaxEncodedLen)] + pub struct ProposalStatusFlags: u8 { + /// Whether the pool proposal passing the committee/democracy voting. + /// + /// # Note + /// + /// A valid pool must passing committee/public's audit procedure regarding legal files and other pool parameters. + const PUBLIC_VOTE_PASSED = 0b0000_0001; + /// Whether the minimum staked amount proposed by curator is satisfied. + /// + /// # Note + /// + /// Currently, a full size must be satisfied. + /// + /// Once a pool is satisfied this requirement, all staked amount can no longer be withdrawed + /// unless the pool is later denied passing by voting or until the end of pool maturity. + /// + /// Otherwise, the pool will be refunded. + const STAKE_AMOUNT_PASSED = 0b0000_0010; + /// Whether the pool guardian has been selected + /// + /// # Note + /// + /// A valid pool must have guardian or a default one will be used (committee) + const GUARDIAN_SELECTED = 0b0000_0100; + /// Whether the proposal expired yet + /// + /// # Note + /// + /// Has nothing to do with pool. Only related to proposal expired time + const PROPOSAL_EXPIRED = 0b0000_1000; + } +} + +#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] +pub struct PoolProposalStatus { + pub pool_proposal_index: PoolProposalIndex, + pub proposal_expire_time: BlockNumber, +} + +#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] +pub struct PoolProposalInfo { + // Proposer/Curator + pub proposer: AccountId, + // Hash of pool info like legal files etc. + pub pool_info_hash: InfoHash, + // The maximum staking amount that the pool can handle + pub max_pool_size: Balance, + // If proposal passed, when the staking pool will start + pub pool_start_time: BlockNumber, + // If proposal passed, when the staking pool will end + pub pool_end_time: BlockNumber, + // estimated APR, but in percentage form + // i.e. 100 => 100% + pub estimated_epoch_reward: Balance, + // Proposal status flags + pub proposal_status_flags: ProposalStatusFlags, +} + +#[derive(Clone, Encode, Debug, Decode, TypeInfo)] +pub struct Bond { + pub owner: Identity, + pub amount: BalanceType, +} + +impl Default for Bond { + fn default() -> Bond { + Bond { + owner: A::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) + .expect("infinite length input; no invalid inputs for type; qed"), + amount: B::default(), + } + } +} + +impl Bond { + pub fn from_owner(owner: A) -> Self { + Bond { owner, amount: B::default() } + } +} + +impl Eq for Bond {} + +impl Ord for Bond { + fn cmp(&self, other: &Self) -> Ordering { + self.owner.cmp(&other.owner) + } +} + +impl PartialOrd for Bond { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl PartialEq for Bond { + fn eq(&self, other: &Self) -> bool { + self.owner == other.owner + } +} + +#[derive(Clone, Encode, Debug, Decode, TypeInfo)] +pub struct PoolProposalPreStaking> { + pub total_pre_staked_amount: Balance, + // Ordered by bond owner AccountId + pub pre_stakings: BoundedVec, S>, + pub total_queued_amount: Balance, + // Ordered by bond owner AccountId + pub queued_pre_stakings: BoundedVec<(Bond, BlockNumber), S>, +} + +impl> + PoolProposalPreStaking +{ + /// Create a new empty default + pub fn new() -> Self { + PoolProposalPreStaking { + total_pre_staked_amount: Default::default(), + pre_stakings: Default::default(), + total_queued_amount: Default::default(), + queued_pre_stakings: Default::default(), + } + } + + pub fn get_pre_staking(&self, account: AccountId) -> Option<(usize, Balance)> { + match self.pre_stakings.binary_search(&Bond::from_owner(account)) { + Ok(loc) => Some((loc, self.pre_stakings.index(loc))), + Err(loc) => None, + } + } + + pub fn add_pre_staking( + &mut self, + account: AccountId, + amount: Balance, + ) -> Result<(), DispatchError> { + if let Some(existing) = self.get_pre_staking(account) { + self.pre_stakings.remove(existing.0); + let new_balance = existing.1.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; + let _ = self + .pre_stakings + .try_insert(existing.0, Bond { owner: account, amount: new_balance }) + .map_err(|_| Error::::StakingPoolOversized)?; + } else { + let _ = self + .pre_stakings + .try_insert(existing.0, Bond { owner: account, amount }) + .map_err(|_| Error::::StakingPoolOversized)?; + } + self::total_pre_staked_amount = self::total_pre_staked_amount + .checked_add(&amount) + .ok_or(ArithmeticError::Overflow)?; + Ok(()) + } + + pub fn withdraw( + &mut self, + account: AccountId, + amount: Balance, + ) -> Result<(), DispatchError> { + // Withdraw Queued one if any + if let Some(existing_q) = self.get_queued_staking(account) { + if (existing_q.1 > amount) { + // Existing queue is larger than target amount + // Finish withdrawing and return early + self.queued_pre_stakings.remove(existing_q.0); + let new_balance_q = + existing_q.1.checked_sub(&amount).ok_or(ArithmeticError::Overflow)?; + self.queued_pre_stakings + .try_insert( + existing_q.0, + (Bond { owner: account, amount: new_balance_q }, existing_q.2), + ) + .map_err(|_| Error::::StakingPoolOversized)?; + + self::total_queued_amount = self::total_queued_amount + .checked_sub(&amount) + .ok_or(ArithmeticError::Overflow)?; + return Ok(()); + } else { + // Totally remove queued + self.queued_pre_stakings.remove(existing_q.0); + self::total_queued_amount = self::total_queued_amount + .checked_sub(&existing_q.1) + .ok_or(ArithmeticError::Overflow)?; + + let left_amount = amount - existing_q.1; + + if let Some(existing_p) = self.get_pre_staking(account) { + // Existing pre-staking is larger than left target amount + // Finish withdrawing and return early + if (existing_p.1 > left_amount) { + self.pre_stakings.remove(existing_p.0); + let new_balance_p = existing_p + .1 + .checked_sub(&left_amount) + .ok_or(ArithmeticError::Overflow)?; + self.pre_stakings + .try_insert( + existing_q.0, + Bond { owner: account, amount: new_balance_p }, + ) + .map_err(|_| Error::::StakingPoolOversized)?; + self::total_pre_staked_amount = self::total_pre_staked_amount + .checked_sub(&left_amount) + .ok_or(ArithmeticError::Overflow)?; + return Ok(()); + } else if (existing_p.1 == left_amount) { + // Exact amount to finish everything + self.pre_stakings.remove(existing_p.0); + self::total_pre_staked_amount = self::total_pre_staked_amount + .checked_sub(&left_amount) + .ok_or(ArithmeticError::Overflow)?; + return Ok(()); + } else { + // Not enough fund to finish operation + return Err(Error::::InsufficientPreStaking); + } + } + } + } + // No pre-staking of all kinds + return Err(Error::::InsufficientPreStaking); + } + + pub fn get_queued_staking(&self, account: AccountId) -> Option<(usize, Balance, BlockNumber)> { + match self + .queued_pre_stakings + .binary_search_by(|p| p.0.cmp(&Bond::from_owner(account))) + { + Ok(loc) => Some(( + loc, + self.queued_pre_stakings.index(loc).0.amount, + self.queued_pre_stakings.index(loc).1, + )), + Err(loc) => None, + } + } + + pub fn add_queued_staking( + &mut self, + account: AccountId, + amount: Balance, + current_block: BlockNumber, + ) -> Result<(), DispatchError> { + if let Some(existing) = self.get_queued_staking(account) { + self.queued_pre_stakings.remove(existing.0); + let new_balance = existing.1.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; + let _ = self + .queued_pre_stakings + .try_insert( + existing.0, + (Bond { owner: account, amount: new_balance }, current_block), + ) + .map_err(|_| Error::::StakingPoolOversized)?; + } else { + let _ = self + .queued_pre_stakings + .try_insert(existing.0, (Bond { owner: account, amount }, current_block)) + .map_err(|_| Error::::StakingPoolOversized)?; + } + self::total_queued_amount = self::total_queued_amount + .checked_add(&amount) + .ok_or(ArithmeticError::Overflow)?; + Ok(()) + } + + // Transfer queued amount into pre staking + pub fn move_queued_to_pre_staking_until( + &mut self, + target_pre_staked_amount: Balance, + ) -> Result>, DispatchError> { + let result: Vec> = Vec::new(); + // Make sure target transfer is possible + ensure!( + self.total_queued_amount + >= target_pre_staked_amount + .checked_sub(self.total_pre_staked_amount) + .ok_or(ArithmeticError::Overflow)?, + Error::::InsufficientPreStaking + ); + + let mut v = self.queued_pre_stakings.into_inner().clone(); + // temp sorted by blocknumber + v.sort_by(|p| p.2); + + for i in v.iter() { + let transfer_amount = target_pre_staked_amount + .checked_sub(self.total_pre_staked_amount) + .ok_or(ArithmeticError::Overflow)?; + if (i.0.amount >= transfer_amount) { + let _ = self.withdraw(i.0.owner, transfer_amount)?; + self.add_pre_staking(i.0.owner, transfer_amount)?; + result.push(Bond { owner: i.0.owner, amount: transfer_amount }); + break; + } else { + let _ = self.withdraw(i.0.owner, i.0.amount)?; + self.add_pre_staking(i.0.owner, i.0.amount)?; + result.push(Bond { owner: i.0.owner, amount: i.0.amount }); + } + } + + Ok(result) + } +} From dedac280f7f13ddfb9351d91fb89d277fd98d06b Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 25 Sep 2024 17:54:03 +0800 Subject: [PATCH 010/215] tmp: rough commit for guardian --- pallets/collab-ai/common/src/lib.rs | 38 +++ pallets/collab-ai/guardian/src/lib.rs | 318 ++++++++++++++++++ pallets/collab-ai/pool-proposal/src/lib.rs | 178 ++++++---- pallets/collab-ai/pool-proposal/src/types.rs | 130 +++---- .../collab-ai/pool-tokens-manager/Cargo.toml | 45 +++ .../collab-ai/pool-tokens-manager/src/lib.rs | 0 runtime/litentry/src/asset_config.rs | 4 +- runtime/rococo/src/asset_config.rs | 4 +- 8 files changed, 580 insertions(+), 137 deletions(-) create mode 100644 pallets/collab-ai/pool-tokens-manager/Cargo.toml create mode 100644 pallets/collab-ai/pool-tokens-manager/src/lib.rs diff --git a/pallets/collab-ai/common/src/lib.rs b/pallets/collab-ai/common/src/lib.rs index a187beddaa..2b7b6ae13e 100644 --- a/pallets/collab-ai/common/src/lib.rs +++ b/pallets/collab-ai/common/src/lib.rs @@ -22,7 +22,9 @@ use sp_runtime::DispatchError; pub type InfoHash = H256; pub type CuratorIndex = u128; +pub type GuardianIndex = u128; pub type PoolProposalIndex = u128; +pub type InvestingPoolIndex = u128; #[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] pub struct PoolSetting { @@ -63,6 +65,24 @@ pub enum CandidateStatus { Banned, } +#[derive(PartialEq, Eq, Clone, Copy, Default, Encode, Decode, Debug, TypeInfo)] +pub enum GuardianVote { + /// Does not care if this guardian get selected + #[default] + #[codec(index = 0)] + Neutral, + /// Want this guardian no matter which pool proposal + #[codec(index = 1)] + Aye, + /// Against this guardian no matter which pool proposal + #[codec(index = 2)] + Nay, + /// Support this guardian for only specific pool proposal + /// And neutral for other pool proposal + #[codec(index = 3)] + Specific(BoundedVec), +} + /// Some sort of check on the account is from some group. pub trait EnsureCurator { /// All curator but banned ones @@ -98,3 +118,21 @@ where Err(()) } } + +pub const INVESTING_POOL_INDEX_SHIFTER: u128 = 1_000_000_000_000_000; +pub const INVESTING_POOL_START_MONTH_SHIFTER: u128 = 1_000; +pub const INVESTING_POOL_END_MONTH_SHIFTER: u128 = 1; + +pub struct InvestingPoolAssetId(sp_std::marker::PhantomData); +impl> InvestingPoolAssetIdGenerator { + /// Create a series of new asset id based on pool index and reward epoch + /// Return None if impossible to generate. e.g. overflow + pub fn get_pool_token(pool_index: InvestingPoolIndex, epoch: u128) -> Option> { + let pool_index_prefix = pool_index.checked_mul(INVESTING_POOL_INDEX_SHIFTER)?; + + let mut vec: Vec = Vec::new(); + for n in 0..(epoch + 1) { + // vec.push(pool_index_prefix + ) + } + } +} diff --git a/pallets/collab-ai/guardian/src/lib.rs b/pallets/collab-ai/guardian/src/lib.rs index e69de29bb2..5e2bc59522 100644 --- a/pallets/collab-ai/guardian/src/lib.rs +++ b/pallets/collab-ai/guardian/src/lib.rs @@ -0,0 +1,318 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . +// +//! # Guardian Pallet +//! +//! - [`Config`] +//! - [`Call`] +//! +//! ## Overview +//! +//! The Guardian pallet handles the administration of general guardian and guardian voting. +//! +//! +#![cfg_attr(not(feature = "std"), no_std)] +use bitflags::bitflags; +use codec::{Decode, Encode}; +use frame_support::{ + ensure, + traits::{Currency, EnsureOrigin, Get, LockableCurrency, ReservableCurrency}, + weights::Weight, +}; +use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; +pub use pallet::*; +use pallet_collab_ai_common::*; + +type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + Sized { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// Currency type for this pallet. + type Currency: ReservableCurrency + + LockableCurrency>; + + /// The minimum amount to be used as a deposit for a guardian + #[pallet::constant] + type MinimumGuardianDeposit: Get>; + + /// Origin from guardian legal file verified by + type GuardianJudgeOrigin: EnsureOrigin; + } + + /// The number of (public) guardian that have been made so far. + #[pallet::storage] + #[pallet::getter(fn public_guardian_count)] + pub type PublicGuardianCount = StorageValue<_, GuardianIndex, ValueQuery>; + + /// The public guardian to index + #[pallet::storage] + #[pallet::getter(fn public_guardian_to_index)] + pub type PublicGuardianToIndex = + StorageMap<_, Twox64Concat, T::AccountId, GuardianIndex, OptionQuery>; + + /// Guardian index to hash and update time. Info Hash is current used guardian legal file hash. + #[pallet::storage] + #[pallet::getter(fn guardian_index_to_info)] + pub type GuardianIndexToInfo = StorageMap< + _, + Twox64Concat, + GuardianIndex, + (InfoHash, BlockNumberFor, T::AccountId, CandidateStatus), + OptionQuery, + >; + + /// Votings for guardian + #[pallet::storage] + #[pallet::getter(fn guardian_votes)] + pub type GuardianVotes = StorageDoubleMap< + _, + Twox64Concat, + T::AccountId, + Twox64Concat, + GuardianIndex, + GuardianVote, + ValueQuery, + >; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + GuardianRegisted { + guardian: T::AccountId, + guardian_index: GuardianIndex, + info_hash: InfoHash, + }, + GuardianUpdated { + guardian: T::AccountId, + guardian_index: GuardianIndex, + info_hash: InfoHash, + }, + GuardianCleaned { + guardian: T::AccountId, + guardian_index: GuardianIndex, + }, + GuardianStatusUpdated { + guardian: T::AccountId, + guardian_index: GuardianIndex, + status: CandidateStatus, + }, + } + + #[pallet::error] + pub enum Error { + GuardianAlreadyRegistered, + GuardianNotRegistered, + GuardianIndexNotExist, + } + + #[pallet::call] + impl Pallet { + /// Registing a guardian legal info + #[pallet::call_index(0)] + #[pallet::weight(W{195_000_000})] + pub fn regist_guardian(origin: OriginFor, info_hash: InfoHash) -> DispatchResult { + let who = ensure_signed(origin)?; + + // Ensure guardian not existing yet + ensure!( + !PublicGuardianToIndex::::contains_key(&who), + Error::::GuardianAlreadyRegistered + ); + // New registed guardian need to make a balance reserve + T::Currency::reserve(&who, MinimumGuardianDeposit::get())?; + + // Update guardian + let current_block = frame_system::Pallet::::block_number(); + let next_guardian_index = PublicGuardianCount::::get(); + + PublicGuardianToIndex::::insert(&who, next_guardian_index); + GuardianIndexToInfo::::insert( + &next_guardian_index, + (info_hash, current_block, who, CandidateStatus::Unverified), + ); + PublicGuardianCount::::put(next_guardian_index.checked_add(1u32.into())?); + + Self::deposit_event(Event::GuardianRegisted { guardian: who, guardian_index, info_hash }); + Ok(()) + } + + /// Updating a guardian legal info + #[pallet::call_index(1)] + #[pallet::weight(W{195_000_000})] + pub fn update_guardian(origin: OriginFor, info_hash: InfoHash) -> DispatchResult { + let who = ensure_signed(origin)?; + + // Ensure existing + let guardian_index = + PublicGuardianToIndex::::get(guardian).ok_or(Error::::GuardianNotRegistered)?; + + // Update guardian + // But if banned, then require extra reserve + GuardianIndexToInfo::::try_mutate_exists( + guardian_index, + |maybe_info| -> Result<(), DispatchError> { + let mut info = maybe_info.as_mut().ok_or(Error::::GuardianIndexNotExist)?; + + if (info.3 == CandidateStatus::Banned) { + T::Currency::reserve(&who, MinimumGuardianDeposit::get())?; + } + + // Update hash + info.0 = info_hash; + // Update block number + info.1 = frame_system::Pallet::::block_number(); + Self::deposit_event(Event::GuardianUpdated { + guardian, + guardian_index, + info_hash, + }); + Ok(()) + }, + )?; + Ok(()) + } + + /// Clean a guardian legal info + /// Impossible when there is a staking pool proposal ongoing + #[pallet::call_index(2)] + #[pallet::weight(W{195_000_000})] + pub fn clean_guardian(origin: OriginFor) -> DispatchResult { + let who = ensure_signed(origin)?; + + // Ensure existing + ensure!( + PublicGuardianToIndex::::contains_key(&who), + Error::::GuardianNotRegistered + ); + + let guardian_index = PublicGuardianToIndex::::take(&who); + + // Update guardian + // But if banned, then require extra reserve + GuardianIndexToInfo::::try_mutate_exists( + guardian_index, + |maybe_info| -> Result<(), DispatchError> { + let info = maybe_info.ok_or(Error::::GuardianIndexNotExist)?; + + if (info.3 != CandidateStatus::Banned) { + T::Currency::unreserve(&who, MinimumGuardianDeposit::get())?; + } + + // Delete item + maybe_info = None; + Self::deposit_event(Event::GuardianCleaned { guardian, guardian_index }); + Ok(()) + }, + )?; + Ok(()) + } + + #[pallet::call_index(3)] + #[pallet::weight(W{195_000_000})] + pub fn judge_guardian_status( + origin: OriginFor, + guardian: T::AccountId, + status: CandidateStatus, + ) -> DispatchResult { + T::GuardianJudgeOrigin::ensure_origin(origin)?; + let guardian_index = + PublicGuardianToIndex::::get(guardian).ok_or(Error::::GuardianNotRegistered)?; + GuardianIndexToInfo::::try_mutate_exists( + guardian_index, + |maybe_info| -> Result<(), DispatchError> { + let mut info = maybe_info.as_mut().ok_or(Error::::GuardianIndexNotExist)?; + // Update block number + info.1 = frame_system::Pallet::::block_number(); + // Update status + info.3 = status; + + Self::deposit_event(Event::GuardianStatusUpdated { + guardian, + guardian_index, + status, + }); + Ok(()) + }, + )?; + } + + /// Anyone can vote for guardian + /// However if voter is not participating the staking pool + /// then its vote will never effecting guardian selection procedure + #[pallet::call_index(4)] + #[pallet::weight(W{195_000_000})] + pub fn vote( + origin: OriginFor, + guardian: T::AccountId, + status: GuardianVote, + ) -> DispatchResult { + + } + + /// Remove vote to default: Neutral + #[pallet::call_index(5)] + #[pallet::weight(W{195_000_000})] + pub fn remove_vote( + origin: OriginFor, + guardian: T::AccountId, + ) -> DispatchResult { + + } + + /// + } +} + +/// Some sort of check on the origin is from guardian. +impl EnsureGuardian for Pallet { + fn is_guardian(account: T::AccountId) -> bool { + if let some(guardian_index) = PublicGuardianToIndex::::get(account) { + if let some(info) = GuardianIndexToInfo::::get(guardian_index) { + if (info.3 != CandidateStatus::Banned) { + return true; + } + } + } + + false + } + + fn is_verified_guardian(account: T::AccountId) -> bool { + if let some(guardian_index) = PublicGuardianToIndex::::get(account) { + if let some(info) = GuardianIndexToInfo::::get(guardian_index) { + if (info.3 == CandidateStatus::Verified) { + return true; + } + } + } + + false + } +} diff --git a/pallets/collab-ai/pool-proposal/src/lib.rs b/pallets/collab-ai/pool-proposal/src/lib.rs index 30767bf288..420c94f7da 100644 --- a/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/pallets/collab-ai/pool-proposal/src/lib.rs @@ -21,7 +21,7 @@ //! //! ## Overview //! -//! The Pool Proposal handles the administration of proposed staking pool and pre-staking. +//! The Pool Proposal handles the administration of proposed investing pool and pre-investing. #![cfg_attr(not(feature = "std"), no_std)] pub mod types; @@ -71,6 +71,8 @@ pub mod pallet { use super::*; + /// CollabAI investing pool proposal + const MODULE_ID: PalletId = PalletId(*b"cbai/ipp"); /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -114,8 +116,11 @@ pub mod pallet { /// Origin who can make a pool proposal pass public vote check type PublicVotingOrigin: EnsureOrigin; - /// System Account holding pre-staking assets - type PreStakingPool: Get; + /// Origin who can change proposal guardian flag + type GuardianFlagOrigin: EnsureOrigin;??? + + /// System Account holding pre-investing assets + type PreInvestingPool: Get; } /// The next free Pool Proposal index, aka the number of pool proposed so far. @@ -134,7 +139,7 @@ pub mod pallet { OptionQuery, >; - // Pending pool proposal status of staking pools + // Pending pool proposal status of investing pools // Ordered by expired time #[pallet::storage] #[pallet::getter(fn pending_pool_proposal_status)] @@ -154,15 +159,15 @@ pub mod pallet { OptionQuery, >; - // Prestaking of pool proposal + // Preinvesting of pool proposal // This storage will be modified/delete correspondingly when solving pending pool #[pallet::storage] - #[pallet::getter(fn staking_pool_pre_stakings)] - pub type StakingPoolPrestakings = StorageMap< + #[pallet::getter(fn pool_pre_investings)] + pub type PoolPreInvestings = StorageMap< _, Twox64Concat, PoolProposalIndex, - PoolProposalPreStaking< + PoolProposalPreInvesting< T::AccountId, AssetBalanceOf, BlockNumberFor, @@ -176,25 +181,25 @@ pub mod pallet { pub enum Event { /// A motion has been proposed by a public account. PoolProposed { proposer: T::AccountId, pool_proposal_index: PoolProposalIndex }, - /// A pre staking becomes valid - PoolPreStaked { + /// A pre investing becomes valid + PoolPreInvested { user: T::AccountId, pool_proposal_index: PoolProposalIndex, amount: AssetBalanceOf, }, - /// A pre staking queued + /// A pre investing queued PoolPreStakeQueued { user: T::AccountId, pool_proposal_index: PoolProposalIndex, amount: AssetBalanceOf, }, - /// A queued pre staking becomes a valid pre staking - PoolQueuedStaked { + /// A queued pre investing becomes a valid pre investing + PoolQueuedInvested { user: T::AccountId, pool_proposal_index: PoolProposalIndex, amount: AssetBalanceOf, }, - /// Some amount of pre staking regardless of queue or pre staked, withdrawed (Withdraw queue ones first) + /// Some amount of pre investing regardless of queue or pre invested, withdrawed (Withdraw queue ones first) PoolWithdrawed { user: T::AccountId, pool_proposal_index: PoolProposalIndex, @@ -206,39 +211,40 @@ pub mod pallet { #[pallet::error] pub enum Error { - PreStakingOverflow, + PreInvestingOverflow, ProposalExpired, - ProposalPreStakingLocked, + ProposalPreInvestingLocked, ProposalPublicTimeTooShort, ProposalNotExist, - StakingPoolOversized, - InsufficientPreStaking, + InvestingPoolOversized, + InsufficientPreInvesting, } #[pallet::hooks] impl Hooks> for Pallet { - /// Weight: see `begin_block` fn on_initialize(n: BlockNumberFor) -> Weight { - Self::begin_block(n) + // Check proposal expire by order + + // Mature the pool by proposal if qualified, refund/transfer all money based on investing pool logic } } #[pallet::call] impl Pallet { - /// Curator propose a staking pool + /// Curator propose a investing pool /// - /// max_pool_size: At most this amount of raised money curator/staking pool willing to take + /// max_pool_size: At most this amount of raised money curator/investing pool willing to take /// min_pool_size: At least this amount of raised money require for curator willing to fulfill contract - /// proposal_last_time: How does the proposal lasts for voting/prestaking. + /// proposal_last_time: How does the proposal lasts for voting/preinvesting. /// All ProposalStatusFlags must be satisfied after this period passed, which is also /// the approximate date when pool begins. - /// pool_last_time: How long does the staking pool last if passed + /// pool_last_time: How long does the investing pool last if passed /// estimated_epoch_reward: This number is only for displaying purpose without any techinical meaning /// pool_info_hash: Hash of pool info for including pool details #[pallet::call_index(0)] #[pallet::weight(W{195_000_000})] #[transactional] - pub fn propose_staking_pool( + pub fn propose_investing_pool( origin: OriginFor, max_pool_size: AssetBalanceOf, proposal_last_time: BlockNumberFor, @@ -333,14 +339,14 @@ pub mod pallet { let asset_actual_transfer_amount: AssetBalanceOf = >::transfer( AIUSDAssetId::get(), who, - PreStakingPool::get(), + PreInvestingPool::get(), amount, Preservation::Expendable, )?; - let mut pool_proposal_pre_staking = - >::take(pool_proposal_index) - .unwrap_or(PoolProposalPreStaking::new()); + let mut pool_proposal_pre_investing = + >::take(pool_proposal_index) + .unwrap_or(PoolProposalPreInvesting::new()); // Check pool maximum size limit and make pool size limit flag change accordingly let mut pool_proposal = @@ -352,59 +358,59 @@ pub mod pallet { .contains(ProposalStatusFlags::PROPOSAL_EXPIRED), Error::::ProposalExpired ); - // If proposal is fully pre-staked or partial oversized after this stake + // If proposal is fully pre-Investing or partial oversized after this stake // Check BoundedVec limit ensure!( - !pool_proposal_pre_staking.pre_stakings.is_full - && !pool_proposal_pre_staking.queued_pre_stakings.is_full, - Error::::StakingPoolOversized + !pool_proposal_pre_investing.pre_investings.is_full + && !pool_proposal_pre_investing.queued_pre_investings.is_full, + Error::::InvestingPoolOversized ); - let target_pre_staked_amount = pool_proposal_pre_staking - .total_pre_staked_amount + let target_pre_investing_amount = pool_proposal_pre_investing + .total_pre_investing_amount .checked_add(asset_actual_transfer_amount) .ok_or(ArithmeticError::Overflow)?; - if (target_pre_staked_amount <= pool_proposal.max_pool_size) { - // take all pre-staking into valid pre-staking line - pool_proposal_pre_staking - .add_pre_staking::(who, asset_actual_transfer_amount)?; + if (target_pre_investing_amount <= pool_proposal.max_pool_size) { + // take all pre-investing into valid pre-investing line + pool_proposal_pre_investing + .add_pre_investing::(who, asset_actual_transfer_amount)?; // Emit event only - Self::deposit_event(Event::PoolPreStaked { + Self::deposit_event(Event::PoolPreInvested { user: who, pool_proposal_index, amount: asset_actual_transfer_amount, }); - // Flag proposal status if pool is just fully staked - if (target_pre_staked_amount == pool_proposal.max_pool_size) { + // Flag proposal status if pool is just fully Investing + if (target_pre_investing_amount == pool_proposal.max_pool_size) { pool_proposal.proposal_status_flags = pool_proposal.proposal_status_flags | ProposalStatusFlags::STAKE_AMOUNT_PASSED; PoolProposal::put(pool_proposal_index, pool_proposal); } } else { // Partially - let queued_pre_staked_amount = target_pre_staked_amount + let queued_pre_investing_amount = target_pre_investing_amount .checked_sub(pool_proposal.max_pool_size) .ok_or(ArithmeticError::Overflow)?; - pool_proposal_pre_staking.add_queued_staking::( + pool_proposal_pre_investing.add_queued_investing::( who, - queued_pre_staked_amount, + queued_pre_investing_amount, frame_system::Pallet::::block_number(), )?; // If pool not already full, flag proposal status - if (asset_actual_transfer_amount > queued_pre_staked_amount) { - let actual_pre_staked_amount = asset_actual_transfer_amount - .checked_sub(queued_pre_staked_amount) + if (asset_actual_transfer_amount > queued_pre_investing_amount) { + let actual_pre_investing_amount = asset_actual_transfer_amount + .checked_sub(queued_pre_investing_amount) .ok_or(ArithmeticError::Overflow)?; - pool_proposal_pre_staking - .add_pre_staking::(who, actual_pre_staked_amount)?; + pool_proposal_pre_investing + .add_pre_investing::(who, actual_pre_investing_amount)?; - Self::deposit_event(Event::PoolPreStaked { + Self::deposit_event(Event::PoolPreInvested { user: who, pool_proposal_index, - amount: actual_pre_staked_amount, + amount: actual_pre_investing_amount, }); pool_proposal.proposal_status_flags = pool_proposal.proposal_status_flags @@ -416,11 +422,11 @@ pub mod pallet { Self::deposit_event(Event::PoolPreStakeQueued { user: who, pool_proposal_index, - amount: queued_pre_staked_amount, + amount: queued_pre_investing_amount, }); } - >::put(pool_proposal_index, pool_proposal_pre_staking); + >::put(pool_proposal_index, pool_proposal_pre_investing); } // Withdraw is not allowed when proposal has STAKE_AMOUNT_PASSED flag @@ -428,43 +434,44 @@ pub mod pallet { #[pallet::call_index(2)] #[pallet::weight(W{195_000_000})] #[transactional] - pub fn withdraw_pre_staking( + pub fn withdraw_pre_investing( origin: OriginFor, pool_proposal_index: PoolProposalIndex, amount: AssetBalanceOf, ) -> DispatchResult { let who = ensure_signed(origin)?; - let mut pool_proposal_pre_staking = - >::take(pool_proposal_index) - .unwrap_or(PoolProposalPreStaking::new()); + let mut pool_proposal_pre_investing = + >::take(pool_proposal_index) + .unwrap_or(PoolProposalPreInvesting::new()); - // Either staking pool has not locked yet, + // Either investing pool has not locked yet, // Or queued amount is enough to replace the withdrawal ensure!( !pool_proposal .proposal_status_flags .contains(ProposalStatusFlags::STAKE_AMOUNT_PASSED) - || (pool_proposal_pre_staking.total_queued_amount >= amount), - Error::::ProposalPreStakingLocked + || (pool_proposal_pre_investing.total_queued_amount >= amount), + Error::::ProposalPreInvestingLocked ); - let _ = pool_proposal_pre_staking.withdraw::(who, amount)?; + let _ = pool_proposal_pre_investing.withdraw::(who, amount)?; Self::deposit_event(Event::PoolWithdrawed { user: who, pool_proposal_index, amount }); let mut pool_proposal = PoolProposal::get(pool_proposal_index).ok_or(Error::::ProposalNotExist)?; - // Make queued amount fill the missing staked amount if pool staked flag ever reached - if ((pool_proposal_pre_staking.total_pre_staked_amount < pool_proposal.max_pool_size) + // Make queued amount fill the missing Investing amount if pool Investing flag ever reached + if ((pool_proposal_pre_investing.total_pre_investing_amount + < pool_proposal.max_pool_size) && (pool_proposal .proposal_status_flags .contains(ProposalStatusFlags::STAKE_AMOUNT_PASSED))) { - let moved_bonds = pool_proposal_pre_staking - .move_queued_to_pre_staking_until::(pool_proposal.max_pool_size)?; + let moved_bonds = pool_proposal_pre_investing + .move_queued_to_pre_investing_until::(pool_proposal.max_pool_size)?; for i in moved_bonds.iter() { // Emit events - Self::deposit_event(Event::PoolQueuedStaked { + Self::deposit_event(Event::PoolQueuedInvested { user: i.owner, pool_proposal_index, amount: i.amount, @@ -475,18 +482,18 @@ pub mod pallet { // Return funds let asset_actual_transfer_amount: AssetBalanceOf = >::transfer( AIUSDAssetId::get(), - PreStakingPool::get(), + PreInvestingPool::get(), who, amount, Preservation::Expendable, )?; - >::put(pool_proposal_index, pool_proposal_pre_staking); + >::put(pool_proposal_index, pool_proposal_pre_investing); Ok(()) } - // This is democracy/committe passing check for staking pool proposal + // This is democracy/committe passing check for investing pool proposal // TODO: Related logic with "pallet-conviction-voting" #[pallet::call_index(3)] #[pallet::weight(W{195_000_000})] @@ -514,5 +521,36 @@ pub mod pallet { }); Ok(()) } + + // A guardian has decided to participate the investing pool + // When proposal expired, the guardian must have everything ready + // Including KYC. Otherwise he will be ignored no matter how much vote he collects + #[pallet::call_index(4)] + #[pallet::weight(W{195_000_000})] + pub fn guardian_participate_proposal( + origin: OriginFor, + pool_proposal_index: PoolProposalIndex, + ) -> DispatchResult { + + } + } + + /// Simple ensure origin from pallet pool proposal + pub struct EnsurePoolProposal(sp_std::marker::PhantomData); + impl EnsureOrigin for EnsurePoolProposal { + type Success = T::AccountId; + fn try_origin(o: T::RuntimeOrigin) -> Result { + let sync_account_id = MODULE_ID.into_account_truncating(); + o.into().and_then(|o| match o { + system::RawOrigin::Signed(who) if who == sync_account_id => Ok(sync_account_id), + r => Err(T::RuntimeOrigin::from(r)), + }) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + let sync_account_id = MODULE_ID.into_account_truncating(); + Ok(T::RuntimeOrigin::from(system::RawOrigin::Signed(sync_account_id))) + } } } diff --git a/pallets/collab-ai/pool-proposal/src/types.rs b/pallets/collab-ai/pool-proposal/src/types.rs index 63fb03f960..006714cc25 100644 --- a/pallets/collab-ai/pool-proposal/src/types.rs +++ b/pallets/collab-ai/pool-proposal/src/types.rs @@ -24,13 +24,13 @@ bitflags! { /// /// A valid pool must passing committee/public's audit procedure regarding legal files and other pool parameters. const PUBLIC_VOTE_PASSED = 0b0000_0001; - /// Whether the minimum staked amount proposed by curator is satisfied. + /// Whether the minimum Investing amount proposed by curator is satisfied. /// /// # Note /// /// Currently, a full size must be satisfied. /// - /// Once a pool is satisfied this requirement, all staked amount can no longer be withdrawed + /// Once a pool is satisfied this requirement, all Investing amount can no longer be withdrawed /// unless the pool is later denied passing by voting or until the end of pool maturity. /// /// Otherwise, the pool will be refunded. @@ -62,11 +62,11 @@ pub struct PoolProposalInfo { pub proposer: AccountId, // Hash of pool info like legal files etc. pub pool_info_hash: InfoHash, - // The maximum staking amount that the pool can handle + // The maximum investing amount that the pool can handle pub max_pool_size: Balance, - // If proposal passed, when the staking pool will start + // If proposal passed, when the investing pool will start pub pool_start_time: BlockNumber, - // If proposal passed, when the staking pool will end + // If proposal passed, when the investing pool will end pub pool_end_time: BlockNumber, // estimated APR, but in percentage form // i.e. 100 => 100% @@ -118,54 +118,55 @@ impl PartialEq for Bond { } #[derive(Clone, Encode, Debug, Decode, TypeInfo)] -pub struct PoolProposalPreStaking> { - pub total_pre_staked_amount: Balance, +pub struct PoolProposalPreInvesting> { + // Exluding queued part + pub total_pre_investing_amount: Balance, // Ordered by bond owner AccountId - pub pre_stakings: BoundedVec, S>, + pub pre_investings: BoundedVec, S>, pub total_queued_amount: Balance, // Ordered by bond owner AccountId - pub queued_pre_stakings: BoundedVec<(Bond, BlockNumber), S>, + pub queued_pre_investings: BoundedVec<(Bond, BlockNumber), S>, } impl> - PoolProposalPreStaking + PoolProposalPreInvesting { /// Create a new empty default pub fn new() -> Self { - PoolProposalPreStaking { - total_pre_staked_amount: Default::default(), - pre_stakings: Default::default(), + PoolProposalPreInvesting { + total_pre_investing_amount: Default::default(), + pre_investings: Default::default(), total_queued_amount: Default::default(), - queued_pre_stakings: Default::default(), + queued_pre_investings: Default::default(), } } - pub fn get_pre_staking(&self, account: AccountId) -> Option<(usize, Balance)> { - match self.pre_stakings.binary_search(&Bond::from_owner(account)) { - Ok(loc) => Some((loc, self.pre_stakings.index(loc))), + pub fn get_pre_investing(&self, account: AccountId) -> Option<(usize, Balance)> { + match self.pre_investings.binary_search(&Bond::from_owner(account)) { + Ok(loc) => Some((loc, self.pre_investings.index(loc))), Err(loc) => None, } } - pub fn add_pre_staking( + pub fn add_pre_investing( &mut self, account: AccountId, amount: Balance, ) -> Result<(), DispatchError> { - if let Some(existing) = self.get_pre_staking(account) { - self.pre_stakings.remove(existing.0); + if let Some(existing) = self.get_pre_investing(account) { + self.pre_investings.remove(existing.0); let new_balance = existing.1.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; let _ = self - .pre_stakings + .pre_investings .try_insert(existing.0, Bond { owner: account, amount: new_balance }) - .map_err(|_| Error::::StakingPoolOversized)?; + .map_err(|_| Error::::InvestingPoolOversized)?; } else { let _ = self - .pre_stakings + .pre_investings .try_insert(existing.0, Bond { owner: account, amount }) - .map_err(|_| Error::::StakingPoolOversized)?; + .map_err(|_| Error::::InvestingPoolOversized)?; } - self::total_pre_staked_amount = self::total_pre_staked_amount + self::total_pre_investing_amount = self::total_pre_investing_amount .checked_add(&amount) .ok_or(ArithmeticError::Overflow)?; Ok(()) @@ -177,19 +178,19 @@ impl> amount: Balance, ) -> Result<(), DispatchError> { // Withdraw Queued one if any - if let Some(existing_q) = self.get_queued_staking(account) { + if let Some(existing_q) = self.get_queued_investing(account) { if (existing_q.1 > amount) { // Existing queue is larger than target amount // Finish withdrawing and return early - self.queued_pre_stakings.remove(existing_q.0); + self.queued_pre_investings.remove(existing_q.0); let new_balance_q = existing_q.1.checked_sub(&amount).ok_or(ArithmeticError::Overflow)?; - self.queued_pre_stakings + self.queued_pre_investings .try_insert( existing_q.0, (Bond { owner: account, amount: new_balance_q }, existing_q.2), ) - .map_err(|_| Error::::StakingPoolOversized)?; + .map_err(|_| Error::::InvestingPoolOversized)?; self::total_queued_amount = self::total_queued_amount .checked_sub(&amount) @@ -197,85 +198,88 @@ impl> return Ok(()); } else { // Totally remove queued - self.queued_pre_stakings.remove(existing_q.0); + self.queued_pre_investings.remove(existing_q.0); self::total_queued_amount = self::total_queued_amount .checked_sub(&existing_q.1) .ok_or(ArithmeticError::Overflow)?; let left_amount = amount - existing_q.1; - if let Some(existing_p) = self.get_pre_staking(account) { - // Existing pre-staking is larger than left target amount + if let Some(existing_p) = self.get_pre_investing(account) { + // Existing pre-investing is larger than left target amount // Finish withdrawing and return early if (existing_p.1 > left_amount) { - self.pre_stakings.remove(existing_p.0); + self.pre_investings.remove(existing_p.0); let new_balance_p = existing_p .1 .checked_sub(&left_amount) .ok_or(ArithmeticError::Overflow)?; - self.pre_stakings + self.pre_investings .try_insert( existing_q.0, Bond { owner: account, amount: new_balance_p }, ) - .map_err(|_| Error::::StakingPoolOversized)?; - self::total_pre_staked_amount = self::total_pre_staked_amount + .map_err(|_| Error::::InvestingPoolOversized)?; + self::total_pre_investing_amount = self::total_pre_investing_amount .checked_sub(&left_amount) .ok_or(ArithmeticError::Overflow)?; return Ok(()); } else if (existing_p.1 == left_amount) { // Exact amount to finish everything - self.pre_stakings.remove(existing_p.0); - self::total_pre_staked_amount = self::total_pre_staked_amount + self.pre_investings.remove(existing_p.0); + self::total_pre_investing_amount = self::total_pre_investing_amount .checked_sub(&left_amount) .ok_or(ArithmeticError::Overflow)?; return Ok(()); } else { // Not enough fund to finish operation - return Err(Error::::InsufficientPreStaking); + return Err(Error::::InsufficientPreInvesting); } } } } - // No pre-staking of all kinds - return Err(Error::::InsufficientPreStaking); + // No pre-investing of all kinds + return Err(Error::::InsufficientPreInvesting); } - pub fn get_queued_staking(&self, account: AccountId) -> Option<(usize, Balance, BlockNumber)> { + pub fn get_queued_investing( + &self, + account: AccountId, + ) -> Option<(usize, Balance, BlockNumber)> { match self - .queued_pre_stakings + .queued_pre_investings .binary_search_by(|p| p.0.cmp(&Bond::from_owner(account))) { Ok(loc) => Some(( loc, - self.queued_pre_stakings.index(loc).0.amount, - self.queued_pre_stakings.index(loc).1, + self.queued_pre_investings.index(loc).0.amount, + self.queued_pre_investings.index(loc).1, )), Err(loc) => None, } } - pub fn add_queued_staking( + pub fn add_queued_investing( &mut self, account: AccountId, amount: Balance, current_block: BlockNumber, ) -> Result<(), DispatchError> { - if let Some(existing) = self.get_queued_staking(account) { - self.queued_pre_stakings.remove(existing.0); + if let Some(existing) = self.get_queued_investing(account) { + self.queued_pre_investings.remove(existing.0); let new_balance = existing.1.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; let _ = self - .queued_pre_stakings + .queued_pre_investings .try_insert( existing.0, (Bond { owner: account, amount: new_balance }, current_block), ) - .map_err(|_| Error::::StakingPoolOversized)?; + .map_err(|_| Error::::InvestingPoolOversized)?; } else { let _ = self - .queued_pre_stakings + .queued_pre_investings .try_insert(existing.0, (Bond { owner: account, amount }, current_block)) - .map_err(|_| Error::::StakingPoolOversized)?; + .map_err(|_| Error::::InvestingPoolOversized)?; } self::total_queued_amount = self::total_queued_amount .checked_add(&amount) @@ -283,37 +287,37 @@ impl> Ok(()) } - // Transfer queued amount into pre staking - pub fn move_queued_to_pre_staking_until( + // Transfer queued amount into pre investing + pub fn move_queued_to_pre_investing_until( &mut self, - target_pre_staked_amount: Balance, + target_pre_investing_amount: Balance, ) -> Result>, DispatchError> { let result: Vec> = Vec::new(); // Make sure target transfer is possible ensure!( self.total_queued_amount - >= target_pre_staked_amount - .checked_sub(self.total_pre_staked_amount) + >= target_pre_investing_amount + .checked_sub(self.total_pre_investing_amount) .ok_or(ArithmeticError::Overflow)?, - Error::::InsufficientPreStaking + Error::::InsufficientPreInvesting ); - let mut v = self.queued_pre_stakings.into_inner().clone(); + let mut v = self.queued_pre_investings.into_inner().clone(); // temp sorted by blocknumber v.sort_by(|p| p.2); for i in v.iter() { - let transfer_amount = target_pre_staked_amount - .checked_sub(self.total_pre_staked_amount) + let transfer_amount = target_pre_investing_amount + .checked_sub(self.total_pre_investing_amount) .ok_or(ArithmeticError::Overflow)?; if (i.0.amount >= transfer_amount) { let _ = self.withdraw(i.0.owner, transfer_amount)?; - self.add_pre_staking(i.0.owner, transfer_amount)?; + self.add_pre_investing(i.0.owner, transfer_amount)?; result.push(Bond { owner: i.0.owner, amount: transfer_amount }); break; } else { let _ = self.withdraw(i.0.owner, i.0.amount)?; - self.add_pre_staking(i.0.owner, i.0.amount)?; + self.add_pre_investing(i.0.owner, i.0.amount)?; result.push(Bond { owner: i.0.owner, amount: i.0.amount }); } } diff --git a/pallets/collab-ai/pool-tokens-manager/Cargo.toml b/pallets/collab-ai/pool-tokens-manager/Cargo.toml new file mode 100644 index 0000000000..1dbdffd098 --- /dev/null +++ b/pallets/collab-ai/pool-tokens-manager/Cargo.toml @@ -0,0 +1,45 @@ +[package] +authors = ['Trust Computing GmbH '] +description = 'Pallet for converting/managing among investing pool derivative tokens' +edition = '2021' +homepage = 'https://litentry.com/' +license = 'GPL-3.0' +name = 'pallet-pool-tokens-manager' +repository = 'https://github.com/litentry/litentry-parachain' +version = '0.1.0' + +[dependencies] +hex-literal = { workspace = true } +parity-scale-codec = { workspace = true } +scale-info = { workspace = true } + +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-assets = { workspace = true } +pallet-balances = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +[features] +default = ["std"] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", +] +std = [ + "parity-scale-codec/std", + "scale-info/std", + "sp-std/std", + "sp-runtime/std", + "sp-io/std", + "sp-core/std", + "frame-support/std", + "frame-system/std", + "pallet-assets/std", + "pallet-balances/std", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/collab-ai/pool-tokens-manager/src/lib.rs b/pallets/collab-ai/pool-tokens-manager/src/lib.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/runtime/litentry/src/asset_config.rs b/runtime/litentry/src/asset_config.rs index b86fd07517..1b0f263b87 100644 --- a/runtime/litentry/src/asset_config.rs +++ b/runtime/litentry/src/asset_config.rs @@ -72,8 +72,8 @@ impl pallet_assets::Config for Runtime { type Balance = Balance; type AssetId = AssetId; type Currency = Balances; - // TODO: We do not allow creating by regular users before pallet_asset_manager fully adopted - // P-937 + // We do not allow creating by regular users + // CollabAI derivative token do not want it that way type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = EnsureRoot; type AssetDeposit = AssetDeposit; diff --git a/runtime/rococo/src/asset_config.rs b/runtime/rococo/src/asset_config.rs index 15c0b67879..436071d20c 100644 --- a/runtime/rococo/src/asset_config.rs +++ b/runtime/rococo/src/asset_config.rs @@ -72,8 +72,8 @@ impl pallet_assets::Config for Runtime { type Balance = Balance; type AssetId = AssetId; type Currency = Balances; - // TODO: We do not allow creating by regular users before pallet_asset_manager fully adopted - // P-937 + // We do not allow creating by regular users + // CollabAI derivative token do not want it that way type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = EnsureRoot; type AssetDeposit = AssetDeposit; From e9f3fabf2a551c1100c22c10936d17b93e887e28 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 29 Sep 2024 15:30:57 +0800 Subject: [PATCH 011/215] feat: rough impl --- Cargo.toml | 1 + pallets/collab-ai/common/src/lib.rs | 19 ++++- pallets/collab-ai/curator/src/lib.rs | 11 ++- pallets/collab-ai/guardian/Cargo.toml | 38 +++++++++ pallets/collab-ai/guardian/src/lib.rs | 59 +++++++++++--- pallets/collab-ai/pool-proposal/src/lib.rs | 80 +++++++++++++++---- .../collab-ai/pool-tokens-manager/Cargo.toml | 45 ----------- .../collab-ai/pool-tokens-manager/src/lib.rs | 0 8 files changed, 171 insertions(+), 82 deletions(-) delete mode 100644 pallets/collab-ai/pool-tokens-manager/Cargo.toml delete mode 100644 pallets/collab-ai/pool-tokens-manager/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 0939a46908..f9cf35a868 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -280,6 +280,7 @@ pallet-evm-assertions = { path = "pallets/evm-assertions", default-features = fa pallet-aiusd-convertor = { path = "pallets/collab-ai/aiusd-convertor", default-features = false } pallet-collab-ai-common = { path = "pallets/collab-ai/common", default-features = false } pallet-curator = { path = "pallets/collab-ai/curator", default-features = false } +pallet-guardian = { path = "pallets/collab-ai/guardian", default-features = false } pallet-pool-proposal = { path = "pallets/collab-ai/pool-proposal", default-features = false } [patch.crates-io] diff --git a/pallets/collab-ai/common/src/lib.rs b/pallets/collab-ai/common/src/lib.rs index 2b7b6ae13e..816d070d4e 100644 --- a/pallets/collab-ai/common/src/lib.rs +++ b/pallets/collab-ai/common/src/lib.rs @@ -68,6 +68,9 @@ pub enum CandidateStatus { #[derive(PartialEq, Eq, Clone, Copy, Default, Encode, Decode, Debug, TypeInfo)] pub enum GuardianVote { /// Does not care if this guardian get selected + /// Please be aware Neutral will increase participate percentage + /// which will increase the winning rate of guardian selection + /// given a large amount of guardian competitor #[default] #[codec(index = 0)] Neutral, @@ -84,7 +87,7 @@ pub enum GuardianVote { } /// Some sort of check on the account is from some group. -pub trait EnsureCurator { +pub trait CuratorQuery { /// All curator but banned ones fn is_curator(account: AccountId) -> bool; @@ -96,7 +99,7 @@ pub struct EnsureSignedAndCurator(sp_std::marker::PhantomData<(Ac impl, O>> + From>, AccountId: Decode> EnsureOrigin for EnsureSignedAndCurator where - EC: EnsureCurator, + EC: CuratorQuery, { type Success = AccountId; fn try_origin(o: O) -> Result { @@ -136,3 +139,15 @@ impl> InvestingPoolAssetIdGenerator { } } } + +/// Some sort of check on the account is from some group. +pub trait GuardianQuery { + /// All guardian but banned ones + fn is_guardian(account: AccountId) -> bool; + + /// Only verified one + fn is_verified_guardian(account: AccountId) -> bool; + + /// Get vote + fn get_vote(voter: AccountId, guardian: AccountId) -> Option; +} diff --git a/pallets/collab-ai/curator/src/lib.rs b/pallets/collab-ai/curator/src/lib.rs index 19b77b4791..2d0dcc4d78 100644 --- a/pallets/collab-ai/curator/src/lib.rs +++ b/pallets/collab-ai/curator/src/lib.rs @@ -187,7 +187,6 @@ pub mod pallet { } /// Clean a curator legal info - /// Impossible when there is a staking pool proposal ongoing #[pallet::call_index(2)] #[pallet::weight(W{195_000_000})] pub fn clean_curator(origin: OriginFor) -> DispatchResult { @@ -253,10 +252,10 @@ pub mod pallet { } /// Some sort of check on the origin is from curator. -impl EnsureCurator for Pallet { +impl CuratorQuery for Pallet { fn is_curator(account: T::AccountId) -> bool { - if let some(curator_index) = PublicCuratorToIndex::::get(account) { - if let some(info) = CuratorIndexToInfo::::get(curator_index) { + if let Some(curator_index) = PublicCuratorToIndex::::get(&account) { + if let Some(info) = CuratorIndexToInfo::::get(curator_index) { if (info.3 != CandidateStatus::Banned) { return true; } @@ -267,8 +266,8 @@ impl EnsureCurator for Pallet { } fn is_verified_curator(account: T::AccountId) -> bool { - if let some(curator_index) = PublicCuratorToIndex::::get(account) { - if let some(info) = CuratorIndexToInfo::::get(curator_index) { + if let Some(curator_index) = PublicCuratorToIndex::::get(&account) { + if let Some(info) = CuratorIndexToInfo::::get(curator_index) { if (info.3 == CandidateStatus::Verified) { return true; } diff --git a/pallets/collab-ai/guardian/Cargo.toml b/pallets/collab-ai/guardian/Cargo.toml index e69de29bb2..9806162581 100644 --- a/pallets/collab-ai/guardian/Cargo.toml +++ b/pallets/collab-ai/guardian/Cargo.toml @@ -0,0 +1,38 @@ +[package] +authors = ['Litentry Dev'] +description = 'Pallet for managing guardian' +edition = '2021' +homepage = 'https://litentry.com/' +license = 'GPL-3.0' +name = 'pallet-guardian' +repository = 'https://github.com/litentry/litentry-parachain' +version = '0.1.0' + +[dependencies] +parity-scale-codec = { workspace = true } +scale-info = { workspace = true } + +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +pallet-collab-ai-common = { workspace = true } + +[features] +default = ["std"] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-collab-ai-common/runtime-benchmarks", +] +std = [ + "parity-scale-codec/std", + "scale-info/std", + "sp-std/std", + "sp-runtime/std", + "frame-support/std", + "frame-system/std", + "pallet-collab-ai-common/std", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/collab-ai/guardian/src/lib.rs b/pallets/collab-ai/guardian/src/lib.rs index 5e2bc59522..a862e6ba03 100644 --- a/pallets/collab-ai/guardian/src/lib.rs +++ b/pallets/collab-ai/guardian/src/lib.rs @@ -98,7 +98,7 @@ pub mod pallet { Twox64Concat, GuardianIndex, GuardianVote, - ValueQuery, + OptionQuery, >; #[pallet::event] @@ -123,6 +123,13 @@ pub mod pallet { guardian_index: GuardianIndex, status: CandidateStatus, }, + VoteGuardian { + voter: T::AccountId + guardian_index: GuardianIndex, + guardian: T::AccountId, + status: Option, + }, + RemoveAllVote {}, } #[pallet::error] @@ -200,7 +207,6 @@ pub mod pallet { } /// Clean a guardian legal info - /// Impossible when there is a staking pool proposal ongoing #[pallet::call_index(2)] #[pallet::weight(W{195_000_000})] pub fn clean_guardian(origin: OriginFor) -> DispatchResult { @@ -271,30 +277,49 @@ pub mod pallet { pub fn vote( origin: OriginFor, guardian: T::AccountId, - status: GuardianVote, + status: Option, ) -> DispatchResult { + let who = ensure_signed(origin)?; + // Ensure existing + let guardian_index = + PublicGuardianToIndex::::get(&guardian).ok_or(Error::::GuardianNotRegistered)?; + if let Some(i) == status { + GuardianVotes::::insert(&who, guardian_index, status); + } else { + GuardianVotes::::remove(&who, guardian_index); + } + Self::deposit_event(Event::VoteGuardian { + voter: who + guardian_index, + guardian, + status, + }); + Ok(()) } - /// Remove vote to default: Neutral + /// Remove vote to None #[pallet::call_index(5)] #[pallet::weight(W{195_000_000})] - pub fn remove_vote( + pub fn remove_all_votes( origin: OriginFor, guardian: T::AccountId, ) -> DispatchResult { - + let who = ensure_signed(origin)?; + let _ = GuardianVotes::::clear_prefix(&who, u32::MAX, None); + Self::deposit_event(Event::RemoveAllVote { + voter: who, + }); + Ok(()) } - - /// } } /// Some sort of check on the origin is from guardian. -impl EnsureGuardian for Pallet { +impl GuardianQuery for Pallet { fn is_guardian(account: T::AccountId) -> bool { - if let some(guardian_index) = PublicGuardianToIndex::::get(account) { - if let some(info) = GuardianIndexToInfo::::get(guardian_index) { + if let Some(guardian_index) = PublicGuardianToIndex::::get(&account) { + if let Some(info) = GuardianIndexToInfo::::get(guardian_index) { if (info.3 != CandidateStatus::Banned) { return true; } @@ -305,8 +330,8 @@ impl EnsureGuardian for Pallet { } fn is_verified_guardian(account: T::AccountId) -> bool { - if let some(guardian_index) = PublicGuardianToIndex::::get(account) { - if let some(info) = GuardianIndexToInfo::::get(guardian_index) { + if let Some(guardian_index) = PublicGuardianToIndex::::get(&account) { + if let Some(info) = GuardianIndexToInfo::::get(guardian_index) { if (info.3 == CandidateStatus::Verified) { return true; } @@ -315,4 +340,12 @@ impl EnsureGuardian for Pallet { false } + + fn get_vote(voter: T::AccountId, guardian: T::AccountId) -> Option { + // Ensure existing + if let Some(guardian_index) = PublicGuardianToIndex::::get(&guardian) { + return GuardianVotes::::get(&voter, guardian_index); + } + None + } } diff --git a/pallets/collab-ai/pool-proposal/src/lib.rs b/pallets/collab-ai/pool-proposal/src/lib.rs index 420c94f7da..abba2f9595 100644 --- a/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/pallets/collab-ai/pool-proposal/src/lib.rs @@ -116,8 +116,12 @@ pub mod pallet { /// Origin who can make a pool proposal pass public vote check type PublicVotingOrigin: EnsureOrigin; - /// Origin who can change proposal guardian flag - type GuardianFlagOrigin: EnsureOrigin;??? + /// Guardian vote resource + type GuardianVote: GuardianQuery; + + /// The maximum amount of guardian allowed for a proposal + #[pallet::constant] + type MaxGuardianPerProposal: Get; /// System Account holding pre-investing assets type PreInvestingPool: Get; @@ -176,6 +180,17 @@ pub mod pallet { OptionQuery, >; + // Guardian willingness of proposal + #[pallet::storage] + #[pallet::getter(fn pool_pre_investings)] + pub type PoolGuardian = StorageMap< + _, + Twox64Concat, + PoolProposalIndex, + OrderedSet, + OptionQuery, + >; + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -212,12 +227,15 @@ pub mod pallet { #[pallet::error] pub enum Error { PreInvestingOverflow, + ProposalDepositDuplicatedOrOversized, ProposalExpired, ProposalPreInvestingLocked, ProposalPublicTimeTooShort, ProposalNotExist, InvestingPoolOversized, InsufficientPreInvesting, + GuardianDuplicatedOrOversized, + GuardianInvalid, } #[pallet::hooks] @@ -290,16 +308,24 @@ pub mod pallet { // We should not care about duplicating since the proposal index is auto-increment match maybe_ordered_set.as_mut() { Some(ordered_set) => { - ordered_set.insert(Bond { - owner: next_proposal_index, - value: reserved_amount, - }); + ensure!( + ordered_set.insert(Bond { + owner: next_proposal_index, + value: reserved_amount, + }), + Error::::ProposalDepositDuplicatedOrOversized + ); }, None => { - let new_ordered_set = OrderedSet::new().insert(Bond { - owner: next_proposal_index, - value: reserved_amount, - }); + let mut new_ordered_set = OrderedSet::new(); + + ensure!( + new_ordered_set.insert(Bond { + owner: next_proposal_index, + value: reserved_amount, + }), + Error::::ProposalDepositDuplicatedOrOversized + ); *maybe_ordered_set = Some(new_ordered_set) }, } @@ -344,9 +370,8 @@ pub mod pallet { Preservation::Expendable, )?; - let mut pool_proposal_pre_investing = - >::take(pool_proposal_index) - .unwrap_or(PoolProposalPreInvesting::new()); + let mut pool_proposal_pre_investing = >::take(pool_proposal_index) + .unwrap_or(PoolProposalPreInvesting::new()); // Check pool maximum size limit and make pool size limit flag change accordingly let mut pool_proposal = @@ -441,9 +466,8 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin)?; - let mut pool_proposal_pre_investing = - >::take(pool_proposal_index) - .unwrap_or(PoolProposalPreInvesting::new()); + let mut pool_proposal_pre_investing = >::take(pool_proposal_index) + .unwrap_or(PoolProposalPreInvesting::new()); // Either investing pool has not locked yet, // Or queued amount is enough to replace the withdrawal @@ -531,7 +555,31 @@ pub mod pallet { origin: OriginFor, pool_proposal_index: PoolProposalIndex, ) -> DispatchResult { + let who = ensure_signed(origin)?; + // Ensure guardian exists when participate, will double check if verified when mature the proposal) + ensure!(GuardianVote::is_guardian(who), Error::::GuardianInvalid); + PoolGuardian::::try_mutate_exists( + &pool_proposal_index, + |maybe_ordered_set| -> Result<(), DispatchError> { + match maybe_ordered_set.as_mut() { + Some(ordered_set) => { + ensure!( + ordered_set.insert(who), + Error::::GuardianDuplicatedOrOversized + ); + }, + None => { + let mut new_ordered_set = OrderedSet::new(); + ensure!( + new_ordered_set.insert(who), + Error::::GuardianDuplicatedOrOversized + ); + *maybe_ordered_set = Some(new_ordered_set) + }, + } + }, + ); } } diff --git a/pallets/collab-ai/pool-tokens-manager/Cargo.toml b/pallets/collab-ai/pool-tokens-manager/Cargo.toml deleted file mode 100644 index 1dbdffd098..0000000000 --- a/pallets/collab-ai/pool-tokens-manager/Cargo.toml +++ /dev/null @@ -1,45 +0,0 @@ -[package] -authors = ['Trust Computing GmbH '] -description = 'Pallet for converting/managing among investing pool derivative tokens' -edition = '2021' -homepage = 'https://litentry.com/' -license = 'GPL-3.0' -name = 'pallet-pool-tokens-manager' -repository = 'https://github.com/litentry/litentry-parachain' -version = '0.1.0' - -[dependencies] -hex-literal = { workspace = true } -parity-scale-codec = { workspace = true } -scale-info = { workspace = true } - -frame-support = { workspace = true } -frame-system = { workspace = true } -pallet-assets = { workspace = true } -pallet-balances = { workspace = true } -sp-core = { workspace = true } -sp-io = { workspace = true } -sp-runtime = { workspace = true } -sp-std = { workspace = true } - -[features] -default = ["std"] -runtime-benchmarks = [ - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-assets/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", -] -std = [ - "parity-scale-codec/std", - "scale-info/std", - "sp-std/std", - "sp-runtime/std", - "sp-io/std", - "sp-core/std", - "frame-support/std", - "frame-system/std", - "pallet-assets/std", - "pallet-balances/std", -] -try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/collab-ai/pool-tokens-manager/src/lib.rs b/pallets/collab-ai/pool-tokens-manager/src/lib.rs deleted file mode 100644 index e69de29bb2..0000000000 From 2f7974e85e4fb58242676aa12b47070a38faafb9 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 29 Sep 2024 15:48:10 +0800 Subject: [PATCH 012/215] debug: reloaction merge --- .../pallets}/collab-ai/aiusd-convertor/Cargo.toml | 0 .../pallets}/collab-ai/aiusd-convertor/src/lib.rs | 0 {pallets => parachain/pallets}/collab-ai/common/Cargo.toml | 0 {pallets => parachain/pallets}/collab-ai/common/src/lib.rs | 0 {pallets => parachain/pallets}/collab-ai/curator/Cargo.toml | 0 {pallets => parachain/pallets}/collab-ai/curator/src/lib.rs | 0 {pallets => parachain/pallets}/collab-ai/guardian/Cargo.toml | 0 {pallets => parachain/pallets}/collab-ai/guardian/src/lib.rs | 0 {pallets => parachain/pallets}/collab-ai/pool-proposal/Cargo.toml | 0 {pallets => parachain/pallets}/collab-ai/pool-proposal/src/lib.rs | 0 .../pallets}/collab-ai/pool-proposal/src/types.rs | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename {pallets => parachain/pallets}/collab-ai/aiusd-convertor/Cargo.toml (100%) rename {pallets => parachain/pallets}/collab-ai/aiusd-convertor/src/lib.rs (100%) rename {pallets => parachain/pallets}/collab-ai/common/Cargo.toml (100%) rename {pallets => parachain/pallets}/collab-ai/common/src/lib.rs (100%) rename {pallets => parachain/pallets}/collab-ai/curator/Cargo.toml (100%) rename {pallets => parachain/pallets}/collab-ai/curator/src/lib.rs (100%) rename {pallets => parachain/pallets}/collab-ai/guardian/Cargo.toml (100%) rename {pallets => parachain/pallets}/collab-ai/guardian/src/lib.rs (100%) rename {pallets => parachain/pallets}/collab-ai/pool-proposal/Cargo.toml (100%) rename {pallets => parachain/pallets}/collab-ai/pool-proposal/src/lib.rs (100%) rename {pallets => parachain/pallets}/collab-ai/pool-proposal/src/types.rs (100%) diff --git a/pallets/collab-ai/aiusd-convertor/Cargo.toml b/parachain/pallets/collab-ai/aiusd-convertor/Cargo.toml similarity index 100% rename from pallets/collab-ai/aiusd-convertor/Cargo.toml rename to parachain/pallets/collab-ai/aiusd-convertor/Cargo.toml diff --git a/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs similarity index 100% rename from pallets/collab-ai/aiusd-convertor/src/lib.rs rename to parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs diff --git a/pallets/collab-ai/common/Cargo.toml b/parachain/pallets/collab-ai/common/Cargo.toml similarity index 100% rename from pallets/collab-ai/common/Cargo.toml rename to parachain/pallets/collab-ai/common/Cargo.toml diff --git a/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs similarity index 100% rename from pallets/collab-ai/common/src/lib.rs rename to parachain/pallets/collab-ai/common/src/lib.rs diff --git a/pallets/collab-ai/curator/Cargo.toml b/parachain/pallets/collab-ai/curator/Cargo.toml similarity index 100% rename from pallets/collab-ai/curator/Cargo.toml rename to parachain/pallets/collab-ai/curator/Cargo.toml diff --git a/pallets/collab-ai/curator/src/lib.rs b/parachain/pallets/collab-ai/curator/src/lib.rs similarity index 100% rename from pallets/collab-ai/curator/src/lib.rs rename to parachain/pallets/collab-ai/curator/src/lib.rs diff --git a/pallets/collab-ai/guardian/Cargo.toml b/parachain/pallets/collab-ai/guardian/Cargo.toml similarity index 100% rename from pallets/collab-ai/guardian/Cargo.toml rename to parachain/pallets/collab-ai/guardian/Cargo.toml diff --git a/pallets/collab-ai/guardian/src/lib.rs b/parachain/pallets/collab-ai/guardian/src/lib.rs similarity index 100% rename from pallets/collab-ai/guardian/src/lib.rs rename to parachain/pallets/collab-ai/guardian/src/lib.rs diff --git a/pallets/collab-ai/pool-proposal/Cargo.toml b/parachain/pallets/collab-ai/pool-proposal/Cargo.toml similarity index 100% rename from pallets/collab-ai/pool-proposal/Cargo.toml rename to parachain/pallets/collab-ai/pool-proposal/Cargo.toml diff --git a/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs similarity index 100% rename from pallets/collab-ai/pool-proposal/src/lib.rs rename to parachain/pallets/collab-ai/pool-proposal/src/lib.rs diff --git a/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs similarity index 100% rename from pallets/collab-ai/pool-proposal/src/types.rs rename to parachain/pallets/collab-ai/pool-proposal/src/types.rs From 992d7e86c21a611e92b9c4fba1fd0bcf9f1548e0 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 29 Sep 2024 15:51:00 +0800 Subject: [PATCH 013/215] chore: taple fmt --- parachain/pallets/collab-ai/common/Cargo.toml | 2 +- parachain/pallets/collab-ai/pool-proposal/Cargo.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/parachain/pallets/collab-ai/common/Cargo.toml b/parachain/pallets/collab-ai/common/Cargo.toml index b74d46cd2e..b5eb2c64df 100644 --- a/parachain/pallets/collab-ai/common/Cargo.toml +++ b/parachain/pallets/collab-ai/common/Cargo.toml @@ -11,8 +11,8 @@ parity-scale-codec = { workspace = true } scale-info = { workspace = true } frame-support = { workspace = true, optional = true } -sp-runtime = { workspace = true } sp-core = { workspace = true } +sp-runtime = { workspace = true } [features] default = ["std"] diff --git a/parachain/pallets/collab-ai/pool-proposal/Cargo.toml b/parachain/pallets/collab-ai/pool-proposal/Cargo.toml index c488eec5c2..f0f5bdf4a3 100644 --- a/parachain/pallets/collab-ai/pool-proposal/Cargo.toml +++ b/parachain/pallets/collab-ai/pool-proposal/Cargo.toml @@ -9,15 +9,15 @@ repository = 'https://github.com/litentry/litentry-parachain' version = '0.1.0' [dependencies] +bitflags = { workspace = true } parity-scale-codec = { workspace = true } scale-info = { workspace = true } -bitflags = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +orml-utilities = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } -orml-utilities = { workspace = true } pallet-collab-ai-common = { workspace = true } From 1a6ae41c361fece3790f2d6555e09fd97e1d1abd Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 29 Sep 2024 15:58:02 +0800 Subject: [PATCH 014/215] chore: Cargo.toml --- parachain/Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/parachain/Cargo.toml b/parachain/Cargo.toml index a8cbd6aaa6..56cbfb2768 100644 --- a/parachain/Cargo.toml +++ b/parachain/Cargo.toml @@ -9,7 +9,9 @@ members = [ 'pallets/bridge/bridge-transfer', 'pallets/bridge/common', 'pallets/collab-ai/aiusd-convertor', + 'pallets/collab-ai/common', 'pallets/collab-ai/curator', + 'pallets/collab-ai/guardian', 'pallets/collab-ai/pool-proposal', 'pallets/extrinsic-filter', 'pallets/evm-address', From 10e63e10dc66aa5335b65b5c4f082baff06cf03b Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 29 Sep 2024 15:59:10 +0800 Subject: [PATCH 015/215] chore: fmt --- .../pallets/collab-ai/guardian/src/lib.rs | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/parachain/pallets/collab-ai/guardian/src/lib.rs b/parachain/pallets/collab-ai/guardian/src/lib.rs index a862e6ba03..9cc2497e99 100644 --- a/parachain/pallets/collab-ai/guardian/src/lib.rs +++ b/parachain/pallets/collab-ai/guardian/src/lib.rs @@ -124,7 +124,7 @@ pub mod pallet { status: CandidateStatus, }, VoteGuardian { - voter: T::AccountId + voter: T::AccountId, guardian_index: GuardianIndex, guardian: T::AccountId, status: Option, @@ -166,7 +166,11 @@ pub mod pallet { ); PublicGuardianCount::::put(next_guardian_index.checked_add(1u32.into())?); - Self::deposit_event(Event::GuardianRegisted { guardian: who, guardian_index, info_hash }); + Self::deposit_event(Event::GuardianRegisted { + guardian: who, + guardian_index, + info_hash, + }); Ok(()) } @@ -177,8 +181,8 @@ pub mod pallet { let who = ensure_signed(origin)?; // Ensure existing - let guardian_index = - PublicGuardianToIndex::::get(guardian).ok_or(Error::::GuardianNotRegistered)?; + let guardian_index = PublicGuardianToIndex::::get(guardian) + .ok_or(Error::::GuardianNotRegistered)?; // Update guardian // But if banned, then require extra reserve @@ -248,8 +252,8 @@ pub mod pallet { status: CandidateStatus, ) -> DispatchResult { T::GuardianJudgeOrigin::ensure_origin(origin)?; - let guardian_index = - PublicGuardianToIndex::::get(guardian).ok_or(Error::::GuardianNotRegistered)?; + let guardian_index = PublicGuardianToIndex::::get(guardian) + .ok_or(Error::::GuardianNotRegistered)?; GuardianIndexToInfo::::try_mutate_exists( guardian_index, |maybe_info| -> Result<(), DispatchError> { @@ -281,16 +285,16 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin)?; // Ensure existing - let guardian_index = - PublicGuardianToIndex::::get(&guardian).ok_or(Error::::GuardianNotRegistered)?; - if let Some(i) == status { + let guardian_index = PublicGuardianToIndex::::get(&guardian) + .ok_or(Error::::GuardianNotRegistered)?; + if let Some(i) = status { GuardianVotes::::insert(&who, guardian_index, status); } else { GuardianVotes::::remove(&who, guardian_index); } Self::deposit_event(Event::VoteGuardian { - voter: who + voter: who, guardian_index, guardian, status, @@ -301,15 +305,10 @@ pub mod pallet { /// Remove vote to None #[pallet::call_index(5)] #[pallet::weight(W{195_000_000})] - pub fn remove_all_votes( - origin: OriginFor, - guardian: T::AccountId, - ) -> DispatchResult { + pub fn remove_all_votes(origin: OriginFor, guardian: T::AccountId) -> DispatchResult { let who = ensure_signed(origin)?; let _ = GuardianVotes::::clear_prefix(&who, u32::MAX, None); - Self::deposit_event(Event::RemoveAllVote { - voter: who, - }); + Self::deposit_event(Event::RemoveAllVote { voter: who }); Ok(()) } } From 26821f30ebf6bdfae60243413d5163318a253238 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 29 Sep 2024 16:04:27 +0800 Subject: [PATCH 016/215] chore: lock file --- parachain/Cargo.lock | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index 89f340693b..d12ac1fd43 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -7595,6 +7595,19 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-guardian" +version = "0.1.0" +dependencies = [ + "frame-support", + "frame-system", + "pallet-collab-ai-common", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-identity" version = "4.0.0-dev" From 1a52f74fbdf9c6bce5b6d53ad2dd1acaf9487fc1 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 29 Sep 2024 16:22:42 +0800 Subject: [PATCH 017/215] chore: fix --- parachain/pallets/collab-ai/common/Cargo.toml | 10 +++++--- parachain/pallets/collab-ai/common/src/lib.rs | 23 ++++++++++++------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/parachain/pallets/collab-ai/common/Cargo.toml b/parachain/pallets/collab-ai/common/Cargo.toml index b5eb2c64df..ee6e02883d 100644 --- a/parachain/pallets/collab-ai/common/Cargo.toml +++ b/parachain/pallets/collab-ai/common/Cargo.toml @@ -10,9 +10,11 @@ version = '0.1.0' parity-scale-codec = { workspace = true } scale-info = { workspace = true } -frame-support = { workspace = true, optional = true } +frame-support = { workspace = true } +frame-system = { workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } +sp-std = { workspace = true } [features] default = ["std"] @@ -23,8 +25,10 @@ runtime-benchmarks = [ std = [ "scale-info/std", "parity-scale-codec/std", - "frame-support?/std", - "sp-runtime/std", + "frame-support/std", + "frame-system/std", "sp-core/std", + "sp-runtime/std", + "sp-std/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index 816d070d4e..0dd6ff9cae 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -15,10 +15,14 @@ // along with Litentry. If not, see . #![cfg_attr(not(feature = "std"), no_std)] -use parity_scale_codec::{Decode, Encode}; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_core::H256; -use sp_runtime::DispatchError; +use sp_core::{RuntimeDebug, H256}; +use sp_runtime::BoundedVec; +use sp_std::marker::PhantomData; + +use frame_support::pallet_prelude::EnsureOrigin; +use frame_system::RawOrigin; pub type InfoHash = H256; pub type CuratorIndex = u128; @@ -95,9 +99,12 @@ pub trait CuratorQuery { fn is_verified_curator(account: AccountId) -> bool; } -pub struct EnsureSignedAndCurator(sp_std::marker::PhantomData<(AccountId, EC)>); -impl, O>> + From>, AccountId: Decode> - EnsureOrigin for EnsureSignedAndCurator +pub struct EnsureSignedAndCurator(PhantomData<(AccountId, EC)>); +impl< + O: Into, O>> + From>, + AccountId: Decode, + EC, + > EnsureOrigin for EnsureSignedAndCurator where EC: CuratorQuery, { @@ -108,7 +115,7 @@ where if EC::is_curator() { Ok(who) } else { - Err(O::from(r)) + Err(O::from(RawOrigin::Signed(who))) } }, r => Err(O::from(r)), @@ -126,7 +133,7 @@ pub const INVESTING_POOL_INDEX_SHIFTER: u128 = 1_000_000_000_000_000; pub const INVESTING_POOL_START_MONTH_SHIFTER: u128 = 1_000; pub const INVESTING_POOL_END_MONTH_SHIFTER: u128 = 1; -pub struct InvestingPoolAssetId(sp_std::marker::PhantomData); +pub struct InvestingPoolAssetIdGenerator(PhantomData); impl> InvestingPoolAssetIdGenerator { /// Create a series of new asset id based on pool index and reward epoch /// Return None if impossible to generate. e.g. overflow From 3eb6951b99ff03c8149bd6d2e5acfece814b5da4 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 29 Sep 2024 16:27:44 +0800 Subject: [PATCH 018/215] chore: lock file --- parachain/Cargo.lock | 2 ++ 1 file changed, 2 insertions(+) diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index d12ac1fd43..5cd879c390 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -7148,10 +7148,12 @@ name = "pallet-collab-ai-common" version = "0.1.0" dependencies = [ "frame-support", + "frame-system", "parity-scale-codec", "scale-info", "sp-core", "sp-runtime", + "sp-std", ] [[package]] From c7ce96ce4d73d75ced5c373a18c497a24706d966 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 29 Sep 2024 16:49:54 +0800 Subject: [PATCH 019/215] chore: fix --- parachain/pallets/collab-ai/common/src/lib.rs | 11 ++++++----- parachain/pallets/collab-ai/guardian/src/lib.rs | 11 +++++++++-- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 4 ++-- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index 0dd6ff9cae..223b68a1a4 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -70,7 +70,7 @@ pub enum CandidateStatus { } #[derive(PartialEq, Eq, Clone, Copy, Default, Encode, Decode, Debug, TypeInfo)] -pub enum GuardianVote { +pub enum GuardianVote> { /// Does not care if this guardian get selected /// Please be aware Neutral will increase participate percentage /// which will increase the winning rate of guardian selection @@ -87,7 +87,7 @@ pub enum GuardianVote { /// Support this guardian for only specific pool proposal /// And neutral for other pool proposal #[codec(index = 3)] - Specific(BoundedVec), + Specific(BoundedVec), } /// Some sort of check on the account is from some group. @@ -112,7 +112,7 @@ where fn try_origin(o: O) -> Result { o.into().and_then(|o| match o { RawOrigin::Signed(who) => { - if EC::is_curator() { + if EC::is_curator(who) { Ok(who) } else { Err(O::from(RawOrigin::Signed(who))) @@ -144,11 +144,12 @@ impl> InvestingPoolAssetIdGenerator { for n in 0..(epoch + 1) { // vec.push(pool_index_prefix + ) } + None } } /// Some sort of check on the account is from some group. -pub trait GuardianQuery { +pub trait GuardianQuery> { /// All guardian but banned ones fn is_guardian(account: AccountId) -> bool; @@ -156,5 +157,5 @@ pub trait GuardianQuery { fn is_verified_guardian(account: AccountId) -> bool; /// Get vote - fn get_vote(voter: AccountId, guardian: AccountId) -> Option; + fn get_vote(voter: AccountId, guardian: AccountId) -> Option>; } diff --git a/parachain/pallets/collab-ai/guardian/src/lib.rs b/parachain/pallets/collab-ai/guardian/src/lib.rs index 9cc2497e99..d29a85ab23 100644 --- a/parachain/pallets/collab-ai/guardian/src/lib.rs +++ b/parachain/pallets/collab-ai/guardian/src/lib.rs @@ -62,6 +62,10 @@ pub mod pallet { #[pallet::constant] type MinimumGuardianDeposit: Get>; + /// The maximum amount of guardian allowed for a proposal + #[pallet::constant] + type MaxProposalPerGuardian: Get; + /// Origin from guardian legal file verified by type GuardianJudgeOrigin: EnsureOrigin; } @@ -97,7 +101,7 @@ pub mod pallet { T::AccountId, Twox64Concat, GuardianIndex, - GuardianVote, + GuardianVote, OptionQuery, >; @@ -340,7 +344,10 @@ impl GuardianQuery for Pallet { false } - fn get_vote(voter: T::AccountId, guardian: T::AccountId) -> Option { + fn get_vote( + voter: T::AccountId, + guardian: T::AccountId, + ) -> Option> { // Ensure existing if let Some(guardian_index) = PublicGuardianToIndex::::get(&guardian) { return GuardianVotes::::get(&voter, guardian_index); diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index abba2f9595..b0746d9372 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -117,7 +117,7 @@ pub mod pallet { type PublicVotingOrigin: EnsureOrigin; /// Guardian vote resource - type GuardianVote: GuardianQuery; + type GuardianVoteResource: GuardianQuery; /// The maximum amount of guardian allowed for a proposal #[pallet::constant] @@ -557,7 +557,7 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin)?; // Ensure guardian exists when participate, will double check if verified when mature the proposal) - ensure!(GuardianVote::is_guardian(who), Error::::GuardianInvalid); + ensure!(GuardianVoteResource::is_guardian(who), Error::::GuardianInvalid); PoolGuardian::::try_mutate_exists( &pool_proposal_index, |maybe_ordered_set| -> Result<(), DispatchError> { From 86fc225e2398ea3f944d2a9768264db92688853c Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 29 Sep 2024 17:02:26 +0800 Subject: [PATCH 020/215] chore: fix --- parachain/pallets/collab-ai/common/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index 223b68a1a4..543de70987 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -17,7 +17,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_core::{RuntimeDebug, H256}; +use sp_core::{Get, RuntimeDebug, H256}; use sp_runtime::BoundedVec; use sp_std::marker::PhantomData; From a99dcb005b6e5f0886bf9d84f4ffccd5f061419c Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 29 Sep 2024 17:27:30 +0800 Subject: [PATCH 021/215] chore: fix --- parachain/pallets/collab-ai/common/src/lib.rs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index 543de70987..58f2ff3a06 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -69,7 +69,7 @@ pub enum CandidateStatus { Banned, } -#[derive(PartialEq, Eq, Clone, Copy, Default, Encode, Decode, Debug, TypeInfo)] +#[derive(PartialEq, Eq, Clone, Default, Encode, Decode, Debug, TypeInfo)] pub enum GuardianVote> { /// Does not care if this guardian get selected /// Please be aware Neutral will increase participate percentage @@ -112,7 +112,7 @@ where fn try_origin(o: O) -> Result { o.into().and_then(|o| match o { RawOrigin::Signed(who) => { - if EC::is_curator(who) { + if EC::is_curator(who.clone()) { Ok(who) } else { Err(O::from(RawOrigin::Signed(who))) @@ -133,20 +133,20 @@ pub const INVESTING_POOL_INDEX_SHIFTER: u128 = 1_000_000_000_000_000; pub const INVESTING_POOL_START_MONTH_SHIFTER: u128 = 1_000; pub const INVESTING_POOL_END_MONTH_SHIFTER: u128 = 1; -pub struct InvestingPoolAssetIdGenerator(PhantomData); -impl> InvestingPoolAssetIdGenerator { - /// Create a series of new asset id based on pool index and reward epoch - /// Return None if impossible to generate. e.g. overflow - pub fn get_pool_token(pool_index: InvestingPoolIndex, epoch: u128) -> Option> { - let pool_index_prefix = pool_index.checked_mul(INVESTING_POOL_INDEX_SHIFTER)?; - - let mut vec: Vec = Vec::new(); - for n in 0..(epoch + 1) { - // vec.push(pool_index_prefix + ) - } - None - } -} +// pub struct InvestingPoolAssetIdGenerator(PhantomData); +// impl> InvestingPoolAssetIdGenerator { +// /// Create a series of new asset id based on pool index and reward epoch +// /// Return None if impossible to generate. e.g. overflow +// pub fn get_pool_token(pool_index: InvestingPoolIndex, epoch: u128) -> Option> { +// let pool_index_prefix = pool_index.checked_mul(INVESTING_POOL_INDEX_SHIFTER)?; + +// let mut vec: Vec = Vec::new(); +// for n in 0..(epoch + 1) { +// // vec.push(pool_index_prefix + ) +// } +// None +// } +// } /// Some sort of check on the account is from some group. pub trait GuardianQuery> { From 556545c99a62c38de485506c228188b88b33938b Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 29 Sep 2024 17:36:21 +0800 Subject: [PATCH 022/215] chore: fix --- parachain/pallets/collab-ai/common/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index 58f2ff3a06..9a632e6372 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -102,7 +102,7 @@ pub trait CuratorQuery { pub struct EnsureSignedAndCurator(PhantomData<(AccountId, EC)>); impl< O: Into, O>> + From>, - AccountId: Decode, + AccountId: Decode + Clone, EC, > EnsureOrigin for EnsureSignedAndCurator where From 7c0434243820e510d8c2c1e61c4fb5901a66c5bf Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 29 Sep 2024 17:48:28 +0800 Subject: [PATCH 023/215] chore: fix --- .../pallets/collab-ai/aiusd-convertor/src/lib.rs | 4 ++-- parachain/pallets/collab-ai/curator/src/lib.rs | 8 ++++---- parachain/pallets/collab-ai/guardian/src/lib.rs | 12 ++++++------ parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 10 +++++----- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index 9e02056cfe..5a216253b9 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -110,7 +110,7 @@ pub mod pallet { impl Pallet { // Lock target_asset_id token and mint AIUSD #[pallet::call_index(0)] - #[pallet::weight(W{195_000_000})] + #[pallet::weight({195_000_000})] pub fn mint_aiusd( origin: OriginFor, target_asset_id: AssetIdOf, @@ -156,7 +156,7 @@ pub mod pallet { // Burn aiusd and get target_asset_id token released // Failed if pool does not have enough token of one type #[pallet::call_index(0)] - #[pallet::weight(W{195_000_000})] + #[pallet::weight({195_000_000})] pub fn burn_aiusd( origin: OriginFor, target_asset_id: AssetIdOf, diff --git a/parachain/pallets/collab-ai/curator/src/lib.rs b/parachain/pallets/collab-ai/curator/src/lib.rs index 2d0dcc4d78..5133e6d899 100644 --- a/parachain/pallets/collab-ai/curator/src/lib.rs +++ b/parachain/pallets/collab-ai/curator/src/lib.rs @@ -123,7 +123,7 @@ pub mod pallet { impl Pallet { /// Registing a curator legal info #[pallet::call_index(0)] - #[pallet::weight(W{195_000_000})] + #[pallet::weight({195_000_000})] pub fn regist_curator(origin: OriginFor, info_hash: InfoHash) -> DispatchResult { let who = ensure_signed(origin)?; @@ -152,7 +152,7 @@ pub mod pallet { /// Updating a curator legal info #[pallet::call_index(1)] - #[pallet::weight(W{195_000_000})] + #[pallet::weight({195_000_000})] pub fn update_curator(origin: OriginFor, info_hash: InfoHash) -> DispatchResult { let who = ensure_signed(origin)?; @@ -188,7 +188,7 @@ pub mod pallet { /// Clean a curator legal info #[pallet::call_index(2)] - #[pallet::weight(W{195_000_000})] + #[pallet::weight({195_000_000})] pub fn clean_curator(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; @@ -221,7 +221,7 @@ pub mod pallet { } #[pallet::call_index(3)] - #[pallet::weight(W{195_000_000})] + #[pallet::weight({195_000_000})] pub fn judge_curator_status( origin: OriginFor, curator: T::AccountId, diff --git a/parachain/pallets/collab-ai/guardian/src/lib.rs b/parachain/pallets/collab-ai/guardian/src/lib.rs index d29a85ab23..a170b86130 100644 --- a/parachain/pallets/collab-ai/guardian/src/lib.rs +++ b/parachain/pallets/collab-ai/guardian/src/lib.rs @@ -147,7 +147,7 @@ pub mod pallet { impl Pallet { /// Registing a guardian legal info #[pallet::call_index(0)] - #[pallet::weight(W{195_000_000})] + #[pallet::weight({195_000_000})] pub fn regist_guardian(origin: OriginFor, info_hash: InfoHash) -> DispatchResult { let who = ensure_signed(origin)?; @@ -180,7 +180,7 @@ pub mod pallet { /// Updating a guardian legal info #[pallet::call_index(1)] - #[pallet::weight(W{195_000_000})] + #[pallet::weight({195_000_000})] pub fn update_guardian(origin: OriginFor, info_hash: InfoHash) -> DispatchResult { let who = ensure_signed(origin)?; @@ -216,7 +216,7 @@ pub mod pallet { /// Clean a guardian legal info #[pallet::call_index(2)] - #[pallet::weight(W{195_000_000})] + #[pallet::weight({195_000_000})] pub fn clean_guardian(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; @@ -249,7 +249,7 @@ pub mod pallet { } #[pallet::call_index(3)] - #[pallet::weight(W{195_000_000})] + #[pallet::weight({195_000_000})] pub fn judge_guardian_status( origin: OriginFor, guardian: T::AccountId, @@ -281,7 +281,7 @@ pub mod pallet { /// However if voter is not participating the staking pool /// then its vote will never effecting guardian selection procedure #[pallet::call_index(4)] - #[pallet::weight(W{195_000_000})] + #[pallet::weight({195_000_000})] pub fn vote( origin: OriginFor, guardian: T::AccountId, @@ -308,7 +308,7 @@ pub mod pallet { /// Remove vote to None #[pallet::call_index(5)] - #[pallet::weight(W{195_000_000})] + #[pallet::weight({195_000_000})] pub fn remove_all_votes(origin: OriginFor, guardian: T::AccountId) -> DispatchResult { let who = ensure_signed(origin)?; let _ = GuardianVotes::::clear_prefix(&who, u32::MAX, None); diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index b0746d9372..56622d7959 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -260,7 +260,7 @@ pub mod pallet { /// estimated_epoch_reward: This number is only for displaying purpose without any techinical meaning /// pool_info_hash: Hash of pool info for including pool details #[pallet::call_index(0)] - #[pallet::weight(W{195_000_000})] + #[pallet::weight({195_000_000})] #[transactional] pub fn propose_investing_pool( origin: OriginFor, @@ -353,7 +353,7 @@ pub mod pallet { } #[pallet::call_index(1)] - #[pallet::weight(W{195_000_000})] + #[pallet::weight({195_000_000})] #[transactional] pub fn pre_stake_proposal( origin: OriginFor, @@ -457,7 +457,7 @@ pub mod pallet { // Withdraw is not allowed when proposal has STAKE_AMOUNT_PASSED flag // unless there is queued amount pending #[pallet::call_index(2)] - #[pallet::weight(W{195_000_000})] + #[pallet::weight({195_000_000})] #[transactional] pub fn withdraw_pre_investing( origin: OriginFor, @@ -520,7 +520,7 @@ pub mod pallet { // This is democracy/committe passing check for investing pool proposal // TODO: Related logic with "pallet-conviction-voting" #[pallet::call_index(3)] - #[pallet::weight(W{195_000_000})] + #[pallet::weight({195_000_000})] pub fn public_vote_proposal( origin: OriginFor, pool_proposal_index: PoolProposalIndex, @@ -550,7 +550,7 @@ pub mod pallet { // When proposal expired, the guardian must have everything ready // Including KYC. Otherwise he will be ignored no matter how much vote he collects #[pallet::call_index(4)] - #[pallet::weight(W{195_000_000})] + #[pallet::weight({195_000_000})] pub fn guardian_participate_proposal( origin: OriginFor, pool_proposal_index: PoolProposalIndex, From 1e6c70b69e7e20e2db29e3c97ecb3697feb666ec Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 29 Sep 2024 18:00:34 +0800 Subject: [PATCH 024/215] chore: fix --- .../pallets/collab-ai/aiusd-convertor/src/lib.rs | 6 +++--- .../pallets/collab-ai/pool-proposal/src/lib.rs | 14 ++++++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index 5a216253b9..f27e028761 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -155,7 +155,7 @@ pub mod pallet { // Burn aiusd and get target_asset_id token released // Failed if pool does not have enough token of one type - #[pallet::call_index(0)] + #[pallet::call_index(1)] #[pallet::weight({195_000_000})] pub fn burn_aiusd( origin: OriginFor, @@ -200,7 +200,7 @@ pub mod pallet { } /// Enable a specific type of token available for switching - #[pallet::call_index(1)] + #[pallet::call_index(2)] #[pallet::weight({195_000_000})] pub fn enable_token( origin: OriginFor, @@ -214,7 +214,7 @@ pub mod pallet { } /// disable a specific type of token available for switching - #[pallet::call_index(2)] + #[pallet::call_index(3)] #[pallet::weight({195_000_000})] pub fn disable_token( origin: OriginFor, diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 56622d7959..a6061a598f 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -311,10 +311,11 @@ pub mod pallet { ensure!( ordered_set.insert(Bond { owner: next_proposal_index, - value: reserved_amount, + amount: reserved_amount, }), Error::::ProposalDepositDuplicatedOrOversized ); + Ok(()) }, None => { let mut new_ordered_set = OrderedSet::new(); @@ -322,11 +323,12 @@ pub mod pallet { ensure!( new_ordered_set.insert(Bond { owner: next_proposal_index, - value: reserved_amount, + amount: reserved_amount, }), Error::::ProposalDepositDuplicatedOrOversized ); - *maybe_ordered_set = Some(new_ordered_set) + *maybe_ordered_set = Some(new_ordered_set); + Ok(()) }, } }, @@ -452,6 +454,7 @@ pub mod pallet { } >::put(pool_proposal_index, pool_proposal_pre_investing); + Ok(()) } // Withdraw is not allowed when proposal has STAKE_AMOUNT_PASSED flag @@ -567,6 +570,7 @@ pub mod pallet { ordered_set.insert(who), Error::::GuardianDuplicatedOrOversized ); + Ok(()) }, None => { let mut new_ordered_set = OrderedSet::new(); @@ -575,11 +579,13 @@ pub mod pallet { new_ordered_set.insert(who), Error::::GuardianDuplicatedOrOversized ); - *maybe_ordered_set = Some(new_ordered_set) + *maybe_ordered_set = Some(new_ordered_set); + Ok(()) }, } }, ); + Ok(()) } } From 08b9db7abd4fe8b92559b675ffdcf5479f67a99c Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 30 Sep 2024 09:57:16 +0800 Subject: [PATCH 025/215] chore: fix --- .../collab-ai/aiusd-convertor/src/lib.rs | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index f27e028761..a6aa19b307 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -20,10 +20,14 @@ use frame_support::{ pallet_prelude::*, traits::{ - tokens::{fungibles::Inspect as FsInspect, Fortitude, Precision, Preservation}, + tokens::{ + fungibles::{Inspect as FsInspect, Mutate as FsMutate}, + Fortitude, Precision, Preservation, + }, StorageVersion, }, }; +use frame_system::pallet_prelude::*; #[frame_support::pallet] pub mod pallet { @@ -115,15 +119,15 @@ pub mod pallet { origin: OriginFor, target_asset_id: AssetIdOf, aiusd_amount: AssetBalanceOf, - ) -> DispatchResultWithPostInfo { - let beneficiary = T::IncConsumerOrigin::ensure_origin(origin)?; + ) -> DispatchResult { + let beneficiary = ensure_signed(origin)?; if let Some(ratio) = EnabledTokens::::get(&target_asset_id) { ensure!( EnabledTokens::::contains_key(&target_asset_id), Error::::AssetNotEnabled ); - let aiusd_id = AIUSDAssetId::get(); - ensure!(InspectFungibles::asset_exists(&aiusd_id) && InspectFungibles::asset_exists(&target_asset_id), Error::::InvalidAssetId); + let aiusd_id = T::AIUSDAssetId::get(); + ensure!(InspectFungibles::asset_exists(&aiusd_id) && InspectFungibles::::asset_exists(&target_asset_id), Error::::InvalidAssetId); // It will fail if insufficient fund let aiusd_minted_amount: AssetBalanceOf = >::mint_into(aiusd_id, beneficiary, aiusd_amount)?; @@ -135,7 +139,7 @@ pub mod pallet { >::transfer( target_asset_id, beneficiary, - ConvertingFeeAccount::get(), + T::ConvertingFeeAccount::get(), aseet_target_mint_amount, Preservation::Expendable, )?; @@ -161,11 +165,15 @@ pub mod pallet { origin: OriginFor, target_asset_id: AssetIdOf, aiusd_amount: AssetBalanceOf, - ) -> DispatchResultWithPostInfo { - let beneficiary = T::IncConsumerOrigin::ensure_origin(origin)?; + ) -> DispatchResult { + let beneficiary = ensure_signed(origin)?; if let Some(ratio) = EnabledTokens::::get(&target_asset_id) { let aiusd_id = AIUSDAssetId::get(); - ensure!(InspectFungibles::asset_exists(&aiusd_id) && InspectFungibles::asset_exists(&target_asset_id), Error::::InvalidAssetId); + ensure!( + InspectFungibles::::asset_exists(&aiusd_id) + && InspectFungibles::::asset_exists(&target_asset_id), + Error::::InvalidAssetId + ); // It will fail if insufficient fund let aiusd_destroyed_amount: AssetBalanceOf = >::burn_from( aiusd_id, @@ -181,7 +189,7 @@ pub mod pallet { let asset_actual_transfer_amount: AssetBalanceOf = >::transfer( target_asset_id, - ConvertingFeeAccount::get(), + T::ConvertingFeeAccount::get(), beneficiary, aseet_target_transfer_amount, Preservation::Expendable, @@ -204,7 +212,7 @@ pub mod pallet { #[pallet::weight({195_000_000})] pub fn enable_token( origin: OriginFor, - target_asset_id: AssetId, + target_asset_id: AssetIdOf, decimal_ratio: AssetBalanceOf, ) -> DispatchResultWithPostInfo { T::ManagerOrigin::ensure_origin(origin)?; From 9b6830253471f6bf2aad099c5faf84242cf74346 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 30 Sep 2024 14:08:44 +0800 Subject: [PATCH 026/215] chore: fix --- .../collab-ai/aiusd-convertor/src/lib.rs | 22 ++++++++++-------- .../pallets/collab-ai/curator/src/lib.rs | 14 +++++------ .../pallets/collab-ai/guardian/src/lib.rs | 23 +++++++++++-------- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index a6aa19b307..ee81f3e835 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -28,7 +28,7 @@ use frame_support::{ }, }; use frame_system::pallet_prelude::*; - +use sp_runtime::traits::{CheckedAdd, CheckedSub}; #[frame_support::pallet] pub mod pallet { use super::*; @@ -127,20 +127,24 @@ pub mod pallet { Error::::AssetNotEnabled ); let aiusd_id = T::AIUSDAssetId::get(); - ensure!(InspectFungibles::asset_exists(&aiusd_id) && InspectFungibles::::asset_exists(&target_asset_id), Error::::InvalidAssetId); + ensure!( + InspectFungibles::::asset_exists(&aiusd_id) + && InspectFungibles::::asset_exists(&target_asset_id), + Error::::InvalidAssetId + ); // It will fail if insufficient fund let aiusd_minted_amount: AssetBalanceOf = - >::mint_into(aiusd_id, beneficiary, aiusd_amount)?; + >::mint_into(aiusd_id, &beneficiary, aiusd_amount)?; // Maybe it is better to save decimal of AIUSD somewhere let aseet_target_transfer_amount = aiusd_minted_amount.checked_mul(ratio)?.checked_div(10 ^ 18)?; let asset_actual_transfer_amount: AssetBalanceOf = - >::transfer( + as FsInspect<::AccountId>>::transfer( target_asset_id, beneficiary, T::ConvertingFeeAccount::get(), - aseet_target_mint_amount, + aseet_target_transfer_amount, Preservation::Expendable, )?; @@ -171,13 +175,13 @@ pub mod pallet { let aiusd_id = AIUSDAssetId::get(); ensure!( InspectFungibles::::asset_exists(&aiusd_id) - && InspectFungibles::::asset_exists(&target_asset_id), + && InspectFungibles::::asset_exists(target_asset_id), Error::::InvalidAssetId ); // It will fail if insufficient fund let aiusd_destroyed_amount: AssetBalanceOf = >::burn_from( aiusd_id, - beneficiary, + &beneficiary, aiusd_amount, Precision::Exact, Fortitude::Polite, @@ -187,7 +191,7 @@ pub mod pallet { let aseet_target_transfer_amount = aiusd_destroyed_amount.checked_mul(ratio)?.checked_div(10 ^ 18)?; let asset_actual_transfer_amount: AssetBalanceOf = - >::transfer( + as FsInspect<::AccountId>>::transfer( target_asset_id, T::ConvertingFeeAccount::get(), beneficiary, @@ -226,7 +230,7 @@ pub mod pallet { #[pallet::weight({195_000_000})] pub fn disable_token( origin: OriginFor, - target_asset_id: AssetId, + target_asset_id: AssetIdOf, ) -> DispatchResultWithPostInfo { T::ManagerOrigin::ensure_origin(origin)?; EnabledTokens::::remove(&target_asset_id); diff --git a/parachain/pallets/collab-ai/curator/src/lib.rs b/parachain/pallets/collab-ai/curator/src/lib.rs index 5133e6d899..7538f58520 100644 --- a/parachain/pallets/collab-ai/curator/src/lib.rs +++ b/parachain/pallets/collab-ai/curator/src/lib.rs @@ -133,7 +133,7 @@ pub mod pallet { Error::::CuratorAlreadyRegistered ); // New registed curator need to make a balance reserve - T::Currency::reserve(&who, MinimumCuratorDeposit::get())?; + T::Currency::reserve(&who, T::MinimumCuratorDeposit::get())?; // Update curator let current_block = frame_system::Pallet::::block_number(); @@ -167,8 +167,8 @@ pub mod pallet { |maybe_info| -> Result<(), DispatchError> { let mut info = maybe_info.as_mut().ok_or(Error::::CuratorIndexNotExist)?; - if (info.3 == CandidateStatus::Banned) { - T::Currency::reserve(&who, MinimumCuratorDeposit::get())?; + if info.3 == CandidateStatus::Banned { + T::Currency::reserve(&who, T::MinimumCuratorDeposit::get())?; } // Update hash @@ -207,8 +207,8 @@ pub mod pallet { |maybe_info| -> Result<(), DispatchError> { let info = maybe_info.ok_or(Error::::CuratorIndexNotExist)?; - if (info.3 != CandidateStatus::Banned) { - T::Currency::unreserve(&who, MinimumCuratorDeposit::get())?; + if info.3 != CandidateStatus::Banned { + T::Currency::unreserve(&who, T::MinimumCuratorDeposit::get())?; } // Delete item @@ -256,7 +256,7 @@ impl CuratorQuery for Pallet { fn is_curator(account: T::AccountId) -> bool { if let Some(curator_index) = PublicCuratorToIndex::::get(&account) { if let Some(info) = CuratorIndexToInfo::::get(curator_index) { - if (info.3 != CandidateStatus::Banned) { + if info.3 != CandidateStatus::Banned { return true; } } @@ -268,7 +268,7 @@ impl CuratorQuery for Pallet { fn is_verified_curator(account: T::AccountId) -> bool { if let Some(curator_index) = PublicCuratorToIndex::::get(&account) { if let Some(info) = CuratorIndexToInfo::::get(curator_index) { - if (info.3 == CandidateStatus::Verified) { + if info.3 == CandidateStatus::Verified { return true; } } diff --git a/parachain/pallets/collab-ai/guardian/src/lib.rs b/parachain/pallets/collab-ai/guardian/src/lib.rs index a170b86130..3c03f4a85f 100644 --- a/parachain/pallets/collab-ai/guardian/src/lib.rs +++ b/parachain/pallets/collab-ai/guardian/src/lib.rs @@ -25,16 +25,16 @@ //! //! #![cfg_attr(not(feature = "std"), no_std)] -use bitflags::bitflags; -use codec::{Decode, Encode}; use frame_support::{ ensure, + pallet_prelude::*, traits::{Currency, EnsureOrigin, Get, LockableCurrency, ReservableCurrency}, weights::Weight, }; use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; pub use pallet::*; use pallet_collab_ai_common::*; +use parity_scale_codec::{Decode, Encode}; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -131,9 +131,11 @@ pub mod pallet { voter: T::AccountId, guardian_index: GuardianIndex, guardian: T::AccountId, - status: Option, + status: Option>, + }, + RemoveAllVote { + voter: T::AccountId, }, - RemoveAllVote {}, } #[pallet::error] @@ -157,7 +159,7 @@ pub mod pallet { Error::::GuardianAlreadyRegistered ); // New registed guardian need to make a balance reserve - T::Currency::reserve(&who, MinimumGuardianDeposit::get())?; + T::Currency::reserve(&who, T::MinimumGuardianDeposit::get())?; // Update guardian let current_block = frame_system::Pallet::::block_number(); @@ -195,8 +197,8 @@ pub mod pallet { |maybe_info| -> Result<(), DispatchError> { let mut info = maybe_info.as_mut().ok_or(Error::::GuardianIndexNotExist)?; - if (info.3 == CandidateStatus::Banned) { - T::Currency::reserve(&who, MinimumGuardianDeposit::get())?; + if info.3 == CandidateStatus::Banned { + T::Currency::reserve(&who, T::MinimumGuardianDeposit::get())?; } // Update hash @@ -236,7 +238,7 @@ pub mod pallet { let info = maybe_info.ok_or(Error::::GuardianIndexNotExist)?; if (info.3 != CandidateStatus::Banned) { - T::Currency::unreserve(&who, MinimumGuardianDeposit::get())?; + T::Currency::unreserve(&who, T::MinimumGuardianDeposit::get())?; } // Delete item @@ -275,6 +277,7 @@ pub mod pallet { Ok(()) }, )?; + Ok(()) } /// Anyone can vote for guardian @@ -323,7 +326,7 @@ impl GuardianQuery for Pallet { fn is_guardian(account: T::AccountId) -> bool { if let Some(guardian_index) = PublicGuardianToIndex::::get(&account) { if let Some(info) = GuardianIndexToInfo::::get(guardian_index) { - if (info.3 != CandidateStatus::Banned) { + if info.3 != CandidateStatus::Banned { return true; } } @@ -335,7 +338,7 @@ impl GuardianQuery for Pallet { fn is_verified_guardian(account: T::AccountId) -> bool { if let Some(guardian_index) = PublicGuardianToIndex::::get(&account) { if let Some(info) = GuardianIndexToInfo::::get(guardian_index) { - if (info.3 == CandidateStatus::Verified) { + if info.3 == CandidateStatus::Verified { return true; } } From 0390219870fc90cc15b770f2f6971633fdee52ee Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 30 Sep 2024 15:57:53 +0800 Subject: [PATCH 027/215] chore: fix --- .../collab-ai/pool-proposal/src/lib.rs | 3 +- .../collab-ai/pool-proposal/src/types.rs | 28 +++++++++++++------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index a6061a598f..cff1e68dff 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -27,11 +27,11 @@ pub mod types; use bitflags::bitflags; -use codec::{Decode, Encode}; use frame_support::{ ensure, error::BadOrigin, traits::{Currency, EnsureOrigin, Get, LockIdentifier, LockableCurrency, ReservableCurrency}, + transactional, weights::Weight, BoundedVec, }; @@ -39,6 +39,7 @@ use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; use orml_utilities::OrderedSet; pub use pallet::*; use pallet_collab_ai_common::*; +use parity_scale_codec::{Decode, Encode}; use sp_runtime::traits::CheckedAdd; use sp_std::{cmp::Ordering, collections::vec_deque::VecDeque}; diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index 006714cc25..7d408c2407 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -13,6 +13,11 @@ // // You should have received a copy of the GNU General Public License // along with Litentry. If not, see . +use crate::{Config, Error}; +use bitflags::bitflags; +use frame_support::{ensure, pallet_prelude::*}; +use pallet_collab_ai_common::PoolProposalIndex; +use sp_runtime::{traits::CheckedAdd, ArithmeticError, BoundedVec}; bitflags! { /// Flags used to record the status of pool proposal @@ -128,7 +133,7 @@ pub struct PoolProposalPreInvesting pub queued_pre_investings: BoundedVec<(Bond, BlockNumber), S>, } -impl> +impl> PoolProposalPreInvesting { /// Create a new empty default @@ -166,7 +171,8 @@ impl> .try_insert(existing.0, Bond { owner: account, amount }) .map_err(|_| Error::::InvestingPoolOversized)?; } - self::total_pre_investing_amount = self::total_pre_investing_amount + self.total_pre_investing_amount = self + .total_pre_investing_amount .checked_add(&amount) .ok_or(ArithmeticError::Overflow)?; Ok(()) @@ -179,7 +185,7 @@ impl> ) -> Result<(), DispatchError> { // Withdraw Queued one if any if let Some(existing_q) = self.get_queued_investing(account) { - if (existing_q.1 > amount) { + if existing_q.1 > amount { // Existing queue is larger than target amount // Finish withdrawing and return early self.queued_pre_investings.remove(existing_q.0); @@ -192,14 +198,16 @@ impl> ) .map_err(|_| Error::::InvestingPoolOversized)?; - self::total_queued_amount = self::total_queued_amount + self.total_queued_amount = self + .total_queued_amount .checked_sub(&amount) .ok_or(ArithmeticError::Overflow)?; return Ok(()); } else { // Totally remove queued self.queued_pre_investings.remove(existing_q.0); - self::total_queued_amount = self::total_queued_amount + self.total_queued_amount = self + .total_queued_amount .checked_sub(&existing_q.1) .ok_or(ArithmeticError::Overflow)?; @@ -208,7 +216,7 @@ impl> if let Some(existing_p) = self.get_pre_investing(account) { // Existing pre-investing is larger than left target amount // Finish withdrawing and return early - if (existing_p.1 > left_amount) { + if existing_p.1 > left_amount { self.pre_investings.remove(existing_p.0); let new_balance_p = existing_p .1 @@ -220,14 +228,16 @@ impl> Bond { owner: account, amount: new_balance_p }, ) .map_err(|_| Error::::InvestingPoolOversized)?; - self::total_pre_investing_amount = self::total_pre_investing_amount + self.total_pre_investing_amount = self + .total_pre_investing_amount .checked_sub(&left_amount) .ok_or(ArithmeticError::Overflow)?; return Ok(()); - } else if (existing_p.1 == left_amount) { + } else if existing_p.1 == left_amount { // Exact amount to finish everything self.pre_investings.remove(existing_p.0); - self::total_pre_investing_amount = self::total_pre_investing_amount + self.total_pre_investing_amount = self + .total_pre_investing_amount .checked_sub(&left_amount) .ok_or(ArithmeticError::Overflow)?; return Ok(()); From 1404fa1c90f213cecb75e284b4806f4a2d873184 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 30 Sep 2024 16:14:03 +0800 Subject: [PATCH 028/215] chore: fix --- .../pallets/collab-ai/aiusd-convertor/src/lib.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index ee81f3e835..9db4cde5f3 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -28,7 +28,8 @@ use frame_support::{ }, }; use frame_system::pallet_prelude::*; -use sp_runtime::traits::{CheckedAdd, CheckedSub}; +use sp_runtime::traits::CheckedMul; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -128,8 +129,8 @@ pub mod pallet { ); let aiusd_id = T::AIUSDAssetId::get(); ensure!( - InspectFungibles::::asset_exists(&aiusd_id) - && InspectFungibles::::asset_exists(&target_asset_id), + InspectFungibles::::asset_exists(aiusd_id) + && InspectFungibles::::asset_exists(target_asset_id), Error::::InvalidAssetId ); // It will fail if insufficient fund @@ -140,7 +141,7 @@ pub mod pallet { let aseet_target_transfer_amount = aiusd_minted_amount.checked_mul(ratio)?.checked_div(10 ^ 18)?; let asset_actual_transfer_amount: AssetBalanceOf = - as FsInspect<::AccountId>>::transfer( + as FsMutate<::AccountId>>::transfer( target_asset_id, beneficiary, T::ConvertingFeeAccount::get(), @@ -172,7 +173,7 @@ pub mod pallet { ) -> DispatchResult { let beneficiary = ensure_signed(origin)?; if let Some(ratio) = EnabledTokens::::get(&target_asset_id) { - let aiusd_id = AIUSDAssetId::get(); + let aiusd_id = T::AIUSDAssetId::get(); ensure!( InspectFungibles::::asset_exists(&aiusd_id) && InspectFungibles::::asset_exists(target_asset_id), @@ -191,7 +192,7 @@ pub mod pallet { let aseet_target_transfer_amount = aiusd_destroyed_amount.checked_mul(ratio)?.checked_div(10 ^ 18)?; let asset_actual_transfer_amount: AssetBalanceOf = - as FsInspect<::AccountId>>::transfer( + as FsMutate<::AccountId>>::transfer( target_asset_id, T::ConvertingFeeAccount::get(), beneficiary, From 3c80dead9a8fa3724db17ed1424332e7a8d77582 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 30 Sep 2024 16:32:08 +0800 Subject: [PATCH 029/215] chore: fix --- .../collab-ai/aiusd-convertor/src/lib.rs | 26 ++++++++++++------- .../pallets/collab-ai/curator/src/lib.rs | 4 +-- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index 9db4cde5f3..8e86aeb249 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -28,7 +28,7 @@ use frame_support::{ }, }; use frame_system::pallet_prelude::*; -use sp_runtime::traits::CheckedMul; +use sp_runtime::traits::{CheckedDiv, CheckedMul}; #[frame_support::pallet] pub mod pallet { @@ -138,13 +138,16 @@ pub mod pallet { >::mint_into(aiusd_id, &beneficiary, aiusd_amount)?; // Maybe it is better to save decimal of AIUSD somewhere - let aseet_target_transfer_amount = - aiusd_minted_amount.checked_mul(ratio)?.checked_div(10 ^ 18)?; + let aseet_target_transfer_amount = aiusd_minted_amount + .checked_mul(&ratio) + .ok_or(Error::::Overflow)? + .checked_div(10 ^ 18) + .ok_or(Error::::Overflow)?; let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( target_asset_id, - beneficiary, - T::ConvertingFeeAccount::get(), + &beneficiary, + &T::ConvertingFeeAccount::get(), aseet_target_transfer_amount, Preservation::Expendable, )?; @@ -176,7 +179,7 @@ pub mod pallet { let aiusd_id = T::AIUSDAssetId::get(); ensure!( InspectFungibles::::asset_exists(&aiusd_id) - && InspectFungibles::::asset_exists(target_asset_id), + && InspectFungibles::::asset_exists(&target_asset_id), Error::::InvalidAssetId ); // It will fail if insufficient fund @@ -189,13 +192,16 @@ pub mod pallet { )?; // Maybe it is better to save decimal of AIUSD somewhere - let aseet_target_transfer_amount = - aiusd_destroyed_amount.checked_mul(ratio)?.checked_div(10 ^ 18)?; + let aseet_target_transfer_amount = aiusd_destroyed_amount + .checked_mul(&ratio) + .ok_or(Error::::Overflow)? + .checked_div(10 ^ 18) + .ok_or(Error::::Overflow)?; let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( target_asset_id, - T::ConvertingFeeAccount::get(), - beneficiary, + &T::ConvertingFeeAccount::get(), + &beneficiary, aseet_target_transfer_amount, Preservation::Expendable, )?; diff --git a/parachain/pallets/collab-ai/curator/src/lib.rs b/parachain/pallets/collab-ai/curator/src/lib.rs index 7538f58520..7583e37e82 100644 --- a/parachain/pallets/collab-ai/curator/src/lib.rs +++ b/parachain/pallets/collab-ai/curator/src/lib.rs @@ -25,16 +25,16 @@ //! //! #![cfg_attr(not(feature = "std"), no_std)] -use bitflags::bitflags; -use codec::{Decode, Encode}; use frame_support::{ ensure, + pallet_prelude::*, traits::{Currency, EnsureOrigin, Get, LockableCurrency, ReservableCurrency}, weights::Weight, }; use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; pub use pallet::*; use pallet_collab_ai_common::*; +use parity_scale_codec::{Decode, Encode}; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; From 005f3714370c8f8b0bed41f53795dc7e380b83e9 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 30 Sep 2024 16:48:27 +0800 Subject: [PATCH 030/215] chore: fix --- parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index 8e86aeb249..fb9006d28e 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -138,10 +138,11 @@ pub mod pallet { >::mint_into(aiusd_id, &beneficiary, aiusd_amount)?; // Maybe it is better to save decimal of AIUSD somewhere + let aiusd_deciaml_unit_expression: T::Balance = 10 ^ 18.try_into()?; let aseet_target_transfer_amount = aiusd_minted_amount .checked_mul(&ratio) .ok_or(Error::::Overflow)? - .checked_div(10 ^ 18) + .checked_div(&aiusd_deciaml_unit_expression) .ok_or(Error::::Overflow)?; let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( @@ -178,8 +179,8 @@ pub mod pallet { if let Some(ratio) = EnabledTokens::::get(&target_asset_id) { let aiusd_id = T::AIUSDAssetId::get(); ensure!( - InspectFungibles::::asset_exists(&aiusd_id) - && InspectFungibles::::asset_exists(&target_asset_id), + InspectFungibles::::asset_exists(aiusd_id) + && InspectFungibles::::asset_exists(target_asset_id), Error::::InvalidAssetId ); // It will fail if insufficient fund From b446284718c8125e7fdb90b24e39c13ceb908bfe Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 30 Sep 2024 17:26:12 +0800 Subject: [PATCH 031/215] chore: fix --- parachain/Cargo.lock | 1 + .../collab-ai/pool-proposal/Cargo.toml | 2 + .../collab-ai/pool-proposal/src/lib.rs | 39 ++++----- .../collab-ai/pool-proposal/src/types.rs | 84 +++++++++++-------- 4 files changed, 71 insertions(+), 55 deletions(-) diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index 5cd879c390..1c4cc50699 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -7892,6 +7892,7 @@ dependencies = [ "frame-support", "frame-system", "orml-utilities", + "pallet-assets", "pallet-collab-ai-common", "parity-scale-codec", "scale-info", diff --git a/parachain/pallets/collab-ai/pool-proposal/Cargo.toml b/parachain/pallets/collab-ai/pool-proposal/Cargo.toml index f0f5bdf4a3..12b7d89a61 100644 --- a/parachain/pallets/collab-ai/pool-proposal/Cargo.toml +++ b/parachain/pallets/collab-ai/pool-proposal/Cargo.toml @@ -18,6 +18,7 @@ frame-system = { workspace = true } orml-utilities = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } +pallet-assets = { workspace = true } pallet-collab-ai-common = { workspace = true } @@ -36,6 +37,7 @@ std = [ "frame-support/std", "frame-system/std", "orml-utilities/std", + "pallet-assets/std", "pallet-collab-ai-common/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index cff1e68dff..b4354d5745 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -26,22 +26,24 @@ pub mod types; -use bitflags::bitflags; use frame_support::{ ensure, - error::BadOrigin, + pallet_prelude::*, traits::{Currency, EnsureOrigin, Get, LockIdentifier, LockableCurrency, ReservableCurrency}, transactional, weights::Weight, - BoundedVec, + PalletId, +}; +use frame_system::{ + ensure_signed, + pallet_prelude::{BlockNumberFor, OriginFor}, }; -use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; use orml_utilities::OrderedSet; pub use pallet::*; use pallet_collab_ai_common::*; -use parity_scale_codec::{Decode, Encode}; -use sp_runtime::traits::CheckedAdd; -use sp_std::{cmp::Ordering, collections::vec_deque::VecDeque}; +use parity_scale_codec::Encode; +use sp_runtime::{traits::CheckedAdd, ArithmeticError}; +use sp_std::collections::vec_deque::VecDeque; pub use types::*; @@ -275,7 +277,7 @@ pub mod pallet { let current_block = frame_system::Pallet::::block_number(); ensure!( - proposal_last_time >= MinimumProposalLastTime::get(), + proposal_last_time >= T::MinimumProposalLastTime::get(), Error::::ProposalPublicTimeTooShort ); @@ -283,7 +285,7 @@ pub mod pallet { current_block.checked_add(proposal_last_time).ok_or(ArithmeticError::Overflow)?; let pool_start_time = proposal_end_time - .checked_add(OfficialGapPeriod::get()) + .checked_add(T::OfficialGapPeriod::get()) .ok_or(ArithmeticError::Overflow)?; let new_proposal_info = PoolProposalInfo { @@ -300,11 +302,10 @@ pub mod pallet { let next_proposal_index = PoolProposalCount::::get(); PoolProposal::::insert(next_proposal_index, new_proposal_info); - PublicCuratorToIndex::::insert(&who, next_curator_index); PoolProposalDepositOf::::try_mutate_exists( &who, |maybe_ordered_set| -> Result<(), DispatchError> { - let reserved_amount = MinimumPoolDeposit::get(); + let reserved_amount = T::MinimumPoolDeposit::get(); let _ = T::Currency::reserve(&who, reserved_amount)?; // We should not care about duplicating since the proposal index is auto-increment match maybe_ordered_set.as_mut() { @@ -366,9 +367,9 @@ pub mod pallet { let who = ensure_signed(origin)?; let asset_actual_transfer_amount: AssetBalanceOf = >::transfer( - AIUSDAssetId::get(), + T::AIUSDAssetId::get(), who, - PreInvestingPool::get(), + T::PreInvestingPool::get(), amount, Preservation::Expendable, )?; @@ -399,7 +400,7 @@ pub mod pallet { .total_pre_investing_amount .checked_add(asset_actual_transfer_amount) .ok_or(ArithmeticError::Overflow)?; - if (target_pre_investing_amount <= pool_proposal.max_pool_size) { + if target_pre_investing_amount <= pool_proposal.max_pool_size { // take all pre-investing into valid pre-investing line pool_proposal_pre_investing .add_pre_investing::(who, asset_actual_transfer_amount)?; @@ -411,7 +412,7 @@ pub mod pallet { amount: asset_actual_transfer_amount, }); // Flag proposal status if pool is just fully Investing - if (target_pre_investing_amount == pool_proposal.max_pool_size) { + if target_pre_investing_amount == pool_proposal.max_pool_size { pool_proposal.proposal_status_flags = pool_proposal.proposal_status_flags | ProposalStatusFlags::STAKE_AMOUNT_PASSED; PoolProposal::put(pool_proposal_index, pool_proposal); @@ -428,7 +429,7 @@ pub mod pallet { )?; // If pool not already full, flag proposal status - if (asset_actual_transfer_amount > queued_pre_investing_amount) { + if asset_actual_transfer_amount > queued_pre_investing_amount { let actual_pre_investing_amount = asset_actual_transfer_amount .checked_sub(queued_pre_investing_amount) .ok_or(ArithmeticError::Overflow)?; @@ -509,8 +510,8 @@ pub mod pallet { // Return funds let asset_actual_transfer_amount: AssetBalanceOf = >::transfer( - AIUSDAssetId::get(), - PreInvestingPool::get(), + T::AIUSDAssetId::get(), + T::PreInvestingPool::get(), who, amount, Preservation::Expendable, @@ -561,7 +562,7 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin)?; // Ensure guardian exists when participate, will double check if verified when mature the proposal) - ensure!(GuardianVoteResource::is_guardian(who), Error::::GuardianInvalid); + ensure!(T::GuardianVoteResource::is_guardian(who), Error::::GuardianInvalid); PoolGuardian::::try_mutate_exists( &pool_proposal_index, |maybe_ordered_set| -> Result<(), DispatchError> { diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index 7d408c2407..6cc623dff7 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -17,7 +17,11 @@ use crate::{Config, Error}; use bitflags::bitflags; use frame_support::{ensure, pallet_prelude::*}; use pallet_collab_ai_common::PoolProposalIndex; -use sp_runtime::{traits::CheckedAdd, ArithmeticError, BoundedVec}; +use sp_runtime::{ + traits::{Bounded, CheckedAdd, StaticLookup}, + ArithmeticError, BoundedVec, +}; +use sp_std::cmp::Ordering; bitflags! { /// Flags used to record the status of pool proposal @@ -146,10 +150,10 @@ impl> } } - pub fn get_pre_investing(&self, account: AccountId) -> Option<(usize, Balance)> { + pub fn get_pre_investing(&self, account: AccountId) -> Result<(usize, Balance), usize> { match self.pre_investings.binary_search(&Bond::from_owner(account)) { - Ok(loc) => Some((loc, self.pre_investings.index(loc))), - Err(loc) => None, + Ok(loc) => Ok((loc, self.pre_investings.index(loc))), + Err(loc) => Err(loc), } } @@ -158,18 +162,22 @@ impl> account: AccountId, amount: Balance, ) -> Result<(), DispatchError> { - if let Some(existing) = self.get_pre_investing(account) { - self.pre_investings.remove(existing.0); - let new_balance = existing.1.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; - let _ = self - .pre_investings - .try_insert(existing.0, Bond { owner: account, amount: new_balance }) - .map_err(|_| Error::::InvestingPoolOversized)?; - } else { - let _ = self - .pre_investings - .try_insert(existing.0, Bond { owner: account, amount }) - .map_err(|_| Error::::InvestingPoolOversized)?; + match self.get_pre_investing(account) { + Ok(existing) => { + self.pre_investings.remove(existing.0); + let new_balance = + existing.1.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; + let _ = self + .pre_investings + .try_insert(existing.0, Bond { owner: account, amount: new_balance }) + .map_err(|_| Error::::InvestingPoolOversized)?; + }, + Err(potential_index) => { + let _ = self + .pre_investings + .try_insert(potential_index, Bond { owner: account, amount }) + .map_err(|_| Error::::InvestingPoolOversized)?; + }, } self.total_pre_investing_amount = self .total_pre_investing_amount @@ -184,7 +192,7 @@ impl> amount: Balance, ) -> Result<(), DispatchError> { // Withdraw Queued one if any - if let Some(existing_q) = self.get_queued_investing(account) { + if let Ok(existing_q) = self.get_queued_investing(account) { if existing_q.1 > amount { // Existing queue is larger than target amount // Finish withdrawing and return early @@ -255,17 +263,17 @@ impl> pub fn get_queued_investing( &self, account: AccountId, - ) -> Option<(usize, Balance, BlockNumber)> { + ) -> Result<(usize, Balance, BlockNumber), usize> { match self .queued_pre_investings .binary_search_by(|p| p.0.cmp(&Bond::from_owner(account))) { - Ok(loc) => Some(( + Ok(loc) => Ok(( loc, self.queued_pre_investings.index(loc).0.amount, self.queued_pre_investings.index(loc).1, )), - Err(loc) => None, + Err(loc) => Err(loc), } } @@ -275,21 +283,25 @@ impl> amount: Balance, current_block: BlockNumber, ) -> Result<(), DispatchError> { - if let Some(existing) = self.get_queued_investing(account) { - self.queued_pre_investings.remove(existing.0); - let new_balance = existing.1.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; - let _ = self - .queued_pre_investings - .try_insert( - existing.0, - (Bond { owner: account, amount: new_balance }, current_block), - ) - .map_err(|_| Error::::InvestingPoolOversized)?; - } else { - let _ = self - .queued_pre_investings - .try_insert(existing.0, (Bond { owner: account, amount }, current_block)) - .map_err(|_| Error::::InvestingPoolOversized)?; + match self.get_queued_investing(account) { + Ok(existing) => { + self.queued_pre_investings.remove(existing.0); + let new_balance = + existing.1.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; + let _ = self + .queued_pre_investings + .try_insert( + existing.0, + (Bond { owner: account, amount: new_balance }, current_block), + ) + .map_err(|_| Error::::InvestingPoolOversized)?; + }, + Err(potential_index) => { + let _ = self + .queued_pre_investings + .try_insert(potential_index, (Bond { owner: account, amount }, current_block)) + .map_err(|_| Error::::InvestingPoolOversized)?; + }, } self::total_queued_amount = self::total_queued_amount .checked_add(&amount) @@ -320,7 +332,7 @@ impl> let transfer_amount = target_pre_investing_amount .checked_sub(self.total_pre_investing_amount) .ok_or(ArithmeticError::Overflow)?; - if (i.0.amount >= transfer_amount) { + if i.0.amount >= transfer_amount { let _ = self.withdraw(i.0.owner, transfer_amount)?; self.add_pre_investing(i.0.owner, transfer_amount)?; result.push(Bond { owner: i.0.owner, amount: transfer_amount }); From 3da8a12dd68f332adc144e94ad42be5f182a3199 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 30 Sep 2024 17:27:53 +0800 Subject: [PATCH 032/215] chore: taplo fmt --- parachain/pallets/collab-ai/pool-proposal/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/Cargo.toml b/parachain/pallets/collab-ai/pool-proposal/Cargo.toml index 12b7d89a61..d70002998a 100644 --- a/parachain/pallets/collab-ai/pool-proposal/Cargo.toml +++ b/parachain/pallets/collab-ai/pool-proposal/Cargo.toml @@ -16,9 +16,9 @@ scale-info = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } orml-utilities = { workspace = true } +pallet-assets = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } -pallet-assets = { workspace = true } pallet-collab-ai-common = { workspace = true } From f5b475ab606a062a83ad108dd7a9221b85dbb185 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 2 Oct 2024 17:52:53 +0800 Subject: [PATCH 033/215] chore: fix --- .../collab-ai/aiusd-convertor/src/lib.rs | 4 +-- .../pallets/collab-ai/guardian/src/lib.rs | 2 +- .../collab-ai/pool-proposal/src/lib.rs | 30 +++++++++++-------- .../collab-ai/pool-proposal/src/types.rs | 12 +++----- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index fb9006d28e..556b995732 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -138,7 +138,7 @@ pub mod pallet { >::mint_into(aiusd_id, &beneficiary, aiusd_amount)?; // Maybe it is better to save decimal of AIUSD somewhere - let aiusd_deciaml_unit_expression: T::Balance = 10 ^ 18.try_into()?; + let aiusd_deciaml_unit_expression: T::Balance = 10.pow(18).try_into()?; let aseet_target_transfer_amount = aiusd_minted_amount .checked_mul(&ratio) .ok_or(Error::::Overflow)? @@ -196,7 +196,7 @@ pub mod pallet { let aseet_target_transfer_amount = aiusd_destroyed_amount .checked_mul(&ratio) .ok_or(Error::::Overflow)? - .checked_div(10 ^ 18) + .checked_div(10.pow(18)) .ok_or(Error::::Overflow)?; let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( diff --git a/parachain/pallets/collab-ai/guardian/src/lib.rs b/parachain/pallets/collab-ai/guardian/src/lib.rs index 3c03f4a85f..75e45562d3 100644 --- a/parachain/pallets/collab-ai/guardian/src/lib.rs +++ b/parachain/pallets/collab-ai/guardian/src/lib.rs @@ -322,7 +322,7 @@ pub mod pallet { } /// Some sort of check on the origin is from guardian. -impl GuardianQuery for Pallet { +impl GuardianQuery for Pallet { fn is_guardian(account: T::AccountId) -> bool { if let Some(guardian_index) = PublicGuardianToIndex::::get(&account) { if let Some(info) = GuardianIndexToInfo::::get(guardian_index) { diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index b4354d5745..7bc63d7cec 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -29,7 +29,10 @@ pub mod types; use frame_support::{ ensure, pallet_prelude::*, - traits::{Currency, EnsureOrigin, Get, LockIdentifier, LockableCurrency, ReservableCurrency}, + traits::{ + tokens::Preservation, Currency, EnsureOrigin, Get, LockIdentifier, LockableCurrency, + ReservableCurrency, + }, transactional, weights::Weight, PalletId, @@ -37,12 +40,16 @@ use frame_support::{ use frame_system::{ ensure_signed, pallet_prelude::{BlockNumberFor, OriginFor}, + RawOrigin, }; use orml_utilities::OrderedSet; pub use pallet::*; use pallet_collab_ai_common::*; use parity_scale_codec::Encode; -use sp_runtime::{traits::CheckedAdd, ArithmeticError}; +use sp_runtime::{ + traits::{Bounded, CheckedAdd, StaticLookup}, + ArithmeticError, +}; use sp_std::collections::vec_deque::VecDeque; pub use types::*; @@ -70,7 +77,6 @@ pub(crate) type AssetIdOf = #[frame_support::pallet] pub mod pallet { use frame_support::{dispatch::DispatchResult, pallet_prelude::OptionQuery}; - use orml_utilities::ordered_set; use super::*; @@ -120,7 +126,7 @@ pub mod pallet { type PublicVotingOrigin: EnsureOrigin; /// Guardian vote resource - type GuardianVoteResource: GuardianQuery; + type GuardianVoteResource: GuardianQuery>; /// The maximum amount of guardian allowed for a proposal #[pallet::constant] @@ -142,7 +148,7 @@ pub mod pallet { _, Twox64Concat, T::AccountId, - OrderedSet>, T::MaxDeposits>, + OrderedSet>, T::MaximumPoolProposed>, OptionQuery, >; @@ -190,7 +196,7 @@ pub mod pallet { _, Twox64Concat, PoolProposalIndex, - OrderedSet, + OrderedSet, OptionQuery, >; @@ -474,6 +480,8 @@ pub mod pallet { let mut pool_proposal_pre_investing = >::take(pool_proposal_index) .unwrap_or(PoolProposalPreInvesting::new()); + let mut pool_proposal = + PoolProposal::get(pool_proposal_index).ok_or(Error::::ProposalNotExist)?; // Either investing pool has not locked yet, // Or queued amount is enough to replace the withdrawal ensure!( @@ -487,14 +495,12 @@ pub mod pallet { let _ = pool_proposal_pre_investing.withdraw::(who, amount)?; Self::deposit_event(Event::PoolWithdrawed { user: who, pool_proposal_index, amount }); - let mut pool_proposal = - PoolProposal::get(pool_proposal_index).ok_or(Error::::ProposalNotExist)?; // Make queued amount fill the missing Investing amount if pool Investing flag ever reached - if ((pool_proposal_pre_investing.total_pre_investing_amount + if (pool_proposal_pre_investing.total_pre_investing_amount < pool_proposal.max_pool_size) && (pool_proposal .proposal_status_flags - .contains(ProposalStatusFlags::STAKE_AMOUNT_PASSED))) + .contains(ProposalStatusFlags::STAKE_AMOUNT_PASSED)) { let moved_bonds = pool_proposal_pre_investing .move_queued_to_pre_investing_until::(pool_proposal.max_pool_size)?; @@ -598,7 +604,7 @@ pub mod pallet { fn try_origin(o: T::RuntimeOrigin) -> Result { let sync_account_id = MODULE_ID.into_account_truncating(); o.into().and_then(|o| match o { - system::RawOrigin::Signed(who) if who == sync_account_id => Ok(sync_account_id), + RawOrigin::Signed(who) if who == sync_account_id => Ok(sync_account_id), r => Err(T::RuntimeOrigin::from(r)), }) } @@ -606,7 +612,7 @@ pub mod pallet { #[cfg(feature = "runtime-benchmarks")] fn try_successful_origin() -> Result { let sync_account_id = MODULE_ID.into_account_truncating(); - Ok(T::RuntimeOrigin::from(system::RawOrigin::Signed(sync_account_id))) + Ok(T::RuntimeOrigin::from(RawOrigin::Signed(sync_account_id))) } } } diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index 6cc623dff7..805bf13348 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -17,10 +17,7 @@ use crate::{Config, Error}; use bitflags::bitflags; use frame_support::{ensure, pallet_prelude::*}; use pallet_collab_ai_common::PoolProposalIndex; -use sp_runtime::{ - traits::{Bounded, CheckedAdd, StaticLookup}, - ArithmeticError, BoundedVec, -}; +use sp_runtime::{traits::CheckedAdd, ArithmeticError, BoundedVec}; use sp_std::cmp::Ordering; bitflags! { @@ -84,7 +81,7 @@ pub struct PoolProposalInfo { pub proposal_status_flags: ProposalStatusFlags, } -#[derive(Clone, Encode, Debug, Decode, TypeInfo)] +#[derive(Clone, Encode, Debug, Decode, MaxEncodedLen, TypeInfo)] pub struct Bond { pub owner: Identity, pub amount: BalanceType, @@ -303,9 +300,8 @@ impl> .map_err(|_| Error::::InvestingPoolOversized)?; }, } - self::total_queued_amount = self::total_queued_amount - .checked_add(&amount) - .ok_or(ArithmeticError::Overflow)?; + self.total_queued_amount = + self.total_queued_amount.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; Ok(()) } From e3c714543cdc76ceb3d427c14e4367d2d881d658 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 2 Oct 2024 18:59:43 +0800 Subject: [PATCH 034/215] chore: fix --- parachain/pallets/collab-ai/common/src/lib.rs | 20 ++++++-- .../pallets/collab-ai/curator/src/lib.rs | 28 +++++++---- .../pallets/collab-ai/guardian/src/lib.rs | 50 +++++++++---------- 3 files changed, 59 insertions(+), 39 deletions(-) diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index 9a632e6372..7bd8d59f83 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -55,7 +55,19 @@ pub struct PoolMetadata { pub description: BoundedString, } -#[derive(PartialEq, Eq, Clone, Copy, Default, Encode, Decode, Debug, TypeInfo)] +#[derive( + PartialEq, + Eq, + Clone, + Copy, + Default, + Encode, + Decode, + Debug, + RuntimeDebug, + MaxEncodedLen, + TypeInfo, +)] pub enum CandidateStatus { /// Initial status of legal file #[default] @@ -70,7 +82,7 @@ pub enum CandidateStatus { } #[derive(PartialEq, Eq, Clone, Default, Encode, Decode, Debug, TypeInfo)] -pub enum GuardianVote> { +pub enum GuardianVote { /// Does not care if this guardian get selected /// Please be aware Neutral will increase participate percentage /// which will increase the winning rate of guardian selection @@ -87,7 +99,7 @@ pub enum GuardianVote> { /// Support this guardian for only specific pool proposal /// And neutral for other pool proposal #[codec(index = 3)] - Specific(BoundedVec), + Specific(PoolProposalIndex), } /// Some sort of check on the account is from some group. @@ -157,5 +169,5 @@ pub trait GuardianQuery> { fn is_verified_guardian(account: AccountId) -> bool; /// Get vote - fn get_vote(voter: AccountId, guardian: AccountId) -> Option>; + fn get_vote(voter: AccountId, guardian: AccountId) -> Option; } diff --git a/parachain/pallets/collab-ai/curator/src/lib.rs b/parachain/pallets/collab-ai/curator/src/lib.rs index 7583e37e82..0eb15d77ef 100644 --- a/parachain/pallets/collab-ai/curator/src/lib.rs +++ b/parachain/pallets/collab-ai/curator/src/lib.rs @@ -31,10 +31,14 @@ use frame_support::{ traits::{Currency, EnsureOrigin, Get, LockableCurrency, ReservableCurrency}, weights::Weight, }; -use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; +use frame_system::{ + ensure_signed, + pallet_prelude::{BlockNumberFor, OriginFor}, +}; pub use pallet::*; use pallet_collab_ai_common::*; use parity_scale_codec::{Decode, Encode}; +use sp_runtime::ArithmeticError; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -124,6 +128,7 @@ pub mod pallet { /// Registing a curator legal info #[pallet::call_index(0)] #[pallet::weight({195_000_000})] + #[transactional] pub fn regist_curator(origin: OriginFor, info_hash: InfoHash) -> DispatchResult { let who = ensure_signed(origin)?; @@ -144,9 +149,15 @@ pub mod pallet { &next_curator_index, (info_hash, current_block, who, CandidateStatus::Unverified), ); - PublicCuratorCount::::put(next_curator_index.checked_add(1u32.into())?); + PublicCuratorCount::::put( + next_curator_index.checked_add(1u32.into()).ok_or(ArithmeticError::Overflow)?, + ); - Self::deposit_event(Event::CuratorRegisted { curator: who, curator_index, info_hash }); + Self::deposit_event(Event::CuratorRegisted { + curator: who, + curator_index: next_curator_index, + info_hash, + }); Ok(()) } @@ -189,16 +200,13 @@ pub mod pallet { /// Clean a curator legal info #[pallet::call_index(2)] #[pallet::weight({195_000_000})] + #[transactional] pub fn clean_curator(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; // Ensure existing - ensure!( - PublicCuratorToIndex::::contains_key(&who), - Error::::CuratorNotRegistered - ); - - let curator_index = PublicCuratorToIndex::::take(&who); + let curator_index = + PublicCuratorToIndex::::take(&who).ok_or(Error::::CuratorNotRegistered)?; // Update curator // But if banned, then require extra reserve @@ -212,7 +220,7 @@ pub mod pallet { } // Delete item - maybe_info = None; + *maybe_info = None; Self::deposit_event(Event::CuratorCleaned { curator, curator_index }); Ok(()) }, diff --git a/parachain/pallets/collab-ai/guardian/src/lib.rs b/parachain/pallets/collab-ai/guardian/src/lib.rs index 75e45562d3..551fce0df4 100644 --- a/parachain/pallets/collab-ai/guardian/src/lib.rs +++ b/parachain/pallets/collab-ai/guardian/src/lib.rs @@ -29,12 +29,15 @@ use frame_support::{ ensure, pallet_prelude::*, traits::{Currency, EnsureOrigin, Get, LockableCurrency, ReservableCurrency}, - weights::Weight, }; -use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; +use frame_system::{ + ensure_signed, + pallet_prelude::{BlockNumberFor, OriginFor}, +}; pub use pallet::*; use pallet_collab_ai_common::*; -use parity_scale_codec::{Decode, Encode}; +use parity_scale_codec::Encode; +use sp_runtime::ArithmeticError; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -101,7 +104,7 @@ pub mod pallet { T::AccountId, Twox64Concat, GuardianIndex, - GuardianVote, + GuardianVote, OptionQuery, >; @@ -131,7 +134,7 @@ pub mod pallet { voter: T::AccountId, guardian_index: GuardianIndex, guardian: T::AccountId, - status: Option>, + status: Option, }, RemoveAllVote { voter: T::AccountId, @@ -150,6 +153,7 @@ pub mod pallet { /// Registing a guardian legal info #[pallet::call_index(0)] #[pallet::weight({195_000_000})] + #[transactional] pub fn regist_guardian(origin: OriginFor, info_hash: InfoHash) -> DispatchResult { let who = ensure_signed(origin)?; @@ -170,11 +174,13 @@ pub mod pallet { &next_guardian_index, (info_hash, current_block, who, CandidateStatus::Unverified), ); - PublicGuardianCount::::put(next_guardian_index.checked_add(1u32.into())?); + PublicGuardianCount::::put( + next_guardian_index.checked_add(1u32.into()).ok_or(ArithmeticError::Overflow)?, + ); Self::deposit_event(Event::GuardianRegisted { guardian: who, - guardian_index, + guardian_index: next_guardian_index, info_hash, }); Ok(()) @@ -187,8 +193,8 @@ pub mod pallet { let who = ensure_signed(origin)?; // Ensure existing - let guardian_index = PublicGuardianToIndex::::get(guardian) - .ok_or(Error::::GuardianNotRegistered)?; + let guardian_index = + PublicGuardianToIndex::::get(who).ok_or(Error::::GuardianNotRegistered)?; // Update guardian // But if banned, then require extra reserve @@ -206,7 +212,7 @@ pub mod pallet { // Update block number info.1 = frame_system::Pallet::::block_number(); Self::deposit_event(Event::GuardianUpdated { - guardian, + guardian: who, guardian_index, info_hash, }); @@ -219,16 +225,13 @@ pub mod pallet { /// Clean a guardian legal info #[pallet::call_index(2)] #[pallet::weight({195_000_000})] + #[transactional] pub fn clean_guardian(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; // Ensure existing - ensure!( - PublicGuardianToIndex::::contains_key(&who), - Error::::GuardianNotRegistered - ); - - let guardian_index = PublicGuardianToIndex::::take(&who); + let guardian_index = + PublicGuardianToIndex::::take(&who).ok_or(Error::::GuardianNotRegistered)?; // Update guardian // But if banned, then require extra reserve @@ -237,13 +240,13 @@ pub mod pallet { |maybe_info| -> Result<(), DispatchError> { let info = maybe_info.ok_or(Error::::GuardianIndexNotExist)?; - if (info.3 != CandidateStatus::Banned) { + if info.3 != CandidateStatus::Banned { T::Currency::unreserve(&who, T::MinimumGuardianDeposit::get())?; } // Delete item - maybe_info = None; - Self::deposit_event(Event::GuardianCleaned { guardian, guardian_index }); + *maybe_info = None; + Self::deposit_event(Event::GuardianCleaned { guardian: who, guardian_index }); Ok(()) }, )?; @@ -258,12 +261,12 @@ pub mod pallet { status: CandidateStatus, ) -> DispatchResult { T::GuardianJudgeOrigin::ensure_origin(origin)?; - let guardian_index = PublicGuardianToIndex::::get(guardian) + let guardian_index = PublicGuardianToIndex::::get(&guardian) .ok_or(Error::::GuardianNotRegistered)?; GuardianIndexToInfo::::try_mutate_exists( guardian_index, |maybe_info| -> Result<(), DispatchError> { - let mut info = maybe_info.as_mut().ok_or(Error::::GuardianIndexNotExist)?; + let info = maybe_info.as_mut().ok_or(Error::::GuardianIndexNotExist)?; // Update block number info.1 = frame_system::Pallet::::block_number(); // Update status @@ -347,10 +350,7 @@ impl GuardianQuery for Palle false } - fn get_vote( - voter: T::AccountId, - guardian: T::AccountId, - ) -> Option> { + fn get_vote(voter: T::AccountId, guardian: T::AccountId) -> Option { // Ensure existing if let Some(guardian_index) = PublicGuardianToIndex::::get(&guardian) { return GuardianVotes::::get(&voter, guardian_index); From 05b7bb4f367e39750e6eb2f7556bb7816782d25d Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 2 Oct 2024 19:17:37 +0800 Subject: [PATCH 035/215] chore: fix --- parachain/pallets/collab-ai/common/src/lib.rs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index 7bd8d59f83..42c3a77ac5 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -18,7 +18,6 @@ use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_core::{Get, RuntimeDebug, H256}; -use sp_runtime::BoundedVec; use sp_std::marker::PhantomData; use frame_support::pallet_prelude::EnsureOrigin; @@ -55,19 +54,7 @@ pub struct PoolMetadata { pub description: BoundedString, } -#[derive( - PartialEq, - Eq, - Clone, - Copy, - Default, - Encode, - Decode, - Debug, - RuntimeDebug, - MaxEncodedLen, - TypeInfo, -)] +#[derive(PartialEq, Eq, Clone, Copy, Default, Encode, Decode, Debug, MaxEncodedLen, TypeInfo)] pub enum CandidateStatus { /// Initial status of legal file #[default] From ee8e71eb37e5113969aaeb5eeb50cb5c424be88e Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 2 Oct 2024 20:56:05 +0800 Subject: [PATCH 036/215] chore: fix --- .../pallets/collab-ai/aiusd-convertor/src/lib.rs | 3 +++ parachain/pallets/collab-ai/common/src/lib.rs | 4 ++-- parachain/pallets/collab-ai/curator/src/lib.rs | 2 +- parachain/pallets/collab-ai/guardian/src/lib.rs | 16 ++++++++-------- .../pallets/collab-ai/pool-proposal/src/lib.rs | 11 +++++++---- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index 556b995732..7ed2a20d3d 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -26,6 +26,7 @@ use frame_support::{ }, StorageVersion, }, + transactional, }; use frame_system::pallet_prelude::*; use sp_runtime::traits::{CheckedDiv, CheckedMul}; @@ -116,6 +117,7 @@ pub mod pallet { // Lock target_asset_id token and mint AIUSD #[pallet::call_index(0)] #[pallet::weight({195_000_000})] + #[transactional] pub fn mint_aiusd( origin: OriginFor, target_asset_id: AssetIdOf, @@ -170,6 +172,7 @@ pub mod pallet { // Failed if pool does not have enough token of one type #[pallet::call_index(1)] #[pallet::weight({195_000_000})] + #[transactional] pub fn burn_aiusd( origin: OriginFor, target_asset_id: AssetIdOf, diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index 42c3a77ac5..04dd3f4568 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -68,7 +68,7 @@ pub enum CandidateStatus { Banned, } -#[derive(PartialEq, Eq, Clone, Default, Encode, Decode, Debug, TypeInfo)] +#[derive(PartialEq, Eq, Clone, Default, Encode, Decode, Debug, MaxEncodedLen, TypeInfo)] pub enum GuardianVote { /// Does not care if this guardian get selected /// Please be aware Neutral will increase participate percentage @@ -148,7 +148,7 @@ pub const INVESTING_POOL_END_MONTH_SHIFTER: u128 = 1; // } /// Some sort of check on the account is from some group. -pub trait GuardianQuery> { +pub trait GuardianQuery { /// All guardian but banned ones fn is_guardian(account: AccountId) -> bool; diff --git a/parachain/pallets/collab-ai/curator/src/lib.rs b/parachain/pallets/collab-ai/curator/src/lib.rs index 0eb15d77ef..5a7a65ccc6 100644 --- a/parachain/pallets/collab-ai/curator/src/lib.rs +++ b/parachain/pallets/collab-ai/curator/src/lib.rs @@ -29,6 +29,7 @@ use frame_support::{ ensure, pallet_prelude::*, traits::{Currency, EnsureOrigin, Get, LockableCurrency, ReservableCurrency}, + transactional, weights::Weight, }; use frame_system::{ @@ -37,7 +38,6 @@ use frame_system::{ }; pub use pallet::*; use pallet_collab_ai_common::*; -use parity_scale_codec::{Decode, Encode}; use sp_runtime::ArithmeticError; type BalanceOf = diff --git a/parachain/pallets/collab-ai/guardian/src/lib.rs b/parachain/pallets/collab-ai/guardian/src/lib.rs index 551fce0df4..b1bf8bebad 100644 --- a/parachain/pallets/collab-ai/guardian/src/lib.rs +++ b/parachain/pallets/collab-ai/guardian/src/lib.rs @@ -29,6 +29,7 @@ use frame_support::{ ensure, pallet_prelude::*, traits::{Currency, EnsureOrigin, Get, LockableCurrency, ReservableCurrency}, + transactional, }; use frame_system::{ ensure_signed, @@ -36,7 +37,6 @@ use frame_system::{ }; pub use pallet::*; use pallet_collab_ai_common::*; -use parity_scale_codec::Encode; use sp_runtime::ArithmeticError; type BalanceOf = @@ -172,7 +172,7 @@ pub mod pallet { PublicGuardianToIndex::::insert(&who, next_guardian_index); GuardianIndexToInfo::::insert( &next_guardian_index, - (info_hash, current_block, who, CandidateStatus::Unverified), + (info_hash, current_block, who.clone(), CandidateStatus::Unverified), ); PublicGuardianCount::::put( next_guardian_index.checked_add(1u32.into()).ok_or(ArithmeticError::Overflow)?, @@ -194,14 +194,14 @@ pub mod pallet { // Ensure existing let guardian_index = - PublicGuardianToIndex::::get(who).ok_or(Error::::GuardianNotRegistered)?; + PublicGuardianToIndex::::get(&who).ok_or(Error::::GuardianNotRegistered)?; // Update guardian // But if banned, then require extra reserve GuardianIndexToInfo::::try_mutate_exists( guardian_index, |maybe_info| -> Result<(), DispatchError> { - let mut info = maybe_info.as_mut().ok_or(Error::::GuardianIndexNotExist)?; + let info = maybe_info.as_mut().ok_or(Error::::GuardianIndexNotExist)?; if info.3 == CandidateStatus::Banned { T::Currency::reserve(&who, T::MinimumGuardianDeposit::get())?; @@ -241,7 +241,7 @@ pub mod pallet { let info = maybe_info.ok_or(Error::::GuardianIndexNotExist)?; if info.3 != CandidateStatus::Banned { - T::Currency::unreserve(&who, T::MinimumGuardianDeposit::get())?; + let _ = T::Currency::unreserve(&who, T::MinimumGuardianDeposit::get()); } // Delete item @@ -298,7 +298,7 @@ pub mod pallet { let guardian_index = PublicGuardianToIndex::::get(&guardian) .ok_or(Error::::GuardianNotRegistered)?; if let Some(i) = status { - GuardianVotes::::insert(&who, guardian_index, status); + GuardianVotes::::insert(&who, guardian_index, i); } else { GuardianVotes::::remove(&who, guardian_index); } @@ -315,7 +315,7 @@ pub mod pallet { /// Remove vote to None #[pallet::call_index(5)] #[pallet::weight({195_000_000})] - pub fn remove_all_votes(origin: OriginFor, guardian: T::AccountId) -> DispatchResult { + pub fn remove_all_votes(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; let _ = GuardianVotes::::clear_prefix(&who, u32::MAX, None); Self::deposit_event(Event::RemoveAllVote { voter: who }); @@ -325,7 +325,7 @@ pub mod pallet { } /// Some sort of check on the origin is from guardian. -impl GuardianQuery for Pallet { +impl GuardianQuery for Pallet { fn is_guardian(account: T::AccountId) -> bool { if let Some(guardian_index) = PublicGuardianToIndex::::get(&account) { if let Some(info) = GuardianIndexToInfo::::get(guardian_index) { diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 7bc63d7cec..b619cb082c 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -30,8 +30,11 @@ use frame_support::{ ensure, pallet_prelude::*, traits::{ - tokens::Preservation, Currency, EnsureOrigin, Get, LockIdentifier, LockableCurrency, - ReservableCurrency, + schedule::v3::Named as ScheduleNamed, + tokens::{ + fungibles::Inspect as FsInspect, Bounded, Currency, EnsureOrigin, Get, LockIdentifier, + LockableCurrency, Preservation, ReservableCurrency, + }, }, transactional, weights::Weight, @@ -47,7 +50,7 @@ pub use pallet::*; use pallet_collab_ai_common::*; use parity_scale_codec::Encode; use sp_runtime::{ - traits::{Bounded, CheckedAdd, StaticLookup}, + traits::{CheckedAdd, StaticLookup}, ArithmeticError, }; use sp_std::collections::vec_deque::VecDeque; @@ -126,7 +129,7 @@ pub mod pallet { type PublicVotingOrigin: EnsureOrigin; /// Guardian vote resource - type GuardianVoteResource: GuardianQuery>; + type GuardianVoteResource: GuardianQuery; /// The maximum amount of guardian allowed for a proposal #[pallet::constant] From 503fba9801458fac8b7ef6066ae9fceb6ab5f8f2 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 3 Oct 2024 02:57:22 +0800 Subject: [PATCH 037/215] chore: fix --- parachain/pallets/collab-ai/common/src/lib.rs | 2 +- parachain/pallets/collab-ai/curator/src/lib.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index 04dd3f4568..44bfff6326 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -17,7 +17,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_core::{Get, RuntimeDebug, H256}; +use sp_core::{RuntimeDebug, H256}; use sp_std::marker::PhantomData; use frame_support::pallet_prelude::EnsureOrigin; diff --git a/parachain/pallets/collab-ai/curator/src/lib.rs b/parachain/pallets/collab-ai/curator/src/lib.rs index 5a7a65ccc6..fe8a015e7f 100644 --- a/parachain/pallets/collab-ai/curator/src/lib.rs +++ b/parachain/pallets/collab-ai/curator/src/lib.rs @@ -30,7 +30,6 @@ use frame_support::{ pallet_prelude::*, traits::{Currency, EnsureOrigin, Get, LockableCurrency, ReservableCurrency}, transactional, - weights::Weight, }; use frame_system::{ ensure_signed, @@ -147,7 +146,7 @@ pub mod pallet { PublicCuratorToIndex::::insert(&who, next_curator_index); CuratorIndexToInfo::::insert( &next_curator_index, - (info_hash, current_block, who, CandidateStatus::Unverified), + (info_hash, current_block, wh.clone(), CandidateStatus::Unverified), ); PublicCuratorCount::::put( next_curator_index.checked_add(1u32.into()).ok_or(ArithmeticError::Overflow)?, @@ -169,7 +168,7 @@ pub mod pallet { // Ensure existing let curator_index = - PublicCuratorToIndex::::get(curator).ok_or(Error::::CuratorNotRegistered)?; + PublicCuratorToIndex::::get(&who).ok_or(Error::::CuratorNotRegistered)?; // Update curator // But if banned, then require extra reserve @@ -187,7 +186,7 @@ pub mod pallet { // Update block number info.1 = frame_system::Pallet::::block_number(); Self::deposit_event(Event::CuratorUpdated { - curator, + curator: who, curator_index, info_hash, }); @@ -216,7 +215,7 @@ pub mod pallet { let info = maybe_info.ok_or(Error::::CuratorIndexNotExist)?; if info.3 != CandidateStatus::Banned { - T::Currency::unreserve(&who, T::MinimumCuratorDeposit::get())?; + let _ = T::Currency::unreserve(&who, T::MinimumCuratorDeposit::get()); } // Delete item @@ -255,6 +254,7 @@ pub mod pallet { Ok(()) }, )?; + Ok(()) } } } From 35d51022e6cf56df4b2d89fb7577e8f73a095e80 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 3 Oct 2024 04:03:27 +0800 Subject: [PATCH 038/215] chore: fix --- .../collab-ai/pool-proposal/src/lib.rs | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index b619cb082c..6882fa8b6e 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -31,10 +31,8 @@ use frame_support::{ pallet_prelude::*, traits::{ schedule::v3::Named as ScheduleNamed, - tokens::{ - fungibles::Inspect as FsInspect, Bounded, Currency, EnsureOrigin, Get, LockIdentifier, - LockableCurrency, Preservation, ReservableCurrency, - }, + tokens::{fungibles::Inspect as FsInspect, Preservation}, + Bounded, Currency, EnsureOrigin, Get, LockIdentifier, LockableCurrency, ReservableCurrency, }, transactional, weights::Weight, @@ -49,10 +47,7 @@ use orml_utilities::OrderedSet; pub use pallet::*; use pallet_collab_ai_common::*; use parity_scale_codec::Encode; -use sp_runtime::{ - traits::{CheckedAdd, StaticLookup}, - ArithmeticError, -}; +use sp_runtime::{traits::CheckedAdd, ArithmeticError}; use sp_std::collections::vec_deque::VecDeque; pub use types::*; @@ -60,14 +55,8 @@ pub use types::*; pub(crate) const POOL_DEMOCRACY_ID: LockIdentifier = *b"spdemocy"; pub(crate) const POOL_COMMITTEE_ID: LockIdentifier = *b"spcomtte"; -type BalanceOf = +pub(crate) type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; -type NegativeImbalanceOf = <::Currency as Currency< - ::AccountId, ->>::NegativeImbalance; -pub type CallOf = ::RuntimeCall; -pub type BoundedCallOf = Bounded>; -type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; pub(crate) type InspectFungibles = pallet_assets::Pallet; /// Balance type alias for balances of assets that implement the `fungibles` trait. @@ -96,8 +85,8 @@ pub mod pallet { pub trait Config: frame_system::Config + pallet_assets::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// The Scheduler. - type Scheduler: ScheduleNamed, CallOf, Self::PalletsOrigin>; + /// The Make pool mature. + // type Scheduler: ScheduleNamed, CallOf, Self::PalletsOrigin>; /// Currency type for this pallet. type Currency: ReservableCurrency From 99506a5c91fdf0de90103d924c534e8d37b7e9b0 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 3 Oct 2024 15:00:04 +0800 Subject: [PATCH 039/215] chore: fix --- .../collab-ai/pool-proposal/src/lib.rs | 43 +++++++++-------- .../collab-ai/pool-proposal/src/types.rs | 48 ++++++++++++------- 2 files changed, 54 insertions(+), 37 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 6882fa8b6e..d7b2ca3e71 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -30,9 +30,8 @@ use frame_support::{ ensure, pallet_prelude::*, traits::{ - schedule::v3::Named as ScheduleNamed, - tokens::{fungibles::Inspect as FsInspect, Preservation}, - Bounded, Currency, EnsureOrigin, Get, LockIdentifier, LockableCurrency, ReservableCurrency, + tokens::{fungibles::Inspect as FsInspect, Mutate as FsMutate, Preservation}, + Currency, EnsureOrigin, Get, LockIdentifier, LockableCurrency, ReservableCurrency, }, transactional, weights::Weight, @@ -47,7 +46,10 @@ use orml_utilities::OrderedSet; pub use pallet::*; use pallet_collab_ai_common::*; use parity_scale_codec::Encode; -use sp_runtime::{traits::CheckedAdd, ArithmeticError}; +use sp_runtime::{ + traits::{AccountIdConversion, CheckedAdd, CheckedSub}, + ArithmeticError, +}; use sp_std::collections::vec_deque::VecDeque; pub use types::*; @@ -183,7 +185,7 @@ pub mod pallet { // Guardian willingness of proposal #[pallet::storage] - #[pallet::getter(fn pool_pre_investings)] + #[pallet::getter(fn pool_guardian)] pub type PoolGuardian = StorageMap< _, Twox64Concat, @@ -279,11 +281,12 @@ pub mod pallet { Error::::ProposalPublicTimeTooShort ); - let proposal_end_time = - current_block.checked_add(proposal_last_time).ok_or(ArithmeticError::Overflow)?; + let proposal_end_time = current_block + .checked_add(&proposal_last_time) + .ok_or(ArithmeticError::Overflow)?; let pool_start_time = proposal_end_time - .checked_add(T::OfficialGapPeriod::get()) + .checked_add(&T::OfficialGapPeriod::get()) .ok_or(ArithmeticError::Overflow)?; let new_proposal_info = PoolProposalInfo { @@ -292,7 +295,7 @@ pub mod pallet { max_pool_size, pool_start_time, pool_end_time: pool_start_time - .checked_add(pool_last_time) + .checked_add(&pool_last_time) .ok_or(ArithmeticError::Overflow)?, estimated_epoch_reward, proposal_status_flags: ProposalStatusFlags::empty(), @@ -304,7 +307,7 @@ pub mod pallet { &who, |maybe_ordered_set| -> Result<(), DispatchError> { let reserved_amount = T::MinimumPoolDeposit::get(); - let _ = T::Currency::reserve(&who, reserved_amount)?; + let _ = ::Currency::reserve(&who, reserved_amount)?; // We should not care about duplicating since the proposal index is auto-increment match maybe_ordered_set.as_mut() { Some(ordered_set) => { @@ -364,7 +367,7 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin)?; - let asset_actual_transfer_amount: AssetBalanceOf = >::transfer( + let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( T::AIUSDAssetId::get(), who, T::PreInvestingPool::get(), @@ -389,8 +392,8 @@ pub mod pallet { // Check BoundedVec limit ensure!( - !pool_proposal_pre_investing.pre_investings.is_full - && !pool_proposal_pre_investing.queued_pre_investings.is_full, + !pool_proposal_pre_investing.pre_investings.is_full() + && !pool_proposal_pre_investing.queued_pre_investings.is_full(), Error::::InvestingPoolOversized ); @@ -413,7 +416,7 @@ pub mod pallet { if target_pre_investing_amount == pool_proposal.max_pool_size { pool_proposal.proposal_status_flags = pool_proposal.proposal_status_flags | ProposalStatusFlags::STAKE_AMOUNT_PASSED; - PoolProposal::put(pool_proposal_index, pool_proposal); + >::put(pool_proposal_index, pool_proposal); } } else { // Partially @@ -442,7 +445,7 @@ pub mod pallet { pool_proposal.proposal_status_flags = pool_proposal.proposal_status_flags | ProposalStatusFlags::STAKE_AMOUNT_PASSED; - PoolProposal::put(pool_proposal_index, pool_proposal); + >::put(pool_proposal_index, pool_proposal); } // Emit events @@ -473,7 +476,7 @@ pub mod pallet { .unwrap_or(PoolProposalPreInvesting::new()); let mut pool_proposal = - PoolProposal::get(pool_proposal_index).ok_or(Error::::ProposalNotExist)?; + >::get(pool_proposal_index).ok_or(Error::::ProposalNotExist)?; // Either investing pool has not locked yet, // Or queued amount is enough to replace the withdrawal ensure!( @@ -507,7 +510,7 @@ pub mod pallet { } // Return funds - let asset_actual_transfer_amount: AssetBalanceOf = >::transfer( + let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( T::AIUSDAssetId::get(), T::PreInvestingPool::get(), who, @@ -531,7 +534,7 @@ pub mod pallet { ) -> DispatchResult { T::PublicVotingOrigin::ensure_origin(origin)?; let mut pool_proposal = - PoolProposal::get(pool_proposal_index).ok_or(Error::::ProposalNotExist)?; + >::get(pool_proposal_index).ok_or(Error::::ProposalNotExist)?; if vote { pool_proposal.proposal_status_flags = @@ -540,7 +543,7 @@ pub mod pallet { pool_proposal.proposal_status_flags = pool_proposal.proposal_status_flags & !ProposalStatusFlags::PUBLIC_VOTE_PASSED; } - PoolProposal::put(pool_proposal_index, pool_proposal); + >::put(pool_proposal_index, pool_proposal); Self::deposit_event(Event::ProposalPublicVoted { pool_proposal_index, @@ -560,7 +563,7 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin)?; // Ensure guardian exists when participate, will double check if verified when mature the proposal) - ensure!(T::GuardianVoteResource::is_guardian(who), Error::::GuardianInvalid); + ensure!(T::GuardianVoteResource::is_guardian(who.clone()), Error::::GuardianInvalid); PoolGuardian::::try_mutate_exists( &pool_proposal_index, |maybe_ordered_set| -> Result<(), DispatchError> { diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index 805bf13348..df0226c765 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -17,12 +17,15 @@ use crate::{Config, Error}; use bitflags::bitflags; use frame_support::{ensure, pallet_prelude::*}; use pallet_collab_ai_common::PoolProposalIndex; -use sp_runtime::{traits::CheckedAdd, ArithmeticError, BoundedVec}; +use sp_runtime::{ + traits::{CheckedAdd, CheckedSub}, + ArithmeticError, BoundedVec, +}; use sp_std::cmp::Ordering; bitflags! { /// Flags used to record the status of pool proposal - #[derive(Encode, Decode, MaxEncodedLen)] + #[derive(Encode, Decode, MaxEncodedLen, TypeInfo)] pub struct ProposalStatusFlags: u8 { /// Whether the pool proposal passing the committee/democracy voting. /// @@ -134,8 +137,13 @@ pub struct PoolProposalPreInvesting pub queued_pre_investings: BoundedVec<(Bond, BlockNumber), S>, } -impl> - PoolProposalPreInvesting +impl< + AccountId: Ord, + Balance: Default + CheckedAdd + CheckedSub, + PartialOrd, + BlockNumber, + S: Get, + > PoolProposalPreInvesting { /// Create a new empty default pub fn new() -> Self { @@ -149,7 +157,7 @@ impl> pub fn get_pre_investing(&self, account: AccountId) -> Result<(usize, Balance), usize> { match self.pre_investings.binary_search(&Bond::from_owner(account)) { - Ok(loc) => Ok((loc, self.pre_investings.index(loc))), + Ok(loc) => Ok((loc, self.pre_investings[loc])), Err(loc) => Err(loc), } } @@ -166,13 +174,16 @@ impl> existing.1.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; let _ = self .pre_investings - .try_insert(existing.0, Bond { owner: account, amount: new_balance }) + .try_insert(existing.0, Bond { owner: account.clone(), amount: new_balance }) .map_err(|_| Error::::InvestingPoolOversized)?; }, Err(potential_index) => { let _ = self .pre_investings - .try_insert(potential_index, Bond { owner: account, amount }) + .try_insert( + potential_index, + Bond { owner: account.clone(), amount: amount.clone() }, + ) .map_err(|_| Error::::InvestingPoolOversized)?; }, } @@ -218,7 +229,7 @@ impl> let left_amount = amount - existing_q.1; - if let Some(existing_p) = self.get_pre_investing(account) { + if let Ok(existing_p) = self.get_pre_investing(account) { // Existing pre-investing is larger than left target amount // Finish withdrawing and return early if existing_p.1 > left_amount { @@ -248,13 +259,13 @@ impl> return Ok(()); } else { // Not enough fund to finish operation - return Err(Error::::InsufficientPreInvesting); + return Err(Error::::InsufficientPreInvesting.into()); } } } } // No pre-investing of all kinds - return Err(Error::::InsufficientPreInvesting); + return Err(Error::::InsufficientPreInvesting.into()); } pub fn get_queued_investing( @@ -267,8 +278,8 @@ impl> { Ok(loc) => Ok(( loc, - self.queued_pre_investings.index(loc).0.amount, - self.queued_pre_investings.index(loc).1, + self.queued_pre_investings[loc].0.amount, + self.queued_pre_investings[loc].1, )), Err(loc) => Err(loc), } @@ -280,7 +291,7 @@ impl> amount: Balance, current_block: BlockNumber, ) -> Result<(), DispatchError> { - match self.get_queued_investing(account) { + match self.get_queued_investing(account.clone()) { Ok(existing) => { self.queued_pre_investings.remove(existing.0); let new_balance = @@ -289,14 +300,17 @@ impl> .queued_pre_investings .try_insert( existing.0, - (Bond { owner: account, amount: new_balance }, current_block), + (Bond { owner: account.clone(), amount: new_balance }, current_block), ) .map_err(|_| Error::::InvestingPoolOversized)?; }, Err(potential_index) => { let _ = self .queued_pre_investings - .try_insert(potential_index, (Bond { owner: account, amount }, current_block)) + .try_insert( + potential_index, + (Bond { owner: account, amount: amount.clone() }, current_block), + ) .map_err(|_| Error::::InvestingPoolOversized)?; }, } @@ -315,7 +329,7 @@ impl> ensure!( self.total_queued_amount >= target_pre_investing_amount - .checked_sub(self.total_pre_investing_amount) + .checked_sub(&self.total_pre_investing_amount) .ok_or(ArithmeticError::Overflow)?, Error::::InsufficientPreInvesting ); @@ -326,7 +340,7 @@ impl> for i in v.iter() { let transfer_amount = target_pre_investing_amount - .checked_sub(self.total_pre_investing_amount) + .checked_sub(&self.total_pre_investing_amount) .ok_or(ArithmeticError::Overflow)?; if i.0.amount >= transfer_amount { let _ = self.withdraw(i.0.owner, transfer_amount)?; From ec2c668f657211166b53e6c7ec927a14971f8edb Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 3 Oct 2024 16:33:19 +0800 Subject: [PATCH 040/215] chore: fix --- .../collab-ai/pool-proposal/src/lib.rs | 21 ++++++++++++------- .../collab-ai/pool-proposal/src/types.rs | 9 ++++---- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index d7b2ca3e71..df9de93d0e 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -30,7 +30,10 @@ use frame_support::{ ensure, pallet_prelude::*, traits::{ - tokens::{fungibles::Inspect as FsInspect, Mutate as FsMutate, Preservation}, + tokens::{ + fungibles::{Inspect as FsInspect, Mutate as FsMutate}, + Preservation, + }, Currency, EnsureOrigin, Get, LockIdentifier, LockableCurrency, ReservableCurrency, }, transactional, @@ -247,6 +250,8 @@ pub mod pallet { // Check proposal expire by order // Mature the pool by proposal if qualified, refund/transfer all money based on investing pool logic + + Weight::zero() } } @@ -290,7 +295,7 @@ pub mod pallet { .ok_or(ArithmeticError::Overflow)?; let new_proposal_info = PoolProposalInfo { - proposer: who, + proposer: who.clone(), pool_info_hash, max_pool_size, pool_start_time, @@ -416,12 +421,12 @@ pub mod pallet { if target_pre_investing_amount == pool_proposal.max_pool_size { pool_proposal.proposal_status_flags = pool_proposal.proposal_status_flags | ProposalStatusFlags::STAKE_AMOUNT_PASSED; - >::put(pool_proposal_index, pool_proposal); + >::insert(pool_proposal_index, pool_proposal); } } else { // Partially let queued_pre_investing_amount = target_pre_investing_amount - .checked_sub(pool_proposal.max_pool_size) + .checked_sub(&pool_proposal.max_pool_size) .ok_or(ArithmeticError::Overflow)?; pool_proposal_pre_investing.add_queued_investing::( who, @@ -445,7 +450,7 @@ pub mod pallet { pool_proposal.proposal_status_flags = pool_proposal.proposal_status_flags | ProposalStatusFlags::STAKE_AMOUNT_PASSED; - >::put(pool_proposal_index, pool_proposal); + >::insert(pool_proposal_index, pool_proposal); } // Emit events @@ -456,7 +461,7 @@ pub mod pallet { }); } - >::put(pool_proposal_index, pool_proposal_pre_investing); + >::insert(pool_proposal_index, pool_proposal_pre_investing); Ok(()) } @@ -518,7 +523,7 @@ pub mod pallet { Preservation::Expendable, )?; - >::put(pool_proposal_index, pool_proposal_pre_investing); + >::insert(pool_proposal_index, pool_proposal_pre_investing); Ok(()) } @@ -543,7 +548,7 @@ pub mod pallet { pool_proposal.proposal_status_flags = pool_proposal.proposal_status_flags & !ProposalStatusFlags::PUBLIC_VOTE_PASSED; } - >::put(pool_proposal_index, pool_proposal); + >::insert(pool_proposal_index, pool_proposal); Self::deposit_event(Event::ProposalPublicVoted { pool_proposal_index, diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index df0226c765..27c5a7aa40 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -138,9 +138,8 @@ pub struct PoolProposalPreInvesting } impl< - AccountId: Ord, - Balance: Default + CheckedAdd + CheckedSub, - PartialOrd, + AccountId: Ord + Clone, + Balance: Default + CheckedAdd + CheckedSub + PartialOrd + Copy, BlockNumber, S: Get, > PoolProposalPreInvesting @@ -157,7 +156,7 @@ impl< pub fn get_pre_investing(&self, account: AccountId) -> Result<(usize, Balance), usize> { match self.pre_investings.binary_search(&Bond::from_owner(account)) { - Ok(loc) => Ok((loc, self.pre_investings[loc])), + Ok(loc) => Ok((loc, self.pre_investings[loc].1)), Err(loc) => Err(loc), } } @@ -274,7 +273,7 @@ impl< ) -> Result<(usize, Balance, BlockNumber), usize> { match self .queued_pre_investings - .binary_search_by(|p| p.0.cmp(&Bond::from_owner(account))) + .binary_search_by(|p| p.0.cmp(&Bond::from_owner(account.clone()))) { Ok(loc) => Ok(( loc, From 04807b2aa29ceedd8cd7bc83e1588f521bfafb80 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 3 Oct 2024 17:32:07 +0800 Subject: [PATCH 041/215] chore: fix --- parachain/pallets/collab-ai/common/src/lib.rs | 2 +- .../pallets/collab-ai/curator/src/lib.rs | 12 +++++----- .../pallets/collab-ai/guardian/src/lib.rs | 2 +- .../collab-ai/pool-proposal/src/lib.rs | 12 +++++----- .../collab-ai/pool-proposal/src/types.rs | 23 ++++++++----------- 5 files changed, 24 insertions(+), 27 deletions(-) diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index 44bfff6326..37e42667b9 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -68,7 +68,7 @@ pub enum CandidateStatus { Banned, } -#[derive(PartialEq, Eq, Clone, Default, Encode, Decode, Debug, MaxEncodedLen, TypeInfo)] +#[derive(PartialEq, Eq, Copy, Clone, Default, Encode, Decode, Debug, MaxEncodedLen, TypeInfo)] pub enum GuardianVote { /// Does not care if this guardian get selected /// Please be aware Neutral will increase participate percentage diff --git a/parachain/pallets/collab-ai/curator/src/lib.rs b/parachain/pallets/collab-ai/curator/src/lib.rs index fe8a015e7f..c9ecf21603 100644 --- a/parachain/pallets/collab-ai/curator/src/lib.rs +++ b/parachain/pallets/collab-ai/curator/src/lib.rs @@ -146,7 +146,7 @@ pub mod pallet { PublicCuratorToIndex::::insert(&who, next_curator_index); CuratorIndexToInfo::::insert( &next_curator_index, - (info_hash, current_block, wh.clone(), CandidateStatus::Unverified), + (info_hash, current_block, who.clone(), CandidateStatus::Unverified), ); PublicCuratorCount::::put( next_curator_index.checked_add(1u32.into()).ok_or(ArithmeticError::Overflow)?, @@ -175,7 +175,7 @@ pub mod pallet { CuratorIndexToInfo::::try_mutate_exists( curator_index, |maybe_info| -> Result<(), DispatchError> { - let mut info = maybe_info.as_mut().ok_or(Error::::CuratorIndexNotExist)?; + let info = maybe_info.as_mut().ok_or(Error::::CuratorIndexNotExist)?; if info.3 == CandidateStatus::Banned { T::Currency::reserve(&who, T::MinimumCuratorDeposit::get())?; @@ -220,7 +220,7 @@ pub mod pallet { // Delete item *maybe_info = None; - Self::deposit_event(Event::CuratorCleaned { curator, curator_index }); + Self::deposit_event(Event::CuratorCleaned { curator: who, curator_index }); Ok(()) }, )?; @@ -235,12 +235,12 @@ pub mod pallet { status: CandidateStatus, ) -> DispatchResult { T::CuratorJudgeOrigin::ensure_origin(origin)?; - let curator_index = - PublicCuratorToIndex::::get(curator).ok_or(Error::::CuratorNotRegistered)?; + let curator_index = PublicCuratorToIndex::::get(curator.clone()) + .ok_or(Error::::CuratorNotRegistered)?; CuratorIndexToInfo::::try_mutate_exists( curator_index, |maybe_info| -> Result<(), DispatchError> { - let mut info = maybe_info.as_mut().ok_or(Error::::CuratorIndexNotExist)?; + let info = maybe_info.as_mut().ok_or(Error::::CuratorIndexNotExist)?; // Update block number info.1 = frame_system::Pallet::::block_number(); // Update status diff --git a/parachain/pallets/collab-ai/guardian/src/lib.rs b/parachain/pallets/collab-ai/guardian/src/lib.rs index b1bf8bebad..8b63673b98 100644 --- a/parachain/pallets/collab-ai/guardian/src/lib.rs +++ b/parachain/pallets/collab-ai/guardian/src/lib.rs @@ -238,7 +238,7 @@ pub mod pallet { GuardianIndexToInfo::::try_mutate_exists( guardian_index, |maybe_info| -> Result<(), DispatchError> { - let info = maybe_info.ok_or(Error::::GuardianIndexNotExist)?; + let info = maybe_info.as_ref().ok_or(Error::::GuardianIndexNotExist)?; if info.3 != CandidateStatus::Banned { let _ = T::Currency::unreserve(&who, T::MinimumGuardianDeposit::get()); diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index df9de93d0e..d768d87f7d 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -374,8 +374,8 @@ pub mod pallet { let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( T::AIUSDAssetId::get(), - who, - T::PreInvestingPool::get(), + &who, + &T::PreInvestingPool::get(), amount, Preservation::Expendable, )?; @@ -404,7 +404,7 @@ pub mod pallet { let target_pre_investing_amount = pool_proposal_pre_investing .total_pre_investing_amount - .checked_add(asset_actual_transfer_amount) + .checked_add(&asset_actual_transfer_amount) .ok_or(ArithmeticError::Overflow)?; if target_pre_investing_amount <= pool_proposal.max_pool_size { // take all pre-investing into valid pre-investing line @@ -437,7 +437,7 @@ pub mod pallet { // If pool not already full, flag proposal status if asset_actual_transfer_amount > queued_pre_investing_amount { let actual_pre_investing_amount = asset_actual_transfer_amount - .checked_sub(queued_pre_investing_amount) + .checked_sub(&queued_pre_investing_amount) .ok_or(ArithmeticError::Overflow)?; pool_proposal_pre_investing .add_pre_investing::(who, actual_pre_investing_amount)?; @@ -517,8 +517,8 @@ pub mod pallet { // Return funds let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( T::AIUSDAssetId::get(), - T::PreInvestingPool::get(), - who, + &T::PreInvestingPool::get(), + &who, amount, Preservation::Expendable, )?; diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index 27c5a7aa40..16aa811f53 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -59,13 +59,13 @@ bitflags! { } } -#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] +#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, MaxEncodedLen, TypeInfo)] pub struct PoolProposalStatus { pub pool_proposal_index: PoolProposalIndex, pub proposal_expire_time: BlockNumber, } -#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] +#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, MaxEncodedLen, TypeInfo)] pub struct PoolProposalInfo { // Proposer/Curator pub proposer: AccountId, @@ -126,7 +126,7 @@ impl PartialEq for Bond { } } -#[derive(Clone, Encode, Debug, Decode, TypeInfo)] +#[derive(Clone, Encode, Debug, Decode, MaxEncodedLen, TypeInfo)] pub struct PoolProposalPreInvesting> { // Exluding queued part pub total_pre_investing_amount: Balance, @@ -156,7 +156,7 @@ impl< pub fn get_pre_investing(&self, account: AccountId) -> Result<(usize, Balance), usize> { match self.pre_investings.binary_search(&Bond::from_owner(account)) { - Ok(loc) => Ok((loc, self.pre_investings[loc].1)), + Ok(loc) => Ok((loc, self.pre_investings[loc].amount)), Err(loc) => Err(loc), } } @@ -166,7 +166,7 @@ impl< account: AccountId, amount: Balance, ) -> Result<(), DispatchError> { - match self.get_pre_investing(account) { + match self.get_pre_investing(account.clone()) { Ok(existing) => { self.pre_investings.remove(existing.0); let new_balance = @@ -179,10 +179,7 @@ impl< Err(potential_index) => { let _ = self .pre_investings - .try_insert( - potential_index, - Bond { owner: account.clone(), amount: amount.clone() }, - ) + .try_insert(potential_index, Bond { owner: account, amount: amount.clone() }) .map_err(|_| Error::::InvestingPoolOversized)?; }, } @@ -199,7 +196,7 @@ impl< amount: Balance, ) -> Result<(), DispatchError> { // Withdraw Queued one if any - if let Ok(existing_q) = self.get_queued_investing(account) { + if let Ok(existing_q) = self.get_queued_investing(account.clone()) { if existing_q.1 > amount { // Existing queue is larger than target amount // Finish withdrawing and return early @@ -228,7 +225,7 @@ impl< let left_amount = amount - existing_q.1; - if let Ok(existing_p) = self.get_pre_investing(account) { + if let Ok(existing_p) = self.get_pre_investing(account.clone()) { // Existing pre-investing is larger than left target amount // Finish withdrawing and return early if existing_p.1 > left_amount { @@ -278,7 +275,7 @@ impl< Ok(loc) => Ok(( loc, self.queued_pre_investings[loc].0.amount, - self.queued_pre_investings[loc].1, + self.queued_pre_investings[loc].1.clone(), )), Err(loc) => Err(loc), } @@ -333,7 +330,7 @@ impl< Error::::InsufficientPreInvesting ); - let mut v = self.queued_pre_investings.into_inner().clone(); + let mut v = self.queued_pre_investings.clone().into_inner(); // temp sorted by blocknumber v.sort_by(|p| p.2); From 9ab1899676048478b5504598838916ac2c9d80bf Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 3 Oct 2024 17:53:58 +0800 Subject: [PATCH 042/215] chore: fix --- parachain/pallets/collab-ai/curator/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/curator/src/lib.rs b/parachain/pallets/collab-ai/curator/src/lib.rs index c9ecf21603..87befabc9e 100644 --- a/parachain/pallets/collab-ai/curator/src/lib.rs +++ b/parachain/pallets/collab-ai/curator/src/lib.rs @@ -212,7 +212,7 @@ pub mod pallet { CuratorIndexToInfo::::try_mutate_exists( curator_index, |maybe_info| -> Result<(), DispatchError> { - let info = maybe_info.ok_or(Error::::CuratorIndexNotExist)?; + let info = maybe_info.as_ref().ok_or(Error::::CuratorIndexNotExist)?; if info.3 != CandidateStatus::Banned { let _ = T::Currency::unreserve(&who, T::MinimumCuratorDeposit::get()); From db47094cab8c746ec9a5f1c1ad21f0f176defe9d Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 3 Oct 2024 18:58:10 +0800 Subject: [PATCH 043/215] chore: fix --- .../pallets/collab-ai/pool-proposal/src/lib.rs | 17 +++++++++++------ .../collab-ai/pool-proposal/src/types.rs | 9 +++++++-- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index d768d87f7d..dbb26e8c2b 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -48,7 +48,7 @@ use frame_system::{ use orml_utilities::OrderedSet; pub use pallet::*; use pallet_collab_ai_common::*; -use parity_scale_codec::Encode; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use sp_runtime::{ traits::{AccountIdConversion, CheckedAdd, CheckedSub}, ArithmeticError, @@ -84,6 +84,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] + #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] @@ -385,7 +386,7 @@ pub mod pallet { // Check pool maximum size limit and make pool size limit flag change accordingly let mut pool_proposal = - PoolProposal::get(pool_proposal_index).ok_or(Error::::ProposalNotExist)?; + >::get(pool_proposal_index).ok_or(Error::::ProposalNotExist)?; // Proposal not expired ensure!( !pool_proposal @@ -480,7 +481,7 @@ pub mod pallet { let mut pool_proposal_pre_investing = >::take(pool_proposal_index) .unwrap_or(PoolProposalPreInvesting::new()); - let mut pool_proposal = + let pool_proposal = >::get(pool_proposal_index).ok_or(Error::::ProposalNotExist)?; // Either investing pool has not locked yet, // Or queued amount is enough to replace the withdrawal @@ -492,8 +493,12 @@ pub mod pallet { Error::::ProposalPreInvestingLocked ); - let _ = pool_proposal_pre_investing.withdraw::(who, amount)?; - Self::deposit_event(Event::PoolWithdrawed { user: who, pool_proposal_index, amount }); + let _ = pool_proposal_pre_investing.withdraw::(who.clone(), amount)?; + Self::deposit_event(Event::PoolWithdrawed { + user: who.clone(), + pool_proposal_index, + amount, + }); // Make queued amount fill the missing Investing amount if pool Investing flag ever reached if (pool_proposal_pre_investing.total_pre_investing_amount @@ -507,7 +512,7 @@ pub mod pallet { for i in moved_bonds.iter() { // Emit events Self::deposit_event(Event::PoolQueuedInvested { - user: i.owner, + user: i.owner.clone(), pool_proposal_index, amount: i.amount, }); diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index 16aa811f53..a021825ca6 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -127,7 +127,12 @@ impl PartialEq for Bond { } #[derive(Clone, Encode, Debug, Decode, MaxEncodedLen, TypeInfo)] -pub struct PoolProposalPreInvesting> { +pub struct PoolProposalPreInvesting< + AccountId, + Balance, + BlockNumber, + S: Get + scale_info::StaticTypeInfo, +> { // Exluding queued part pub total_pre_investing_amount: Balance, // Ordered by bond owner AccountId @@ -140,7 +145,7 @@ pub struct PoolProposalPreInvesting impl< AccountId: Ord + Clone, Balance: Default + CheckedAdd + CheckedSub + PartialOrd + Copy, - BlockNumber, + BlockNumber: Clone, S: Get, > PoolProposalPreInvesting { From 25c492e10e6d6351a0d54a63349951c5049ab60f Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 3 Oct 2024 19:10:52 +0800 Subject: [PATCH 044/215] chore: revert type info --- parachain/pallets/collab-ai/pool-proposal/src/types.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index a021825ca6..4145a42272 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -127,12 +127,7 @@ impl PartialEq for Bond { } #[derive(Clone, Encode, Debug, Decode, MaxEncodedLen, TypeInfo)] -pub struct PoolProposalPreInvesting< - AccountId, - Balance, - BlockNumber, - S: Get + scale_info::StaticTypeInfo, -> { +pub struct PoolProposalPreInvesting> { // Exluding queued part pub total_pre_investing_amount: Balance, // Ordered by bond owner AccountId From ef18b2067a5bd765601e8b3209a34f923e3ce9a8 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 3 Oct 2024 19:13:29 +0800 Subject: [PATCH 045/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/types.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index 4145a42272..ad27712a59 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -127,7 +127,12 @@ impl PartialEq for Bond { } #[derive(Clone, Encode, Debug, Decode, MaxEncodedLen, TypeInfo)] -pub struct PoolProposalPreInvesting> { +pub struct PoolProposalPreInvesting< + AccountId, + Balance, + BlockNumber, + S: Get + scale_info::TypeInfo, +> { // Exluding queued part pub total_pre_investing_amount: Balance, // Ordered by bond owner AccountId From 0f1bfec6c69635f6fea24fb15fbc288ac45d68e1 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 3 Oct 2024 20:32:39 +0800 Subject: [PATCH 046/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/types.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index ad27712a59..4145a42272 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -127,12 +127,7 @@ impl PartialEq for Bond { } #[derive(Clone, Encode, Debug, Decode, MaxEncodedLen, TypeInfo)] -pub struct PoolProposalPreInvesting< - AccountId, - Balance, - BlockNumber, - S: Get + scale_info::TypeInfo, -> { +pub struct PoolProposalPreInvesting> { // Exluding queued part pub total_pre_investing_amount: Balance, // Ordered by bond owner AccountId From ccf804b1f69782da11545df0ff8a6d006c9c137f Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 3 Oct 2024 22:30:18 +0800 Subject: [PATCH 047/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 10 +++++----- parachain/pallets/collab-ai/pool-proposal/src/types.rs | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index dbb26e8c2b..709b88cd61 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -410,11 +410,11 @@ pub mod pallet { if target_pre_investing_amount <= pool_proposal.max_pool_size { // take all pre-investing into valid pre-investing line pool_proposal_pre_investing - .add_pre_investing::(who, asset_actual_transfer_amount)?; + .add_pre_investing::(who.clone(), asset_actual_transfer_amount)?; // Emit event only Self::deposit_event(Event::PoolPreInvested { - user: who, + user: who.clone(), pool_proposal_index, amount: asset_actual_transfer_amount, }); @@ -430,7 +430,7 @@ pub mod pallet { .checked_sub(&pool_proposal.max_pool_size) .ok_or(ArithmeticError::Overflow)?; pool_proposal_pre_investing.add_queued_investing::( - who, + who.clone(), queued_pre_investing_amount, frame_system::Pallet::::block_number(), )?; @@ -441,10 +441,10 @@ pub mod pallet { .checked_sub(&queued_pre_investing_amount) .ok_or(ArithmeticError::Overflow)?; pool_proposal_pre_investing - .add_pre_investing::(who, actual_pre_investing_amount)?; + .add_pre_investing::(who.clone(), actual_pre_investing_amount)?; Self::deposit_event(Event::PoolPreInvested { - user: who, + user: who.clone(), pool_proposal_index, amount: actual_pre_investing_amount, }); diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index 4145a42272..bf7d472ee9 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -127,6 +127,7 @@ impl PartialEq for Bond { } #[derive(Clone, Encode, Debug, Decode, MaxEncodedLen, TypeInfo)] +#[scale_info(skip_type_params(S))] pub struct PoolProposalPreInvesting> { // Exluding queued part pub total_pre_investing_amount: Balance, From 8e247e0d33fc84186def15d8a588fb860e3e7954 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 3 Oct 2024 22:53:48 +0800 Subject: [PATCH 048/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 5 ++--- parachain/pallets/collab-ai/pool-proposal/src/types.rs | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 709b88cd61..ff6b329575 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -48,7 +48,6 @@ use frame_system::{ use orml_utilities::OrderedSet; pub use pallet::*; use pallet_collab_ai_common::*; -use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use sp_runtime::{ traits::{AccountIdConversion, CheckedAdd, CheckedSub}, ArithmeticError, @@ -247,7 +246,7 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { - fn on_initialize(n: BlockNumberFor) -> Weight { + fn on_initialize(_n: BlockNumberFor) -> Weight { // Check proposal expire by order // Mature the pool by proposal if qualified, refund/transfer all money based on investing pool logic @@ -520,7 +519,7 @@ pub mod pallet { } // Return funds - let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( + let _asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( T::AIUSDAssetId::get(), &T::PreInvestingPool::get(), &who, diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index bf7d472ee9..823a4774c9 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -332,8 +332,8 @@ impl< ); let mut v = self.queued_pre_investings.clone().into_inner(); - // temp sorted by blocknumber - v.sort_by(|p| p.2); + // temp sorted by blocknumber from smallest to largest + v.sort_by(|a, b| a.2.cmp(b.2)); for i in v.iter() { let transfer_amount = target_pre_investing_amount From d6f81e5388fc546b90d1cc7148b9219b99a93cb2 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 3 Oct 2024 23:23:10 +0800 Subject: [PATCH 049/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index 823a4774c9..050218fbda 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -333,7 +333,7 @@ impl< let mut v = self.queued_pre_investings.clone().into_inner(); // temp sorted by blocknumber from smallest to largest - v.sort_by(|a, b| a.2.cmp(b.2)); + v.sort_by(|a, b| a.1.cmp(&b.1)); for i in v.iter() { let transfer_amount = target_pre_investing_amount From 11717992e7ffd7601b8de0834617539ea848e8f8 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 3 Oct 2024 23:36:00 +0800 Subject: [PATCH 050/215] chore: fix --- parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs | 4 ++-- parachain/pallets/collab-ai/pool-proposal/src/types.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index 7ed2a20d3d..8e052c95de 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -140,7 +140,7 @@ pub mod pallet { >::mint_into(aiusd_id, &beneficiary, aiusd_amount)?; // Maybe it is better to save decimal of AIUSD somewhere - let aiusd_deciaml_unit_expression: T::Balance = 10.pow(18).try_into()?; + let aiusd_deciaml_unit_expression: T::Balance = 10u128.pow(18).try_into()?; let aseet_target_transfer_amount = aiusd_minted_amount .checked_mul(&ratio) .ok_or(Error::::Overflow)? @@ -199,7 +199,7 @@ pub mod pallet { let aseet_target_transfer_amount = aiusd_destroyed_amount .checked_mul(&ratio) .ok_or(Error::::Overflow)? - .checked_div(10.pow(18)) + .checked_div(10u128.pow(18)) .ok_or(Error::::Overflow)?; let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index 050218fbda..12776ab6f8 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -141,7 +141,7 @@ pub struct PoolProposalPreInvesting impl< AccountId: Ord + Clone, Balance: Default + CheckedAdd + CheckedSub + PartialOrd + Copy, - BlockNumber: Clone, + BlockNumber: Ord + Clone, S: Get, > PoolProposalPreInvesting { From 19b2a43355c27fdb54bc0606ff4b388b877ac9c4 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 4 Oct 2024 00:00:32 +0800 Subject: [PATCH 051/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/types.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index 12776ab6f8..554b3e8027 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -321,7 +321,7 @@ impl< &mut self, target_pre_investing_amount: Balance, ) -> Result>, DispatchError> { - let result: Vec> = Vec::new(); + let mut result: Vec> = Vec::new(); // Make sure target transfer is possible ensure!( self.total_queued_amount @@ -340,13 +340,13 @@ impl< .checked_sub(&self.total_pre_investing_amount) .ok_or(ArithmeticError::Overflow)?; if i.0.amount >= transfer_amount { - let _ = self.withdraw(i.0.owner, transfer_amount)?; - self.add_pre_investing(i.0.owner, transfer_amount)?; + let _ = self.withdraw::(i.0.owner, transfer_amount)?; + self.add_pre_investing::(i.0.owner, transfer_amount)?; result.push(Bond { owner: i.0.owner, amount: transfer_amount }); break; } else { - let _ = self.withdraw(i.0.owner, i.0.amount)?; - self.add_pre_investing(i.0.owner, i.0.amount)?; + let _ = self.withdraw::(i.0.owner, i.0.amount)?; + self.add_pre_investing::(i.0.owner, i.0.amount)?; result.push(Bond { owner: i.0.owner, amount: i.0.amount }); } } From dbf33f0f0321e3e9646b53308f23fb5fbac23c05 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 4 Oct 2024 00:16:35 +0800 Subject: [PATCH 052/215] chore: fix --- .../pallets/collab-ai/pool-proposal/src/types.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index 554b3e8027..390940f888 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -336,18 +336,19 @@ impl< v.sort_by(|a, b| a.1.cmp(&b.1)); for i in v.iter() { + let target_bond_owner = i.0.owner.as_ref(); let transfer_amount = target_pre_investing_amount .checked_sub(&self.total_pre_investing_amount) .ok_or(ArithmeticError::Overflow)?; if i.0.amount >= transfer_amount { - let _ = self.withdraw::(i.0.owner, transfer_amount)?; - self.add_pre_investing::(i.0.owner, transfer_amount)?; - result.push(Bond { owner: i.0.owner, amount: transfer_amount }); + let _ = self.withdraw::(target_bond_owner, transfer_amount)?; + self.add_pre_investing::(target_bond_owner, transfer_amount)?; + result.push(Bond { owner: target_bond_owner, amount: transfer_amount }); break; } else { - let _ = self.withdraw::(i.0.owner, i.0.amount)?; - self.add_pre_investing::(i.0.owner, i.0.amount)?; - result.push(Bond { owner: i.0.owner, amount: i.0.amount }); + let _ = self.withdraw::(target_bond_owner, i.0.amount)?; + self.add_pre_investing::(target_bond_owner, i.0.amount)?; + result.push(Bond { owner: target_bond_owner, amount: i.0.amount }); } } From 0bbff9881e270a8ffe18493c5ed8abd203f412be Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 4 Oct 2024 00:33:39 +0800 Subject: [PATCH 053/215] chore: fix --- parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs | 5 +++-- parachain/pallets/collab-ai/pool-proposal/src/types.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index 8e052c95de..a3239409eb 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -140,7 +140,8 @@ pub mod pallet { >::mint_into(aiusd_id, &beneficiary, aiusd_amount)?; // Maybe it is better to save decimal of AIUSD somewhere - let aiusd_deciaml_unit_expression: T::Balance = 10u128.pow(18).try_into()?; + let aiusd_deciaml_unit_expression: T::Balance = + 10u128.pow(18).try_into().or(Error::::Overflow)?; let aseet_target_transfer_amount = aiusd_minted_amount .checked_mul(&ratio) .ok_or(Error::::Overflow)? @@ -199,7 +200,7 @@ pub mod pallet { let aseet_target_transfer_amount = aiusd_destroyed_amount .checked_mul(&ratio) .ok_or(Error::::Overflow)? - .checked_div(10u128.pow(18)) + .checked_div(10u128.pow(18).try_into().or(Error::::Overflow)?) .ok_or(Error::::Overflow)?; let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index 390940f888..a92a3e0505 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -139,7 +139,7 @@ pub struct PoolProposalPreInvesting } impl< - AccountId: Ord + Clone, + AccountId: Ord + Clone + AsRef, Balance: Default + CheckedAdd + CheckedSub + PartialOrd + Copy, BlockNumber: Ord + Clone, S: Get, From 9d7386af7a52d58bc1497c1dfe8d0b7bd9d1d70c Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 4 Oct 2024 00:53:18 +0800 Subject: [PATCH 054/215] chore: fix --- .../pallets/collab-ai/aiusd-convertor/src/lib.rs | 4 ++-- .../pallets/collab-ai/pool-proposal/src/types.rs | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index a3239409eb..07db52f2ff 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -141,7 +141,7 @@ pub mod pallet { // Maybe it is better to save decimal of AIUSD somewhere let aiusd_deciaml_unit_expression: T::Balance = - 10u128.pow(18).try_into().or(Error::::Overflow)?; + 10u32.pow(18).try_into().or(Err(Error::::Overflow))?; let aseet_target_transfer_amount = aiusd_minted_amount .checked_mul(&ratio) .ok_or(Error::::Overflow)? @@ -200,7 +200,7 @@ pub mod pallet { let aseet_target_transfer_amount = aiusd_destroyed_amount .checked_mul(&ratio) .ok_or(Error::::Overflow)? - .checked_div(10u128.pow(18).try_into().or(Error::::Overflow)?) + .checked_div(10u32.pow(18).try_into().or(Err(Error::::Overflow))?) .ok_or(Error::::Overflow)?; let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index a92a3e0505..da823bab2e 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -139,7 +139,7 @@ pub struct PoolProposalPreInvesting } impl< - AccountId: Ord + Clone + AsRef, + AccountId: Ord + Clone, Balance: Default + CheckedAdd + CheckedSub + PartialOrd + Copy, BlockNumber: Ord + Clone, S: Get, @@ -336,18 +336,18 @@ impl< v.sort_by(|a, b| a.1.cmp(&b.1)); for i in v.iter() { - let target_bond_owner = i.0.owner.as_ref(); + let target_bond_owner = i.0.owner.clone(); let transfer_amount = target_pre_investing_amount .checked_sub(&self.total_pre_investing_amount) .ok_or(ArithmeticError::Overflow)?; if i.0.amount >= transfer_amount { - let _ = self.withdraw::(target_bond_owner, transfer_amount)?; - self.add_pre_investing::(target_bond_owner, transfer_amount)?; - result.push(Bond { owner: target_bond_owner, amount: transfer_amount }); + let _ = self.withdraw::(target_bond_owner.clone(), transfer_amount)?; + self.add_pre_investing::(target_bond_owner.clone(), transfer_amount)?; + result.push(Bond { owner: target_bond_owner.clone(), amount: transfer_amount }); break; } else { - let _ = self.withdraw::(target_bond_owner, i.0.amount)?; - self.add_pre_investing::(target_bond_owner, i.0.amount)?; + let _ = self.withdraw::(target_bond_owner.clone(), i.0.amount)?; + self.add_pre_investing::(target_bond_owner.clone(), i.0.amount)?; result.push(Bond { owner: target_bond_owner, amount: i.0.amount }); } } From fe7df1be2f42f5462c597807659c1ff4bd143fca Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 4 Oct 2024 01:24:14 +0800 Subject: [PATCH 055/215] chore: fix --- parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs | 10 ++++++---- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 7 +++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index 07db52f2ff..8da2cf4fc5 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -131,7 +131,7 @@ pub mod pallet { ); let aiusd_id = T::AIUSDAssetId::get(); ensure!( - InspectFungibles::::asset_exists(aiusd_id) + InspectFungibles::::asset_exists(aiusd_id.clone()) && InspectFungibles::::asset_exists(target_asset_id), Error::::InvalidAssetId ); @@ -141,7 +141,7 @@ pub mod pallet { // Maybe it is better to save decimal of AIUSD somewhere let aiusd_deciaml_unit_expression: T::Balance = - 10u32.pow(18).try_into().or(Err(Error::::Overflow))?; + 10u128.pow(18).try_into().or(Err(Error::::Overflow))?; let aseet_target_transfer_amount = aiusd_minted_amount .checked_mul(&ratio) .ok_or(Error::::Overflow)? @@ -149,7 +149,7 @@ pub mod pallet { .ok_or(Error::::Overflow)?; let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( - target_asset_id, + target_asset_id.clone(), &beneficiary, &T::ConvertingFeeAccount::get(), aseet_target_transfer_amount, @@ -197,10 +197,12 @@ pub mod pallet { )?; // Maybe it is better to save decimal of AIUSD somewhere + let aiusd_deciaml_unit_expression: T::Balance = + 10u128.pow(18).try_into().or(Err(Error::::Overflow))?; let aseet_target_transfer_amount = aiusd_destroyed_amount .checked_mul(&ratio) .ok_or(Error::::Overflow)? - .checked_div(10u32.pow(18).try_into().or(Err(Error::::Overflow))?) + .checked_div(&aiusd_deciaml_unit_expression) .ok_or(Error::::Overflow)?; let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index ff6b329575..77b481f757 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -308,7 +308,7 @@ pub mod pallet { let next_proposal_index = PoolProposalCount::::get(); PoolProposal::::insert(next_proposal_index, new_proposal_info); - PoolProposalDepositOf::::try_mutate_exists( + let _ = PoolProposalDepositOf::::try_mutate_exists( &who, |maybe_ordered_set| -> Result<(), DispatchError> { let reserved_amount = T::MinimumPoolDeposit::get(); @@ -340,7 +340,7 @@ pub mod pallet { }, } }, - ); + )?; >::mutate(|pending_porposals| { let new_proposal_status = PoolProposalStatus { pool_proposal_index: next_proposal_index, @@ -596,8 +596,7 @@ pub mod pallet { }, } }, - ); - Ok(()) + ) } } From 3b5f7a5913811b1be96e7b01339c3492aa18ea8b Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 4 Oct 2024 01:25:18 +0800 Subject: [PATCH 056/215] chore: fix --- parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index 8da2cf4fc5..dcdca9f5e4 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -132,7 +132,7 @@ pub mod pallet { let aiusd_id = T::AIUSDAssetId::get(); ensure!( InspectFungibles::::asset_exists(aiusd_id.clone()) - && InspectFungibles::::asset_exists(target_asset_id), + && InspectFungibles::::asset_exists(target_asset_id.clone()), Error::::InvalidAssetId ); // It will fail if insufficient fund From 7eff2d1bc2277f68adcd8f6796cb070850b53fee Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 4 Oct 2024 01:34:38 +0800 Subject: [PATCH 057/215] chore: fix --- parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index dcdca9f5e4..d0ca50b08d 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -183,8 +183,8 @@ pub mod pallet { if let Some(ratio) = EnabledTokens::::get(&target_asset_id) { let aiusd_id = T::AIUSDAssetId::get(); ensure!( - InspectFungibles::::asset_exists(aiusd_id) - && InspectFungibles::::asset_exists(target_asset_id), + InspectFungibles::::asset_exists(aiusd_id.clone()) + && InspectFungibles::::asset_exists(target_asset_id.clone()), Error::::InvalidAssetId ); // It will fail if insufficient fund @@ -206,7 +206,7 @@ pub mod pallet { .ok_or(Error::::Overflow)?; let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( - target_asset_id, + target_asset_id.clone(), &T::ConvertingFeeAccount::get(), &beneficiary, aseet_target_transfer_amount, From 4a9c63905f22e37e6506880121597ac82bebc34f Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 4 Oct 2024 02:07:37 +0800 Subject: [PATCH 058/215] chore: fix clippy --- .../collab-ai/pool-proposal/src/lib.rs | 25 +++++-------- .../collab-ai/pool-proposal/src/types.rs | 37 +++++++++++-------- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 77b481f757..73ca434a63 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -23,7 +23,7 @@ //! //! The Pool Proposal handles the administration of proposed investing pool and pre-investing. #![cfg_attr(not(feature = "std"), no_std)] - +#![allow(clippy::type_complexity)] pub mod types; use frame_support::{ @@ -56,9 +56,6 @@ use sp_std::collections::vec_deque::VecDeque; pub use types::*; -pub(crate) const POOL_DEMOCRACY_ID: LockIdentifier = *b"spdemocy"; -pub(crate) const POOL_COMMITTEE_ID: LockIdentifier = *b"spcomtte"; - pub(crate) type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -308,11 +305,11 @@ pub mod pallet { let next_proposal_index = PoolProposalCount::::get(); PoolProposal::::insert(next_proposal_index, new_proposal_info); - let _ = PoolProposalDepositOf::::try_mutate_exists( + PoolProposalDepositOf::::try_mutate_exists( &who, |maybe_ordered_set| -> Result<(), DispatchError> { let reserved_amount = T::MinimumPoolDeposit::get(); - let _ = ::Currency::reserve(&who, reserved_amount)?; + ::Currency::reserve(&who, reserved_amount)?; // We should not care about duplicating since the proposal index is auto-increment match maybe_ordered_set.as_mut() { Some(ordered_set) => { @@ -419,8 +416,7 @@ pub mod pallet { }); // Flag proposal status if pool is just fully Investing if target_pre_investing_amount == pool_proposal.max_pool_size { - pool_proposal.proposal_status_flags = pool_proposal.proposal_status_flags - | ProposalStatusFlags::STAKE_AMOUNT_PASSED; + pool_proposal.proposal_status_flags |= ProposalStatusFlags::STAKE_AMOUNT_PASSED; >::insert(pool_proposal_index, pool_proposal); } } else { @@ -448,8 +444,7 @@ pub mod pallet { amount: actual_pre_investing_amount, }); - pool_proposal.proposal_status_flags = pool_proposal.proposal_status_flags - | ProposalStatusFlags::STAKE_AMOUNT_PASSED; + pool_proposal.proposal_status_flags |= ProposalStatusFlags::STAKE_AMOUNT_PASSED; >::insert(pool_proposal_index, pool_proposal); } @@ -492,7 +487,7 @@ pub mod pallet { Error::::ProposalPreInvestingLocked ); - let _ = pool_proposal_pre_investing.withdraw::(who.clone(), amount)?; + pool_proposal_pre_investing.withdraw::(who.clone(), amount)?; Self::deposit_event(Event::PoolWithdrawed { user: who.clone(), pool_proposal_index, @@ -546,11 +541,9 @@ pub mod pallet { >::get(pool_proposal_index).ok_or(Error::::ProposalNotExist)?; if vote { - pool_proposal.proposal_status_flags = - pool_proposal.proposal_status_flags | ProposalStatusFlags::PUBLIC_VOTE_PASSED; + pool_proposal.proposal_status_flags |= ProposalStatusFlags::PUBLIC_VOTE_PASSED; } else { - pool_proposal.proposal_status_flags = - pool_proposal.proposal_status_flags & !ProposalStatusFlags::PUBLIC_VOTE_PASSED; + pool_proposal.proposal_status_flags &= !ProposalStatusFlags::PUBLIC_VOTE_PASSED; } >::insert(pool_proposal_index, pool_proposal); @@ -574,7 +567,7 @@ pub mod pallet { // Ensure guardian exists when participate, will double check if verified when mature the proposal) ensure!(T::GuardianVoteResource::is_guardian(who.clone()), Error::::GuardianInvalid); PoolGuardian::::try_mutate_exists( - &pool_proposal_index, + pool_proposal_index, |maybe_ordered_set| -> Result<(), DispatchError> { match maybe_ordered_set.as_mut() { Some(ordered_set) => { diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index da823bab2e..f13dbec3b4 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -172,15 +172,13 @@ impl< self.pre_investings.remove(existing.0); let new_balance = existing.1.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; - let _ = self - .pre_investings + self.pre_investings .try_insert(existing.0, Bond { owner: account.clone(), amount: new_balance }) .map_err(|_| Error::::InvestingPoolOversized)?; }, Err(potential_index) => { - let _ = self - .pre_investings - .try_insert(potential_index, Bond { owner: account, amount: amount.clone() }) + self.pre_investings + .try_insert(potential_index, Bond { owner: account, amount }) .map_err(|_| Error::::InvestingPoolOversized)?; }, } @@ -262,7 +260,7 @@ impl< } } // No pre-investing of all kinds - return Err(Error::::InsufficientPreInvesting.into()); + Err(Error::::InsufficientPreInvesting.into()) } pub fn get_queued_investing( @@ -293,8 +291,7 @@ impl< self.queued_pre_investings.remove(existing.0); let new_balance = existing.1.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; - let _ = self - .queued_pre_investings + self.queued_pre_investings .try_insert( existing.0, (Bond { owner: account.clone(), amount: new_balance }, current_block), @@ -302,12 +299,8 @@ impl< .map_err(|_| Error::::InvestingPoolOversized)?; }, Err(potential_index) => { - let _ = self - .queued_pre_investings - .try_insert( - potential_index, - (Bond { owner: account, amount: amount.clone() }, current_block), - ) + self.queued_pre_investings + .try_insert(potential_index, (Bond { owner: account, amount }, current_block)) .map_err(|_| Error::::InvestingPoolOversized)?; }, } @@ -341,12 +334,12 @@ impl< .checked_sub(&self.total_pre_investing_amount) .ok_or(ArithmeticError::Overflow)?; if i.0.amount >= transfer_amount { - let _ = self.withdraw::(target_bond_owner.clone(), transfer_amount)?; + self.withdraw::(target_bond_owner.clone(), transfer_amount)?; self.add_pre_investing::(target_bond_owner.clone(), transfer_amount)?; result.push(Bond { owner: target_bond_owner.clone(), amount: transfer_amount }); break; } else { - let _ = self.withdraw::(target_bond_owner.clone(), i.0.amount)?; + self.withdraw::(target_bond_owner.clone(), i.0.amount)?; self.add_pre_investing::(target_bond_owner.clone(), i.0.amount)?; result.push(Bond { owner: target_bond_owner, amount: i.0.amount }); } @@ -355,3 +348,15 @@ impl< Ok(result) } } + +impl< + AccountId: Ord + Clone, + Balance: Default + CheckedAdd + CheckedSub + PartialOrd + Copy, + BlockNumber: Ord + Clone, + S: Get, + > Default for PoolProposalPreInvesting +{ + fn default() -> Self { + Self::new() + } +} From 15714dd1b695497d702ad7d65d8b871c11150583 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 4 Oct 2024 02:24:40 +0800 Subject: [PATCH 059/215] chore: fix --- parachain/pallets/collab-ai/guardian/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/guardian/src/lib.rs b/parachain/pallets/collab-ai/guardian/src/lib.rs index 8b63673b98..2059fa1fda 100644 --- a/parachain/pallets/collab-ai/guardian/src/lib.rs +++ b/parachain/pallets/collab-ai/guardian/src/lib.rs @@ -171,7 +171,7 @@ pub mod pallet { PublicGuardianToIndex::::insert(&who, next_guardian_index); GuardianIndexToInfo::::insert( - &next_guardian_index, + next_guardian_index, (info_hash, current_block, who.clone(), CandidateStatus::Unverified), ); PublicGuardianCount::::put( From 686a6d588a8f25af7d4ce5164a34f23250798c60 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 4 Oct 2024 13:36:09 +0800 Subject: [PATCH 060/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 73ca434a63..9e5fc0721b 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -34,7 +34,7 @@ use frame_support::{ fungibles::{Inspect as FsInspect, Mutate as FsMutate}, Preservation, }, - Currency, EnsureOrigin, Get, LockIdentifier, LockableCurrency, ReservableCurrency, + Currency, EnsureOrigin, Get, LockableCurrency, ReservableCurrency, }, transactional, weights::Weight, @@ -377,8 +377,8 @@ pub mod pallet { Preservation::Expendable, )?; - let mut pool_proposal_pre_investing = >::take(pool_proposal_index) - .unwrap_or(PoolProposalPreInvesting::new()); + let mut pool_proposal_pre_investing = + >::take(pool_proposal_index).unwrap_or_default(); // Check pool maximum size limit and make pool size limit flag change accordingly let mut pool_proposal = @@ -472,8 +472,8 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin)?; - let mut pool_proposal_pre_investing = >::take(pool_proposal_index) - .unwrap_or(PoolProposalPreInvesting::new()); + let mut pool_proposal_pre_investing = + >::take(pool_proposal_index).unwrap_or_default(); let pool_proposal = >::get(pool_proposal_index).ok_or(Error::::ProposalNotExist)?; From 57823e35cc6865fd0b93814a707e5ce6387c52a1 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 4 Oct 2024 13:51:38 +0800 Subject: [PATCH 061/215] chore: fix --- parachain/pallets/collab-ai/curator/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/curator/src/lib.rs b/parachain/pallets/collab-ai/curator/src/lib.rs index 87befabc9e..4c2cecf2eb 100644 --- a/parachain/pallets/collab-ai/curator/src/lib.rs +++ b/parachain/pallets/collab-ai/curator/src/lib.rs @@ -145,7 +145,7 @@ pub mod pallet { PublicCuratorToIndex::::insert(&who, next_curator_index); CuratorIndexToInfo::::insert( - &next_curator_index, + next_curator_index, (info_hash, current_block, who.clone(), CandidateStatus::Unverified), ); PublicCuratorCount::::put( From 1c9ccbbb80dff189eb03769cb62508f4bd8a4114 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 7 Oct 2024 17:04:12 +0800 Subject: [PATCH 062/215] feat: add precompile --- parachain/Cargo.toml | 15 +- .../collab-ai/aiusd-convertor/src/lib.rs | 5 +- .../collab-ai/pool-proposal/src/lib.rs | 5 +- .../aiusd-convertor/AIUSDConvertor.sol | 18 +++ .../collab-ai/aiusd-convertor/Cargo.toml | 49 +++++++ .../collab-ai/aiusd-convertor/src/lib.rs | 60 ++++++++ .../precompiles/collab-ai/curator/Cargo.toml | 49 +++++++ .../precompiles/collab-ai/curator/Curator.sol | 21 +++ .../precompiles/collab-ai/curator/src/lib.rs | 56 ++++++++ .../precompiles/collab-ai/guardian/Cargo.toml | 51 +++++++ .../collab-ai/guardian/Guardian.sol | 39 ++++++ .../precompiles/collab-ai/guardian/src/lib.rs | 100 ++++++++++++++ .../collab-ai/pool-proposal/Cargo.toml | 51 +++++++ .../collab-ai/pool-proposal/PoolProposal.sol | 34 +++++ .../collab-ai/pool-proposal/src/lib.rs | 130 ++++++++++++++++++ 15 files changed, 677 insertions(+), 6 deletions(-) create mode 100644 parachain/precompiles/collab-ai/aiusd-convertor/AIUSDConvertor.sol create mode 100644 parachain/precompiles/collab-ai/aiusd-convertor/Cargo.toml create mode 100644 parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs create mode 100644 parachain/precompiles/collab-ai/curator/Cargo.toml create mode 100644 parachain/precompiles/collab-ai/curator/Curator.sol create mode 100644 parachain/precompiles/collab-ai/curator/src/lib.rs create mode 100644 parachain/precompiles/collab-ai/guardian/Cargo.toml create mode 100644 parachain/precompiles/collab-ai/guardian/Guardian.sol create mode 100644 parachain/precompiles/collab-ai/guardian/src/lib.rs create mode 100644 parachain/precompiles/collab-ai/pool-proposal/Cargo.toml create mode 100644 parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol create mode 100644 parachain/precompiles/collab-ai/pool-proposal/src/lib.rs diff --git a/parachain/Cargo.toml b/parachain/Cargo.toml index dd506501dd..d1050f99cd 100644 --- a/parachain/Cargo.toml +++ b/parachain/Cargo.toml @@ -23,7 +23,14 @@ members = [ 'pallets/teebag', 'pallets/vc-management', 'pallets/xcm-asset-manager', - 'precompiles/*', + 'precompiles/assets-erc20', + 'precompiles/bridge-transfer', + 'precompiles/collab-ai/aiusd-convertor', + 'precompiles/collab-ai/curator', + 'precompiles/collab-ai/guardian', + 'precompiles/collab-ai/pool-proposal', + 'precompiles/parachain-staking', + 'precompiles/score-staking', 'runtime/litentry', 'runtime/rococo', 'runtime/paseo', @@ -272,6 +279,12 @@ pallet-evm-precompile-assets-erc20 = { path = "precompiles/assets-erc20", defaul pallet-evm-precompile-bridge-transfer = { path = "precompiles/bridge-transfer", default-features = false } pallet-evm-precompile-parachain-staking = { path = "precompiles/parachain-staking", default-features = false } pallet-evm-precompile-score-staking = { path = "precompiles/score-staking", default-features = false } + +pallet-evm-precompile-aiusd-convertor = { path = "precompiles/collab-ai/aiusd-convertor", default-features = false } +pallet-evm-precompile-curator = { path = "precompiles/collab-ai/curator", default-features = false } +pallet-evm-precompile-guardian = { path = "precompiles/collab-ai/guardian", default-features = false } +pallet-evm-precompile-pool-proposal = { path = "precompiles/collab-ai/pool-proposal", default-features = false } + pallet-evm-assertions = { path = "pallets/evm-assertions", default-features = false } # CollabAI local diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index d0ca50b08d..91d1976e33 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -29,6 +29,7 @@ use frame_support::{ transactional, }; use frame_system::pallet_prelude::*; +pub use pallet::*; use sp_runtime::traits::{CheckedDiv, CheckedMul}; #[frame_support::pallet] @@ -36,10 +37,10 @@ pub mod pallet { use super::*; pub(crate) type InspectFungibles = pallet_assets::Pallet; /// Balance type alias for balances of assets that implement the `fungibles` trait. - pub(crate) type AssetBalanceOf = + pub type AssetBalanceOf = as FsInspect<::AccountId>>::Balance; /// Type alias for Asset IDs. - pub(crate) type AssetIdOf = + pub type AssetIdOf = as FsInspect<::AccountId>>::AssetId; /// The current storage version. diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 9e5fc0721b..5b780bed61 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -61,10 +61,10 @@ pub(crate) type BalanceOf = pub(crate) type InspectFungibles = pallet_assets::Pallet; /// Balance type alias for balances of assets that implement the `fungibles` trait. -pub(crate) type AssetBalanceOf = +pub type AssetBalanceOf = as FsInspect<::AccountId>>::Balance; /// Type alias for Asset IDs. -pub(crate) type AssetIdOf = +pub type AssetIdOf = as FsInspect<::AccountId>>::AssetId; #[frame_support::pallet] @@ -257,7 +257,6 @@ pub mod pallet { /// Curator propose a investing pool /// /// max_pool_size: At most this amount of raised money curator/investing pool willing to take - /// min_pool_size: At least this amount of raised money require for curator willing to fulfill contract /// proposal_last_time: How does the proposal lasts for voting/preinvesting. /// All ProposalStatusFlags must be satisfied after this period passed, which is also /// the approximate date when pool begins. diff --git a/parachain/precompiles/collab-ai/aiusd-convertor/AIUSDConvertor.sol b/parachain/precompiles/collab-ai/aiusd-convertor/AIUSDConvertor.sol new file mode 100644 index 0000000000..be633ca881 --- /dev/null +++ b/parachain/precompiles/collab-ai/aiusd-convertor/AIUSDConvertor.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity >=0.8.3; + +interface IAIUSDConvertor { + /// @notice Lock target asset_id and mint AIUSD + /// @param asset_id: target asset id in exchange for AIUSD + /// @param aiusd_amount: The amount of AIUSD token + /// @custom:selector 0x1a15980f + /// mintAIUSD(uint256,uint256) + function mintAIUSD(uint256 asset_id, uint256 aiusd_amount) external; + + /// @notice Burn aiusd and get target asset_id token released + /// @param asset_id: target asset id in exchange for AIUSD + /// @param aiusd_amount: The amount of AIUSD token + /// @custom:selector 0xa89bb55f + /// burnAIUSD(uint256,uint256) + function burnAIUSD(uint256 asset_id, uint256 aiusd_amount) external; +} diff --git a/parachain/precompiles/collab-ai/aiusd-convertor/Cargo.toml b/parachain/precompiles/collab-ai/aiusd-convertor/Cargo.toml new file mode 100644 index 0000000000..9696d23e01 --- /dev/null +++ b/parachain/precompiles/collab-ai/aiusd-convertor/Cargo.toml @@ -0,0 +1,49 @@ +[package] +authors = ["Trust Computing GmbH "] +edition = '2021' +name = "pallet-evm-precompile-aiusd-convertor" +version = '0.1.0' + +[dependencies] +precompile-utils = { workspace = true } + +# Substrate +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-aiusd-convertor = { workspace = true } +parity-scale-codec = { workspace = true, features = ["max-encoded-len"] } +scale-info = { workspace = true, features = ["derive"] } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +# Frontier +fp-evm = { workspace = true } +pallet-evm = { workspace = true, features = ["forbid-evm-reentrancy"] } + +[dev-dependencies] +derive_more = { workspace = true } +hex-literal = { workspace = true } +libsecp256k1 = { workspace = true } +serde = { workspace = true } +sha3 = { workspace = true } +precompile-utils = { workspace = true, features = ["std", "testing"] } +pallet-timestamp = { workspace = true, features = ["std"] } +parity-scale-codec = { workspace = true, features = ["max-encoded-len", "std"] } +scale-info = { workspace = true, features = ["derive"] } +sp-runtime = { workspace = true, features = ["std"] } + +[features] +default = ["std"] +std = [ + "fp-evm/std", + "frame-support/std", + "frame-system/std", + "pallet-aiusd-convertor/std", + "pallet-evm/std", + "pallet-timestamp/std", + "precompile-utils/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs b/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs new file mode 100644 index 0000000000..a2eba7d897 --- /dev/null +++ b/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs @@ -0,0 +1,60 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use fp_evm::{PrecompileFailure, PrecompileHandle}; + +use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; +use pallet_evm::AddressMapping; +use precompile_utils::prelude::*; +use sp_runtime::traits::Dispatchable; + +use sp_core::{H256, U256}; +use sp_std::{marker::PhantomData, vec::Vec}; + +use pallet_aiusd_convertor::{AssetBalanceOf, AssetIdOf}; + +pub struct AIUSDConvertorPrecompile(PhantomData); + +#[precompile_utils::precompile] +impl AIUSDConvertorPrecompile +where + Runtime: pallet_aiusd_convertor::Config + pallet_evm::Config, + Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, + Runtime::RuntimeCall: From>, + ::RuntimeOrigin: From>, + AssetBalanceOf: TryFrom + Into, + AssetIdOf: TryFrom + Into, +{ + #[precompile::public("mintAIUSD(uint256,uint256)")] + fn mint_aiusd(handle: &mut impl PrecompileHandle, asset_id: U256, amount: U256) -> EvmResult { + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + + let asset_id: AssetIdOf = amount.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("asset id type")) + })?; + let amount: AssetBalanceOf = amount.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("balance type")) + })?; + + let call = pallet_aiusd_convertor::Call::::mint_aiusd { asset_id, amount }; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + + Ok(()) + } + + #[precompile::public("burnAIUSD(uint256,uint256)")] + fn burn_aiusd(handle: &mut impl PrecompileHandle, asset_id: U256, amount: U256) -> EvmResult { + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + + let asset_id: AssetIdOf = amount.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("asset id type")) + })?; + let amount: AssetBalanceOf = amount.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("balance type")) + })?; + + let call = pallet_aiusd_convertor::Call::::burn_aiusd { asset_id, amount }; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + + Ok(()) + } +} diff --git a/parachain/precompiles/collab-ai/curator/Cargo.toml b/parachain/precompiles/collab-ai/curator/Cargo.toml new file mode 100644 index 0000000000..8013a728d9 --- /dev/null +++ b/parachain/precompiles/collab-ai/curator/Cargo.toml @@ -0,0 +1,49 @@ +[package] +authors = ["Trust Computing GmbH "] +edition = '2021' +name = "pallet-evm-precompile-curator" +version = '0.1.0' + +[dependencies] +precompile-utils = { workspace = true } + +# Substrate +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-curator = { workspace = true } +parity-scale-codec = { workspace = true, features = ["max-encoded-len"] } +scale-info = { workspace = true, features = ["derive"] } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +# Frontier +fp-evm = { workspace = true } +pallet-evm = { workspace = true, features = ["forbid-evm-reentrancy"] } + +[dev-dependencies] +derive_more = { workspace = true } +hex-literal = { workspace = true } +libsecp256k1 = { workspace = true } +serde = { workspace = true } +sha3 = { workspace = true } +precompile-utils = { workspace = true, features = ["std", "testing"] } +pallet-timestamp = { workspace = true, features = ["std"] } +parity-scale-codec = { workspace = true, features = ["max-encoded-len", "std"] } +scale-info = { workspace = true, features = ["derive"] } +sp-runtime = { workspace = true, features = ["std"] } + +[features] +default = ["std"] +std = [ + "fp-evm/std", + "frame-support/std", + "frame-system/std", + "pallet-curator/std", + "pallet-evm/std", + "pallet-timestamp/std", + "precompile-utils/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/parachain/precompiles/collab-ai/curator/Curator.sol b/parachain/precompiles/collab-ai/curator/Curator.sol new file mode 100644 index 0000000000..1ba6d5b27c --- /dev/null +++ b/parachain/precompiles/collab-ai/curator/Curator.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity >=0.8.3; + +interface ICurator { + /// @notice Regist info hash of curator and reserve funds, only work if not already registed + /// @param info_hash: H256 hash of info image + /// @custom:selector 0x8ead391c + /// registCurator(bytes32) + function registCurator(bytes32 info_hash) external; + + /// @notice Update info hash of curator, only work if already registed + /// @param info_hash: H256 hash of info image + /// @custom:selector 0x457c00e6 + /// updateCurator(bytes32) + function updateCurator(bytes32 info_hash) external; + + /// @notice clean curator info and return funds if not banned, otherwise no fund return + /// @custom:selector 0xe3b134e6 + /// cleanCurator() + function cleanCurator() external; +} \ No newline at end of file diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs new file mode 100644 index 0000000000..a2a51f867b --- /dev/null +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -0,0 +1,56 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use fp_evm::{PrecompileFailure, PrecompileHandle}; + +use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; +use pallet_evm::AddressMapping; +use precompile_utils::prelude::*; +use sp_runtime::traits::Dispatchable; + +use sp_core::{H256, U256}; +use sp_std::{marker::PhantomData, vec::Vec}; + +pub struct CuratorPrecompile(PhantomData); + +#[precompile_utils::precompile] +impl CuratorPrecompile +where + Runtime: pallet_curator::Config + pallet_evm::Config, + Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, + Runtime::RuntimeCall: From>, + ::RuntimeOrigin: From>, +{ + #[precompile::public("registCurator(bytes32)")] + fn regist_curator(handle: &mut impl PrecompileHandle, info_hash: H256) -> EvmResult { + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + + let info_hash = info_hash.into(); + + let call = pallet_curator::Call::::regist_curator { info_hash }; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + + Ok(()) + } + + #[precompile::public("updateCurator(bytes32)")] + fn update_curator(handle: &mut impl PrecompileHandle, info_hash: H256) -> EvmResult { + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + + let info_hash = info_hash.into(); + + let call = pallet_curator::Call::::update_curator { info_hash }; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + + Ok(()) + } + + #[precompile::public("cleanCurator()")] + fn clean_curator(handle: &mut impl PrecompileHandle) -> EvmResult { + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + + let call = pallet_curator::Call::::clean_curator {}; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + + Ok(()) + } +} diff --git a/parachain/precompiles/collab-ai/guardian/Cargo.toml b/parachain/precompiles/collab-ai/guardian/Cargo.toml new file mode 100644 index 0000000000..0f66ac38d1 --- /dev/null +++ b/parachain/precompiles/collab-ai/guardian/Cargo.toml @@ -0,0 +1,51 @@ +[package] +authors = ["Trust Computing GmbH "] +edition = '2021' +name = "pallet-evm-precompile-guardian" +version = '0.1.0' + +[dependencies] +precompile-utils = { workspace = true } + +# Substrate +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-collab-ai-common = { workspace = true } +pallet-guardian = { workspace = true } +parity-scale-codec = { workspace = true, features = ["max-encoded-len"] } +scale-info = { workspace = true, features = ["derive"] } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +# Frontier +fp-evm = { workspace = true } +pallet-evm = { workspace = true, features = ["forbid-evm-reentrancy"] } + +[dev-dependencies] +derive_more = { workspace = true } +hex-literal = { workspace = true } +libsecp256k1 = { workspace = true } +serde = { workspace = true } +sha3 = { workspace = true } +precompile-utils = { workspace = true, features = ["std", "testing"] } +pallet-timestamp = { workspace = true, features = ["std"] } +parity-scale-codec = { workspace = true, features = ["max-encoded-len", "std"] } +scale-info = { workspace = true, features = ["derive"] } +sp-runtime = { workspace = true, features = ["std"] } + +[features] +default = ["std"] +std = [ + "fp-evm/std", + "frame-support/std", + "frame-system/std", + "pallet-collab-ai-common/std", + "pallet-guardian/std", + "pallet-evm/std", + "pallet-timestamp/std", + "precompile-utils/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/parachain/precompiles/collab-ai/guardian/Guardian.sol b/parachain/precompiles/collab-ai/guardian/Guardian.sol new file mode 100644 index 0000000000..6593da2526 --- /dev/null +++ b/parachain/precompiles/collab-ai/guardian/Guardian.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity >=0.8.3; + +interface IGuardian { + + /// @dev Defines GuardianVote type + enum GuardianVote { + Neutral, + Aye, + Nay, + Specific + } + /// @notice Regist info hash of guardian and reserve funds, only work if not already registed + /// @param info_hash: H256 hash of info image + /// @custom:selector 0x3cf5464a + /// registGuardian(bytes32) + function registGuardian(bytes32 info_hash) external; + + /// @notice Update info hash of guardian, only work if already registed + /// @param info_hash: H256 hash of info image + /// @custom:selector 0x2b764649 + /// updateGuardian(bytes32) + function updateGuardian(bytes32 info_hash) external; + + /// @notice Clean guardian info and return funds if not banned, otherwise no fund return + /// @custom:selector 0xc654e77d + /// cleanGuardian() + function cleanGuardian() external; + + /// @notice Vote guardian and express the corresponding status + /// @custom:selector 0x55b90ea7 + /// vote(bytes32,uint8,uint256) + function vote(bytes32 guardian, GuardianVote status, uint256 potential_proposal_index) external; + + /// @notice Remove msg.sender's all existing guardian vote + /// @custom:selector 0x3219bdc0 + /// removeAllVotes() + function removeAllVotes() external; +} \ No newline at end of file diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs new file mode 100644 index 0000000000..0147a3b329 --- /dev/null +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -0,0 +1,100 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use fp_evm::{PrecompileFailure, PrecompileHandle}; + +use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; +use pallet_collab_ai_common::GuardianVote; +use pallet_evm::AddressMapping; +use precompile_utils::prelude::*; +use sp_runtime::traits::Dispatchable; + +use sp_core::{H256, U256}; +use sp_std::{marker::PhantomData, vec::Vec}; + +pub struct GuardianPrecompile(PhantomData); + +#[precompile_utils::precompile] +impl GuardianPrecompile +where + Runtime: pallet_guardian::Config + pallet_evm::Config, + Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, + Runtime::RuntimeCall: From>, + ::RuntimeOrigin: From>, +{ + #[precompile::public("registGuardian(bytes32)")] + fn regist_guardian(handle: &mut impl PrecompileHandle, info_hash: H256) -> EvmResult { + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + + let info_hash = info_hash.into(); + + let call = pallet_guardian::Call::::regist_guardian { info_hash }; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + + Ok(()) + } + + #[precompile::public("updateGuardian(bytes32)")] + fn update_guardian(handle: &mut impl PrecompileHandle, info_hash: H256) -> EvmResult { + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + + let info_hash = info_hash.into(); + + let call = pallet_guardian::Call::::update_guardian { info_hash }; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + + Ok(()) + } + + #[precompile::public("cleanGuardian()")] + fn clean_guardian(handle: &mut impl PrecompileHandle) -> EvmResult { + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + + let call = pallet_guardian::Call::::clean_guardian {}; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + + Ok(()) + } + + #[precompile::public("vote(bytes32,uint8,uint256)")] + fn vote( + handle: &mut impl PrecompileHandle, + guardian: H256, + status: u8, + potential_proposal_index: U256, + ) -> EvmResult { + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + + let guardian = Runtime::AccountId::from(guardian); + let guardian_vote: GuardianVote = + to_guardian_vote(status, potential_proposal_index).in_field("guardianVote")?; + let call = pallet_guardian::Call::::vote { guardian, status: guardian_vote }; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + + Ok(()) + } + + fn to_guardian_vote(status: u8, potential_proposal_index: U256) -> MayRevert { + match status { + 0u8 => Ok(GuardianVote::Neutral), + 1u8 => Ok(GuardianVote::Aye), + 2u8 => Ok(GuardianVote::Nay), + 3u8 => { + Ok(GuardianVote::Specific(potential_proposal_index.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large( + "proposal index type", + )) + })?)) + }, + } + } + + #[precompile::public("removeAllVotes()")] + fn remove_all_votes(handle: &mut impl PrecompileHandle) -> EvmResult { + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + + let call = pallet_guardian::Call::::remove_all_votes {}; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + + Ok(()) + } +} diff --git a/parachain/precompiles/collab-ai/pool-proposal/Cargo.toml b/parachain/precompiles/collab-ai/pool-proposal/Cargo.toml new file mode 100644 index 0000000000..915be20b27 --- /dev/null +++ b/parachain/precompiles/collab-ai/pool-proposal/Cargo.toml @@ -0,0 +1,51 @@ +[package] +authors = ["Trust Computing GmbH "] +edition = '2021' +name = "pallet-evm-precompile-pool-proposal" +version = '0.1.0' + +[dependencies] +precompile-utils = { workspace = true } + +# Substrate +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-collab-ai-common = { workspace = true } +pallet-pool-proposal = { workspace = true } +parity-scale-codec = { workspace = true, features = ["max-encoded-len"] } +scale-info = { workspace = true, features = ["derive"] } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +# Frontier +fp-evm = { workspace = true } +pallet-evm = { workspace = true, features = ["forbid-evm-reentrancy"] } + +[dev-dependencies] +derive_more = { workspace = true } +hex-literal = { workspace = true } +libsecp256k1 = { workspace = true } +serde = { workspace = true } +sha3 = { workspace = true } +precompile-utils = { workspace = true, features = ["std", "testing"] } +pallet-timestamp = { workspace = true, features = ["std"] } +parity-scale-codec = { workspace = true, features = ["max-encoded-len", "std"] } +scale-info = { workspace = true, features = ["derive"] } +sp-runtime = { workspace = true, features = ["std"] } + +[features] +default = ["std"] +std = [ + "fp-evm/std", + "frame-support/std", + "frame-system/std", + "pallet-collab-ai-common/std", + "pallet-pool-proposal/std", + "pallet-evm/std", + "pallet-timestamp/std", + "precompile-utils/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol b/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol new file mode 100644 index 0000000000..31936a8e9b --- /dev/null +++ b/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity >=0.8.3; + +interface IPoolProposal { + /// @notice Propose an investing pool proposal + /// @param max_pool_size: At most this amount of raised money curator/investing pool willing to take + /// @param proposal_last_time: How does the proposal lasts for voting/preinvesting. + /// @param pool_last_time: How long does the investing pool last if passed + /// @param estimated_epoch_reward: This number is only for displaying purpose without any techinical meaning + /// @param pool_info_hash: H256 hash of pool info for including pool details + /// @custom:selector 0x7bc55add + /// proposeInvestingPool(uint256,uint256,uint256,uint256,bytes32) + function proposeInvestingPool(uint256 max_pool_size, uint256 proposal_last_time, uint256 pool_last_time, uint256 estimated_epoch_reward, bytes32 pool_info_hash) external; + + /// @notice Prestake the pool proposal + /// @param pool_proposal_index: Index of pool proposal + /// @param amount: Amount of per-staking user provides + /// @custom:selector 0x68e3a76c + /// preStakeProposal(uint256,uint256) + function preStakeProposal(uint256 pool_proposal_index, uint256 amount) external; + + /// @notice Withdrawal the prestaking the pool proposal + /// @param pool_proposal_index: Index of pool proposal + /// @param amount: Amount of per-staking user provides + /// @custom:selector 0x389cd4af + /// withdrawPreInvesting(uint256,uint256) + function withdrawPreInvesting(uint256 pool_proposal_index, uint256 amount) external; + + /// @notice A guardian declaring his incentive of participating pool + /// @param pool_proposal_index: Index of pool proposal + /// @custom:selector 0x619c08e2 + /// guardianParticipateProposal(uint256) + function guardianParticipateProposal(uint256 pool_proposal_index) external; +} \ No newline at end of file diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs new file mode 100644 index 0000000000..04a3456771 --- /dev/null +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -0,0 +1,130 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use fp_evm::{PrecompileFailure, PrecompileHandle}; +use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; +use frame_system::pallet_prelude::BlockNumberFor; +use pallet_evm::AddressMapping; +use pallet_pool_proposal::{AssetBalanceOf, AssetIdOf}; +use precompile_utils::prelude::*; +use sp_runtime::traits::Dispatchable; + +use sp_core::{H256, U256}; +use sp_std::{marker::PhantomData, vec::Vec}; + +pub struct GuardianPrecompile(PhantomData); + +#[precompile_utils::precompile] +impl GuardianPrecompile +where + Runtime: pallet_pool_proposal::Config + pallet_evm::Config, + Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, + Runtime::RuntimeCall: From>, + ::RuntimeOrigin: From>, + AssetBalanceOf: TryFrom + Into, + BlockNumberFor: TryFrom + Into, +{ + #[precompile::public("proposeInvestingPool(uint256,uint256,uint256,uint256,bytes32)")] + fn propose_investing_pool( + handle: &mut impl PrecompileHandle, + max_pool_size: U256, + proposal_last_time: U256, + pool_last_time: U256, + estimated_epoch_reward: U256, + pool_info_hash: H256, + ) -> EvmResult { + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + + let max_pool_size: AssetBalanceOf = max_pool_size.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("balance type")) + })?; + + let proposal_last_time: BlockNumberFor = + proposal_last_time.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large( + "block number type", + )) + })?; + + let pool_last_time: AssetBalanceOf = pool_last_time.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("block number type")) + })?; + + let estimated_epoch_reward: AssetBalanceOf = + estimated_epoch_reward.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("balance type")) + })?; + + let pool_info_hash = pool_info_hash.into(); + + let call = pallet_guardian::Call::::propose_investing_pool { + max_pool_size, + proposal_last_time, + pool_last_time, + estimated_epoch_reward, + pool_info_hash, + }; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + + Ok(()) + } + + #[precompile::public("preStakeProposal(uint256,uint256)")] + fn pre_stake_proposal( + handle: &mut impl PrecompileHandle, + pool_proposal_index: U256, + amount: U256, + ) -> EvmResult { + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + + let pool_proposal_index = pool_proposal_index.into(); + + let amount: AssetBalanceOf = amount.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("balance type")) + })?; + + let call = + pallet_guardian::Call::::pre_stake_proposal { pool_proposal_index, amount }; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + + Ok(()) + } + + #[precompile::public("withdrawPreInvesting(uint256,uint256)")] + fn withdraw_pre_investing( + handle: &mut impl PrecompileHandle, + pool_proposal_index: U256, + amount: U256, + ) -> EvmResult { + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + + let pool_proposal_index = pool_proposal_index.into(); + + let amount: AssetBalanceOf = amount.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("balance type")) + })?; + + let call = pallet_guardian::Call::::withdraw_pre_investing { + pool_proposal_index, + amount, + }; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + + Ok(()) + } + + #[precompile::public("guardianParticipateProposal(uint256)")] + fn guardian_participate_proposal( + handle: &mut impl PrecompileHandle, + pool_proposal_index: U256, + ) -> EvmResult { + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + + let pool_proposal_index = pool_proposal_index.into(); + + let call = + pallet_guardian::Call::::guardian_participate_proposal { pool_proposal_index }; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + + Ok(()) + } +} From e7f00bdacc137841d1c022233bb53d9247fc364e Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 7 Oct 2024 17:10:07 +0800 Subject: [PATCH 063/215] chore: lock file --- parachain/Cargo.lock | 94 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index f964d556c0..39c8db07e0 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -7362,6 +7362,29 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-evm-precompile-aiusd-convertor" +version = "0.1.0" +dependencies = [ + "derive_more", + "fp-evm", + "frame-support", + "frame-system", + "hex-literal", + "libsecp256k1", + "pallet-aiusd-convertor", + "pallet-evm", + "pallet-timestamp", + "parity-scale-codec", + "precompile-utils", + "scale-info", + "serde", + "sha3", + "sp-core", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-evm-precompile-assets-erc20" version = "0.1.0" @@ -7426,6 +7449,29 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-evm-precompile-curator" +version = "0.1.0" +dependencies = [ + "derive_more", + "fp-evm", + "frame-support", + "frame-system", + "hex-literal", + "libsecp256k1", + "pallet-curator", + "pallet-evm", + "pallet-timestamp", + "parity-scale-codec", + "precompile-utils", + "scale-info", + "serde", + "sha3", + "sp-core", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-evm-precompile-dispatch" version = "2.0.0-dev" @@ -7447,6 +7493,30 @@ dependencies = [ "fp-evm", ] +[[package]] +name = "pallet-evm-precompile-guardian" +version = "0.1.0" +dependencies = [ + "derive_more", + "fp-evm", + "frame-support", + "frame-system", + "hex-literal", + "libsecp256k1", + "pallet-collab-ai-common", + "pallet-evm", + "pallet-guardian", + "pallet-timestamp", + "parity-scale-codec", + "precompile-utils", + "scale-info", + "serde", + "sha3", + "sp-core", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-evm-precompile-modexp" version = "2.0.0-dev" @@ -7479,6 +7549,30 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-evm-precompile-pool-proposal" +version = "0.1.0" +dependencies = [ + "derive_more", + "fp-evm", + "frame-support", + "frame-system", + "hex-literal", + "libsecp256k1", + "pallet-collab-ai-common", + "pallet-evm", + "pallet-pool-proposal", + "pallet-timestamp", + "parity-scale-codec", + "precompile-utils", + "scale-info", + "serde", + "sha3", + "sp-core", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-evm-precompile-score-staking" version = "0.1.0" From bae645314c2238cd064ea69aa3d582836a6163cb Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 7 Oct 2024 18:13:34 +0800 Subject: [PATCH 064/215] chore: fix --- .../collab-ai/aiusd-convertor/src/lib.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs b/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs index a2eba7d897..a3cc0d0c06 100644 --- a/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs @@ -7,8 +7,8 @@ use pallet_evm::AddressMapping; use precompile_utils::prelude::*; use sp_runtime::traits::Dispatchable; -use sp_core::{H256, U256}; -use sp_std::{marker::PhantomData, vec::Vec}; +use sp_core::U256; +use sp_std::marker::PhantomData; use pallet_aiusd_convertor::{AssetBalanceOf, AssetIdOf}; @@ -35,7 +35,10 @@ where Into::::into(RevertReason::value_is_too_large("balance type")) })?; - let call = pallet_aiusd_convertor::Call::::mint_aiusd { asset_id, amount }; + let call = pallet_aiusd_convertor::Call::::mint_aiusd { + target_asset_id: asset_id, + aiusd_amount: amount, + }; RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; Ok(()) @@ -52,7 +55,10 @@ where Into::::into(RevertReason::value_is_too_large("balance type")) })?; - let call = pallet_aiusd_convertor::Call::::burn_aiusd { asset_id, amount }; + let call = pallet_aiusd_convertor::Call::::burn_aiusd { + target_asset_id: asset_id, + aiusd_amount: amount, + }; RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; Ok(()) From 00576f32429f6b5ceb5b060845f8ab76406acdb2 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 7 Oct 2024 19:21:50 +0800 Subject: [PATCH 065/215] chore: fix --- .../collab-ai/aiusd-convertor/src/lib.rs | 4 ++-- .../precompiles/collab-ai/curator/src/lib.rs | 2 +- .../precompiles/collab-ai/guardian/src/lib.rs | 19 +++++++++---------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs b/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs index a3cc0d0c06..f186affa9d 100644 --- a/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs @@ -28,7 +28,7 @@ where fn mint_aiusd(handle: &mut impl PrecompileHandle, asset_id: U256, amount: U256) -> EvmResult { let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); - let asset_id: AssetIdOf = amount.try_into().map_err(|_| { + let asset_id: AssetIdOf = asset_id.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("asset id type")) })?; let amount: AssetBalanceOf = amount.try_into().map_err(|_| { @@ -48,7 +48,7 @@ where fn burn_aiusd(handle: &mut impl PrecompileHandle, asset_id: U256, amount: U256) -> EvmResult { let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); - let asset_id: AssetIdOf = amount.try_into().map_err(|_| { + let asset_id: AssetIdOf = asset_id.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("asset id type")) })?; let amount: AssetBalanceOf = amount.try_into().map_err(|_| { diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index a2a51f867b..c1d1e1b8c3 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -7,7 +7,7 @@ use pallet_evm::AddressMapping; use precompile_utils::prelude::*; use sp_runtime::traits::Dispatchable; -use sp_core::{H256, U256}; +use sp_core::H256; use sp_std::{marker::PhantomData, vec::Vec}; pub struct CuratorPrecompile(PhantomData); diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index 0147a3b329..d93416c0dd 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -3,13 +3,13 @@ use fp_evm::{PrecompileFailure, PrecompileHandle}; use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; -use pallet_collab_ai_common::GuardianVote; +use pallet_collab_ai_common::{GuardianVote, PoolProposalIndex}; use pallet_evm::AddressMapping; use precompile_utils::prelude::*; use sp_runtime::traits::Dispatchable; use sp_core::{H256, U256}; -use sp_std::{marker::PhantomData, vec::Vec}; +use sp_std::marker::PhantomData; pub struct GuardianPrecompile(PhantomData); @@ -64,9 +64,10 @@ where ) -> EvmResult { let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + let guardian: [u8; 32] = guardian.into(); let guardian = Runtime::AccountId::from(guardian); let guardian_vote: GuardianVote = - to_guardian_vote(status, potential_proposal_index).in_field("guardianVote")?; + Self::to_guardian_vote(status, potential_proposal_index).in_field("guardianVote")?; let call = pallet_guardian::Call::::vote { guardian, status: guardian_vote }; RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; @@ -78,13 +79,11 @@ where 0u8 => Ok(GuardianVote::Neutral), 1u8 => Ok(GuardianVote::Aye), 2u8 => Ok(GuardianVote::Nay), - 3u8 => { - Ok(GuardianVote::Specific(potential_proposal_index.try_into().map_err(|_| { - Into::::into(RevertReason::value_is_too_large( - "proposal index type", - )) - })?)) - }, + 3u8 => Ok(GuardianVote::Specific( + potential_proposal_index + .try_into() + .map_err(|_| RevertReason::value_is_too_large("proposal index type")?), + )), } } From 71b5a0cabcd8351873a3e796dd34d748e1a6980c Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 7 Oct 2024 20:18:30 +0800 Subject: [PATCH 066/215] chore: fix --- .../collab-ai/pool-proposal/src/lib.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index 04a3456771..8c76968ca5 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -4,12 +4,12 @@ use fp_evm::{PrecompileFailure, PrecompileHandle}; use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; use frame_system::pallet_prelude::BlockNumberFor; use pallet_evm::AddressMapping; -use pallet_pool_proposal::{AssetBalanceOf, AssetIdOf}; +use pallet_pool_proposal::AssetBalanceOf; use precompile_utils::prelude::*; use sp_runtime::traits::Dispatchable; use sp_core::{H256, U256}; -use sp_std::{marker::PhantomData, vec::Vec}; +use sp_std::marker::PhantomData; pub struct GuardianPrecompile(PhantomData); @@ -56,7 +56,7 @@ where let pool_info_hash = pool_info_hash.into(); - let call = pallet_guardian::Call::::propose_investing_pool { + let call = pallet_pool_proposal::Call::::propose_investing_pool { max_pool_size, proposal_last_time, pool_last_time, @@ -82,8 +82,10 @@ where Into::::into(RevertReason::value_is_too_large("balance type")) })?; - let call = - pallet_guardian::Call::::pre_stake_proposal { pool_proposal_index, amount }; + let call = pallet_pool_proposal::Call::::pre_stake_proposal { + pool_proposal_index, + amount, + }; RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; Ok(()) @@ -103,7 +105,7 @@ where Into::::into(RevertReason::value_is_too_large("balance type")) })?; - let call = pallet_guardian::Call::::withdraw_pre_investing { + let call = pallet_pool_proposal::Call::::withdraw_pre_investing { pool_proposal_index, amount, }; @@ -121,8 +123,9 @@ where let pool_proposal_index = pool_proposal_index.into(); - let call = - pallet_guardian::Call::::guardian_participate_proposal { pool_proposal_index }; + let call = pallet_pool_proposal::Call::::guardian_participate_proposal { + pool_proposal_index, + }; RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; Ok(()) From 95c3037bf53332594a42345030e8bd78c6111fed Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 7 Oct 2024 20:35:51 +0800 Subject: [PATCH 067/215] chore: fix --- .../precompiles/collab-ai/guardian/src/lib.rs | 5 +++-- .../collab-ai/pool-proposal/src/lib.rs | 18 ++++++++++++------ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index d93416c0dd..8748b73d31 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -17,6 +17,7 @@ pub struct GuardianPrecompile(PhantomData); impl GuardianPrecompile where Runtime: pallet_guardian::Config + pallet_evm::Config, + Runtime::AccountId: From<[u8; 32]>, Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, Runtime::RuntimeCall: From>, ::RuntimeOrigin: From>, @@ -68,7 +69,7 @@ where let guardian = Runtime::AccountId::from(guardian); let guardian_vote: GuardianVote = Self::to_guardian_vote(status, potential_proposal_index).in_field("guardianVote")?; - let call = pallet_guardian::Call::::vote { guardian, status: guardian_vote }; + let call = pallet_guardian::Call::::vote { guardian, status: Some(guardian_vote) }; RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; Ok(()) @@ -82,7 +83,7 @@ where 3u8 => Ok(GuardianVote::Specific( potential_proposal_index .try_into() - .map_err(|_| RevertReason::value_is_too_large("proposal index type")?), + .map_err(|_| RevertReason::value_is_too_large("proposal index type"))?, )), } } diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index 8c76968ca5..f4967c181e 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -11,10 +11,10 @@ use sp_runtime::traits::Dispatchable; use sp_core::{H256, U256}; use sp_std::marker::PhantomData; -pub struct GuardianPrecompile(PhantomData); +pub struct PoolProposalPrecompile(PhantomData); #[precompile_utils::precompile] -impl GuardianPrecompile +impl PoolProposalPrecompile where Runtime: pallet_pool_proposal::Config + pallet_evm::Config, Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, @@ -45,7 +45,7 @@ where )) })?; - let pool_last_time: AssetBalanceOf = pool_last_time.try_into().map_err(|_| { + let pool_last_time: BlockNumberFor = pool_last_time.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("block number type")) })?; @@ -76,7 +76,9 @@ where ) -> EvmResult { let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); - let pool_proposal_index = pool_proposal_index.into(); + let pool_proposal_index = pool_proposal_index.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; let amount: AssetBalanceOf = amount.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("balance type")) @@ -99,7 +101,9 @@ where ) -> EvmResult { let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); - let pool_proposal_index = pool_proposal_index.into(); + let pool_proposal_index = pool_proposal_index.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; let amount: AssetBalanceOf = amount.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("balance type")) @@ -121,7 +125,9 @@ where ) -> EvmResult { let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); - let pool_proposal_index = pool_proposal_index.into(); + let pool_proposal_index = pool_proposal_index.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; let call = pallet_pool_proposal::Call::::guardian_participate_proposal { pool_proposal_index, From 510e4999ca8280c038c2b2c0cd5c5c13c4298b5b Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 7 Oct 2024 20:47:03 +0800 Subject: [PATCH 068/215] chore: fix --- parachain/precompiles/collab-ai/curator/src/lib.rs | 4 ++-- parachain/precompiles/collab-ai/guardian/src/lib.rs | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index c1d1e1b8c3..2829906057 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -1,6 +1,6 @@ #![cfg_attr(not(feature = "std"), no_std)] -use fp_evm::{PrecompileFailure, PrecompileHandle}; +use fp_evm::PrecompileHandle; use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; use pallet_evm::AddressMapping; @@ -8,7 +8,7 @@ use precompile_utils::prelude::*; use sp_runtime::traits::Dispatchable; use sp_core::H256; -use sp_std::{marker::PhantomData, vec::Vec}; +use sp_std::marker::PhantomData; pub struct CuratorPrecompile(PhantomData); diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index 8748b73d31..fe9b19cae2 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -1,9 +1,9 @@ #![cfg_attr(not(feature = "std"), no_std)] -use fp_evm::{PrecompileFailure, PrecompileHandle}; +use fp_evm::PrecompileHandle; use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; -use pallet_collab_ai_common::{GuardianVote, PoolProposalIndex}; +use pallet_collab_ai_common::GuardianVote; use pallet_evm::AddressMapping; use precompile_utils::prelude::*; use sp_runtime::traits::Dispatchable; @@ -85,6 +85,7 @@ where .try_into() .map_err(|_| RevertReason::value_is_too_large("proposal index type"))?, )), + _ => RevertReason::custom("Out of potential status result"), } } From 89a59912683afb4d9bde62af3a049b73892fe02a Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 7 Oct 2024 21:03:24 +0800 Subject: [PATCH 069/215] chore: fix --- parachain/precompiles/collab-ai/guardian/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index fe9b19cae2..7d14d7bd8e 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -83,9 +83,9 @@ where 3u8 => Ok(GuardianVote::Specific( potential_proposal_index .try_into() - .map_err(|_| RevertReason::value_is_too_large("proposal index type"))?, + .map_err(|_| RevertReason::value_is_too_large("proposal index type").into())?, )), - _ => RevertReason::custom("Out of potential status result"), + _ => Err(RevertReason::custom("Out of potential status result").into()), } } From 7e74d05794d7ef91e4376dedd4d4b4c1412b2b0d Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 7 Oct 2024 21:13:47 +0800 Subject: [PATCH 070/215] chore: fix --- parachain/precompiles/collab-ai/guardian/src/lib.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index 7d14d7bd8e..21e44bf92c 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -80,11 +80,13 @@ where 0u8 => Ok(GuardianVote::Neutral), 1u8 => Ok(GuardianVote::Aye), 2u8 => Ok(GuardianVote::Nay), - 3u8 => Ok(GuardianVote::Specific( - potential_proposal_index - .try_into() - .map_err(|_| RevertReason::value_is_too_large("proposal index type").into())?, - )), + 3u8 => { + Ok(GuardianVote::Specific(potential_proposal_index.try_into().map_err(|_| { + >::into(RevertReason::value_is_too_large( + "proposal index type", + )) + })?)) + }, _ => Err(RevertReason::custom("Out of potential status result").into()), } } From df33cbcc3c4d15708084590ee18bc6409228ed2c Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 7 Oct 2024 21:32:56 +0800 Subject: [PATCH 071/215] chore: fix --- parachain/precompiles/collab-ai/pool-proposal/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index f4967c181e..8f23cc154c 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -54,7 +54,7 @@ where Into::::into(RevertReason::value_is_too_large("balance type")) })?; - let pool_info_hash = pool_info_hash.into(); + let pool_info_hash = pool_info_hash; let call = pallet_pool_proposal::Call::::propose_investing_pool { max_pool_size, From ef765eda15c75592bb7b5e97e2ec547a81e96db4 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 7 Oct 2024 22:22:25 +0800 Subject: [PATCH 072/215] chore: fix --- parachain/precompiles/collab-ai/pool-proposal/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index 8f23cc154c..838d5b47a8 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -54,8 +54,6 @@ where Into::::into(RevertReason::value_is_too_large("balance type")) })?; - let pool_info_hash = pool_info_hash; - let call = pallet_pool_proposal::Call::::propose_investing_pool { max_pool_size, proposal_last_time, From 2725e7e11f6a43894135c8e26cad5a501a7af4bd Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Tue, 8 Oct 2024 10:07:47 +0800 Subject: [PATCH 073/215] chore: fix --- parachain/precompiles/collab-ai/curator/src/lib.rs | 4 ---- parachain/precompiles/collab-ai/guardian/src/lib.rs | 4 ---- 2 files changed, 8 deletions(-) diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index 2829906057..c959acd433 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -24,8 +24,6 @@ where fn regist_curator(handle: &mut impl PrecompileHandle, info_hash: H256) -> EvmResult { let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); - let info_hash = info_hash.into(); - let call = pallet_curator::Call::::regist_curator { info_hash }; RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; @@ -36,8 +34,6 @@ where fn update_curator(handle: &mut impl PrecompileHandle, info_hash: H256) -> EvmResult { let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); - let info_hash = info_hash.into(); - let call = pallet_curator::Call::::update_curator { info_hash }; RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index 21e44bf92c..1d079dd3f4 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -26,8 +26,6 @@ where fn regist_guardian(handle: &mut impl PrecompileHandle, info_hash: H256) -> EvmResult { let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); - let info_hash = info_hash.into(); - let call = pallet_guardian::Call::::regist_guardian { info_hash }; RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; @@ -38,8 +36,6 @@ where fn update_guardian(handle: &mut impl PrecompileHandle, info_hash: H256) -> EvmResult { let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); - let info_hash = info_hash.into(); - let call = pallet_guardian::Call::::update_guardian { info_hash }; RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; From b77b4916523ae4c5cb374314fc882d58af5496d5 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Tue, 8 Oct 2024 16:16:37 +0800 Subject: [PATCH 074/215] chore: small adjust --- parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs | 2 -- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 1 - 2 files changed, 3 deletions(-) diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index 91d1976e33..0d94f6ddc5 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -82,8 +82,6 @@ pub mod pallet { pub enum Error { InvalidAssetId, AssetNotEnabled, - CannotPayAsFee, - ReachMaximumSupply, Overflow, } diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 5b780bed61..41cb699ed5 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -229,7 +229,6 @@ pub mod pallet { #[pallet::error] pub enum Error { - PreInvestingOverflow, ProposalDepositDuplicatedOrOversized, ProposalExpired, ProposalPreInvestingLocked, From 989b1483122915a74807e1b81b2ccad13d402627 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 9 Oct 2024 11:49:24 +0800 Subject: [PATCH 075/215] feat: add view method for precompile --- parachain/Cargo.lock | 1 + .../precompiles/collab-ai/curator/Cargo.toml | 2 + .../precompiles/collab-ai/curator/Curator.sol | 30 ++++ .../precompiles/collab-ai/curator/src/lib.rs | 76 ++++++++++ .../collab-ai/guardian/Guardian.sol | 41 +++++- .../precompiles/collab-ai/guardian/src/lib.rs | 135 +++++++++++++++++- 6 files changed, 282 insertions(+), 3 deletions(-) diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index 4a424ced3c..24579707ed 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -7459,6 +7459,7 @@ dependencies = [ "frame-system", "hex-literal", "libsecp256k1", + "pallet-collab-ai-common", "pallet-curator", "pallet-evm", "pallet-timestamp", diff --git a/parachain/precompiles/collab-ai/curator/Cargo.toml b/parachain/precompiles/collab-ai/curator/Cargo.toml index 8013a728d9..053963d93d 100644 --- a/parachain/precompiles/collab-ai/curator/Cargo.toml +++ b/parachain/precompiles/collab-ai/curator/Cargo.toml @@ -10,6 +10,7 @@ precompile-utils = { workspace = true } # Substrate frame-support = { workspace = true } frame-system = { workspace = true } +pallet-collab-ai-common = { workspace = true } pallet-curator = { workspace = true } parity-scale-codec = { workspace = true, features = ["max-encoded-len"] } scale-info = { workspace = true, features = ["derive"] } @@ -39,6 +40,7 @@ std = [ "fp-evm/std", "frame-support/std", "frame-system/std", + "pallet-collab-ai-common/std", "pallet-curator/std", "pallet-evm/std", "pallet-timestamp/std", diff --git a/parachain/precompiles/collab-ai/curator/Curator.sol b/parachain/precompiles/collab-ai/curator/Curator.sol index 1ba6d5b27c..bb4fc874b0 100644 --- a/parachain/precompiles/collab-ai/curator/Curator.sol +++ b/parachain/precompiles/collab-ai/curator/Curator.sol @@ -2,6 +2,13 @@ pragma solidity >=0.8.3; interface ICurator { + /// @dev Defines the candidate status type. + enum CandidateStatus { + Unverified, + Verified, + Banned + } + /// @notice Regist info hash of curator and reserve funds, only work if not already registed /// @param info_hash: H256 hash of info image /// @custom:selector 0x8ead391c @@ -18,4 +25,27 @@ interface ICurator { /// @custom:selector 0xe3b134e6 /// cleanCurator() function cleanCurator() external; + + /// @notice public curator count of next curator index will be + /// @custom:selector 0x566537c5 + /// publicCuratorCount() + function publicCuratorCount() external view returns (uint256 count); + + /// @notice public curator to index, substrate address format + /// @param curator: substrate format address + /// @custom:selector 0x039997d0 + /// publicCuratorToIndex(bytes32) + function publicCuratorToIndex(bytes32 curator) external view returns (uint256 index); + + /// @notice public curator to index, ethereum address format + /// @param curator: ethereum format address + /// @custom:selector 0x52fe170b + /// publicCuratorToIndex(address) + function publicCuratorToIndex(address curator) external view returns (uint256 index); + + /// @notice Curator index to curator info + /// @param index: Curator index + /// @custom:selector 0x916d9a0d + /// curatorIndexToInfo(address) + function curatorIndexToInfo(uint256 index) external view returns (bytes32 info_hash, uint256 update_block, bytes32 curator, CandidateStatus status); } \ No newline at end of file diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index c959acd433..7e6a7746de 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -10,15 +10,19 @@ use sp_runtime::traits::Dispatchable; use sp_core::H256; use sp_std::marker::PhantomData; +use pallet_collab_ai_common::CandidateStatus; + pub struct CuratorPrecompile(PhantomData); #[precompile_utils::precompile] impl CuratorPrecompile where Runtime: pallet_curator::Config + pallet_evm::Config, + Runtime::AccountId: Into<[u8; 32]>, Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, Runtime::RuntimeCall: From>, ::RuntimeOrigin: From>, + BlockNumberFor: TryFrom + Into, { #[precompile::public("registCurator(bytes32)")] fn regist_curator(handle: &mut impl PrecompileHandle, info_hash: H256) -> EvmResult { @@ -49,4 +53,76 @@ where Ok(()) } + + #[precompile::public("publicCuratorCount()")] + #[precompile::view] + fn public_curator_count(handle: &mut impl PrecompileHandle) -> EvmResult { + // Storage item: CuratorIndex u128: + // 16 + handle.record_db_read::(16)?; + + Ok(pallet_curator::Pallet::::public_curator_count().into()) + } + + #[precompile::public("publicCuratorToIndex(bytes32)")] + #[precompile::view] + fn public_curator_to_index_sub( + handle: &mut impl PrecompileHandle, + curator: H256, + ) -> EvmResult { + // Storage item: CuratorIndex u128: + // Twox64Concat(8) + T::AccountId(32) + CuratorIndex(16) + handle.record_db_read::(56)?; + + let curator = Runtime::AccountId::from(curator); + + Ok(pallet_curator::Pallet::::public_curator_to_index(curator).into()) + } + + #[precompile::public("publicCuratorToIndex(address)")] + #[precompile::view] + fn public_curator_to_index_evm( + handle: &mut impl PrecompileHandle, + curator: Address, + ) -> EvmResult { + // Storage item: CuratorIndex u128: + // Twox64Concat(8) + T::AccountId(32) + CuratorIndex(16) + handle.record_db_read::(56)?; + + let curator = Runtime::AddressMapping::into_account_id(curator.into()); + + Ok(pallet_curator::Pallet::::public_curator_to_index(curator).into()) + } + + fn candidate_status_to_u8(status: CandidateStatus) -> MayRevert { + status + .try_into() + .map_err(|_| RevertReason::value_is_too_large("trackId type").into()) + } + + #[precompile::public("curatorIndexToInfo(uint256)")] + #[precompile::view] + fn curator_index_to_info( + handle: &mut impl PrecompileHandle, + index: U256, + ) -> EvmResult<(H256, U256, H256, u8)> { + // Storage item: CuratorIndex u128: + // Twox64Concat(8) + CuratorIndex(16) + InfoHash(32) + BlockNumber(4) + T::AccountId(32) + CandidateStatus(1) + handle.record_db_read::(93)?; + + let index: AssetBalanceOf = index.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + let (info_hash, update_block, curator, status) = + pallet_curator::Pallet::::curator_index_to_info(index); + + let update_block: U256 = update_block.into(); + + let curator: [u8; 32] = curator.into(); + let curator: H256 = curator.into(); + + let status = Self::candidate_status_to_u8(status).in_field("candidateStatus")?; + + Ok((info_hash, update_block, curator, status)) + } } diff --git a/parachain/precompiles/collab-ai/guardian/Guardian.sol b/parachain/precompiles/collab-ai/guardian/Guardian.sol index 6593da2526..717cb5e8a3 100644 --- a/parachain/precompiles/collab-ai/guardian/Guardian.sol +++ b/parachain/precompiles/collab-ai/guardian/Guardian.sol @@ -2,6 +2,12 @@ pragma solidity >=0.8.3; interface IGuardian { + /// @dev Defines the candidate status type. + enum CandidateStatus { + Unverified, + Verified, + Banned + } /// @dev Defines GuardianVote type enum GuardianVote { @@ -27,7 +33,7 @@ interface IGuardian { /// cleanGuardian() function cleanGuardian() external; - /// @notice Vote guardian and express the corresponding status + /// @notice Vote guardian and express the corresponding status, evm /// @custom:selector 0x55b90ea7 /// vote(bytes32,uint8,uint256) function vote(bytes32 guardian, GuardianVote status, uint256 potential_proposal_index) external; @@ -36,4 +42,37 @@ interface IGuardian { /// @custom:selector 0x3219bdc0 /// removeAllVotes() function removeAllVotes() external; + + /// @notice public guardian count of next guardian index will be + /// @custom:selector 0x69d0b14e + /// publicGuardianCount() + function publicGuardianCount() external view returns (uint256 count); + + /// @notice public guardian to index, substrate address format + /// @param guardian: substrate format address + /// @custom:selector 0xf46175b8 + /// publicGuardianToIndex(bytes32) + function publicGuardianToIndex(bytes32 guardian) external view returns (uint256 index); + + /// @notice public guardian to index, ethereum address format + /// @param guardian: ethereum format address + /// @custom:selector 0x02916580 + /// publicGuardianToIndex(address) + function publicGuardianToIndex(address guardian) external view returns (uint256 index); + + /// @notice Guardian index to guardian info + /// @param index: Guardian index + /// @custom:selector 0x59c95743 + /// guardianIndexToInfo(address) + function guardianIndexToInfo(uint256 index) external view returns (bytes32 info_hash, uint256 update_block, bytes32 guardian, CandidateStatus status); + + /// @notice Query voter's vote of one specific guardian given its guardian index, substrate + /// @custom:selector 0xfaad0ba2 + /// guardianVotes(bytes32,uint256) + function guardianVotes(bytes32 voter, uint256 guardian_index) external view returns (GuardianVote guardian_vote, uint256 potential_proposal_index); + + /// @notice Query voter's vote of one specific guardian given its guardian index, ethereum + /// @custom:selector 0xcbdbf0b2 + /// guardianVotes(address,uint256) + function guardianVotes(address voter, uint256 guardian_index) external view returns (GuardianVote guardian_vote, uint256 potential_proposal_index); } \ No newline at end of file diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index 1d079dd3f4..4e4aaca285 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -3,7 +3,6 @@ use fp_evm::PrecompileHandle; use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; -use pallet_collab_ai_common::GuardianVote; use pallet_evm::AddressMapping; use precompile_utils::prelude::*; use sp_runtime::traits::Dispatchable; @@ -11,16 +10,19 @@ use sp_runtime::traits::Dispatchable; use sp_core::{H256, U256}; use sp_std::marker::PhantomData; +use pallet_collab_ai_common::{CandidateStatus, GuardianVote}; + pub struct GuardianPrecompile(PhantomData); #[precompile_utils::precompile] impl GuardianPrecompile where Runtime: pallet_guardian::Config + pallet_evm::Config, - Runtime::AccountId: From<[u8; 32]>, + Runtime::AccountId: From<[u8; 32]> + Into<[u8; 32]>, Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, Runtime::RuntimeCall: From>, ::RuntimeOrigin: From>, + BlockNumberFor: TryFrom + Into, { #[precompile::public("registGuardian(bytes32)")] fn regist_guardian(handle: &mut impl PrecompileHandle, info_hash: H256) -> EvmResult { @@ -87,6 +89,16 @@ where } } + fn guardian_vote_to(guardian_vote: Option) -> MayRevert<(u8, U256)> { + match guardian_vote { + None => Ok((0u8, 0.into())), + Some(GuardianVote::Neutral) => Ok((0u8, 0.into())), + Some(GuardianVote::Aye) => Ok((1u8, 0.into())), + Some(GuardianVote::Nay) => Ok((2u8, 0.into())), + Some(GuardianVote::Specific(i)) => Ok((3u8, i.into())), + } + } + #[precompile::public("removeAllVotes()")] fn remove_all_votes(handle: &mut impl PrecompileHandle) -> EvmResult { let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); @@ -96,4 +108,123 @@ where Ok(()) } + + #[precompile::public("PublicGuardianCount()")] + #[precompile::view] + fn public_guardian_count(handle: &mut impl PrecompileHandle) -> EvmResult { + // Storage item: GuardianIndex u128: + // 16 + handle.record_db_read::(16)?; + + Ok(pallet_guardian::Pallet::::public_guardian_count().into()) + } + + #[precompile::public("publicGuardianToIndex(bytes32)")] + #[precompile::view] + fn public_guardian_to_index_sub( + handle: &mut impl PrecompileHandle, + guardian: H256, + ) -> EvmResult { + // Storage item: GuardianIndex u128: + // Twox64Concat(8) + T::AccountId(32) + GuardianIndex(16) + handle.record_db_read::(56)?; + + let guardian = Runtime::AccountId::from(guardian); + + Ok(pallet_guardian::Pallet::::public_guardian_to_index(guardian).into()) + } + + #[precompile::public("publicGuardianToIndex(address)")] + #[precompile::view] + fn public_guardian_to_index_evm( + handle: &mut impl PrecompileHandle, + guardian: Address, + ) -> EvmResult { + // Storage item: GuardianIndex u128: + // Twox64Concat(8) + T::AccountId(32) + GuardianIndex(16) + handle.record_db_read::(56)?; + + let guardian = Runtime::AddressMapping::into_account_id(guardian.into()); + + Ok(pallet_guardian::Pallet::::public_guardian_to_index(guardian).into()) + } + + fn candidate_status_to_u8(status: CandidateStatus) -> MayRevert { + status + .try_into() + .map_err(|_| RevertReason::value_is_too_large("trackId type").into()) + } + + #[precompile::public("guardianIndexToInfo(uint256)")] + #[precompile::view] + fn guardian_index_to_info( + handle: &mut impl PrecompileHandle, + index: U256, + ) -> EvmResult<(H256, U256, H256, u8)> { + // Storage item: GuardianIndex u128: + // Twox64Concat(8) + GuardianIndex(16) + InfoHash(32) + BlockNumber(4) + T::AccountId(32) + CandidateStatus(1) + handle.record_db_read::(93)?; + + let index: AssetBalanceOf = index.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + let (info_hash, update_block, guardian, status) = + pallet_guardian::Pallet::::guardian_index_to_info(index); + + let update_block: U256 = update_block.into(); + + let guardian: [u8; 32] = guardian.into(); + let guardian: H256 = guardian.into(); + + let status = Self::candidate_status_to_u8(status).in_field("candidateStatus")?; + + Ok((info_hash, update_block, guardian, status)) + } + + #[precompile::public("guardianVotes(bytes32,uint256)")] + #[precompile::view] + fn guardian_votes_sub( + handle: &mut impl PrecompileHandle, + voter: H256, + guardian_index: U256, + ) -> EvmResult<(u8, U256)> { + // Storage item: GuardianIndex u128: + // 2 * Twox64Concat(8) + GuardianIndex(16) + T::AccountId(32) + GuardianVote(1) + ProposalIndex(16) + handle.record_db_read::(81)?; + + let voter = Runtime::AccountId::from(voter); + + let guardian_index: AssetBalanceOf = guardian_index.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + let result = Self::guardian_vote_to( + pallet_guardian::Pallet::::guardian_votes(voter, guardian_index), + ) + .in_field("GuardianVote")?; + + Ok(result) + } + + #[precompile::public("guardianVotes(address,uint256)")] + #[precompile::view] + fn guardian_votes_evm( + handle: &mut impl PrecompileHandle, + voter: Address, + guardian_index: U256, + ) -> EvmResult<(u8, U256)> { + // Storage item: GuardianIndex u128: + // 2 * Twox64Concat(8) + GuardianIndex(16) + T::AccountId(32) + GuardianVote(1) + ProposalIndex(16) + handle.record_db_read::(81)?; + + let voter = Runtime::AddressMapping::into_account_id(voter.into()); + let guardian_index: AssetBalanceOf = guardian_index.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + let result = Self::guardian_vote_to( + pallet_guardian::Pallet::::guardian_votes(voter, guardian_index), + ) + .in_field("GuardianVote")?; + + Ok(result) + } } From 9d5535acc8aaff0af4c18594905cd6da0773bde9 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 9 Oct 2024 13:04:12 +0800 Subject: [PATCH 076/215] chore: fix --- .../precompiles/collab-ai/curator/src/lib.rs | 12 +++---- .../precompiles/collab-ai/guardian/src/lib.rs | 32 ++++++++++--------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index 7e6a7746de..29e6534399 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -1,6 +1,6 @@ #![cfg_attr(not(feature = "std"), no_std)] -use fp_evm::PrecompileHandle; +use fp_evm::{PrecompileFailure, PrecompileHandle}; use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; use pallet_evm::AddressMapping; @@ -61,7 +61,7 @@ where // 16 handle.record_db_read::(16)?; - Ok(pallet_curator::Pallet::::public_curator_count().into()) + Ok(pallet_curator::Pallet::::public_curator_count().into()) } #[precompile::public("publicCuratorToIndex(bytes32)")] @@ -74,9 +74,9 @@ where // Twox64Concat(8) + T::AccountId(32) + CuratorIndex(16) handle.record_db_read::(56)?; - let curator = Runtime::AccountId::from(curator); + let curator = Runtime::AccountId::from(curator.into()); - Ok(pallet_curator::Pallet::::public_curator_to_index(curator).into()) + Ok(pallet_curator::Pallet::::public_curator_to_index(curator).into()) } #[precompile::public("publicCuratorToIndex(address)")] @@ -91,7 +91,7 @@ where let curator = Runtime::AddressMapping::into_account_id(curator.into()); - Ok(pallet_curator::Pallet::::public_curator_to_index(curator).into()) + Ok(pallet_curator::Pallet::::public_curator_to_index(curator).into()) } fn candidate_status_to_u8(status: CandidateStatus) -> MayRevert { @@ -114,7 +114,7 @@ where Into::::into(RevertReason::value_is_too_large("index type")) })?; let (info_hash, update_block, curator, status) = - pallet_curator::Pallet::::curator_index_to_info(index); + pallet_curator::Pallet::::curator_index_to_info(index); let update_block: U256 = update_block.into(); diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index 4e4aaca285..136ad605e6 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -1,8 +1,8 @@ #![cfg_attr(not(feature = "std"), no_std)] -use fp_evm::PrecompileHandle; - +use fp_evm::{PrecompileFailure, PrecompileHandle}; use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; +use frame_system::pallet_prelude::BlockNumberFor; use pallet_evm::AddressMapping; use precompile_utils::prelude::*; use sp_runtime::traits::Dispatchable; @@ -116,7 +116,7 @@ where // 16 handle.record_db_read::(16)?; - Ok(pallet_guardian::Pallet::::public_guardian_count().into()) + Ok(pallet_guardian::Pallet::::public_guardian_count().into()) } #[precompile::public("publicGuardianToIndex(bytes32)")] @@ -129,9 +129,9 @@ where // Twox64Concat(8) + T::AccountId(32) + GuardianIndex(16) handle.record_db_read::(56)?; - let guardian = Runtime::AccountId::from(guardian); + let guardian = Runtime::AccountId::from(guardian.into()); - Ok(pallet_guardian::Pallet::::public_guardian_to_index(guardian).into()) + Ok(pallet_guardian::Pallet::::public_guardian_to_index(guardian).into()) } #[precompile::public("publicGuardianToIndex(address)")] @@ -146,7 +146,7 @@ where let guardian = Runtime::AddressMapping::into_account_id(guardian.into()); - Ok(pallet_guardian::Pallet::::public_guardian_to_index(guardian).into()) + Ok(pallet_guardian::Pallet::::public_guardian_to_index(guardian).into()) } fn candidate_status_to_u8(status: CandidateStatus) -> MayRevert { @@ -168,8 +168,8 @@ where let index: AssetBalanceOf = index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; - let (info_hash, update_block, guardian, status) = - pallet_guardian::Pallet::::guardian_index_to_info(index); + let Some((info_hash, update_block, guardian, status)) = + pallet_guardian::Pallet::::guardian_index_to_info(index); let update_block: U256 = update_block.into(); @@ -192,14 +192,15 @@ where // 2 * Twox64Concat(8) + GuardianIndex(16) + T::AccountId(32) + GuardianVote(1) + ProposalIndex(16) handle.record_db_read::(81)?; - let voter = Runtime::AccountId::from(voter); + let voter = Runtime::AccountId::from(voter.into()); let guardian_index: AssetBalanceOf = guardian_index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; - let result = Self::guardian_vote_to( - pallet_guardian::Pallet::::guardian_votes(voter, guardian_index), - ) + let result = Self::guardian_vote_to(pallet_guardian::Pallet::::guardian_votes( + voter, + guardian_index, + )) .in_field("GuardianVote")?; Ok(result) @@ -220,9 +221,10 @@ where let guardian_index: AssetBalanceOf = guardian_index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; - let result = Self::guardian_vote_to( - pallet_guardian::Pallet::::guardian_votes(voter, guardian_index), - ) + let result = Self::guardian_vote_to(pallet_guardian::Pallet::::guardian_votes( + voter, + guardian_index, + )) .in_field("GuardianVote")?; Ok(result) From 2d9149393d4eb5afa9fdd1501974f0157a11794b Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 9 Oct 2024 13:41:12 +0800 Subject: [PATCH 077/215] chore: fix --- .../precompiles/collab-ai/curator/Curator.sol | 6 +-- .../precompiles/collab-ai/curator/src/lib.rs | 45 ++++++++++------ .../collab-ai/guardian/Guardian.sol | 6 +-- .../precompiles/collab-ai/guardian/src/lib.rs | 53 ++++++++++++------- 4 files changed, 69 insertions(+), 41 deletions(-) diff --git a/parachain/precompiles/collab-ai/curator/Curator.sol b/parachain/precompiles/collab-ai/curator/Curator.sol index bb4fc874b0..a4869d5bf2 100644 --- a/parachain/precompiles/collab-ai/curator/Curator.sol +++ b/parachain/precompiles/collab-ai/curator/Curator.sol @@ -35,17 +35,17 @@ interface ICurator { /// @param curator: substrate format address /// @custom:selector 0x039997d0 /// publicCuratorToIndex(bytes32) - function publicCuratorToIndex(bytes32 curator) external view returns (uint256 index); + function publicCuratorToIndex(bytes32 curator) external view returns (bool exist, uint256 index); /// @notice public curator to index, ethereum address format /// @param curator: ethereum format address /// @custom:selector 0x52fe170b /// publicCuratorToIndex(address) - function publicCuratorToIndex(address curator) external view returns (uint256 index); + function publicCuratorToIndex(address curator) external view returns (bool exist, uint256 index); /// @notice Curator index to curator info /// @param index: Curator index /// @custom:selector 0x916d9a0d /// curatorIndexToInfo(address) - function curatorIndexToInfo(uint256 index) external view returns (bytes32 info_hash, uint256 update_block, bytes32 curator, CandidateStatus status); + function curatorIndexToInfo(uint256 index) external view returns (bool exist, bytes32 info_hash, uint256 update_block, bytes32 curator, CandidateStatus status); } \ No newline at end of file diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index 29e6534399..eb12a2effd 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -69,14 +69,18 @@ where fn public_curator_to_index_sub( handle: &mut impl PrecompileHandle, curator: H256, - ) -> EvmResult { + ) -> EvmResult<(bool, U256)> { // Storage item: CuratorIndex u128: // Twox64Concat(8) + T::AccountId(32) + CuratorIndex(16) handle.record_db_read::(56)?; let curator = Runtime::AccountId::from(curator.into()); - Ok(pallet_curator::Pallet::::public_curator_to_index(curator).into()) + if let Some(result) = pallet_curator::Pallet::::public_curator_to_index(guardian) { + Ok((true, result.into())) + } else { + Ok((false, 0.into())) + } } #[precompile::public("publicCuratorToIndex(address)")] @@ -91,13 +95,19 @@ where let curator = Runtime::AddressMapping::into_account_id(curator.into()); - Ok(pallet_curator::Pallet::::public_curator_to_index(curator).into()) + if let Some(result) = pallet_curator::Pallet::::public_curator_to_index(guardian) { + Ok((true, result.into())) + } else { + Ok((false, 0.into())) + } } fn candidate_status_to_u8(status: CandidateStatus) -> MayRevert { - status - .try_into() - .map_err(|_| RevertReason::value_is_too_large("trackId type").into()) + match status { + CandidateStatus::Unverified => Ok(0u8), + CandidateStatus::Verified => Ok(1u8), + CandidateStatus::Banned => Ok(2u8), + } } #[precompile::public("curatorIndexToInfo(uint256)")] @@ -105,24 +115,27 @@ where fn curator_index_to_info( handle: &mut impl PrecompileHandle, index: U256, - ) -> EvmResult<(H256, U256, H256, u8)> { + ) -> EvmResult<(bool, H256, U256, H256, u8)> { // Storage item: CuratorIndex u128: // Twox64Concat(8) + CuratorIndex(16) + InfoHash(32) + BlockNumber(4) + T::AccountId(32) + CandidateStatus(1) handle.record_db_read::(93)?; - let index: AssetBalanceOf = index.try_into().map_err(|_| { + let index = index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; - let (info_hash, update_block, curator, status) = - pallet_curator::Pallet::::curator_index_to_info(index); - - let update_block: U256 = update_block.into(); + if let Some((info_hash, update_block, curator, status)) = + pallet_curator::Pallet::::curator_index_to_info(index) + { + let update_block: U256 = update_block.into(); - let curator: [u8; 32] = curator.into(); - let curator: H256 = curator.into(); + let curator: [u8; 32] = curator.into(); + let curator: H256 = curator.into(); - let status = Self::candidate_status_to_u8(status).in_field("candidateStatus")?; + let status = Self::candidate_status_to_u8(status).in_field("candidateStatus")?; - Ok((info_hash, update_block, curator, status)) + Ok((true, info_hash, update_block, curator, status)) + } else { + Ok((false, 0.into(), 0.into(), 0.into(), 0u8)) + } } } diff --git a/parachain/precompiles/collab-ai/guardian/Guardian.sol b/parachain/precompiles/collab-ai/guardian/Guardian.sol index 717cb5e8a3..e518ae6de4 100644 --- a/parachain/precompiles/collab-ai/guardian/Guardian.sol +++ b/parachain/precompiles/collab-ai/guardian/Guardian.sol @@ -52,19 +52,19 @@ interface IGuardian { /// @param guardian: substrate format address /// @custom:selector 0xf46175b8 /// publicGuardianToIndex(bytes32) - function publicGuardianToIndex(bytes32 guardian) external view returns (uint256 index); + function publicGuardianToIndex(bytes32 guardian) external view returns (bool exist, uint256 index); /// @notice public guardian to index, ethereum address format /// @param guardian: ethereum format address /// @custom:selector 0x02916580 /// publicGuardianToIndex(address) - function publicGuardianToIndex(address guardian) external view returns (uint256 index); + function publicGuardianToIndex(address guardian) external view returns (bool exist, uint256 index); /// @notice Guardian index to guardian info /// @param index: Guardian index /// @custom:selector 0x59c95743 /// guardianIndexToInfo(address) - function guardianIndexToInfo(uint256 index) external view returns (bytes32 info_hash, uint256 update_block, bytes32 guardian, CandidateStatus status); + function guardianIndexToInfo(uint256 index) external view returns (bool exist, bytes32 info_hash, uint256 update_block, bytes32 guardian, CandidateStatus status); /// @notice Query voter's vote of one specific guardian given its guardian index, substrate /// @custom:selector 0xfaad0ba2 diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index 136ad605e6..07a5e13458 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -124,14 +124,19 @@ where fn public_guardian_to_index_sub( handle: &mut impl PrecompileHandle, guardian: H256, - ) -> EvmResult { + ) -> EvmResult<(bool, U256)> { // Storage item: GuardianIndex u128: // Twox64Concat(8) + T::AccountId(32) + GuardianIndex(16) handle.record_db_read::(56)?; let guardian = Runtime::AccountId::from(guardian.into()); - Ok(pallet_guardian::Pallet::::public_guardian_to_index(guardian).into()) + if let Some(result) = pallet_guardian::Pallet::::public_guardian_to_index(guardian) + { + Ok((true, result.into())) + } else { + Ok((false, 0.into())) + } } #[precompile::public("publicGuardianToIndex(address)")] @@ -139,20 +144,27 @@ where fn public_guardian_to_index_evm( handle: &mut impl PrecompileHandle, guardian: Address, - ) -> EvmResult { + ) -> EvmResult<(bool, U256)> { // Storage item: GuardianIndex u128: // Twox64Concat(8) + T::AccountId(32) + GuardianIndex(16) handle.record_db_read::(56)?; let guardian = Runtime::AddressMapping::into_account_id(guardian.into()); - Ok(pallet_guardian::Pallet::::public_guardian_to_index(guardian).into()) + if let Some(result) = pallet_guardian::Pallet::::public_guardian_to_index(guardian) + { + Ok((true, result.into())) + } else { + Ok((false, 0.into())) + } } fn candidate_status_to_u8(status: CandidateStatus) -> MayRevert { - status - .try_into() - .map_err(|_| RevertReason::value_is_too_large("trackId type").into()) + match status { + CandidateStatus::Unverified => Ok(0u8), + CandidateStatus::Verified => Ok(1u8), + CandidateStatus::Banned => Ok(2u8), + } } #[precompile::public("guardianIndexToInfo(uint256)")] @@ -160,25 +172,28 @@ where fn guardian_index_to_info( handle: &mut impl PrecompileHandle, index: U256, - ) -> EvmResult<(H256, U256, H256, u8)> { + ) -> EvmResult<(bool, H256, U256, H256, u8)> { // Storage item: GuardianIndex u128: // Twox64Concat(8) + GuardianIndex(16) + InfoHash(32) + BlockNumber(4) + T::AccountId(32) + CandidateStatus(1) handle.record_db_read::(93)?; - let index: AssetBalanceOf = index.try_into().map_err(|_| { + let index = index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; - let Some((info_hash, update_block, guardian, status)) = - pallet_guardian::Pallet::::guardian_index_to_info(index); + if let Some((info_hash, update_block, guardian, status)) = + pallet_guardian::Pallet::::guardian_index_to_info(index) + { + let update_block: U256 = update_block.into(); - let update_block: U256 = update_block.into(); + let guardian: [u8; 32] = guardian.into(); + let guardian: H256 = guardian.into(); - let guardian: [u8; 32] = guardian.into(); - let guardian: H256 = guardian.into(); - - let status = Self::candidate_status_to_u8(status).in_field("candidateStatus")?; + let status = Self::candidate_status_to_u8(status).in_field("candidateStatus")?; - Ok((info_hash, update_block, guardian, status)) + Ok((true, info_hash, update_block, guardian, status)) + } else { + Ok((false, 0.into(), 0.into(), 0.into(), 0u8)) + } } #[precompile::public("guardianVotes(bytes32,uint256)")] @@ -194,7 +209,7 @@ where let voter = Runtime::AccountId::from(voter.into()); - let guardian_index: AssetBalanceOf = guardian_index.try_into().map_err(|_| { + let guardian_index = guardian_index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; let result = Self::guardian_vote_to(pallet_guardian::Pallet::::guardian_votes( @@ -218,7 +233,7 @@ where handle.record_db_read::(81)?; let voter = Runtime::AddressMapping::into_account_id(voter.into()); - let guardian_index: AssetBalanceOf = guardian_index.try_into().map_err(|_| { + let guardian_index = guardian_index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; let result = Self::guardian_vote_to(pallet_guardian::Pallet::::guardian_votes( From 43786983d470e7fce3ce4dec72099522f566d4aa Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 9 Oct 2024 13:59:37 +0800 Subject: [PATCH 078/215] chore: fix --- .../precompiles/collab-ai/curator/Curator.sol | 6 +++--- .../precompiles/collab-ai/curator/src/lib.rs | 16 ++++++++++++---- .../precompiles/collab-ai/guardian/Guardian.sol | 10 +++++++--- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/parachain/precompiles/collab-ai/curator/Curator.sol b/parachain/precompiles/collab-ai/curator/Curator.sol index a4869d5bf2..3a90955eac 100644 --- a/parachain/precompiles/collab-ai/curator/Curator.sol +++ b/parachain/precompiles/collab-ai/curator/Curator.sol @@ -31,19 +31,19 @@ interface ICurator { /// publicCuratorCount() function publicCuratorCount() external view returns (uint256 count); - /// @notice public curator to index, substrate address format + /// @notice public curator to index, substrate address format, bool represents if such index exists /// @param curator: substrate format address /// @custom:selector 0x039997d0 /// publicCuratorToIndex(bytes32) function publicCuratorToIndex(bytes32 curator) external view returns (bool exist, uint256 index); - /// @notice public curator to index, ethereum address format + /// @notice public curator to index, ethereum address format, bool represents if such index exists /// @param curator: ethereum format address /// @custom:selector 0x52fe170b /// publicCuratorToIndex(address) function publicCuratorToIndex(address curator) external view returns (bool exist, uint256 index); - /// @notice Curator index to curator info + /// @notice Curator index to curator info, bool represents if such info exists /// @param index: Curator index /// @custom:selector 0x916d9a0d /// curatorIndexToInfo(address) diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index eb12a2effd..482ca5b03c 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -3,11 +3,12 @@ use fp_evm::{PrecompileFailure, PrecompileHandle}; use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; +use frame_system::pallet_prelude::BlockNumberFor; use pallet_evm::AddressMapping; use precompile_utils::prelude::*; use sp_runtime::traits::Dispatchable; -use sp_core::H256; +use sp_core::{H256, U256}; use sp_std::marker::PhantomData; use pallet_collab_ai_common::CandidateStatus; @@ -74,9 +75,10 @@ where // Twox64Concat(8) + T::AccountId(32) + CuratorIndex(16) handle.record_db_read::(56)?; + let curator: [u8; 32] = curator.into(); let curator = Runtime::AccountId::from(curator.into()); - if let Some(result) = pallet_curator::Pallet::::public_curator_to_index(guardian) { + if let Some(result) = pallet_curator::Pallet::::public_curator_to_index(curator) { Ok((true, result.into())) } else { Ok((false, 0.into())) @@ -95,7 +97,7 @@ where let curator = Runtime::AddressMapping::into_account_id(curator.into()); - if let Some(result) = pallet_curator::Pallet::::public_curator_to_index(guardian) { + if let Some(result) = pallet_curator::Pallet::::public_curator_to_index(curator) { Ok((true, result.into())) } else { Ok((false, 0.into())) @@ -135,7 +137,13 @@ where Ok((true, info_hash, update_block, curator, status)) } else { - Ok((false, 0.into(), 0.into(), 0.into(), 0u8)) + Ok(( + false, + Default::default(), + Default::default(), + Default::default(), + Default::default(), + )) } } } diff --git a/parachain/precompiles/collab-ai/guardian/Guardian.sol b/parachain/precompiles/collab-ai/guardian/Guardian.sol index e518ae6de4..1036296d8e 100644 --- a/parachain/precompiles/collab-ai/guardian/Guardian.sol +++ b/parachain/precompiles/collab-ai/guardian/Guardian.sol @@ -48,30 +48,34 @@ interface IGuardian { /// publicGuardianCount() function publicGuardianCount() external view returns (uint256 count); - /// @notice public guardian to index, substrate address format + /// @notice public guardian to index, substrate address format, bool represents if such index exists /// @param guardian: substrate format address /// @custom:selector 0xf46175b8 /// publicGuardianToIndex(bytes32) function publicGuardianToIndex(bytes32 guardian) external view returns (bool exist, uint256 index); - /// @notice public guardian to index, ethereum address format + /// @notice public guardian to index, ethereum address format, bool represents if such index exists /// @param guardian: ethereum format address /// @custom:selector 0x02916580 /// publicGuardianToIndex(address) function publicGuardianToIndex(address guardian) external view returns (bool exist, uint256 index); - /// @notice Guardian index to guardian info + /// @notice Guardian index to guardian info, bool represents if such info exists /// @param index: Guardian index /// @custom:selector 0x59c95743 /// guardianIndexToInfo(address) function guardianIndexToInfo(uint256 index) external view returns (bool exist, bytes32 info_hash, uint256 update_block, bytes32 guardian, CandidateStatus status); /// @notice Query voter's vote of one specific guardian given its guardian index, substrate + /// @param voter: voter address, substrate + /// @param guardian_index: Guardian index /// @custom:selector 0xfaad0ba2 /// guardianVotes(bytes32,uint256) function guardianVotes(bytes32 voter, uint256 guardian_index) external view returns (GuardianVote guardian_vote, uint256 potential_proposal_index); /// @notice Query voter's vote of one specific guardian given its guardian index, ethereum + /// @param voter: voter address, ethereum + /// @param guardian_index: Guardian index /// @custom:selector 0xcbdbf0b2 /// guardianVotes(address,uint256) function guardianVotes(address voter, uint256 guardian_index) external view returns (GuardianVote guardian_vote, uint256 potential_proposal_index); From d07cab668444316bc101e96c48dbbbf230a6f7d0 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 9 Oct 2024 14:12:10 +0800 Subject: [PATCH 079/215] chore: fix --- .../precompiles/collab-ai/curator/src/lib.rs | 4 ++-- .../precompiles/collab-ai/guardian/src/lib.rs | 16 +++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index 482ca5b03c..9bd1d61a1a 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -81,7 +81,7 @@ where if let Some(result) = pallet_curator::Pallet::::public_curator_to_index(curator) { Ok((true, result.into())) } else { - Ok((false, 0.into())) + Ok((false, Default::default())) } } @@ -100,7 +100,7 @@ where if let Some(result) = pallet_curator::Pallet::::public_curator_to_index(curator) { Ok((true, result.into())) } else { - Ok((false, 0.into())) + Ok((false, Default::default())) } } diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index 07a5e13458..c4727f8b75 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -135,7 +135,7 @@ where { Ok((true, result.into())) } else { - Ok((false, 0.into())) + Ok((false, Default::default())) } } @@ -155,7 +155,7 @@ where { Ok((true, result.into())) } else { - Ok((false, 0.into())) + Ok((false, Default::default())) } } @@ -192,7 +192,13 @@ where Ok((true, info_hash, update_block, guardian, status)) } else { - Ok((false, 0.into(), 0.into(), 0.into(), 0u8)) + Ok(( + false, + Default::default(), + Default::default(), + Default::default(), + Default::default(), + )) } } @@ -209,7 +215,7 @@ where let voter = Runtime::AccountId::from(voter.into()); - let guardian_index = guardian_index.try_into().map_err(|_| { + let guardian_index: u128 = guardian_index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; let result = Self::guardian_vote_to(pallet_guardian::Pallet::::guardian_votes( @@ -233,7 +239,7 @@ where handle.record_db_read::(81)?; let voter = Runtime::AddressMapping::into_account_id(voter.into()); - let guardian_index = guardian_index.try_into().map_err(|_| { + let guardian_index: u128 = guardian_index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; let result = Self::guardian_vote_to(pallet_guardian::Pallet::::guardian_votes( From 7d643f5d77a89bf7c677b6d5212bdcc30c91217a Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 9 Oct 2024 14:29:52 +0800 Subject: [PATCH 080/215] chore: fix --- .../precompiles/collab-ai/curator/Curator.sol | 6 --- .../precompiles/collab-ai/curator/src/lib.rs | 25 ++-------- .../collab-ai/guardian/Guardian.sol | 13 ----- .../precompiles/collab-ai/guardian/src/lib.rs | 48 +------------------ 4 files changed, 5 insertions(+), 87 deletions(-) diff --git a/parachain/precompiles/collab-ai/curator/Curator.sol b/parachain/precompiles/collab-ai/curator/Curator.sol index 3a90955eac..8d74cbe300 100644 --- a/parachain/precompiles/collab-ai/curator/Curator.sol +++ b/parachain/precompiles/collab-ai/curator/Curator.sol @@ -37,12 +37,6 @@ interface ICurator { /// publicCuratorToIndex(bytes32) function publicCuratorToIndex(bytes32 curator) external view returns (bool exist, uint256 index); - /// @notice public curator to index, ethereum address format, bool represents if such index exists - /// @param curator: ethereum format address - /// @custom:selector 0x52fe170b - /// publicCuratorToIndex(address) - function publicCuratorToIndex(address curator) external view returns (bool exist, uint256 index); - /// @notice Curator index to curator info, bool represents if such info exists /// @param index: Curator index /// @custom:selector 0x916d9a0d diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index 9bd1d61a1a..e2072a6b6c 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -19,7 +19,7 @@ pub struct CuratorPrecompile(PhantomData); impl CuratorPrecompile where Runtime: pallet_curator::Config + pallet_evm::Config, - Runtime::AccountId: Into<[u8; 32]>, + Runtime::AccountId: From<[u8; 32]> + Into<[u8; 32]>, Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, Runtime::RuntimeCall: From>, ::RuntimeOrigin: From>, @@ -67,7 +67,7 @@ where #[precompile::public("publicCuratorToIndex(bytes32)")] #[precompile::view] - fn public_curator_to_index_sub( + fn public_curator_to_index( handle: &mut impl PrecompileHandle, curator: H256, ) -> EvmResult<(bool, U256)> { @@ -85,25 +85,6 @@ where } } - #[precompile::public("publicCuratorToIndex(address)")] - #[precompile::view] - fn public_curator_to_index_evm( - handle: &mut impl PrecompileHandle, - curator: Address, - ) -> EvmResult { - // Storage item: CuratorIndex u128: - // Twox64Concat(8) + T::AccountId(32) + CuratorIndex(16) - handle.record_db_read::(56)?; - - let curator = Runtime::AddressMapping::into_account_id(curator.into()); - - if let Some(result) = pallet_curator::Pallet::::public_curator_to_index(curator) { - Ok((true, result.into())) - } else { - Ok((false, Default::default())) - } - } - fn candidate_status_to_u8(status: CandidateStatus) -> MayRevert { match status { CandidateStatus::Unverified => Ok(0u8), @@ -122,7 +103,7 @@ where // Twox64Concat(8) + CuratorIndex(16) + InfoHash(32) + BlockNumber(4) + T::AccountId(32) + CandidateStatus(1) handle.record_db_read::(93)?; - let index = index.try_into().map_err(|_| { + let index: u128 = index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; if let Some((info_hash, update_block, curator, status)) = diff --git a/parachain/precompiles/collab-ai/guardian/Guardian.sol b/parachain/precompiles/collab-ai/guardian/Guardian.sol index 1036296d8e..4f171a134c 100644 --- a/parachain/precompiles/collab-ai/guardian/Guardian.sol +++ b/parachain/precompiles/collab-ai/guardian/Guardian.sol @@ -54,12 +54,6 @@ interface IGuardian { /// publicGuardianToIndex(bytes32) function publicGuardianToIndex(bytes32 guardian) external view returns (bool exist, uint256 index); - /// @notice public guardian to index, ethereum address format, bool represents if such index exists - /// @param guardian: ethereum format address - /// @custom:selector 0x02916580 - /// publicGuardianToIndex(address) - function publicGuardianToIndex(address guardian) external view returns (bool exist, uint256 index); - /// @notice Guardian index to guardian info, bool represents if such info exists /// @param index: Guardian index /// @custom:selector 0x59c95743 @@ -72,11 +66,4 @@ interface IGuardian { /// @custom:selector 0xfaad0ba2 /// guardianVotes(bytes32,uint256) function guardianVotes(bytes32 voter, uint256 guardian_index) external view returns (GuardianVote guardian_vote, uint256 potential_proposal_index); - - /// @notice Query voter's vote of one specific guardian given its guardian index, ethereum - /// @param voter: voter address, ethereum - /// @param guardian_index: Guardian index - /// @custom:selector 0xcbdbf0b2 - /// guardianVotes(address,uint256) - function guardianVotes(address voter, uint256 guardian_index) external view returns (GuardianVote guardian_vote, uint256 potential_proposal_index); } \ No newline at end of file diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index c4727f8b75..e6873ab937 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -121,7 +121,7 @@ where #[precompile::public("publicGuardianToIndex(bytes32)")] #[precompile::view] - fn public_guardian_to_index_sub( + fn public_guardian_to_index( handle: &mut impl PrecompileHandle, guardian: H256, ) -> EvmResult<(bool, U256)> { @@ -139,26 +139,6 @@ where } } - #[precompile::public("publicGuardianToIndex(address)")] - #[precompile::view] - fn public_guardian_to_index_evm( - handle: &mut impl PrecompileHandle, - guardian: Address, - ) -> EvmResult<(bool, U256)> { - // Storage item: GuardianIndex u128: - // Twox64Concat(8) + T::AccountId(32) + GuardianIndex(16) - handle.record_db_read::(56)?; - - let guardian = Runtime::AddressMapping::into_account_id(guardian.into()); - - if let Some(result) = pallet_guardian::Pallet::::public_guardian_to_index(guardian) - { - Ok((true, result.into())) - } else { - Ok((false, Default::default())) - } - } - fn candidate_status_to_u8(status: CandidateStatus) -> MayRevert { match status { CandidateStatus::Unverified => Ok(0u8), @@ -204,7 +184,7 @@ where #[precompile::public("guardianVotes(bytes32,uint256)")] #[precompile::view] - fn guardian_votes_sub( + fn guardian_votes( handle: &mut impl PrecompileHandle, voter: H256, guardian_index: U256, @@ -226,28 +206,4 @@ where Ok(result) } - - #[precompile::public("guardianVotes(address,uint256)")] - #[precompile::view] - fn guardian_votes_evm( - handle: &mut impl PrecompileHandle, - voter: Address, - guardian_index: U256, - ) -> EvmResult<(u8, U256)> { - // Storage item: GuardianIndex u128: - // 2 * Twox64Concat(8) + GuardianIndex(16) + T::AccountId(32) + GuardianVote(1) + ProposalIndex(16) - handle.record_db_read::(81)?; - - let voter = Runtime::AddressMapping::into_account_id(voter.into()); - let guardian_index: u128 = guardian_index.try_into().map_err(|_| { - Into::::into(RevertReason::value_is_too_large("index type")) - })?; - let result = Self::guardian_vote_to(pallet_guardian::Pallet::::guardian_votes( - voter, - guardian_index, - )) - .in_field("GuardianVote")?; - - Ok(result) - } } From e80e9d55ea40ea656e272276e4336a9cf0a75ae8 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 9 Oct 2024 14:39:13 +0800 Subject: [PATCH 081/215] chore: fix --- parachain/precompiles/collab-ai/guardian/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index e6873ab937..f76ddd9446 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -157,7 +157,7 @@ where // Twox64Concat(8) + GuardianIndex(16) + InfoHash(32) + BlockNumber(4) + T::AccountId(32) + CandidateStatus(1) handle.record_db_read::(93)?; - let index = index.try_into().map_err(|_| { + let index: u128 = index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; if let Some((info_hash, update_block, guardian, status)) = From 611d8f831d94e414fb58c1950686729c276c94f0 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 9 Oct 2024 14:56:06 +0800 Subject: [PATCH 082/215] chore: fix clippy --- .../precompiles/collab-ai/curator/src/lib.rs | 2 +- .../collab-ai/pool-proposal/PoolProposal.sol | 83 +++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index e2072a6b6c..892e103550 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -76,7 +76,7 @@ where handle.record_db_read::(56)?; let curator: [u8; 32] = curator.into(); - let curator = Runtime::AccountId::from(curator.into()); + let curator = Runtime::AccountId::from(curator); if let Some(result) = pallet_curator::Pallet::::public_curator_to_index(curator) { Ok((true, result.into())) diff --git a/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol b/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol index 31936a8e9b..0da3c1463c 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol +++ b/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol @@ -2,6 +2,54 @@ pragma solidity >=0.8.3; interface IPoolProposal { + /// @dev A structure for bonding of all kind + struct Bond { + bytes32 owner; + uint256 amount; + } + + /// @dev A structure for proposal and its expiry time + struct PoolProposalStatus { + uint256 index; + uint256 expiryTime; + } + + struct PoolProposalInfo { + // Proposer/Curator + bytes32 proposer; + // Hash of pool info like legal files etc. + bytes32 infoHash; + // The maximum investing amount that the pool can handle + uint256 maxPoolSize; + // If proposal passed, when the investing pool will start, Block number + uint256 poolStartTime; + // If proposal passed, when the investing pool will end, Block number + uint256 poolEndTime; + // estimated APR, but in percentage form + // i.e. 100 => 100% + uint256 estimatedEpochReward; + // Proposal status flags + // /// Whether the pool proposal passing the committee/democracy voting. + // /// A valid pool must passing committee/public's audit procedure regarding legal files and other pool parameters. + // const PUBLIC_VOTE_PASSED = 0b0000_0001; + // /// + // /// Whether the minimum Investing amount proposed by curator is satisfied. + // /// Currently, a full size must be satisfied. + // /// Once a pool is satisfied this requirement, all Investing amount can no longer be withdrawed + // /// unless the pool is later denied passing by voting or until the end of pool maturity. + // /// Otherwise, the pool will be refunded. + // const STAKE_AMOUNT_PASSED = 0b0000_0010; + // /// + // /// Whether the pool guardian has been selected + // /// A valid pool must have guardian or a default one will be used (committee) + // const GUARDIAN_SELECTED = 0b0000_0100; + // /// + // /// Whether the proposal expired yet + // /// Has nothing to do with pool. Only related to proposal expired time + // const PROPOSAL_EXPIRED = 0b0000_1000; + uint8 proposalStatusFlags; +} + /// @notice Propose an investing pool proposal /// @param max_pool_size: At most this amount of raised money curator/investing pool willing to take /// @param proposal_last_time: How does the proposal lasts for voting/preinvesting. @@ -31,4 +79,39 @@ interface IPoolProposal { /// @custom:selector 0x619c08e2 /// guardianParticipateProposal(uint256) function guardianParticipateProposal(uint256 pool_proposal_index) external; + + /// @notice Query a curator's pool proposal deposit, bond owner = proposal index + /// @param curator: curator address, substrate + /// @custom:selector 0x87178c26 + /// poolProposalDepositOf(bytes32) + function poolProposalDepositOf(bytes32 curator) external view returns (Bond[] memory deposit_record); + + /// @notice Query all pending pool proposal and their schedule + /// @custom:selector 0x2f4f6b2a + /// pendingPoolProposalStatus() + function pendingPoolProposalStatus() external view returns (PoolProposalStatus[] memory proposal_status); + + /// @notice Query a single pool proposal and its detail + /// @param pool_proposal_index: Index of pool proposal + /// @custom:selector 0x18afd9ad + /// poolProposal(uint256) + function poolProposal(uint256 pool_proposal_index) external view returns (PoolProposalInfo memory proposal_info); + + /// @notice Query a single pool proposal and its existing included pre staking + /// @param pool_proposal_index: Index of pool proposal + /// @custom:selector 0xf081aa73 + /// poolPreInvestings(uint256) + function poolPreInvestings(uint256 pool_proposal_index) external view returns (Bond[] memory pre_investing_bond); + + /// @notice Query a single pool proposal and its queued pre staking + /// @param pool_proposal_index: Index of pool proposal + /// @custom:selector 0x884df5eb + /// poolPreInvestingsQueued(uint256) + function poolPreInvestingsQueued(uint256 pool_proposal_index) external view returns (Bond[] memory queued_bond); + + /// @notice Query a single pool proposal and its potential guardian detail + /// @param pool_proposal_index: Index of pool proposal + /// @custom:selector 0x6630e6ee + /// poolGuardian(uint256) + function poolGuardian(uint256 pool_proposal_index) external view returns (bytes32[] memory guardian); } \ No newline at end of file From c1fa4634bf273ed125567ad35192d5c63bd48995 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 10 Oct 2024 10:47:38 +0800 Subject: [PATCH 083/215] chore: add pool proposal precompile view --- .../collab-ai/pool-proposal/PoolProposal.sol | 32 +- .../collab-ai/pool-proposal/src/lib.rs | 284 +++++++++++++++++- 2 files changed, 308 insertions(+), 8 deletions(-) diff --git a/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol b/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol index 0da3c1463c..ce745648c2 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol +++ b/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol @@ -2,10 +2,23 @@ pragma solidity >=0.8.3; interface IPoolProposal { - /// @dev A structure for bonding of all kind - struct Bond { + /// @dev A structure for bonding of curator's pool desposit + struct DepositBond { + uint256 owner; + uint256 amount; + } + + /// @dev A structure for bonding of user's official pre-staking + struct StakingBond { + bytes32 owner; + uint256 amount; + } + + /// @dev A structure for bonding of user's queued pre-staking + struct QueuedStakingBond { bytes32 owner; uint256 amount; + uint256 queuedTime; } /// @dev A structure for proposal and its expiry time @@ -80,34 +93,39 @@ interface IPoolProposal { /// guardianParticipateProposal(uint256) function guardianParticipateProposal(uint256 pool_proposal_index) external; + /// @notice The next free Pool Proposal index, aka the number of pool proposed so far. + /// @custom:selector 0x1b9e695b + /// poolProposalCount() + function poolProposalCount() external view returns (uint256 next_proposal_index); + /// @notice Query a curator's pool proposal deposit, bond owner = proposal index /// @param curator: curator address, substrate /// @custom:selector 0x87178c26 /// poolProposalDepositOf(bytes32) - function poolProposalDepositOf(bytes32 curator) external view returns (Bond[] memory deposit_record); + function poolProposalDepositOf(bytes32 curator) external view returns (DepositBond[] memory deposit_record); /// @notice Query all pending pool proposal and their schedule /// @custom:selector 0x2f4f6b2a /// pendingPoolProposalStatus() function pendingPoolProposalStatus() external view returns (PoolProposalStatus[] memory proposal_status); - /// @notice Query a single pool proposal and its detail + /// @notice Query a single pool proposal and its detail, bool represents if such info exists /// @param pool_proposal_index: Index of pool proposal /// @custom:selector 0x18afd9ad /// poolProposal(uint256) - function poolProposal(uint256 pool_proposal_index) external view returns (PoolProposalInfo memory proposal_info); + function poolProposal(uint256 pool_proposal_index) external view returns (bool exist, PoolProposalInfo memory proposal_info); /// @notice Query a single pool proposal and its existing included pre staking /// @param pool_proposal_index: Index of pool proposal /// @custom:selector 0xf081aa73 /// poolPreInvestings(uint256) - function poolPreInvestings(uint256 pool_proposal_index) external view returns (Bond[] memory pre_investing_bond); + function poolPreInvestings(uint256 pool_proposal_index) external view returns (StakingBond[] memory pre_investing_bond); /// @notice Query a single pool proposal and its queued pre staking /// @param pool_proposal_index: Index of pool proposal /// @custom:selector 0x884df5eb /// poolPreInvestingsQueued(uint256) - function poolPreInvestingsQueued(uint256 pool_proposal_index) external view returns (Bond[] memory queued_bond); + function poolPreInvestingsQueued(uint256 pool_proposal_index) external view returns (QueuedStakingBond[] memory queued_bond); /// @notice Query a single pool proposal and its potential guardian detail /// @param pool_proposal_index: Index of pool proposal diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index 838d5b47a8..271bbb44ac 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -4,24 +4,36 @@ use fp_evm::{PrecompileFailure, PrecompileHandle}; use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; use frame_system::pallet_prelude::BlockNumberFor; use pallet_evm::AddressMapping; -use pallet_pool_proposal::AssetBalanceOf; +use pallet_pool_proposal::{ + AssetBalanceOf, PoolProposalInfo as PalletPoolProposalInfo, + PoolProposalStatus as PalletPoolProposalStatus, +}; +use parity_scale_codec::MaxEncodedLen; use precompile_utils::prelude::*; use sp_runtime::traits::Dispatchable; use sp_core::{H256, U256}; use sp_std::marker::PhantomData; +use pallet_collab_ai_common::PoolProposalIndex; + pub struct PoolProposalPrecompile(PhantomData); +type BalanceOf = <::Currency as Currency< + ::AccountId, +>>::Balance; + #[precompile_utils::precompile] impl PoolProposalPrecompile where Runtime: pallet_pool_proposal::Config + pallet_evm::Config, + Runtime::AccountId: From<[u8; 32]> + Into<[u8; 32]>, Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, Runtime::RuntimeCall: From>, ::RuntimeOrigin: From>, AssetBalanceOf: TryFrom + Into, BlockNumberFor: TryFrom + Into, + BalanceOf: TryFrom + Into, { #[precompile::public("proposeInvestingPool(uint256,uint256,uint256,uint256,bytes32)")] fn propose_investing_pool( @@ -134,4 +146,274 @@ where Ok(()) } + + #[precompile::public("poolProposalCount()")] + #[precompile::view] + fn pool_proposal_count(handle: &mut impl PrecompileHandle) -> EvmResult { + // Storage item: PoolProposalCount -> + // PoolProposalIndex (16) + handle.record_db_read::(16)?; + + let next_proposal_index: U256 = + pallet_pool_proposal::Pallet::::pool_proposal_count().into(); + Ok(next_proposal_index) + } + + #[precompile::public("poolProposalDepositOf(bytes32)")] + #[precompile::view] + fn pool_proposal_deposit_of( + handle: &mut impl PrecompileHandle, + curator: H256, + ) -> EvmResult> { + // Storage item: PoolProposalDepositOf -> + // OrderedSet>, T::MaximumPoolProposed> + handle.record_db_read::( + Bond < PoolProposalIndex, + BalanceOf + < Runtime + >> ::max_encoded_len() + .saturating_mul(Runtime::MaximumPoolProposed::get() as usize), + )?; + + let curator: [u8; 32] = curator.into(); + let curator = Runtime::AccountId::from(curator); + + if let Some(result) = + pallet_pool_proposal::Pallet::::pool_proposal_deposit_of(curator) + { + Ok(result + .0 + .into_iter() + .enumerate() + .map(|(index, bond)| DepositBond { + owner: bond.owner.into(), + amount: bond.amount.into(), + }) + .collect()) + } else { + Ok(Vec::new()) + } + } + + #[precompile::public("pendingPoolProposalStatus()")] + #[precompile::view] + fn pending_pool_proposal_status( + handle: &mut impl PrecompileHandle, + ) -> EvmResult> { + // Storage item: PendingPoolProposalStatus -> + // VecDeque> + handle.record_db_read::(VecDeque::< + PalletPoolProposalStatus>, + >::max_encoded_len())?; + + let result = pallet_pool_proposal::Pallet::::pending_pool_proposal_status() + .into_iter() + .enumerate() + .map(|(index, status)| PoolProposalStatus { + index: status.pool_proposal_index.into(), + expiryTime: status.proposal_expire_time.into(), + }) + .collect(); + + Ok(result) + } + + #[precompile::public("poolProposal(uint256)")] + #[precompile::view] + fn pool_proposal( + handle: &mut impl PrecompileHandle, + pool_proposal_index: U256, + ) -> EvmResult<(bool, Vec)> { + // Storage item: PoolProposal -> + // PoolProposalInfo, BlockNumberFor, T::AccountId> + handle.record_db_read::( + PalletPoolProposalInfo < H256, + AssetBalanceOf::, + BlockNumberFor::, + Runtime::AccountId > ::max_encoded_len(), + )?; + + let pool_proposal_index = pool_proposal_index.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + + if let Some(result) = + pallet_pool_proposal::Pallet::::pool_proposal(pool_proposal_index) + { + let info_vec = result + .into_iter() + .enumerate() + .map(|(index, info)| { + let proposer: [u8; 32] = info.proposer.into(); + let proposer = proposer.into(); + + PoolProposalInfo { + proposer, + infoHash: info.pool_info_hash, + maxPoolSize: info.max_pool_size.into(), + poolStartTime: info.pool_start_time.into(), + poolEndTime: info.pool_end_time.into(), + estimatedEpochReward: info.estimated_epoch_reward.into(), + proposalStatusFlags: info.proposal_status_flags.bits(), + } + }) + .collect(); + + Ok((true, info_vec)) + } else { + Ok((false, Default::default())) + } + } + + #[precompile::public("poolPreInvestings(uint256)")] + #[precompile::view] + fn pool_pre_investings( + handle: &mut impl PrecompileHandle, + pool_proposal_index: U256, + ) -> EvmResult> { + // Storage item: PoolPreInvestings -> + // PoolProposalPreInvesting, BlockNumberFor, T::MaximumPoolProposed> + handle.record_db_read::( + Bond < Runtime::AccountId, + AssetBalanceOf::::max_encoded_len() + .saturating_mul(Runtime::MaximumPoolProposed::get() as usize), + )?; + + let pool_proposal_index = pool_proposal_index.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + + if let Some(result) = + pallet_pool_proposal::Pallet::::pool_pre_investings(pool_proposal_index) + { + let bond_vec = result + .pre_investings + .into_iter() + .enumerate() + .map(|(index, bond)| { + let owner: [u8; 32] = bond.owner.into(); + let owner = owner.into(); + StakingBond { owner, amount: bond.amount.into() } + }) + .collect(); + + Ok(bond_vec) + } else { + Ok(Default::default()) + } + } + + #[precompile::public("poolPreInvestingsQueued(uint256)")] + #[precompile::view] + fn pool_pre_investings_queued( + handle: &mut impl PrecompileHandle, + pool_proposal_index: U256, + ) -> EvmResult> { + // Storage item: PoolPreInvestings -> + // PoolProposalPreInvesting, BlockNumberFor, T::MaximumPoolProposed> + handle.record_db_read::( + Bond < Runtime::AccountId, + AssetBalanceOf::::max_encoded_len() + .saturating_mul(Runtime::MaximumPoolProposed::get() as usize), + )?; + + let pool_proposal_index = pool_proposal_index.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + + if let Some(result) = + pallet_pool_proposal::Pallet::::pool_pre_investings(pool_proposal_index) + { + let bond_vec = result + .queued_pre_investings + .into_iter() + .enumerate() + .map(|(index, bond)| { + let owner: [u8; 32] = bond.0.owner.into(); + let owner = owner.into(); + QueuedStakingBond { + owner, + amount: bond.0.amount.into(), + queuedTime: bond.1.into(), + } + }) + .collect(); + + Ok(bond_vec) + } else { + Ok(Default::default()) + } + } + + #[precompile::public("poolGuardian(uint256)")] + #[precompile::view] + fn pool_guardian( + handle: &mut impl PrecompileHandle, + pool_proposal_index: U256, + ) -> EvmResult> { + // Storage item: PoolGuardian -> + // OrderedSet + handle.record_db_read::( + 32.saturating_mul(Runtime::MaxGuardianPerProposal::get() as usize), + )?; + + let pool_proposal_index = pool_proposal_index.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + + if let Some(result) = + pallet_pool_proposal::Pallet::::pool_guardian(pool_proposal_index) + { + let guardian_vec = result + .queued_pre_investings + .0 + .into_iter() + .enumerate() + .map(|(index, guardian)| { + let guardian: [u8; 32] = guardian.into(); + guardian.into() + }) + .collect(); + + Ok(guardian_vec) + } else { + Ok(Default::default()) + } + } +} + +#[derive(Default, Debug, solidity::Codec)] +pub struct DepositBond { + owner: U256, + amount: U256, +} + +#[derive(Default, Debug, solidity::Codec)] +pub struct StakingBond { + owner: H256, + amount: U256, +} + +#[derive(Default, Debug, solidity::Codec)] +pub struct QueuedStakingBond { + owner: H256, + amount: U256, + queuedTime: U256, +} + +#[derive(Default, Debug, solidity::Codec)] +pub struct PoolProposalStatus { + index: U256, + expiryTime: U256, +} + +#[derive(Default, Debug, solidity::Codec)] +struct PoolProposalInfo { + proposer: H256, + infoHash: H256, + maxPoolSize: U256, + poolStartTime: U256, + poolEndTime: U256, + estimatedEpochReward: U256, + proposalStatusFlags: u8, } From f09328d4177cc30ff5ae7a725a88c6d73b600747 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 10 Oct 2024 11:09:37 +0800 Subject: [PATCH 084/215] chore: fix --- .../collab-ai/pool-proposal/src/lib.rs | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index 271bbb44ac..08f98d3533 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -1,19 +1,22 @@ #![cfg_attr(not(feature = "std"), no_std)] use fp_evm::{PrecompileFailure, PrecompileHandle}; -use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; +use frame_support::{ + dispatch::{GetDispatchInfo, PostDispatchInfo}, + traits::Currency, +}; use frame_system::pallet_prelude::BlockNumberFor; use pallet_evm::AddressMapping; use pallet_pool_proposal::{ - AssetBalanceOf, PoolProposalInfo as PalletPoolProposalInfo, + AssetBalanceOf, Bond as PalletBond, PoolProposalInfo as PalletPoolProposalInfo, PoolProposalStatus as PalletPoolProposalStatus, }; use parity_scale_codec::MaxEncodedLen; use precompile_utils::prelude::*; use sp_runtime::traits::Dispatchable; -use sp_core::{H256, U256}; -use sp_std::marker::PhantomData; +use sp_core::{get, H256, U256}; +use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData}; use pallet_collab_ai_common::PoolProposalIndex; @@ -33,7 +36,7 @@ where ::RuntimeOrigin: From>, AssetBalanceOf: TryFrom + Into, BlockNumberFor: TryFrom + Into, - BalanceOf: TryFrom + Into, + BalanceOf: TryFrom + Into, { #[precompile::public("proposeInvestingPool(uint256,uint256,uint256,uint256,bytes32)")] fn propose_investing_pool( @@ -168,11 +171,8 @@ where // Storage item: PoolProposalDepositOf -> // OrderedSet>, T::MaximumPoolProposed> handle.record_db_read::( - Bond < PoolProposalIndex, - BalanceOf - < Runtime - >> ::max_encoded_len() - .saturating_mul(Runtime::MaximumPoolProposed::get() as usize), + PalletBond::>::max_encoded_len() + .saturating_mul(Runtime::MaximumPoolProposed::get() as usize), )?; let curator: [u8; 32] = curator.into(); @@ -226,12 +226,12 @@ where ) -> EvmResult<(bool, Vec)> { // Storage item: PoolProposal -> // PoolProposalInfo, BlockNumberFor, T::AccountId> - handle.record_db_read::( - PalletPoolProposalInfo < H256, - AssetBalanceOf::, - BlockNumberFor::, - Runtime::AccountId > ::max_encoded_len(), - )?; + handle.record_db_read::(PalletPoolProposalInfo::< + H256, + AssetBalanceOf, + BlockNumberFor, + Runtime::AccountId, + >::max_encoded_len())?; let pool_proposal_index = pool_proposal_index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) @@ -274,8 +274,7 @@ where // Storage item: PoolPreInvestings -> // PoolProposalPreInvesting, BlockNumberFor, T::MaximumPoolProposed> handle.record_db_read::( - Bond < Runtime::AccountId, - AssetBalanceOf::::max_encoded_len() + PalletBond::>::max_encoded_len() .saturating_mul(Runtime::MaximumPoolProposed::get() as usize), )?; @@ -312,8 +311,7 @@ where // Storage item: PoolPreInvestings -> // PoolProposalPreInvesting, BlockNumberFor, T::MaximumPoolProposed> handle.record_db_read::( - Bond < Runtime::AccountId, - AssetBalanceOf::::max_encoded_len() + PalletBond::>::max_encoded_len() .saturating_mul(Runtime::MaximumPoolProposed::get() as usize), )?; From ece02943071e1f6ed36abf83204f3951866908c5 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 10 Oct 2024 11:26:20 +0800 Subject: [PATCH 085/215] chore: fix --- .../collab-ai/pool-proposal/src/lib.rs | 52 ++++++++----------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index 08f98d3533..d364028de1 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -15,7 +15,7 @@ use parity_scale_codec::MaxEncodedLen; use precompile_utils::prelude::*; use sp_runtime::traits::Dispatchable; -use sp_core::{get, H256, U256}; +use sp_core::{Get, H256, U256}; use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData}; use pallet_collab_ai_common::PoolProposalIndex; @@ -202,9 +202,10 @@ where ) -> EvmResult> { // Storage item: PendingPoolProposalStatus -> // VecDeque> - handle.record_db_read::(VecDeque::< - PalletPoolProposalStatus>, - >::max_encoded_len())?; + // 16 * max number + handle.record_db_read::( + 16usize.saturating_mul(Runtime::MaximumPoolProposed::get() as usize), + )?; let result = pallet_pool_proposal::Pallet::::pending_pool_proposal_status() .into_iter() @@ -223,7 +224,7 @@ where fn pool_proposal( handle: &mut impl PrecompileHandle, pool_proposal_index: U256, - ) -> EvmResult<(bool, Vec)> { + ) -> EvmResult<(bool, PoolProposalInfo)> { // Storage item: PoolProposal -> // PoolProposalInfo, BlockNumberFor, T::AccountId> handle.record_db_read::(PalletPoolProposalInfo::< @@ -237,29 +238,23 @@ where Into::::into(RevertReason::value_is_too_large("index type")) })?; - if let Some(result) = + if let Some(info) = pallet_pool_proposal::Pallet::::pool_proposal(pool_proposal_index) { - let info_vec = result - .into_iter() - .enumerate() - .map(|(index, info)| { - let proposer: [u8; 32] = info.proposer.into(); - let proposer = proposer.into(); - - PoolProposalInfo { - proposer, - infoHash: info.pool_info_hash, - maxPoolSize: info.max_pool_size.into(), - poolStartTime: info.pool_start_time.into(), - poolEndTime: info.pool_end_time.into(), - estimatedEpochReward: info.estimated_epoch_reward.into(), - proposalStatusFlags: info.proposal_status_flags.bits(), - } - }) - .collect(); - - Ok((true, info_vec)) + let proposer: [u8; 32] = info.proposer.into(); + let proposer = proposer.into(); + + let info = PoolProposalInfo { + proposer, + infoHash: info.pool_info_hash, + maxPoolSize: info.max_pool_size.into(), + poolStartTime: info.pool_start_time.into(), + poolEndTime: info.pool_end_time.into(), + estimatedEpochReward: info.estimated_epoch_reward.into(), + proposalStatusFlags: info.proposal_status_flags.bits(), + }; + + Ok((true, info)) } else { Ok((false, Default::default())) } @@ -307,7 +302,7 @@ where fn pool_pre_investings_queued( handle: &mut impl PrecompileHandle, pool_proposal_index: U256, - ) -> EvmResult> { + ) -> EvmResult> { // Storage item: PoolPreInvestings -> // PoolProposalPreInvesting, BlockNumberFor, T::MaximumPoolProposed> handle.record_db_read::( @@ -352,7 +347,7 @@ where // Storage item: PoolGuardian -> // OrderedSet handle.record_db_read::( - 32.saturating_mul(Runtime::MaxGuardianPerProposal::get() as usize), + 32usize.saturating_mul(Runtime::MaxGuardianPerProposal::get() as usize), )?; let pool_proposal_index = pool_proposal_index.try_into().map_err(|_| { @@ -363,7 +358,6 @@ where pallet_pool_proposal::Pallet::::pool_guardian(pool_proposal_index) { let guardian_vec = result - .queued_pre_investings .0 .into_iter() .enumerate() From 7112efc68e3c96348051e7bd075d9d08564713d4 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 10 Oct 2024 11:39:20 +0800 Subject: [PATCH 086/215] chore: fix --- .../collab-ai/pool-proposal/src/lib.rs | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index d364028de1..a596318633 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -9,14 +9,13 @@ use frame_system::pallet_prelude::BlockNumberFor; use pallet_evm::AddressMapping; use pallet_pool_proposal::{ AssetBalanceOf, Bond as PalletBond, PoolProposalInfo as PalletPoolProposalInfo, - PoolProposalStatus as PalletPoolProposalStatus, }; use parity_scale_codec::MaxEncodedLen; use precompile_utils::prelude::*; use sp_runtime::traits::Dispatchable; use sp_core::{Get, H256, U256}; -use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData}; +use sp_std::marker::PhantomData; use pallet_collab_ai_common::PoolProposalIndex; @@ -89,7 +88,7 @@ where ) -> EvmResult { let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); - let pool_proposal_index = pool_proposal_index.try_into().map_err(|_| { + let pool_proposal_index: u128 = pool_proposal_index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; @@ -114,7 +113,7 @@ where ) -> EvmResult { let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); - let pool_proposal_index = pool_proposal_index.try_into().map_err(|_| { + let pool_proposal_index: u128 = pool_proposal_index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; @@ -138,7 +137,7 @@ where ) -> EvmResult { let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); - let pool_proposal_index = pool_proposal_index.try_into().map_err(|_| { + let pool_proposal_index: u128 = pool_proposal_index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; @@ -185,7 +184,7 @@ where .0 .into_iter() .enumerate() - .map(|(index, bond)| DepositBond { + .map(|(_index, bond)| DepositBond { owner: bond.owner.into(), amount: bond.amount.into(), }) @@ -210,7 +209,7 @@ where let result = pallet_pool_proposal::Pallet::::pending_pool_proposal_status() .into_iter() .enumerate() - .map(|(index, status)| PoolProposalStatus { + .map(|(_index, status)| PoolProposalStatus { index: status.pool_proposal_index.into(), expiryTime: status.proposal_expire_time.into(), }) @@ -234,7 +233,7 @@ where Runtime::AccountId, >::max_encoded_len())?; - let pool_proposal_index = pool_proposal_index.try_into().map_err(|_| { + let pool_proposal_index: u128 = pool_proposal_index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; @@ -273,7 +272,7 @@ where .saturating_mul(Runtime::MaximumPoolProposed::get() as usize), )?; - let pool_proposal_index = pool_proposal_index.try_into().map_err(|_| { + let pool_proposal_index: u128 = pool_proposal_index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; @@ -310,7 +309,7 @@ where .saturating_mul(Runtime::MaximumPoolProposed::get() as usize), )?; - let pool_proposal_index = pool_proposal_index.try_into().map_err(|_| { + let pool_proposal_index: u128 = pool_proposal_index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; @@ -350,7 +349,7 @@ where 32usize.saturating_mul(Runtime::MaxGuardianPerProposal::get() as usize), )?; - let pool_proposal_index = pool_proposal_index.try_into().map_err(|_| { + let pool_proposal_index: u128 = pool_proposal_index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; From aac356150b71655a40bfcc065b508d8d30a4a037 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 10 Oct 2024 13:58:03 +0800 Subject: [PATCH 087/215] chore: fix --- .../collab-ai/pool-proposal/src/lib.rs | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index a596318633..812da8d70d 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -211,7 +211,7 @@ where .enumerate() .map(|(_index, status)| PoolProposalStatus { index: status.pool_proposal_index.into(), - expiryTime: status.proposal_expire_time.into(), + expiry_time: status.proposal_expire_time.into(), }) .collect(); @@ -245,12 +245,12 @@ where let info = PoolProposalInfo { proposer, - infoHash: info.pool_info_hash, - maxPoolSize: info.max_pool_size.into(), - poolStartTime: info.pool_start_time.into(), - poolEndTime: info.pool_end_time.into(), - estimatedEpochReward: info.estimated_epoch_reward.into(), - proposalStatusFlags: info.proposal_status_flags.bits(), + info_hash: info.pool_info_hash, + max_pool_size: info.max_pool_size.into(), + pool_start_time: info.pool_start_time.into(), + pool_end_time: info.pool_end_time.into(), + estimated_epoch_reward: info.estimated_epoch_reward.into(), + proposal_status_flags: info.proposal_status_flags.bits(), }; Ok((true, info)) @@ -283,7 +283,7 @@ where .pre_investings .into_iter() .enumerate() - .map(|(index, bond)| { + .map(|(_index, bond)| { let owner: [u8; 32] = bond.owner.into(); let owner = owner.into(); StakingBond { owner, amount: bond.amount.into() } @@ -320,13 +320,13 @@ where .queued_pre_investings .into_iter() .enumerate() - .map(|(index, bond)| { + .map(|(_index, bond)| { let owner: [u8; 32] = bond.0.owner.into(); let owner = owner.into(); QueuedStakingBond { owner, amount: bond.0.amount.into(), - queuedTime: bond.1.into(), + queued_time: bond.1.into(), } }) .collect(); @@ -360,7 +360,7 @@ where .0 .into_iter() .enumerate() - .map(|(index, guardian)| { + .map(|(_index, guardian)| { let guardian: [u8; 32] = guardian.into(); guardian.into() }) @@ -389,22 +389,22 @@ pub struct StakingBond { pub struct QueuedStakingBond { owner: H256, amount: U256, - queuedTime: U256, + queued_time: U256, } #[derive(Default, Debug, solidity::Codec)] pub struct PoolProposalStatus { index: U256, - expiryTime: U256, + expiry_time: U256, } #[derive(Default, Debug, solidity::Codec)] struct PoolProposalInfo { proposer: H256, - infoHash: H256, - maxPoolSize: U256, - poolStartTime: U256, - poolEndTime: U256, - estimatedEpochReward: U256, - proposalStatusFlags: u8, + info_hash: H256, + max_pool_size: U256, + pool_start_time: U256, + pool_end_time: U256, + estimated_epoch_reward: U256, + proposal_status_flags: u8, } From 7d4d8d4b81ff32df3d3c987d8a5b3ce8de25a163 Mon Sep 17 00:00:00 2001 From: "will.li" <120463031+higherordertech@users.noreply.github.com> Date: Mon, 14 Oct 2024 13:07:51 +1100 Subject: [PATCH 088/215] feat: p-1020 add unit test for collab-ai aiusd-convertor pallet and precompile (#3125) Co-authored-by: higherordertech --- parachain/Cargo.lock | 3 + .../collab-ai/aiusd-convertor/src/lib.rs | 22 +- .../collab-ai/aiusd-convertor/src/mock.rs | 170 +++++++++++++ .../collab-ai/aiusd-convertor/src/tests.rs | 155 ++++++++++++ .../collab-ai/aiusd-convertor/Cargo.toml | 9 + .../collab-ai/aiusd-convertor/src/lib.rs | 5 + .../collab-ai/aiusd-convertor/src/mock.rs | 239 ++++++++++++++++++ .../collab-ai/aiusd-convertor/src/tests.rs | 98 +++++++ 8 files changed, 692 insertions(+), 9 deletions(-) create mode 100644 parachain/pallets/collab-ai/aiusd-convertor/src/mock.rs create mode 100644 parachain/pallets/collab-ai/aiusd-convertor/src/tests.rs create mode 100644 parachain/precompiles/collab-ai/aiusd-convertor/src/mock.rs create mode 100644 parachain/precompiles/collab-ai/aiusd-convertor/src/tests.rs diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index 24579707ed..98ed83bb06 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -7373,6 +7373,8 @@ dependencies = [ "hex-literal", "libsecp256k1", "pallet-aiusd-convertor", + "pallet-assets", + "pallet-balances", "pallet-evm", "pallet-timestamp", "parity-scale-codec", @@ -7381,6 +7383,7 @@ dependencies = [ "serde", "sha3", "sp-core", + "sp-io", "sp-runtime", "sp-std", ] diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index 0d94f6ddc5..b7cce3f4e7 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -31,11 +31,15 @@ use frame_support::{ use frame_system::pallet_prelude::*; pub use pallet::*; use sp_runtime::traits::{CheckedDiv, CheckedMul}; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; #[frame_support::pallet] pub mod pallet { use super::*; - pub(crate) type InspectFungibles = pallet_assets::Pallet; + pub type InspectFungibles = pallet_assets::Pallet; /// Balance type alias for balances of assets that implement the `fungibles` trait. pub type AssetBalanceOf = as FsInspect<::AccountId>>::Balance; @@ -139,19 +143,19 @@ pub mod pallet { >::mint_into(aiusd_id, &beneficiary, aiusd_amount)?; // Maybe it is better to save decimal of AIUSD somewhere - let aiusd_deciaml_unit_expression: T::Balance = + let aiusd_decimal_unit_expression: T::Balance = 10u128.pow(18).try_into().or(Err(Error::::Overflow))?; - let aseet_target_transfer_amount = aiusd_minted_amount + let asset_target_transfer_amount = aiusd_minted_amount .checked_mul(&ratio) .ok_or(Error::::Overflow)? - .checked_div(&aiusd_deciaml_unit_expression) + .checked_div(&aiusd_decimal_unit_expression) .ok_or(Error::::Overflow)?; let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( target_asset_id.clone(), &beneficiary, &T::ConvertingFeeAccount::get(), - aseet_target_transfer_amount, + asset_target_transfer_amount, Preservation::Expendable, )?; @@ -196,19 +200,19 @@ pub mod pallet { )?; // Maybe it is better to save decimal of AIUSD somewhere - let aiusd_deciaml_unit_expression: T::Balance = + let aiusd_decimal_unit_expression: T::Balance = 10u128.pow(18).try_into().or(Err(Error::::Overflow))?; - let aseet_target_transfer_amount = aiusd_destroyed_amount + let asset_target_transfer_amount = aiusd_destroyed_amount .checked_mul(&ratio) .ok_or(Error::::Overflow)? - .checked_div(&aiusd_deciaml_unit_expression) + .checked_div(&aiusd_decimal_unit_expression) .ok_or(Error::::Overflow)?; let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( target_asset_id.clone(), &T::ConvertingFeeAccount::get(), &beneficiary, - aseet_target_transfer_amount, + asset_target_transfer_amount, Preservation::Expendable, )?; diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/mock.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/mock.rs new file mode 100644 index 0000000000..393dcb4e03 --- /dev/null +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/mock.rs @@ -0,0 +1,170 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate as pallet_aiusd; +use frame_support::{ + assert_ok, construct_runtime, parameter_types, + traits::{ + tokens::fungibles::{Inspect, Mutate}, + AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, Everything, + }, +}; +use sp_core::{Get, H256}; +use sp_runtime::{ + traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, + AccountId32, BuildStorage, +}; + +pub type Signature = sp_runtime::MultiSignature; +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + +pub type Balance = u128; + +// Configure a mock runtime to test the pallet. +construct_runtime!( + pub enum Test { + System: frame_system, + Assets: pallet_assets, + Balances: pallet_balances, + AIUSD: pallet_aiusd, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const AIUSDAssetId: u32 = 1; +} + +impl frame_system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type Block = frame_system::mocking::MockBlock; + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = ConstU16<31>; + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl pallet_assets::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = u32; + type AssetIdParameter = u32; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type AssetDeposit = ConstU128<1>; + type AssetAccountDeposit = ConstU128<10>; + type MetadataDepositBase = ConstU128<1>; + type MetadataDepositPerByte = ConstU128<1>; + type ApprovalDeposit = ConstU128<1>; + type StringLimit = ConstU32<50>; + type Freezer = (); + type WeightInfo = (); + type CallbackHandle = (); + type Extra = (); + type RemoveItemsLimit = ConstU32<5>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + +impl pallet_balances::Config for Test { + type MaxLocks = (); + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ConstU128<1>; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = (); + type ReserveIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = (); + type MaxFreezes = (); + type RuntimeHoldReason = (); +} + +pub struct ConvertingFeeAccount; +impl Get for ConvertingFeeAccount { + fn get() -> AccountId32 { + AccountId32::new([1u8; 32]) + } +} + +impl pallet_aiusd::Config for Test { + type RuntimeEvent = RuntimeEvent; + type ConvertingFeeAccount = ConvertingFeeAccount; + type AIUSDAssetId = AIUSDAssetId; + type ManagerOrigin = frame_system::EnsureRoot<::AccountId>; +} + +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + + let owner = AccountId32::from([2u8; 32]); + let origin = RuntimeOrigin::root(); + + // Create the AIUSD asset + assert_ok!(pallet_assets::Pallet::::force_create( + origin.clone(), + 1, // AIUSD asset id + owner.clone(), + true, + 1, + )); + // Create the target asset + let target_asset_id = 2; + assert_ok!(pallet_assets::Pallet::::force_create( + origin, + target_asset_id, + owner.clone(), + true, + 1, + )); + + // Check if these assets exists + assert!(pallet_aiusd::InspectFungibles::::asset_exists(1)); + assert!(pallet_aiusd::InspectFungibles::::asset_exists(2)); + + // Set total supply + assert_ok!(pallet_aiusd::InspectFungibles::::mint_into( + target_asset_id, + &owner, + 1_000_000_000 // 1000 (10^6 * 1000) + )); + }); + ext +} diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/tests.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/tests.rs new file mode 100644 index 0000000000..1e32ed76dc --- /dev/null +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/tests.rs @@ -0,0 +1,155 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate::mock::*; +use crate::*; +use frame_support::{assert_err, assert_ok}; +use sp_runtime::{AccountId32, TokenError}; + +#[test] +fn test_mint_aiusd() { + new_test_ext().execute_with(|| { + let beneficiary: AccountId32 = AccountId32::from([2u8; 32]); + let aiusd_asset_id: u32 = 1; + let target_asset_id: u32 = 2; + let target_decimal_ratio = 1_000_000; + let target_asset_supply_amount: u128 = target_decimal_ratio * 1000; + let mint_amount: u128 = 2_000_000_000_000_000_000; // 2 AIUSD (10^18 * 2) + + // Check balance + let aiusd_balance = InspectFungibles::::balance(aiusd_asset_id, &beneficiary); + assert_eq!(aiusd_balance, 0); + let target_balance = InspectFungibles::::balance(target_asset_id, &beneficiary); + assert_eq!(target_balance, target_asset_supply_amount); + + assert_ok!(AIUSD::enable_token( + RuntimeOrigin::root(), + target_asset_id, + target_decimal_ratio + )); + + assert_err!( + AIUSD::mint_aiusd(RuntimeOrigin::signed(beneficiary.clone()), 3, mint_amount), + Error::::AssetNotEnabled + ); + + assert_ok!(AIUSD::mint_aiusd( + RuntimeOrigin::signed(beneficiary.clone()), + target_asset_id, + mint_amount + )); + // Check balance after mint + let asset_amount = target_decimal_ratio * 2; + let aiusd_balance = InspectFungibles::::balance(aiusd_asset_id, &beneficiary); + assert_eq!(aiusd_balance, mint_amount); + let target_balance = InspectFungibles::::balance(target_asset_id, &beneficiary); + assert_eq!(target_balance, target_asset_supply_amount - asset_amount); + + System::assert_last_event(RuntimeEvent::AIUSD(Event::AIUSDCreated { + beneficiary, + aiusd_amount: mint_amount, + asset_id: target_asset_id, + asset_amount, + })); + }); +} + +#[test] +fn test_burn_aiusd() { + new_test_ext().execute_with(|| { + let beneficiary: AccountId32 = AccountId32::from([2u8; 32]); + let aiusd_asset_id: u32 = 1; + let target_asset_id: u32 = 2; + let target_decimal_ratio = 1_000_000; + let target_asset_supply_amount: u128 = target_decimal_ratio * 1000; + let aiusd_amount: u128 = 2_000_000_000_000_000_000; // 2 AIUSD (10^18 * 2) + + // Check balance + let aiusd_balance = InspectFungibles::::balance(aiusd_asset_id, &beneficiary); + assert_eq!(aiusd_balance, 0); + let target_balance = InspectFungibles::::balance(target_asset_id, &beneficiary); + assert_eq!(target_balance, target_asset_supply_amount); + + assert_ok!(AIUSD::enable_token( + RuntimeOrigin::root(), + target_asset_id, + target_decimal_ratio + )); + + // FundsUnavailable + assert_err!( + AIUSD::burn_aiusd( + RuntimeOrigin::signed(beneficiary.clone()), + target_asset_id, + aiusd_amount + ), + TokenError::FundsUnavailable + ); + + assert_ok!(AIUSD::mint_aiusd( + RuntimeOrigin::signed(beneficiary.clone()), + target_asset_id, + aiusd_amount + )); + // Check balance after mint + let aiusd_balance = InspectFungibles::::balance(aiusd_asset_id, &beneficiary); + assert_eq!(aiusd_balance, aiusd_amount); + let target_balance = InspectFungibles::::balance(target_asset_id, &beneficiary); + assert_eq!(target_balance, target_asset_supply_amount - target_decimal_ratio * 2); + + assert_ok!(AIUSD::burn_aiusd( + RuntimeOrigin::signed(beneficiary.clone()), + target_asset_id, + aiusd_amount + )); + // Check balance after burn + let aiusd_balance = InspectFungibles::::balance(aiusd_asset_id, &beneficiary); + assert_eq!(aiusd_balance, 0); + let target_balance = InspectFungibles::::balance(target_asset_id, &beneficiary); + assert_eq!(target_balance, target_asset_supply_amount); + + System::assert_last_event(RuntimeEvent::AIUSD(Event::AIUSDDestroyed { + beneficiary, + aiusd_amount, + asset_id: target_asset_id, + asset_amount: target_decimal_ratio * 2, + })); + }); +} + +#[test] +fn test_enable_disable_token() { + new_test_ext().execute_with(|| { + let target_asset_id: u32 = 2; + let decimal_ratio: u128 = 1_000_000; + + // enable + assert_ok!(AIUSD::enable_token(RuntimeOrigin::root(), target_asset_id, decimal_ratio)); + assert!(AIUSD::enabled_tokens(target_asset_id).is_some()); + System::assert_last_event(RuntimeEvent::AIUSD(Event::AssetEnabled { + asset_id: target_asset_id, + decimal_ratio, + })); + + // disable + assert_ok!(AIUSD::disable_token(RuntimeOrigin::root(), target_asset_id)); + assert!(AIUSD::enabled_tokens(target_asset_id).is_none()); + + System::assert_last_event(RuntimeEvent::AIUSD(Event::AssetDisabled { + asset_id: target_asset_id, + })); + }); +} diff --git a/parachain/precompiles/collab-ai/aiusd-convertor/Cargo.toml b/parachain/precompiles/collab-ai/aiusd-convertor/Cargo.toml index 9696d23e01..0acb788a11 100644 --- a/parachain/precompiles/collab-ai/aiusd-convertor/Cargo.toml +++ b/parachain/precompiles/collab-ai/aiusd-convertor/Cargo.toml @@ -29,12 +29,21 @@ serde = { workspace = true } sha3 = { workspace = true } precompile-utils = { workspace = true, features = ["std", "testing"] } pallet-timestamp = { workspace = true, features = ["std"] } +pallet-assets = { workspace = true } +pallet-balances = { workspace = true, features = ["std", "insecure_zero_ed"] } parity-scale-codec = { workspace = true, features = ["max-encoded-len", "std"] } scale-info = { workspace = true, features = ["derive"] } +sp-io = { workspace = true } sp-runtime = { workspace = true, features = ["std"] } [features] default = ["std"] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", +] std = [ "fp-evm/std", "frame-support/std", diff --git a/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs b/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs index f186affa9d..20909c94c3 100644 --- a/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs @@ -12,6 +12,11 @@ use sp_std::marker::PhantomData; use pallet_aiusd_convertor::{AssetBalanceOf, AssetIdOf}; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + pub struct AIUSDConvertorPrecompile(PhantomData); #[precompile_utils::precompile] diff --git a/parachain/precompiles/collab-ai/aiusd-convertor/src/mock.rs b/parachain/precompiles/collab-ai/aiusd-convertor/src/mock.rs new file mode 100644 index 0000000000..db7f1f88fc --- /dev/null +++ b/parachain/precompiles/collab-ai/aiusd-convertor/src/mock.rs @@ -0,0 +1,239 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate::*; +use frame_support::{ + assert_ok, construct_runtime, + pallet_prelude::Weight, + parameter_types, + traits::{ + tokens::fungibles::{Inspect, Mutate}, + AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, ConstU64, Everything, + }, +}; +use pallet_aiusd_convertor as pallet_aiusd; +use pallet_evm::{EnsureAddressNever, EnsureAddressRoot}; +use precompile_utils::precompile_set::{AddressU64, PrecompileAt, PrecompileSetBuilder}; +use sp_core::{Get, H160, H256}; +use sp_runtime::{ + traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, + AccountId32, BuildStorage, +}; + +pub type Signature = sp_runtime::MultiSignature; +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + +pub type Balance = u128; + +// Configure a mock runtime to test the pallet. +construct_runtime!( + pub enum Test { + System: frame_system, + Timestamp: pallet_timestamp, + Assets: pallet_assets, + Balances: pallet_balances, + Evm: pallet_evm, + AIUSD: pallet_aiusd, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const AIUSDAssetId: u32 = 1; +} + +impl frame_system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type Block = frame_system::mocking::MockBlock; + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = ConstU16<31>; + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl pallet_assets::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = u32; + type AssetIdParameter = u32; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type AssetDeposit = ConstU128<1>; + type AssetAccountDeposit = ConstU128<10>; + type MetadataDepositBase = ConstU128<1>; + type MetadataDepositPerByte = ConstU128<1>; + type ApprovalDeposit = ConstU128<1>; + type StringLimit = ConstU32<50>; + type Freezer = (); + type WeightInfo = (); + type CallbackHandle = (); + type Extra = (); + type RemoveItemsLimit = ConstU32<5>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + +impl pallet_balances::Config for Test { + type MaxLocks = (); + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ConstU128<1>; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = (); + type ReserveIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = (); + type MaxFreezes = (); + type RuntimeHoldReason = (); +} +pub struct ConvertingFeeAccount; +impl Get for ConvertingFeeAccount { + fn get() -> AccountId32 { + let h160_address: H160 = H160::from_low_u64_be(1000); + TruncatedAddressMapping::into_account_id(h160_address) + } +} + +impl pallet_aiusd::Config for Test { + type RuntimeEvent = RuntimeEvent; + type ConvertingFeeAccount = ConvertingFeeAccount; + type AIUSDAssetId = AIUSDAssetId; + type ManagerOrigin = frame_system::EnsureRoot<::AccountId>; +} + +pub fn precompile_address() -> H160 { + H160::from_low_u64_be(20480 + 115) +} + +pub type AIUSDConvertorMockPrecompile = + PrecompileSetBuilder, AIUSDConvertorPrecompile>,)>; + +pub type PCall = AIUSDConvertorPrecompileCall; + +pub struct TruncatedAddressMapping; +impl AddressMapping for TruncatedAddressMapping { + fn into_account_id(address: H160) -> AccountId { + let mut data = [0u8; 32]; + data[0..20].copy_from_slice(&address[..]); + AccountId::from(Into::<[u8; 32]>::into(data)) + } +} + +parameter_types! { + pub PrecompilesValue: AIUSDConvertorMockPrecompile = AIUSDConvertorMockPrecompile::new(); + pub WeightPerGas: Weight = Weight::from_parts(1, 0); +} + +impl pallet_evm::Config for Test { + type FeeCalculator = (); + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + type CallOrigin = EnsureAddressRoot; + type WithdrawOrigin = EnsureAddressNever; + type AddressMapping = TruncatedAddressMapping; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type Runner = pallet_evm::runner::stack::Runner; + type PrecompilesType = AIUSDConvertorMockPrecompile; + type PrecompilesValue = PrecompilesValue; + type Timestamp = Timestamp; + type ChainId = (); + type OnChargeTransaction = (); + type BlockGasLimit = (); + type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; + type FindAuthor = (); + type OnCreate = (); + type WeightInfo = (); + type GasLimitPovSizeRatio = ConstU64<4>; +} + +parameter_types! { + pub const VerifyPRuntime: bool = false; + pub const VerifyRelaychainGenesisBlockHash: bool = false; +} + +impl pallet_timestamp::Config for Test { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<1>; + type WeightInfo = (); +} + +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + + let h160_address: H160 = H160::from_low_u64_be(1001); + let owner = TruncatedAddressMapping::into_account_id(h160_address); + let origin = RuntimeOrigin::root(); + + // Create the AIUSD asset + assert_ok!(pallet_assets::Pallet::::force_create( + origin.clone(), + 1, // AIUSD asset id + owner.clone(), + true, + 1, + )); + // Create the target asset + let target_asset_id = 2; + assert_ok!(pallet_assets::Pallet::::force_create( + origin, + target_asset_id, + owner.clone(), + true, + 1, + )); + + // Check if these assets exists + assert!(pallet_aiusd::InspectFungibles::::asset_exists(1)); + assert!(pallet_aiusd::InspectFungibles::::asset_exists(2)); + + // Set total supply + assert_ok!(pallet_aiusd::InspectFungibles::::mint_into( + target_asset_id, + &owner, + 1_000_000_000 // 1000 (10^6 * 1000) + )); + + // Enable assert + assert_ok!(AIUSD::enable_token(RuntimeOrigin::root(), target_asset_id, 1_000_000)); + }); + ext +} diff --git a/parachain/precompiles/collab-ai/aiusd-convertor/src/tests.rs b/parachain/precompiles/collab-ai/aiusd-convertor/src/tests.rs new file mode 100644 index 0000000000..dea5598600 --- /dev/null +++ b/parachain/precompiles/collab-ai/aiusd-convertor/src/tests.rs @@ -0,0 +1,98 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate::mock::*; +use pallet_aiusd_convertor::{Event, InspectFungibles}; +use pallet_evm::AddressMapping; +use precompile_utils::testing::PrecompileTesterExt; +use sp_core::H160; +use sp_runtime::AccountId32; + +#[test] +fn test_mint_and_burn_aiusd() { + new_test_ext().execute_with(|| { + let aiusd_asset_id = 1; + let target_asset_id = 2; + let target_decimal_ratio = 1_000_000; + let target_asset_supply_amount: u128 = target_decimal_ratio * 1000; + let h160_address: H160 = H160::from_low_u64_be(1001); + let beneficiary = + >::into_account_id(h160_address); + + // Check balance + let aiusd_balance = InspectFungibles::::balance(aiusd_asset_id, &beneficiary); + assert_eq!(aiusd_balance, 0); + let target_balance = InspectFungibles::::balance(target_asset_id, &beneficiary); + assert_eq!(target_balance, target_asset_supply_amount); + + // mint + let mint_amount: u128 = 3_000_000_000_000_000_000; // 3 AIUSD (10^18 * 3) + PrecompilesValue::get() + .prepare_test( + h160_address, + precompile_address(), + PCall::::mint_aiusd { + asset_id: target_asset_id.into(), + amount: mint_amount.into(), + }, + ) + .expect_no_logs() + .execute_returns(()); + + let mint_asset_amount = target_decimal_ratio * 3; + // Check balance after mint + let aiusd_balance = InspectFungibles::::balance(aiusd_asset_id, &beneficiary); + assert_eq!(aiusd_balance, mint_amount); + let target_balance = InspectFungibles::::balance(target_asset_id, &beneficiary); + assert_eq!(target_balance, target_asset_supply_amount - mint_asset_amount); + System::assert_last_event(RuntimeEvent::AIUSD(Event::AIUSDCreated { + beneficiary: beneficiary.clone(), + aiusd_amount: mint_amount, + asset_id: target_asset_id, + asset_amount: mint_asset_amount, + })); + + // burn + let burn_amount: u128 = 2_000_000_000_000_000_000; // 2 AIUSD (10^18 * 2) + PrecompilesValue::get() + .prepare_test( + h160_address, + precompile_address(), + PCall::::burn_aiusd { + asset_id: target_asset_id.into(), + amount: burn_amount.into(), + }, + ) + .expect_no_logs() + .execute_returns(()); + + let burn_asset_amount = target_decimal_ratio * 2; + // Check balance after burn + let aiusd_balance = InspectFungibles::::balance(aiusd_asset_id, &beneficiary); + assert_eq!(aiusd_balance, mint_amount - burn_amount); + let target_balance = InspectFungibles::::balance(target_asset_id, &beneficiary); + assert_eq!( + target_balance, + target_asset_supply_amount - mint_asset_amount + burn_asset_amount + ); + System::assert_last_event(RuntimeEvent::AIUSD(Event::AIUSDDestroyed { + beneficiary, + aiusd_amount: burn_amount, + asset_id: target_asset_id, + asset_amount: burn_asset_amount, + })); + }); +} From 83bbc989ecc7eca8ef76463b50a75be8eb2bb59b Mon Sep 17 00:00:00 2001 From: BillyWooo Date: Wed, 16 Oct 2024 10:48:37 +0200 Subject: [PATCH 089/215] add test for pallet guardian (#3130) * add test for pallet guardian * fix test * add more tests --- parachain/Cargo.lock | 5 + .../pallets/collab-ai/guardian/Cargo.toml | 4 + .../pallets/collab-ai/guardian/src/lib.rs | 5 + .../pallets/collab-ai/guardian/src/mock.rs | 118 ++++++ .../pallets/collab-ai/guardian/src/tests.rs | 156 ++++++++ .../precompiles/collab-ai/guardian/Cargo.toml | 3 + .../precompiles/collab-ai/guardian/src/lib.rs | 21 ++ .../collab-ai/guardian/src/mock.rs | 173 +++++++++ .../collab-ai/guardian/src/tests.rs | 342 ++++++++++++++++++ 9 files changed, 827 insertions(+) create mode 100644 parachain/pallets/collab-ai/guardian/src/mock.rs create mode 100644 parachain/pallets/collab-ai/guardian/src/tests.rs create mode 100644 parachain/precompiles/collab-ai/guardian/src/mock.rs create mode 100644 parachain/precompiles/collab-ai/guardian/src/tests.rs diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index c0234a9dd8..59fbfb207a 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -7518,6 +7518,7 @@ dependencies = [ "frame-system", "hex-literal", "libsecp256k1", + "pallet-balances", "pallet-collab-ai-common", "pallet-evm", "pallet-guardian", @@ -7528,6 +7529,7 @@ dependencies = [ "serde", "sha3", "sp-core", + "sp-io", "sp-runtime", "sp-std", ] @@ -7713,9 +7715,12 @@ version = "0.1.0" dependencies = [ "frame-support", "frame-system", + "pallet-balances", "pallet-collab-ai-common", "parity-scale-codec", "scale-info", + "sp-core", + "sp-io", "sp-runtime", "sp-std", ] diff --git a/parachain/pallets/collab-ai/guardian/Cargo.toml b/parachain/pallets/collab-ai/guardian/Cargo.toml index 9806162581..5b6f11e88a 100644 --- a/parachain/pallets/collab-ai/guardian/Cargo.toml +++ b/parachain/pallets/collab-ai/guardian/Cargo.toml @@ -14,9 +14,12 @@ scale-info = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } +pallet-balances = { workspace = true } pallet-collab-ai-common = { workspace = true } [features] @@ -34,5 +37,6 @@ std = [ "frame-support/std", "frame-system/std", "pallet-collab-ai-common/std", + "pallet-balances/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/parachain/pallets/collab-ai/guardian/src/lib.rs b/parachain/pallets/collab-ai/guardian/src/lib.rs index 2059fa1fda..c958f34083 100644 --- a/parachain/pallets/collab-ai/guardian/src/lib.rs +++ b/parachain/pallets/collab-ai/guardian/src/lib.rs @@ -42,6 +42,11 @@ use sp_runtime::ArithmeticError; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + #[frame_support::pallet] pub mod pallet { use super::*; diff --git a/parachain/pallets/collab-ai/guardian/src/mock.rs b/parachain/pallets/collab-ai/guardian/src/mock.rs new file mode 100644 index 0000000000..4299b2bc9d --- /dev/null +++ b/parachain/pallets/collab-ai/guardian/src/mock.rs @@ -0,0 +1,118 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate as pallet_guardian; +use frame_support::{ + construct_runtime, parameter_types, + traits::{ConstU16, ConstU32, Everything}, +}; +use sp_core::H256; +use sp_runtime::{ + traits::{BlakeTwo256, IdentityLookup}, + AccountId32, +}; +// use sp_io::TestExternalities; +use frame_support::traits::ConstU128; +use sp_runtime::BuildStorage; + +// Define mock runtime types +pub type Balance = u128; +pub type AccountId = AccountId32; + +// Configure a mock runtime to test the pallet. +construct_runtime!( + pub enum Test { + System: frame_system, + Balances: pallet_balances, + Guardian: pallet_guardian, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MinimumGuardianDeposit: Balance = 10; + pub const MaxProposalPerGuardian: u32 = 10; +} + +// Implement frame_system config trait for mock runtime. +impl frame_system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Nonce = u64; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + // type BlockNumber = u64; // Add this + type Hash = H256; + type Block = frame_system::mocking::MockBlock; // Add this + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + // type Header = sp_runtime::generic::Header; // Add this + type BlockHashCount = BlockHashCount; + type Version = (); // Add this + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = ConstU16<31>; + type OnSetCode = (); // Add this + type MaxConsumers = ConstU32<16>; // Add this +} + +// Implement pallet_balances config trait for mock runtime. +impl pallet_balances::Config for Test { + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ConstU128<1>; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = (); + type MaxFreezes = (); + type RuntimeHoldReason = (); +} + +// Implement pallet_guardian config trait for mock runtime. +impl pallet_guardian::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type MinimumGuardianDeposit = MinimumGuardianDeposit; + type MaxProposalPerGuardian = MaxProposalPerGuardian; + type GuardianJudgeOrigin = frame_system::EnsureRoot; +} + +// Helper function to initialize the test environment. +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(AccountId32::from([1u8; 32]), 100), (AccountId32::from([2u8; 32]), 100)], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} diff --git a/parachain/pallets/collab-ai/guardian/src/tests.rs b/parachain/pallets/collab-ai/guardian/src/tests.rs new file mode 100644 index 0000000000..08dcc69c33 --- /dev/null +++ b/parachain/pallets/collab-ai/guardian/src/tests.rs @@ -0,0 +1,156 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate::mock::*; +use frame_support::assert_ok; +use pallet_collab_ai_common::GuardianQuery; // Import GuardianQuery trait +use pallet_collab_ai_common::GuardianVote; +use sp_runtime::AccountId32; + +#[test] +fn test_regist_guardian() { + new_test_ext().execute_with(|| { + let guardian: AccountId32 = AccountId32::from([1u8; 32]); + let info_hash: [u8; 32] = [1; 32]; + + // Register guardian + assert_ok!(Guardian::regist_guardian( + RuntimeOrigin::signed(guardian.clone()), + sp_core::H256(info_hash) + )); + + // Check if guardian is stored correctly + assert_eq!(Guardian::public_guardian_to_index(&guardian), Some(0)); + System::assert_last_event(RuntimeEvent::Guardian(crate::Event::GuardianRegisted { + guardian, + guardian_index: 0, + info_hash: sp_core::H256(info_hash), + })); + }); +} + +#[test] +fn test_update_guardian() { + new_test_ext().execute_with(|| { + let guardian: AccountId32 = AccountId32::from([1u8; 32]); + let info_hash: [u8; 32] = [1; 32]; + let updated_hash: [u8; 32] = [2; 32]; + + // Register guardian + assert_ok!(Guardian::regist_guardian( + RuntimeOrigin::signed(guardian.clone()), + sp_core::H256(info_hash) + )); + + // Update guardian + assert_ok!(Guardian::update_guardian( + RuntimeOrigin::signed(guardian.clone()), + sp_core::H256(updated_hash) + )); + + // Check if guardian info is updated correctly + let guardian_info = Guardian::guardian_index_to_info(0).unwrap(); + assert_eq!(guardian_info.0, sp_core::H256(updated_hash)); + System::assert_last_event(RuntimeEvent::Guardian(crate::Event::GuardianUpdated { + guardian, + guardian_index: 0, + info_hash: sp_core::H256(updated_hash), + })); + }); +} + +#[test] +fn test_clean_guardian() { + new_test_ext().execute_with(|| { + let guardian: AccountId32 = AccountId32::from([1u8; 32]); + let info_hash: [u8; 32] = [1; 32]; + + // Register and clean guardian + assert_ok!(Guardian::regist_guardian( + RuntimeOrigin::signed(guardian.clone()), + sp_core::H256(info_hash) + )); + assert_ok!(Guardian::clean_guardian(RuntimeOrigin::signed(guardian.clone()))); + + // Check if guardian is removed + assert_eq!(Guardian::public_guardian_to_index(&guardian), None); + System::assert_last_event(RuntimeEvent::Guardian(crate::Event::GuardianCleaned { + guardian, + guardian_index: 0, + })); + }); +} + +#[test] +fn test_vote_for_guardian() { + new_test_ext().execute_with(|| { + let guardian: AccountId32 = AccountId32::from([1u8; 32]); + let voter: AccountId32 = AccountId32::from([2u8; 32]); + let info_hash: [u8; 32] = [1; 32]; + + // Register guardian + assert_ok!(Guardian::regist_guardian( + RuntimeOrigin::signed(guardian.clone()), + sp_core::H256(info_hash) + )); + + // Cast a vote + assert_ok!(Guardian::vote( + RuntimeOrigin::signed(voter.clone()), + guardian.clone(), + Some(GuardianVote::Specific(1)) + )); + + // Check if vote is recorded + assert_eq!( + Guardian::get_vote(voter.clone(), guardian.clone()), + Some(GuardianVote::Specific(1)) + ); + System::assert_last_event(RuntimeEvent::Guardian(crate::Event::VoteGuardian { + voter, + guardian_index: 0, + guardian, + status: Some(GuardianVote::Specific(1)), + })); + }); +} + +#[test] +fn test_remove_all_votes() { + new_test_ext().execute_with(|| { + let guardian: AccountId32 = AccountId32::from([1u8; 32]); + let voter: AccountId32 = AccountId32::from([2u8; 32]); + let info_hash: [u8; 32] = [1; 32]; + + // Register guardian and vote + assert_ok!(Guardian::regist_guardian( + RuntimeOrigin::signed(guardian.clone()), + sp_core::H256(info_hash) + )); + assert_ok!(Guardian::vote( + RuntimeOrigin::signed(voter.clone()), + guardian.clone(), + Some(GuardianVote::Specific(1)) + )); + + // Remove all votes + assert_ok!(Guardian::remove_all_votes(RuntimeOrigin::signed(voter.clone()))); + + // Check if votes are removed + assert_eq!(Guardian::get_vote(voter.clone(), guardian.clone()), None); + System::assert_last_event(RuntimeEvent::Guardian(crate::Event::RemoveAllVote { voter })); + }); +} diff --git a/parachain/precompiles/collab-ai/guardian/Cargo.toml b/parachain/precompiles/collab-ai/guardian/Cargo.toml index 0f66ac38d1..9c58050c68 100644 --- a/parachain/precompiles/collab-ai/guardian/Cargo.toml +++ b/parachain/precompiles/collab-ai/guardian/Cargo.toml @@ -5,6 +5,7 @@ name = "pallet-evm-precompile-guardian" version = '0.1.0' [dependencies] +pallet-balances = { workspace = true } precompile-utils = { workspace = true } # Substrate @@ -15,6 +16,7 @@ pallet-guardian = { workspace = true } parity-scale-codec = { workspace = true, features = ["max-encoded-len"] } scale-info = { workspace = true, features = ["derive"] } sp-core = { workspace = true } +sp-io = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } @@ -41,6 +43,7 @@ std = [ "frame-support/std", "frame-system/std", "pallet-collab-ai-common/std", + "pallet-balances/std", "pallet-guardian/std", "pallet-evm/std", "pallet-timestamp/std", diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index f76ddd9446..bc44300254 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -1,3 +1,19 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + #![cfg_attr(not(feature = "std"), no_std)] use fp_evm::{PrecompileFailure, PrecompileHandle}; @@ -12,6 +28,11 @@ use sp_std::marker::PhantomData; use pallet_collab_ai_common::{CandidateStatus, GuardianVote}; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + pub struct GuardianPrecompile(PhantomData); #[precompile_utils::precompile] diff --git a/parachain/precompiles/collab-ai/guardian/src/mock.rs b/parachain/precompiles/collab-ai/guardian/src/mock.rs new file mode 100644 index 0000000000..798a60c363 --- /dev/null +++ b/parachain/precompiles/collab-ai/guardian/src/mock.rs @@ -0,0 +1,173 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate::*; +use frame_support::{ + assert_ok, construct_runtime, parameter_types, + traits::{AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, ConstU64, Everything}, +}; +use pallet_balances; +use pallet_evm::{EnsureAddressNever, EnsureAddressRoot}; +use pallet_guardian; +use precompile_utils::precompile_set::{AddressU64, PrecompileAt, PrecompileSetBuilder}; +use sp_core::{Get, H160, H256}; +use sp_io::TestExternalities; +use sp_runtime::{ + traits::{BlakeTwo256, IdentityLookup}, + AccountId32, BuildStorage, +}; + +pub type Balance = u128; +pub type AccountId = AccountId32; + +// Configure a mock runtime to test the pallet. +construct_runtime!( + pub enum Test { + System: frame_system, + Balances: pallet_balances, + Evm: pallet_evm, + Guardian: pallet_guardian, + Timestamp: pallet_timestamp, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MinimumGuardianDeposit: Balance = 10; + pub const MaxProposalPerGuardian: u32 = 10; +} + +impl frame_system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Block = frame_system::mocking::MockBlock; // Add this + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = ConstU16<31>; + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl pallet_balances::Config for Test { + type MaxLocks = (); + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ConstU128<1>; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = (); + type ReserveIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = (); + type MaxFreezes = (); + type RuntimeHoldReason = (); +} + +// Implement pallet_guardian config trait for mock runtime. +impl pallet_guardian::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type MinimumGuardianDeposit = MinimumGuardianDeposit; + type MaxProposalPerGuardian = MaxProposalPerGuardian; + type GuardianJudgeOrigin = frame_system::EnsureRoot; +} + +// Setup EVM configuration +parameter_types! { + pub WeightPerGas: u64 = 1; +} + +impl pallet_evm::Config for Test { + type FeeCalculator = (); + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + type CallOrigin = EnsureAddressRoot; + type WithdrawOrigin = EnsureAddressNever; + type AddressMapping = TruncatedAddressMapping; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type Runner = pallet_evm::runner::stack::Runner; + type PrecompilesType = GuardianMockPrecompile; + type PrecompilesValue = PrecompilesValue; + type ChainId = (); + type Timestamp = Timestamp; + type OnChargeTransaction = (); + type BlockGasLimit = (); + type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; + type FindAuthor = (); + type OnCreate = (); + type WeightInfo = (); + type GasLimitPovSizeRatio = ConstU64<4>; +} + +impl pallet_timestamp::Config for Test { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<1>; + type WeightInfo = (); +} + +pub struct TruncatedAddressMapping; +impl pallet_evm::AddressMapping for TruncatedAddressMapping { + fn into_account_id(address: H160) -> AccountId { + let mut data = [0u8; 32]; + data[0..20].copy_from_slice(&address[..]); + AccountId::from(Into::<[u8; 32]>::into(data)) + } +} + +pub type GuardianMockPrecompile = + PrecompileSetBuilder, GuardianPrecompile>,)>; + +parameter_types! { + pub PrecompilesValue: GuardianMockPrecompile = GuardianMockPrecompile::new(); +} + +// Helper function to initialize the test environment. +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + // Add initial balances for the involved accounts + pallet_balances::GenesisConfig:: { + balances: vec![ + (TruncatedAddressMapping::into_account_id(H160::from_low_u64_be(1000)), 1_000_000), + (TruncatedAddressMapping::into_account_id(H160::from_low_u64_be(1001)), 1_000_000), + (TruncatedAddressMapping::into_account_id(H160::from_low_u64_be(1002)), 1_000_000), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} diff --git a/parachain/precompiles/collab-ai/guardian/src/tests.rs b/parachain/precompiles/collab-ai/guardian/src/tests.rs new file mode 100644 index 0000000000..ed39451913 --- /dev/null +++ b/parachain/precompiles/collab-ai/guardian/src/tests.rs @@ -0,0 +1,342 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate::mock::RuntimeEvent; +use crate::mock::*; +use pallet_collab_ai_common::GuardianVote; +use pallet_evm::AddressMapping; +use pallet_guardian::Event; +// use pallet_evm::AddressMapping::GuardianPrecompileCall; +use crate::GuardianPrecompileCall; +use precompile_utils::testing::PrecompileTesterExt; +use sp_core::{H160, H256, U256}; + +pub type PCall = GuardianPrecompileCall; + +#[test] +fn test_regist_guardian() { + new_test_ext().execute_with(|| { + let guardian: H160 = H160::from_low_u64_be(1001); + let info_hash: H256 = H256::from([1u8; 32]); + + PrecompilesValue::get() + .prepare_test( + guardian, + H160::from_low_u64_be(1000), + PCall::::regist_guardian { info_hash }, + ) + .expect_no_logs() + .execute_returns(()); + + System::assert_last_event(RuntimeEvent::Guardian(Event::GuardianRegisted { + guardian: TruncatedAddressMapping::into_account_id(guardian), + guardian_index: 0, + info_hash, + })); + }); +} + +#[test] +fn test_update_guardian() { + new_test_ext().execute_with(|| { + let guardian: H160 = H160::from_low_u64_be(1001); + let info_hash: H256 = H256::from([1u8; 32]); + let updated_hash: H256 = H256::from([2u8; 32]); + + PrecompilesValue::get() + .prepare_test( + guardian, + H160::from_low_u64_be(1000), + PCall::::regist_guardian { info_hash }, + ) + .execute_returns(()); + + PrecompilesValue::get() + .prepare_test( + guardian, + H160::from_low_u64_be(1000), + PCall::::update_guardian { info_hash: updated_hash }, + ) + .execute_returns(()); + + System::assert_last_event(RuntimeEvent::Guardian(Event::GuardianUpdated { + guardian: TruncatedAddressMapping::into_account_id(guardian), + guardian_index: 0, + info_hash: updated_hash, + })); + }); +} + +#[test] +fn test_clean_guardian() { + new_test_ext().execute_with(|| { + let guardian: H160 = H160::from_low_u64_be(1001); + let info_hash: H256 = H256::from([1u8; 32]); + + PrecompilesValue::get() + .prepare_test( + guardian, + H160::from_low_u64_be(1000), + PCall::::regist_guardian { info_hash }, + ) + .execute_returns(()); + + PrecompilesValue::get() + .prepare_test(guardian, H160::from_low_u64_be(1000), PCall::::clean_guardian {}) + .execute_returns(()); + + System::assert_last_event(RuntimeEvent::Guardian(Event::GuardianCleaned { + guardian: TruncatedAddressMapping::into_account_id(guardian), + guardian_index: 0, + })); + }); +} + +#[test] +fn test_vote_for_guardian() { + new_test_ext().execute_with(|| { + let guardian: H160 = H160::from_low_u64_be(1001); + let voter: H160 = H160::from_low_u64_be(1002); + let info_hash: H256 = H256::from([1u8; 32]); + + // Register the guardian first + PrecompilesValue::get() + .prepare_test( + guardian, + H160::from_low_u64_be(1000), + PCall::::regist_guardian { info_hash }, + ) + .execute_returns(()); + + // Ensure the guardian is successfully registered before proceeding + assert!(pallet_guardian::Pallet::::public_guardian_to_index( + TruncatedAddressMapping::into_account_id(guardian) + ) + .is_some()); + + let guardian_account = TruncatedAddressMapping::into_account_id(guardian); + let guardian_account: [u8; 32] = guardian_account.into(); + let guardian_account: H256 = guardian_account.into(); + // Cast the vote + PrecompilesValue::get() + .prepare_test( + voter, + H160::from_low_u64_be(1000), + PCall::::vote { + guardian: guardian_account, + status: 1, + potential_proposal_index: 0.into(), + }, + ) + .execute_returns(()); + + System::assert_last_event(RuntimeEvent::Guardian(Event::VoteGuardian { + voter: TruncatedAddressMapping::into_account_id(voter), + guardian_index: 0, + guardian: TruncatedAddressMapping::into_account_id(guardian), + status: Some(GuardianVote::Aye), + })); + }); +} + +#[test] +fn test_remove_all_votes() { + new_test_ext().execute_with(|| { + let guardian: H160 = H160::from_low_u64_be(1001); + let voter: H160 = H160::from_low_u64_be(1002); + let info_hash: H256 = H256::from([1u8; 32]); + + // Register the guardian first + PrecompilesValue::get() + .prepare_test( + guardian, + H160::from_low_u64_be(1000), + PCall::::regist_guardian { info_hash }, + ) + .execute_returns(()); + + // Ensure the guardian is successfully registered before proceeding + assert!(pallet_guardian::Pallet::::public_guardian_to_index( + TruncatedAddressMapping::into_account_id(guardian) + ) + .is_some()); + + let guardian_account = TruncatedAddressMapping::into_account_id(guardian); + let guardian_account: [u8; 32] = guardian_account.into(); + let guardian_account: H256 = guardian_account.into(); + // Cast a vote + PrecompilesValue::get() + .prepare_test( + voter, + H160::from_low_u64_be(1000), + PCall::::vote { + guardian: guardian_account, + status: 1, + potential_proposal_index: 0.into(), + }, + ) + .execute_returns(()); + + // Remove all votes + PrecompilesValue::get() + .prepare_test(voter, H160::from_low_u64_be(1000), PCall::::remove_all_votes {}) + .execute_returns(()); + + System::assert_last_event(RuntimeEvent::Guardian(Event::RemoveAllVote { + voter: TruncatedAddressMapping::into_account_id(voter), + })); + }); +} + +#[test] +fn test_public_guardian_count() { + new_test_ext().execute_with(|| { + // Initially, there should be no guardians + PrecompilesValue::get() + .prepare_test( + H160::from_low_u64_be(1001), + H160::from_low_u64_be(1000), + PCall::::public_guardian_count {}, + ) + .execute_returns(U256::from(0)); // Provide expected result + + // Register a guardian to increase the count + let info_hash: H256 = H256::from([1u8; 32]); + PrecompilesValue::get() + .prepare_test( + H160::from_low_u64_be(1001), + H160::from_low_u64_be(1000), + PCall::::regist_guardian { info_hash }, + ) + .execute_returns(()); + + // Check the guardian count again, should be 1 + PrecompilesValue::get() + .prepare_test( + H160::from_low_u64_be(1001), + H160::from_low_u64_be(1000), + PCall::::public_guardian_count {}, + ) + .execute_returns(U256::from(1)); + }); +} + +#[test] +fn test_public_guardian_to_index() { + new_test_ext().execute_with(|| { + let guardian: H160 = H160::from_low_u64_be(1001); + let info_hash: H256 = H256::from([1u8; 32]); + + // Register the guardian + PrecompilesValue::get() + .prepare_test( + guardian, + H160::from_low_u64_be(1000), + PCall::::regist_guardian { info_hash }, + ) + .execute_returns(()); + + // Query the guardian's index + + let guardian_account = TruncatedAddressMapping::into_account_id(guardian); + let guardian_account: [u8; 32] = guardian_account.into(); + let guardian_account: H256 = guardian_account.into(); + PrecompilesValue::get() + .prepare_test( + guardian, + H160::from_low_u64_be(1000), + PCall::::public_guardian_to_index { guardian: guardian_account }, + ) + .execute_returns((true, U256::from(0))); + }); +} + +#[test] +fn test_guardian_index_to_info() { + new_test_ext().execute_with(|| { + let guardian: H160 = H160::from_low_u64_be(1001); + let info_hash: H256 = H256::from([1u8; 32]); + + // Register the guardian + PrecompilesValue::get() + .prepare_test( + guardian, + H160::from_low_u64_be(1000), + PCall::::regist_guardian { info_hash }, + ) + .execute_returns(()); + + // Query the guardian info by index + + let guardian_account = TruncatedAddressMapping::into_account_id(guardian); + let guardian_account: [u8; 32] = guardian_account.into(); + let guardian_account: H256 = guardian_account.into(); + PrecompilesValue::get() + .prepare_test( + guardian, + H160::from_low_u64_be(1000), + PCall::::guardian_index_to_info { index: 0.into() }, + ) + .execute_returns((true, info_hash, U256::from(1), guardian_account, 0u8)); + }); +} + +#[test] +fn test_guardian_votes() { + new_test_ext().execute_with(|| { + let guardian: H160 = H160::from_low_u64_be(1001); + let voter: H160 = H160::from_low_u64_be(1002); + let info_hash: H256 = H256::from([1u8; 32]); + + // Register the guardian + PrecompilesValue::get() + .prepare_test( + guardian, + H160::from_low_u64_be(1000), + PCall::::regist_guardian { info_hash }, + ) + .execute_returns(()); + + // Cast a vote for the guardian + let guardian_account = TruncatedAddressMapping::into_account_id(guardian); + let guardian_account: [u8; 32] = guardian_account.into(); + let guardian_account: H256 = guardian_account.into(); + PrecompilesValue::get() + .prepare_test( + voter, + H160::from_low_u64_be(1000), + PCall::::vote { + guardian: guardian_account, + status: 1, + potential_proposal_index: 0.into(), + }, + ) + .execute_returns(()); + + // Check the vote for the guardian + + let voter_account = TruncatedAddressMapping::into_account_id(voter); + let voter_account: [u8; 32] = voter_account.into(); + let voter_account: H256 = voter_account.into(); + PrecompilesValue::get() + .prepare_test( + voter, + H160::from_low_u64_be(1000), + PCall::::guardian_votes { voter: voter_account, guardian_index: 0.into() }, + ) + .execute_returns((1u8, U256::from(0))); // Aye vote + }); +} From fe5b345f8e9c2b7b69609c6707c67a0f062f4eed Mon Sep 17 00:00:00 2001 From: Yang Date: Wed, 16 Oct 2024 09:19:45 +0000 Subject: [PATCH 090/215] fix clippy --- parachain/precompiles/collab-ai/guardian/src/mock.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/parachain/precompiles/collab-ai/guardian/src/mock.rs b/parachain/precompiles/collab-ai/guardian/src/mock.rs index 798a60c363..390092b1da 100644 --- a/parachain/precompiles/collab-ai/guardian/src/mock.rs +++ b/parachain/precompiles/collab-ai/guardian/src/mock.rs @@ -16,15 +16,12 @@ use crate::*; use frame_support::{ - assert_ok, construct_runtime, parameter_types, - traits::{AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, ConstU64, Everything}, + construct_runtime, parameter_types, + traits::{ConstU128, ConstU16, ConstU32, ConstU64, Everything}, }; -use pallet_balances; use pallet_evm::{EnsureAddressNever, EnsureAddressRoot}; -use pallet_guardian; use precompile_utils::precompile_set::{AddressU64, PrecompileAt, PrecompileSetBuilder}; -use sp_core::{Get, H160, H256}; -use sp_io::TestExternalities; +use sp_core::{H160, H256}; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, AccountId32, BuildStorage, From 1fa19fc7d8cb0084e9303fd80d860f06b96dba51 Mon Sep 17 00:00:00 2001 From: Faisal Ahmed <42486737+felixfaisal@users.noreply.github.com> Date: Wed, 23 Oct 2024 11:07:40 +0530 Subject: [PATCH 091/215] feat: add unit tests for curator (#3142) * feat: add unit tests for curator pallet * feat: add unit tests for pre-compile curator --- .../pallets/collab-ai/curator/Cargo.toml | 6 + .../pallets/collab-ai/curator/src/lib.rs | 5 + .../pallets/collab-ai/curator/src/mock.rs | 116 +++++++ .../pallets/collab-ai/curator/src/tests.rs | 328 ++++++++++++++++++ .../precompiles/collab-ai/curator/Cargo.toml | 3 + .../precompiles/collab-ai/curator/src/lib.rs | 5 + .../precompiles/collab-ai/curator/src/mock.rs | 168 +++++++++ .../collab-ai/curator/src/tests.rs | 196 +++++++++++ 8 files changed, 827 insertions(+) create mode 100644 parachain/pallets/collab-ai/curator/src/mock.rs create mode 100644 parachain/pallets/collab-ai/curator/src/tests.rs create mode 100644 parachain/precompiles/collab-ai/curator/src/mock.rs create mode 100644 parachain/precompiles/collab-ai/curator/src/tests.rs diff --git a/parachain/pallets/collab-ai/curator/Cargo.toml b/parachain/pallets/collab-ai/curator/Cargo.toml index a9f4fa7114..a05b731fe6 100644 --- a/parachain/pallets/collab-ai/curator/Cargo.toml +++ b/parachain/pallets/collab-ai/curator/Cargo.toml @@ -19,6 +19,11 @@ sp-std = { workspace = true } pallet-collab-ai-common = { workspace = true } +[dev-dependencies] +pallet-balances = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } + [features] default = ["std"] runtime-benchmarks = [ @@ -34,5 +39,6 @@ std = [ "frame-support/std", "frame-system/std", "pallet-collab-ai-common/std", + "pallet-balances/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/parachain/pallets/collab-ai/curator/src/lib.rs b/parachain/pallets/collab-ai/curator/src/lib.rs index 4c2cecf2eb..974791dedf 100644 --- a/parachain/pallets/collab-ai/curator/src/lib.rs +++ b/parachain/pallets/collab-ai/curator/src/lib.rs @@ -39,6 +39,11 @@ pub use pallet::*; use pallet_collab_ai_common::*; use sp_runtime::ArithmeticError; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; diff --git a/parachain/pallets/collab-ai/curator/src/mock.rs b/parachain/pallets/collab-ai/curator/src/mock.rs new file mode 100644 index 0000000000..d13eac3d76 --- /dev/null +++ b/parachain/pallets/collab-ai/curator/src/mock.rs @@ -0,0 +1,116 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate as pallet_curator; +use frame_support::{ + construct_runtime, parameter_types, + traits::{ConstU16, ConstU32, Everything}, +}; +use sp_core::H256; +use sp_runtime::{ + traits::{BlakeTwo256, IdentityLookup}, + AccountId32, +}; +// use sp_io::TestExternalities; +use frame_support::traits::ConstU128; +use sp_runtime::BuildStorage; + +// Define mock runtime types +pub type Balance = u128; +pub type AccountId = AccountId32; + +// Configure a mock runtime to test the pallet. +construct_runtime!( + pub enum Test { + System: frame_system, + Balances: pallet_balances, + Curator: pallet_curator, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MinimumCuratorDeposit: Balance = 10; +} + +// Implement frame_system config trait for mock runtime. +impl frame_system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Nonce = u64; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + // type BlockNumber = u64; // Add this + type Hash = H256; + type Block = frame_system::mocking::MockBlock; // Add this + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + // type Header = sp_runtime::generic::Header; // Add this + type BlockHashCount = BlockHashCount; + type Version = (); // Add this + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = ConstU16<31>; + type OnSetCode = (); // Add this + type MaxConsumers = ConstU32<16>; // Add this +} + +// Implement pallet_balances config trait for mock runtime. +impl pallet_balances::Config for Test { + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ConstU128<1>; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = (); + type MaxFreezes = (); + type RuntimeHoldReason = (); +} + +// Implement pallet_curator config trait for mock runtime. +impl pallet_curator::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type MinimumCuratorDeposit = MinimumCuratorDeposit; + type CuratorJudgeOrigin = frame_system::EnsureRoot; +} + +// Helper function to initialize the test environment. +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(AccountId32::from([1u8; 32]), 100), (AccountId32::from([2u8; 32]), 11)], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} diff --git a/parachain/pallets/collab-ai/curator/src/tests.rs b/parachain/pallets/collab-ai/curator/src/tests.rs new file mode 100644 index 0000000000..b8d73b4c73 --- /dev/null +++ b/parachain/pallets/collab-ai/curator/src/tests.rs @@ -0,0 +1,328 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate::mock::*; +use crate::{CandidateStatus, CuratorIndexToInfo, Error, PublicCuratorCount, PublicCuratorToIndex}; +use frame_support::{assert_noop, assert_ok}; +use pallet_balances::Error as BalanceError; +use sp_core::crypto::AccountId32; + +#[test] +fn test_register_curator_ok() { + new_test_ext().execute_with(|| { + let curator: AccountId32 = AccountId32::from([1u8; 32]); + let info_hash: [u8; 32] = [1; 32]; + let curator_index = PublicCuratorCount::::get(); + + // Register curator + assert_ok!(Curator::regist_curator( + RuntimeOrigin::signed(curator.clone()), + sp_core::H256(info_hash) + )); + + // Check if curator is stored correctly + assert_eq!(PublicCuratorToIndex::::get(&curator), Some(curator_index)); + assert_eq!(PublicCuratorCount::::get(), curator_index + 1); + assert_eq!( + CuratorIndexToInfo::::get(curator_index), + Some((sp_core::H256(info_hash), 1, curator.clone(), CandidateStatus::Unverified)) + ); + + System::assert_last_event(RuntimeEvent::Curator(crate::Event::CuratorRegisted { + curator, + curator_index, + info_hash: sp_core::H256(info_hash), + })); + }) +} + +#[test] +fn test_register_curator_curator_already_registered() { + new_test_ext().execute_with(|| { + let curator: AccountId32 = AccountId32::from([1u8; 32]); + let info_hash: [u8; 32] = [1; 32]; + + // Register curator + assert_ok!(Curator::regist_curator( + RuntimeOrigin::signed(curator.clone()), + sp_core::H256(info_hash) + )); + + // Register curator twice + assert_noop!( + Curator::regist_curator( + RuntimeOrigin::signed(curator.clone()), + sp_core::H256(info_hash) + ), + Error::::CuratorAlreadyRegistered + ); + }); +} + +#[test] +fn test_register_curator_without_minimum_curator_deposit() { + new_test_ext().execute_with(|| { + let curator: AccountId32 = AccountId32::from([5u8; 32]); + let info_hash: [u8; 32] = [1; 32]; + + // Register curator with insufficient balance + assert_noop!( + Curator::regist_curator( + RuntimeOrigin::signed(curator.clone()), + sp_core::H256(info_hash) + ), + BalanceError::::InsufficientBalance + ); + }); +} + +#[test] +fn test_update_curator_ok() { + new_test_ext().execute_with(|| { + let curator: AccountId32 = AccountId32::from([1u8; 32]); + let curator_index = PublicCuratorCount::::get(); + let info_hash: [u8; 32] = [1; 32]; + let updated_info_hash: [u8; 32] = [2; 32]; + + // Register curator with info_hash + assert_ok!(Curator::regist_curator( + RuntimeOrigin::signed(curator.clone()), + sp_core::H256(info_hash) + )); + + // Check the storage + assert_eq!( + CuratorIndexToInfo::::get(curator_index), + Some((sp_core::H256(info_hash), 1, curator.clone(), CandidateStatus::Unverified)) + ); + + // Update the info hash + assert_ok!(Curator::update_curator( + RuntimeOrigin::signed(curator.clone()), + sp_core::H256(updated_info_hash) + )); + + // Check the storage after update + assert_eq!( + CuratorIndexToInfo::::get(curator_index), + Some(( + sp_core::H256(updated_info_hash), + 1, + curator.clone(), + CandidateStatus::Unverified + )) + ); + + System::assert_last_event(RuntimeEvent::Curator(crate::Event::CuratorUpdated { + curator, + curator_index, + info_hash: sp_core::H256(updated_info_hash), + })); + }); +} + +#[test] +fn test_update_curator_curator_not_registered() { + new_test_ext().execute_with(|| { + let curator: AccountId32 = AccountId32::from([1u8; 32]); + let info_hash: [u8; 32] = [1; 32]; + + // Update the info hash + assert_noop!( + Curator::update_curator( + RuntimeOrigin::signed(curator.clone()), + sp_core::H256(info_hash) + ), + Error::::CuratorNotRegistered + ); + }); +} + +#[test] +fn test_update_curator_curator_banned_insufficient_balance() { + new_test_ext().execute_with(|| { + let curator: AccountId32 = AccountId32::from([2u8; 32]); + let info_hash: [u8; 32] = [1; 32]; + let updated_info_hash: [u8; 32] = [2; 32]; + + // Register curator with info_hash + assert_ok!(Curator::regist_curator( + RuntimeOrigin::signed(curator.clone()), + sp_core::H256(info_hash) + )); + + assert_ok!(Curator::judge_curator_status( + RuntimeOrigin::root(), + curator.clone(), + CandidateStatus::Banned + )); + + // Update the info hash + assert_noop!( + Curator::update_curator( + RuntimeOrigin::signed(curator.clone()), + sp_core::H256(updated_info_hash) + ), + BalanceError::::InsufficientBalance + ); + }); +} + +#[test] +fn test_update_curator_curator_banned_sufficient_balance() { + new_test_ext().execute_with(|| { + let curator: AccountId32 = AccountId32::from([1u8; 32]); + let curator_index = PublicCuratorCount::::get(); + let info_hash: [u8; 32] = [1; 32]; + let updated_info_hash: [u8; 32] = [2; 32]; + + // Register curator with info_hash + assert_ok!(Curator::regist_curator( + RuntimeOrigin::signed(curator.clone()), + sp_core::H256(info_hash) + )); + + // Check the storage + assert_eq!( + CuratorIndexToInfo::::get(curator_index), + Some((sp_core::H256(info_hash), 1, curator.clone(), CandidateStatus::Unverified)) + ); + + assert_ok!(Curator::judge_curator_status( + RuntimeOrigin::root(), + curator.clone(), + CandidateStatus::Banned + )); + + // Update the info hash + assert_ok!(Curator::update_curator( + RuntimeOrigin::signed(curator.clone()), + sp_core::H256(updated_info_hash) + )); + + // Check the storage after update + assert_eq!( + CuratorIndexToInfo::::get(curator_index), + Some((sp_core::H256(updated_info_hash), 1, curator.clone(), CandidateStatus::Banned)) + ); + + System::assert_last_event(RuntimeEvent::Curator(crate::Event::CuratorUpdated { + curator, + curator_index, + info_hash: sp_core::H256(updated_info_hash), + })); + }); +} + +#[test] +fn test_judge_curator_status_ok() { + new_test_ext().execute_with(|| { + let curator: AccountId32 = AccountId32::from([1u8; 32]); + let curator_index = PublicCuratorCount::::get(); + let info_hash: [u8; 32] = [1; 32]; + + // Register curator with info_hash + assert_ok!(Curator::regist_curator( + RuntimeOrigin::signed(curator.clone()), + sp_core::H256(info_hash) + )); + + // Check the storage + assert_eq!( + CuratorIndexToInfo::::get(curator_index), + Some((sp_core::H256(info_hash), 1, curator.clone(), CandidateStatus::Unverified)) + ); + + assert_ok!(Curator::judge_curator_status( + RuntimeOrigin::root(), + curator.clone(), + CandidateStatus::Verified + )); + + // Check the storage after status update + assert_eq!( + CuratorIndexToInfo::::get(curator_index), + Some((sp_core::H256(info_hash), 1, curator.clone(), CandidateStatus::Verified)) + ); + + System::assert_last_event(RuntimeEvent::Curator(crate::Event::CuratorStatusUpdated { + curator, + curator_index, + status: CandidateStatus::Verified, + })); + }); +} + +#[test] +fn test_judge_curator_curator_not_registered() { + new_test_ext().execute_with(|| { + let curator: AccountId32 = AccountId32::from([1u8; 32]); + + // Try judging the curator status + assert_noop!( + Curator::judge_curator_status( + RuntimeOrigin::root(), + curator.clone(), + CandidateStatus::Verified + ), + Error::::CuratorNotRegistered + ); + }) +} + +#[test] +fn test_clean_curator_ok() { + new_test_ext().execute_with(|| { + let curator: AccountId32 = AccountId32::from([1u8; 32]); + let curator_index = PublicCuratorCount::::get(); + let info_hash: [u8; 32] = [1; 32]; + + // Register curator with info_hash + assert_ok!(Curator::regist_curator( + RuntimeOrigin::signed(curator.clone()), + sp_core::H256(info_hash) + )); + + // Check the storage + assert_eq!( + CuratorIndexToInfo::::get(curator_index), + Some((sp_core::H256(info_hash), 1, curator.clone(), CandidateStatus::Unverified)) + ); + + assert_ok!(Curator::clean_curator(RuntimeOrigin::signed(curator.clone()),)); + + // Check the storage after status update + assert_eq!(CuratorIndexToInfo::::get(curator_index), None); + + System::assert_last_event(RuntimeEvent::Curator(crate::Event::CuratorCleaned { + curator, + curator_index, + })); + }); +} + +#[test] +fn test_clean_curator_curator_not_registered() { + new_test_ext().execute_with(|| { + let curator: AccountId32 = AccountId32::from([1u8; 32]); + + // Try cleaning the curator info + assert_noop!( + Curator::clean_curator(RuntimeOrigin::signed(curator),), + Error::::CuratorNotRegistered + ); + }) +} diff --git a/parachain/precompiles/collab-ai/curator/Cargo.toml b/parachain/precompiles/collab-ai/curator/Cargo.toml index 053963d93d..6d35244ddf 100644 --- a/parachain/precompiles/collab-ai/curator/Cargo.toml +++ b/parachain/precompiles/collab-ai/curator/Cargo.toml @@ -5,6 +5,7 @@ name = "pallet-evm-precompile-curator" version = '0.1.0' [dependencies] +pallet-balances = { workspace = true } precompile-utils = { workspace = true } # Substrate @@ -15,6 +16,7 @@ pallet-curator = { workspace = true } parity-scale-codec = { workspace = true, features = ["max-encoded-len"] } scale-info = { workspace = true, features = ["derive"] } sp-core = { workspace = true } +sp-io = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } @@ -44,6 +46,7 @@ std = [ "pallet-curator/std", "pallet-evm/std", "pallet-timestamp/std", + "pallet-balances/std", "precompile-utils/std", "sp-core/std", "sp-runtime/std", diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index 892e103550..ce634002cd 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -13,6 +13,11 @@ use sp_std::marker::PhantomData; use pallet_collab_ai_common::CandidateStatus; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + pub struct CuratorPrecompile(PhantomData); #[precompile_utils::precompile] diff --git a/parachain/precompiles/collab-ai/curator/src/mock.rs b/parachain/precompiles/collab-ai/curator/src/mock.rs new file mode 100644 index 0000000000..c0688b648a --- /dev/null +++ b/parachain/precompiles/collab-ai/curator/src/mock.rs @@ -0,0 +1,168 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate::*; +use frame_support::{ + construct_runtime, parameter_types, + traits::{ConstU128, ConstU16, ConstU32, ConstU64, Everything}, +}; +use pallet_evm::{EnsureAddressNever, EnsureAddressRoot}; +use precompile_utils::precompile_set::{AddressU64, PrecompileAt, PrecompileSetBuilder}; +use sp_core::{H160, H256}; +use sp_runtime::{ + traits::{BlakeTwo256, IdentityLookup}, + AccountId32, BuildStorage, +}; + +pub type Balance = u128; +pub type AccountId = AccountId32; + +// Configure a mock runtime to test the pallet. +construct_runtime!( + pub enum Test { + System: frame_system, + Balances: pallet_balances, + Evm: pallet_evm, + Curator: pallet_curator, + Timestamp: pallet_timestamp, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MinimumCuratorDeposit: Balance = 10; +} + +impl frame_system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Block = frame_system::mocking::MockBlock; // Add this + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = ConstU16<31>; + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl pallet_balances::Config for Test { + type MaxLocks = (); + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ConstU128<1>; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = (); + type ReserveIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = (); + type MaxFreezes = (); + type RuntimeHoldReason = (); +} + +// Implement pallet_curator config trait for mock runtime. +impl pallet_curator::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type MinimumCuratorDeposit = MinimumCuratorDeposit; + type CuratorJudgeOrigin = frame_system::EnsureRoot; +} + +// Setup EVM configuration +parameter_types! { + pub WeightPerGas: u64 = 1; +} + +impl pallet_evm::Config for Test { + type FeeCalculator = (); + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + type CallOrigin = EnsureAddressRoot; + type WithdrawOrigin = EnsureAddressNever; + type AddressMapping = TruncatedAddressMapping; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type Runner = pallet_evm::runner::stack::Runner; + type PrecompilesType = CuratorMockPrecompile; + type PrecompilesValue = PrecompilesValue; + type ChainId = (); + type Timestamp = Timestamp; + type OnChargeTransaction = (); + type BlockGasLimit = (); + type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; + type FindAuthor = (); + type OnCreate = (); + type WeightInfo = (); + type GasLimitPovSizeRatio = ConstU64<4>; +} + +impl pallet_timestamp::Config for Test { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<1>; + type WeightInfo = (); +} + +pub struct TruncatedAddressMapping; +impl pallet_evm::AddressMapping for TruncatedAddressMapping { + fn into_account_id(address: H160) -> AccountId { + let mut data = [0u8; 32]; + data[0..20].copy_from_slice(&address[..]); + AccountId::from(Into::<[u8; 32]>::into(data)) + } +} + +pub type CuratorMockPrecompile = + PrecompileSetBuilder, CuratorPrecompile>,)>; + +parameter_types! { + pub PrecompilesValue: CuratorMockPrecompile = CuratorMockPrecompile::new(); +} + +// Helper function to initialize the test environment. +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + // Add initial balances for the involved accounts + pallet_balances::GenesisConfig:: { + balances: vec![ + (TruncatedAddressMapping::into_account_id(H160::from_low_u64_be(1000)), 1_000_000), + (TruncatedAddressMapping::into_account_id(H160::from_low_u64_be(1001)), 1_000_000), + (TruncatedAddressMapping::into_account_id(H160::from_low_u64_be(1002)), 1_000_000), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} diff --git a/parachain/precompiles/collab-ai/curator/src/tests.rs b/parachain/precompiles/collab-ai/curator/src/tests.rs new file mode 100644 index 0000000000..3d40e7eb8b --- /dev/null +++ b/parachain/precompiles/collab-ai/curator/src/tests.rs @@ -0,0 +1,196 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate::mock::RuntimeEvent; +use crate::mock::*; +use pallet_evm::AddressMapping; +// use pallet_evm::AddressMapping::GuardianPrecompileCall; +use crate::CuratorPrecompileCall; +use pallet_curator::Event; +use precompile_utils::testing::PrecompileTesterExt; +use sp_core::{H160, H256, U256}; + +pub type PCall = CuratorPrecompileCall; + +#[test] +fn test_regist_curator() { + new_test_ext().execute_with(|| { + let curator: H160 = H160::from_low_u64_be(1001); + let info_hash: H256 = H256::from([1u8; 32]); + + PrecompilesValue::get() + .prepare_test( + curator, + H160::from_low_u64_be(1000), + PCall::::regist_curator { info_hash }, + ) + .expect_no_logs() + .execute_returns(()); + + System::assert_last_event(RuntimeEvent::Curator(Event::CuratorRegisted { + curator: TruncatedAddressMapping::into_account_id(curator), + curator_index: 0, + info_hash, + })); + }); +} + +#[test] +fn test_update_curator() { + new_test_ext().execute_with(|| { + let curator: H160 = H160::from_low_u64_be(1001); + let info_hash: H256 = H256::from([1u8; 32]); + let updated_hash: H256 = H256::from([2u8; 32]); + + PrecompilesValue::get() + .prepare_test( + curator, + H160::from_low_u64_be(1000), + PCall::::regist_curator { info_hash }, + ) + .execute_returns(()); + + PrecompilesValue::get() + .prepare_test( + curator, + H160::from_low_u64_be(1000), + PCall::::update_curator { info_hash: updated_hash }, + ) + .execute_returns(()); + + System::assert_last_event(RuntimeEvent::Curator(Event::CuratorUpdated { + curator: TruncatedAddressMapping::into_account_id(curator), + curator_index: 0, + info_hash: updated_hash, + })); + }); +} + +#[test] +fn test_clean_curator() { + new_test_ext().execute_with(|| { + let curator: H160 = H160::from_low_u64_be(1001); + let info_hash: H256 = H256::from([1u8; 32]); + + PrecompilesValue::get() + .prepare_test( + curator, + H160::from_low_u64_be(1000), + PCall::::regist_curator { info_hash }, + ) + .execute_returns(()); + + PrecompilesValue::get() + .prepare_test(curator, H160::from_low_u64_be(1000), PCall::::clean_curator {}) + .execute_returns(()); + + System::assert_last_event(RuntimeEvent::Curator(Event::CuratorCleaned { + curator: TruncatedAddressMapping::into_account_id(curator), + curator_index: 0, + })); + }); +} + +#[test] +fn test_public_curator_count() { + new_test_ext().execute_with(|| { + // Initially, there should be no curators + PrecompilesValue::get() + .prepare_test( + H160::from_low_u64_be(1001), + H160::from_low_u64_be(1000), + PCall::::public_curator_count {}, + ) + .execute_returns(U256::from(0)); // Provide expected result + + // Register a curator to increase the count + let info_hash: H256 = H256::from([1u8; 32]); + PrecompilesValue::get() + .prepare_test( + H160::from_low_u64_be(1001), + H160::from_low_u64_be(1000), + PCall::::regist_curator { info_hash }, + ) + .execute_returns(()); + + // Check the curator count again, should be 1 + PrecompilesValue::get() + .prepare_test( + H160::from_low_u64_be(1001), + H160::from_low_u64_be(1000), + PCall::::public_curator_count {}, + ) + .execute_returns(U256::from(1)); + }); +} + +#[test] +fn test_public_curator_to_index() { + new_test_ext().execute_with(|| { + let curator: H160 = H160::from_low_u64_be(1001); + let info_hash: H256 = H256::from([1u8; 32]); + + // Register the curator + PrecompilesValue::get() + .prepare_test( + curator, + H160::from_low_u64_be(1000), + PCall::::regist_curator { info_hash }, + ) + .execute_returns(()); + + // Query the curator's index + let curator_account = TruncatedAddressMapping::into_account_id(curator); + let curator_account: [u8; 32] = curator_account.into(); + let curator_account: H256 = curator_account.into(); + PrecompilesValue::get() + .prepare_test( + curator, + H160::from_low_u64_be(1000), + PCall::::public_curator_to_index { curator: curator_account }, + ) + .execute_returns((true, U256::from(0))); + }); +} + +#[test] +fn test_curator_index_to_info() { + new_test_ext().execute_with(|| { + let curator: H160 = H160::from_low_u64_be(1001); + let info_hash: H256 = H256::from([1u8; 32]); + + // Register the guardian + PrecompilesValue::get() + .prepare_test( + curator, + H160::from_low_u64_be(1000), + PCall::::regist_curator { info_hash }, + ) + .execute_returns(()); + + // Query the curator info by index + let curator_account = TruncatedAddressMapping::into_account_id(curator); + let curator_account: [u8; 32] = curator_account.into(); + let curator_account: H256 = curator_account.into(); + PrecompilesValue::get() + .prepare_test( + curator, + H160::from_low_u64_be(1000), + PCall::::curator_index_to_info { index: 0.into() }, + ) + .execute_returns((true, info_hash, U256::from(1), curator_account, 0u8)); + }); +} From 601cde9ab2fe3dac57efb82375f057672a792a1b Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 23 Oct 2024 14:23:47 +0800 Subject: [PATCH 092/215] chore: fix lock file --- parachain/Cargo.lock | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index d87f2e4d2d..b3a93c4fa6 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -7208,9 +7208,12 @@ version = "0.1.0" dependencies = [ "frame-support", "frame-system", + "pallet-balances", "pallet-collab-ai-common", "parity-scale-codec", "scale-info", + "sp-core", + "sp-io", "sp-runtime", "sp-std", ] @@ -7473,6 +7476,7 @@ dependencies = [ "frame-system", "hex-literal", "libsecp256k1", + "pallet-balances", "pallet-collab-ai-common", "pallet-curator", "pallet-evm", @@ -7483,6 +7487,7 @@ dependencies = [ "serde", "sha3", "sp-core", + "sp-io", "sp-runtime", "sp-std", ] From b07ba232a7e8c9051c6b97c8284cd71a13125c41 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 23 Oct 2024 18:09:12 +0800 Subject: [PATCH 093/215] chore: add extra method - curator --- parachain/pallets/collab-ai/common/src/lib.rs | 99 +++++++++++++++---- .../collab-ai/pool-proposal/src/lib.rs | 15 ++- .../precompiles/collab-ai/curator/Curator.sol | 20 +++- .../precompiles/collab-ai/curator/src/lib.rs | 54 ++++++++++ .../collab-ai/curator/src/tests.rs | 38 +++++++ .../collab-ai/pool-proposal/PoolProposal.sol | 33 ++++--- 6 files changed, 220 insertions(+), 39 deletions(-) diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index 37e42667b9..379cd2b279 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -20,14 +20,14 @@ use scale_info::TypeInfo; use sp_core::{RuntimeDebug, H256}; use sp_std::marker::PhantomData; -use frame_support::pallet_prelude::EnsureOrigin; -use frame_system::RawOrigin; +use frame_support::{pallet_prelude::EnsureOrigin, traits::EitherOfDiverse}; +use frame_system::{EnsureRoot, RawOrigin}; pub type InfoHash = H256; pub type CuratorIndex = u128; pub type GuardianIndex = u128; pub type PoolProposalIndex = u128; -pub type InvestingPoolIndex = u128; +pub type InvestingPoolIndex = PoolProposalIndex; #[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] pub struct PoolSetting { @@ -98,6 +98,10 @@ pub trait CuratorQuery { fn is_verified_curator(account: AccountId) -> bool; } +pub trait ProposerQuery { + fn is_proposer(account: AccountId, proposal_index: PoolProposalIndex) -> bool; +} + pub struct EnsureSignedAndCurator(PhantomData<(AccountId, EC)>); impl< O: Into, O>> + From>, @@ -128,24 +132,74 @@ where } } +pub struct EnsureSignedAndVerifiedCurator(PhantomData<(AccountId, EC)>); +impl< + O: Into, O>> + From>, + AccountId: Decode + Clone, + EC, + > EnsureOrigin for EnsureSignedAndCurator +where + EC: CuratorQuery, +{ + type Success = AccountId; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + RawOrigin::Signed(who) => { + if EC::is_verified_curator(who.clone()) { + Ok(who) + } else { + Err(O::from(RawOrigin::Signed(who))) + } + }, + r => Err(O::from(r)), + }) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + // No promised successful_origin + Err(()) + } +} + +pub type EnsureRootOrVerifiedCurator> = + EitherOfDiverse, EnsureSignedAndVerifiedCurator>; + pub const INVESTING_POOL_INDEX_SHIFTER: u128 = 1_000_000_000_000_000; -pub const INVESTING_POOL_START_MONTH_SHIFTER: u128 = 1_000; -pub const INVESTING_POOL_END_MONTH_SHIFTER: u128 = 1; - -// pub struct InvestingPoolAssetIdGenerator(PhantomData); -// impl> InvestingPoolAssetIdGenerator { -// /// Create a series of new asset id based on pool index and reward epoch -// /// Return None if impossible to generate. e.g. overflow -// pub fn get_pool_token(pool_index: InvestingPoolIndex, epoch: u128) -> Option> { -// let pool_index_prefix = pool_index.checked_mul(INVESTING_POOL_INDEX_SHIFTER)?; - -// let mut vec: Vec = Vec::new(); -// for n in 0..(epoch + 1) { -// // vec.push(pool_index_prefix + ) -// } -// None -// } -// } +pub const INVESTING_POOL_START_EPOCH_SHIFTER: u128 = 1_000; +pub const INVESTING_POOL_END_EPOCH_SHIFTER: u128 = 1; + +pub struct InvestingPoolAssetIdGenerator(PhantomData); +impl> InvestingPoolAssetIdGenerator { + /// Create a series of new asset id based on pool index and reward epoch + /// Return None if impossible to generate. e.g. overflow + pub fn get_all_pool_token(pool_index: InvestingPoolIndex, epoch: u128) -> Option> { + let pool_index_prefix = pool_index.checked_mul(INVESTING_POOL_INDEX_SHIFTER)?; + + let mut vec: Vec = Vec::new(); + let end_epoch_suffix = epoch.checked_mul(INVESTING_POOL_END_EPOCH_SHIFTER)?; + for n in 0..(epoch + 1) { + let infix = n.checked_mul(INVESTING_POOL_START_EPOCH_SHIFTER)?; + vec.push(pool_index_prefix.checked_add(infix)?.checked_add(end_epoch_suffix)?.into()); + } + Some(vec) + } + + pub fn get_epoch_token(pool_index: InvestingPoolIndex, epoch: u128) -> Option { + let pool_index_prefix = pool_index.checked_mul(INVESTING_POOL_INDEX_SHIFTER)?; + + let end_epoch_suffix = epoch.checked_mul(INVESTING_POOL_END_EPOCH_SHIFTER)?; + let infix = 1u128.checked_mul(INVESTING_POOL_START_EPOCH_SHIFTER)?; + Some(pool_index_prefix.checked_add(infix)?.checked_add(end_epoch_suffix)?.into()) + } + + pub fn get_debt_token(pool_index: InvestingPoolIndex, epoch: u128) -> Option { + let pool_index_prefix = pool_index.checked_mul(INVESTING_POOL_INDEX_SHIFTER)?; + + let end_epoch_suffix = epoch.checked_mul(INVESTING_POOL_END_EPOCH_SHIFTER)?; + Some(pool_index_prefix.checked_add(end_epoch_suffix)?.into()) + } +} /// Some sort of check on the account is from some group. pub trait GuardianQuery { @@ -158,3 +212,8 @@ pub trait GuardianQuery { /// Get vote fn get_vote(voter: AccountId, guardian: AccountId) -> Option; } + +/// Inject investment into pool +pub trait InvestmentInjector { + fn inject_investment(pool_id: InvestingPoolIndex, investments: Vec<(AccountId, Balance)>); +} diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 41cb699ed5..305bc80f15 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -245,6 +245,8 @@ pub mod pallet { fn on_initialize(_n: BlockNumberFor) -> Weight { // Check proposal expire by order + // curator must be verified by this time + // check epoch number not too large so asset id will not overflow // Mature the pool by proposal if qualified, refund/transfer all money based on investing pool logic Weight::zero() @@ -256,7 +258,7 @@ pub mod pallet { /// Curator propose a investing pool /// /// max_pool_size: At most this amount of raised money curator/investing pool willing to take - /// proposal_last_time: How does the proposal lasts for voting/preinvesting. + /// proposal_last_time: How long does the proposal lasts for voting/preinvesting. /// All ProposalStatusFlags must be satisfied after this period passed, which is also /// the approximate date when pool begins. /// pool_last_time: How long does the investing pool last if passed @@ -609,4 +611,15 @@ pub mod pallet { Ok(T::RuntimeOrigin::from(RawOrigin::Signed(sync_account_id))) } } + + /// Some sort of check on the origin is from proposer. + impl ProposerQuery for Pallet { + fn is_proposer(account: AccountId, proposal_index: PoolProposalIndex) -> bool { + if let Some(info) = Self::pool_proposal(proposal_index) { + info.proposer == account + } else { + false + } + } + } } diff --git a/parachain/precompiles/collab-ai/curator/Curator.sol b/parachain/precompiles/collab-ai/curator/Curator.sol index 8d74cbe300..af4e1a0084 100644 --- a/parachain/precompiles/collab-ai/curator/Curator.sol +++ b/parachain/precompiles/collab-ai/curator/Curator.sol @@ -9,6 +9,15 @@ interface ICurator { Banned } + /// @dev A structure for curator query result + struct CuratorQueryResult { + bool exist; + bytes32 info_hash; + uint256 update_block; + bytes32 curator; + CandidateStatus status; + } + /// @notice Regist info hash of curator and reserve funds, only work if not already registed /// @param info_hash: H256 hash of info image /// @custom:selector 0x8ead391c @@ -39,7 +48,14 @@ interface ICurator { /// @notice Curator index to curator info, bool represents if such info exists /// @param index: Curator index - /// @custom:selector 0x916d9a0d - /// curatorIndexToInfo(address) + /// @custom:selector 0x74cded61 + /// curatorIndexToInfo(uint256) function curatorIndexToInfo(uint256 index) external view returns (bool exist, bytes32 info_hash, uint256 update_block, bytes32 curator, CandidateStatus status); + + /// @notice Curator index to curator info, bool represents if such info exists + /// @param index: Curator index + /// @custom:selector 0xa84c8d74 + /// batchCuratorIndexToInfo(uint256[]) + function batchCuratorIndexToInfo(uint256[] calldata index) external view returns (CuratorQueryResult[] memory result); + } \ No newline at end of file diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index ce634002cd..ad509b04b7 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -132,4 +132,58 @@ where )) } } + + #[precompile::public("batchCuratorIndexToInfo(uint256[])")] + #[precompile::view] + fn batch_curator_index_to_info( + handle: &mut impl PrecompileHandle, + index: Vec, + ) -> EvmResult> { + // Storage item: CuratorIndex u128: + // Twox64Concat(8) + CuratorIndex(16) + InfoHash(32) + BlockNumber(4) + T::AccountId(32) + CandidateStatus(1) + handle.record_db_read::(93 * index.len())?; + + let result = Vec::::new(); + + let result = index + .into_iter() + .enumerate() + .map(|i| { + let i: u128 = i.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + if let Some((info_hash, update_block, curator, status)) = + pallet_curator::Pallet::::curator_index_to_info(i) + { + let update_block: U256 = update_block.into(); + + let curator: [u8; 32] = curator.into(); + let curator: H256 = curator.into(); + + let status = + Self::candidate_status_to_u8(status).in_field("candidateStatus")?; + + CuratorQueryResult { exist: true, info_hash, update_block, curator, status } + } else { + CuratorQueryResult { + exist: false, + info_hash: Default::default(), + update_block: Default::default(), + curator: Default::default(), + status: Default::default(), + } + } + }) + .collect(); + Ok(result) + } +} + +#[derive(Default, Debug, solidity::Codec)] +struct CuratorQueryResult { + exist: bool, + info_hash: H256, + update_block: U256, + curator: H256, + status: u8, } diff --git a/parachain/precompiles/collab-ai/curator/src/tests.rs b/parachain/precompiles/collab-ai/curator/src/tests.rs index 3d40e7eb8b..b44a15a754 100644 --- a/parachain/precompiles/collab-ai/curator/src/tests.rs +++ b/parachain/precompiles/collab-ai/curator/src/tests.rs @@ -194,3 +194,41 @@ fn test_curator_index_to_info() { .execute_returns((true, info_hash, U256::from(1), curator_account, 0u8)); }); } + +#[test] +fn test_curator_index_to_info() { + new_test_ext().execute_with(|| { + let curator: H160 = H160::from_low_u64_be(1001); + let info_hash: H256 = H256::from([1u8; 32]); + + // Register the guardian + PrecompilesValue::get() + .prepare_test( + curator, + H160::from_low_u64_be(1000), + PCall::::regist_curator { info_hash }, + ) + .execute_returns(()); + + // Query the curator info by index + let curator_account = TruncatedAddressMapping::into_account_id(curator); + let curator_account: [u8; 32] = curator_account.into(); + let curator_account: H256 = curator_account.into(); + + let tmp_index_vec = Vec::::new(); + tmp_index_vec.push(0.into()); + PrecompilesValue::get() + .prepare_test( + curator, + H160::from_low_u64_be(1000), + PCall::::batch_curator_index_to_info { index: tmp_index_vec }, + ) + .execute_returns(vec![crate::CuratorQueryResult { + exist: true, + info_hash, + update_block: U256::from(1), + curator: curator_account, + status: 0u8, + }]); + }); +} diff --git a/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol b/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol index ce745648c2..df1fed979a 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol +++ b/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol @@ -27,21 +27,22 @@ interface IPoolProposal { uint256 expiryTime; } + /// @dev A strcuture for proposal details struct PoolProposalInfo { - // Proposer/Curator - bytes32 proposer; - // Hash of pool info like legal files etc. - bytes32 infoHash; - // The maximum investing amount that the pool can handle - uint256 maxPoolSize; - // If proposal passed, when the investing pool will start, Block number - uint256 poolStartTime; - // If proposal passed, when the investing pool will end, Block number - uint256 poolEndTime; - // estimated APR, but in percentage form - // i.e. 100 => 100% - uint256 estimatedEpochReward; - // Proposal status flags + // Proposer/Curator + bytes32 proposer; + // Hash of pool info like legal files etc. + bytes32 infoHash; + // The maximum investing amount that the pool can handle + uint256 maxPoolSize; + // If proposal passed, when the investing pool will start, Block number + uint256 poolStartTime; + // If proposal passed, when the investing pool will end, Block number + uint256 poolEndTime; + // estimated APR, but in percentage form + // i.e. 100 => 100% + uint256 estimatedEpochReward; + // Proposal status flags // /// Whether the pool proposal passing the committee/democracy voting. // /// A valid pool must passing committee/public's audit procedure regarding legal files and other pool parameters. // const PUBLIC_VOTE_PASSED = 0b0000_0001; @@ -60,8 +61,8 @@ interface IPoolProposal { // /// Whether the proposal expired yet // /// Has nothing to do with pool. Only related to proposal expired time // const PROPOSAL_EXPIRED = 0b0000_1000; - uint8 proposalStatusFlags; -} + uint8 proposalStatusFlags; + } /// @notice Propose an investing pool proposal /// @param max_pool_size: At most this amount of raised money curator/investing pool willing to take From d442c3dfaebcdad91b1a9dacd5c09ff46b71af94 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 10:58:02 +0800 Subject: [PATCH 094/215] chore: fix --- parachain/pallets/collab-ai/common/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index 379cd2b279..5f7f7b4006 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -137,7 +137,7 @@ impl< O: Into, O>> + From>, AccountId: Decode + Clone, EC, - > EnsureOrigin for EnsureSignedAndCurator + > EnsureOrigin for EnsureSignedAndVerifiedCurator where EC: CuratorQuery, { From 0aff376bb0aa24faff18e19b7688c9136c367657 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 11:11:35 +0800 Subject: [PATCH 095/215] chore: fix --- parachain/pallets/collab-ai/common/src/lib.rs | 2 +- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index 5f7f7b4006..b7947b53a3 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -162,7 +162,7 @@ where } } -pub type EnsureRootOrVerifiedCurator> = +pub type EnsureRootOrVerifiedCurator = EitherOfDiverse, EnsureSignedAndVerifiedCurator>; pub const INVESTING_POOL_INDEX_SHIFTER: u128 = 1_000_000_000_000_000; diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 305bc80f15..db8d66b25d 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -614,7 +614,7 @@ pub mod pallet { /// Some sort of check on the origin is from proposer. impl ProposerQuery for Pallet { - fn is_proposer(account: AccountId, proposal_index: PoolProposalIndex) -> bool { + fn is_proposer(account: T::AccountId, proposal_index: PoolProposalIndex) -> bool { if let Some(info) = Self::pool_proposal(proposal_index) { info.proposer == account } else { From 893a42e9fec826e1988e50ab8fb9eaed89ee3321 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 11:34:56 +0800 Subject: [PATCH 096/215] chore: fix --- parachain/precompiles/collab-ai/curator/src/lib.rs | 10 ++++------ parachain/precompiles/collab-ai/curator/src/tests.rs | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index ad509b04b7..6db10ba43b 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -147,7 +147,6 @@ where let result = index .into_iter() - .enumerate() .map(|i| { let i: u128 = i.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) @@ -160,18 +159,17 @@ where let curator: [u8; 32] = curator.into(); let curator: H256 = curator.into(); - let status = - Self::candidate_status_to_u8(status).in_field("candidateStatus")?; + let status: u8 = Self::candidate_status_to_u8(status).unwrap_or_default(); - CuratorQueryResult { exist: true, info_hash, update_block, curator, status } + Ok(CuratorQueryResult { exist: true, info_hash, update_block, curator, status }) } else { - CuratorQueryResult { + Ok(CuratorQueryResult { exist: false, info_hash: Default::default(), update_block: Default::default(), curator: Default::default(), status: Default::default(), - } + }) } }) .collect(); diff --git a/parachain/precompiles/collab-ai/curator/src/tests.rs b/parachain/precompiles/collab-ai/curator/src/tests.rs index b44a15a754..41b81cedd2 100644 --- a/parachain/precompiles/collab-ai/curator/src/tests.rs +++ b/parachain/precompiles/collab-ai/curator/src/tests.rs @@ -196,7 +196,7 @@ fn test_curator_index_to_info() { } #[test] -fn test_curator_index_to_info() { +fn test_batch_curator_index_to_info() { new_test_ext().execute_with(|| { let curator: H160 = H160::from_low_u64_be(1001); let info_hash: H256 = H256::from([1u8; 32]); @@ -215,7 +215,7 @@ fn test_curator_index_to_info() { let curator_account: [u8; 32] = curator_account.into(); let curator_account: H256 = curator_account.into(); - let tmp_index_vec = Vec::::new(); + let mut tmp_index_vec = Vec::::new(); tmp_index_vec.push(0.into()); PrecompilesValue::get() .prepare_test( From 762a36acd591f7388948d966c5ba55c357cad920 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 11:45:39 +0800 Subject: [PATCH 097/215] chore: fix --- parachain/precompiles/collab-ai/curator/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index 6db10ba43b..d9a46498a5 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -146,7 +146,7 @@ where let result = Vec::::new(); let result = index - .into_iter() + .iter() .map(|i| { let i: u128 = i.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) From 0d5d8369aa56d4196b44bd8d47ddc8ccde9b1cac Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 13:41:32 +0800 Subject: [PATCH 098/215] chore: fix --- parachain/precompiles/collab-ai/curator/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index d9a46498a5..c59d8613c4 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -148,7 +148,7 @@ where let result = index .iter() .map(|i| { - let i: u128 = i.try_into().map_err(|_| { + let i: u128 = i.clone().try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; if let Some((info_hash, update_block, curator, status)) = @@ -161,15 +161,15 @@ where let status: u8 = Self::candidate_status_to_u8(status).unwrap_or_default(); - Ok(CuratorQueryResult { exist: true, info_hash, update_block, curator, status }) + CuratorQueryResult { exist: true, info_hash, update_block, curator, status } } else { - Ok(CuratorQueryResult { + CuratorQueryResult { exist: false, info_hash: Default::default(), update_block: Default::default(), curator: Default::default(), status: Default::default(), - }) + } } }) .collect(); From edf39aaadddf273df96fa74332abc998fa52b484 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 13:42:12 +0800 Subject: [PATCH 099/215] chore: fix --- parachain/precompiles/collab-ai/curator/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index c59d8613c4..d5404e599a 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -143,8 +143,6 @@ where // Twox64Concat(8) + CuratorIndex(16) + InfoHash(32) + BlockNumber(4) + T::AccountId(32) + CandidateStatus(1) handle.record_db_read::(93 * index.len())?; - let result = Vec::::new(); - let result = index .iter() .map(|i| { From c3d577920e3c1e1b192ce060643102cc3e5f784f Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 13:43:24 +0800 Subject: [PATCH 100/215] chore: fix --- parachain/precompiles/collab-ai/curator/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index d5404e599a..e3f6d9c7fd 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -146,11 +146,11 @@ where let result = index .iter() .map(|i| { - let i: u128 = i.clone().try_into().map_err(|_| { + let tmp_index: u128 = *i.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; if let Some((info_hash, update_block, curator, status)) = - pallet_curator::Pallet::::curator_index_to_info(i) + pallet_curator::Pallet::::curator_index_to_info(tmp_index) { let update_block: U256 = update_block.into(); From 9a09d70260501e3b10afed7dd33105b7dd83c0d0 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 13:59:48 +0800 Subject: [PATCH 101/215] chore: fix --- .../precompiles/collab-ai/curator/src/lib.rs | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index e3f6d9c7fd..e1c2ea459c 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -145,22 +145,31 @@ where let result = index .iter() - .map(|i| { - let tmp_index: u128 = *i.try_into().map_err(|_| { - Into::::into(RevertReason::value_is_too_large("index type")) - })?; - if let Some((info_hash, update_block, curator, status)) = - pallet_curator::Pallet::::curator_index_to_info(tmp_index) - { - let update_block: U256 = update_block.into(); - - let curator: [u8; 32] = curator.into(); - let curator: H256 = curator.into(); - - let status: u8 = Self::candidate_status_to_u8(status).unwrap_or_default(); - - CuratorQueryResult { exist: true, info_hash, update_block, curator, status } + .map(|&i| { + if let Ok(tmp_index) = i.try_into() { + if let Some((info_hash, update_block, curator, status)) = + pallet_curator::Pallet::::curator_index_to_info(tmp_index) + { + let update_block: U256 = update_block.into(); + + let curator: [u8; 32] = curator.into(); + let curator: H256 = curator.into(); + + let status: u8 = Self::candidate_status_to_u8(status).unwrap_or_default(); + + CuratorQueryResult { exist: true, info_hash, update_block, curator, status } + } else { + CuratorQueryResult { + exist: false, + info_hash: Default::default(), + update_block: Default::default(), + curator: Default::default(), + status: Default::default(), + } + } } else { + // If value_is_too_large error from U256 to u128 + // return default CuratorQueryResult { exist: false, info_hash: Default::default(), From 6ef8256dcbf7852d4187d87b90eacdcb58d4fc2d Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 14:01:18 +0800 Subject: [PATCH 102/215] chore: fix --- .../collab-ai/investing-pool/Cargo.toml | 65 ++ .../collab-ai/investing-pool/src/lib.rs | 669 ++++++++++++++++++ .../collab-ai/investing-pool/src/mock.rs | 191 +++++ .../collab-ai/investing-pool/src/test.rs | 580 +++++++++++++++ .../precompiles/collab-ai/curator/src/lib.rs | 2 +- 5 files changed, 1506 insertions(+), 1 deletion(-) create mode 100644 parachain/pallets/collab-ai/investing-pool/Cargo.toml create mode 100644 parachain/pallets/collab-ai/investing-pool/src/lib.rs create mode 100644 parachain/pallets/collab-ai/investing-pool/src/mock.rs create mode 100644 parachain/pallets/collab-ai/investing-pool/src/test.rs diff --git a/parachain/pallets/collab-ai/investing-pool/Cargo.toml b/parachain/pallets/collab-ai/investing-pool/Cargo.toml new file mode 100644 index 0000000000..15bb21e2b2 --- /dev/null +++ b/parachain/pallets/collab-ai/investing-pool/Cargo.toml @@ -0,0 +1,65 @@ +[package] +name = 'pallet-investing-pool' +description = 'pallet for creating and interacting with investing pool' +version = '0.1.0' +license = 'GPL-3.0' +authors.workspace = true +homepage.workspace = true +repository.workspace = true +edition.workspace = true +publish = false + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { workspace = true } +scale-info = { workspace = true } +serde = { workspace = true } + +frame-benchmarking = { workspace = true, optional = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-std = { workspace = true } +sp-runtime = { workspace = true, features = ["serde"] } +pallet-assets = { workspace = true } + +pallet-collab-ai-common = { workspace = true } + +[dev-dependencies] +sp-core = { workspace = true } +sp-io = { workspace = true } +pallet-balances = { workspace = true } + +[features] +default = ["std"] +std = [ + "codec/std", + "serde/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", + "pallet-balances/std", + "pallet-assets/std", + "pallet-collab-ai-common/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "pallet-collab-ai-common/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", +] \ No newline at end of file diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs new file mode 100644 index 0000000000..c67c3d172c --- /dev/null +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -0,0 +1,669 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +#![cfg_attr(not(feature = "std"), no_std)] +use frame_support::{ + pallet_prelude::*, + traits::{ + tokens::{ + fungible::{Inspect as FInspect, Mutate as FMutate}, + fungibles::{Inspect as FsInspect, Mutate as FsMutate, Create as FsCreate}, + Preservation, + }, + StorageVersion, + }, + PalletId, +}; +use frame_system::pallet_prelude::*; +pub use pallet::*; +use sp_runtime::{ + traits::{ + AccountIdConversion, AtLeast32BitUnsigned, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, + One, + }, + ArithmeticError, Perquintill, Saturating, +}; +use sp_std::{collections::vec_deque::VecDeque, fmt::Debug, prelude::*}; + +use pallet_collab_ai_common::*; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] +pub struct CANWeightedInfo { + // For a single position or + // Synthetic overall average effective_time weighted by staked amount + pub effective_time: BlockNumber, + // Staked amount + pub amount: Balance, + // This is recorded for not allowing weight calculation when time < some of history effective + // time + pub last_add_time: BlockNumber, +} + +impl CANWeightedInfo +where + Balance: AtLeast32BitUnsigned + Copy, + BlockNumber: AtLeast32BitUnsigned + Copy, +{ + // Mixing a new added investing position, replace the checkpoint with Synthetic new one + // Notice: The logic will be wrong if weight calculated time is before any single added + // effective_time + // None means TypeIncompatible Or Overflow Or Division Zero + fn add(&mut self, effective_time: BlockNumber, amount: Balance) -> Option<()> { + // If last_add_time always > effective_time, only new added effective time can effect + // last_add_time + self.last_add_time = self.last_add_time.max(effective_time); + + // We try force all types into u128, then convert it back + let e: u128 = effective_time.try_into().ok()?; + let s: u128 = amount.try_into().ok()?; + + let oe: u128 = self.effective_time.try_into().ok()?; + let os: u128 = self.amount.try_into().ok()?; + + let new_amount: u128 = os.checked_add(s)?; + // (oe * os + e * s) / (os + s) + let new_effective_time: u128 = + (oe.checked_mul(os)?.checked_add(e.checked_mul(s)?)?).checked_div(new_amount)?; + self.amount = new_amount.try_into().ok()?; + self.effective_time = new_effective_time.try_into().ok()?; + Some(()) + } + + // Claim/Update weighted info based on target until-block and return the consumed weight + // None means TypeIncompatible Or Overflow + fn claim(&mut self, n: BlockNumber) -> Option { + // Claim time before last_add_time is not allowed, since weight can not be calculated + let weight = self.weight(n)?; + self.effective_time = n; + + Some(weight) + } + + // consume corresponding weight, change effective time without changing staked amount, return + // the changed effective time + // This function is mostly used for Synthetic checkpoint change + // None means TypeIncompatible Or Division Zero + fn claim_based_on_weight(&mut self, weight: u128) -> Option { + let oe: u128 = self.effective_time.try_into().ok()?; + let os: u128 = self.amount.try_into().ok()?; + + let delta_e: u128 = weight.checked_div(os)?; + let new_effective_time: BlockNumber = (oe + delta_e).try_into().ok()?; + self.effective_time = new_effective_time; + + Some(new_effective_time) + } + + // Withdraw investing amount and return the amount after withdrawal + // None means underflow + fn withdraw(&mut self, v: Balance) -> Option { + self.amount = self.amount.checked_sub(&v)?; + + Some(self.amount) + } + + // You should never use n < any single effective_time + // it only works for n > all effective_time + // None means TypeIncompatible Or Overflow + fn weight(&self, n: BlockNumber) -> Option { + // Estimate weight before last_add_time can be biased so not allowed + if self.last_add_time > n { + return None; + } + + let e: u128 = n.checked_sub(&self.effective_time)?.try_into().ok()?; + let s: u128 = self.amount.try_into().ok()?; + e.checked_mul(s) + } + + // Force estimate weight regardless + // None means TypeIncompatible Or Overflow + fn weight_force(&self, n: BlockNumber) -> Option { + let e: u128 = n.checked_sub(&self.effective_time)?.try_into().ok()?; + let s: u128 = self.amount.try_into().ok()?; + e.checked_mul(s) + } +} + +#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] +pub struct PoolSetting { + // The start time of investing pool + pub start_time: BlockNumber, + // How many epoch will investing pool last, n > 0, valid epoch index :[0..n) + pub epoch: u128, + // How many blocks each epoch consist + pub epoch_range: BlockNumber, + // Max staked amount of pool + pub pool_cap: Balance, + // Curator + pub admin: AccountId, +} + +impl PoolSetting +where + Balance: AtLeast32BitUnsigned + Copy, + BlockNumber: AtLeast32BitUnsigned + Copy, +{ + // None means TypeIncompatible Or Overflow + fn end_time(&self) -> Option { + let er: u128 = self.epoch_range.try_into().ok()?; + let st: u128 = self.start_time.try_into().ok()?; + let result = st.checked_add(er.checked_mul(self.epoch)?)?; + result.try_into().ok() + } +} + +#[frame_support::pallet] +pub mod pallet { + use frame_support::transactional; + + use super::*; + + pub type BalanceOf = + <::Fungibles as FsInspect<::AccountId>>::Balance; + + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + pallet_assets::Config { + /// Overarching event type + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// Pool proposal pallet origin used to start an investing pool + type PoolProposalPalletOrigin: EnsureOrigin; + + /// Origin used to update epoch reward for investing pool + type RewardUpdateOrigin: EnsureOrigin; + + /// Origin used to administer the investing pool + type InvestingPoolAdminOrigin: EnsureOrigin; + + type Fungibles: FsMutate + FsCreate; + + type Fungible: FMutate;???? + + /// The beneficiary PalletId, used fro deriving its sovereign account to hold assets of reward + #[pallet::constant] + type StableTokenBeneficiaryId: Get; + + /// The beneficiary PalletId, used for deriving its sovereign AccountId for providing native + /// token reward + #[pallet::constant] + type CANBeneficiaryId: Get; + } + + // Setting of investing pools + #[pallet::storage] + #[pallet::getter(fn investing_pool_setting)] + pub type InvestingPoolSetting = StorageMap< + _, + Twox64Concat, + InvestingPoolIndex, + PoolSetting, BalanceOf>, + OptionQuery, + >; + + // investing pools' stable token reward waiting claiming + // Pool id, epcoh index => unclaimed total reward + #[pallet::storage] + #[pallet::getter(fn stable_investing_pool_epoch_reward)] + pub type StableInvestingPoolEpochReward = + StorageDoubleMap<_, Twox64Concat, InvestingPoolIndex, Twox64Concat, u128, BalanceOf, OptionQuery>; + + // Checkpoint of overall investing condition synthetic by tracking all investing pools + // For CAN token reward distribution + #[pallet::storage] + #[pallet::getter(fn native_checkpoint)] + pub type CANCheckpoint = + StorageValue<_, CANWeightedInfo, BalanceOf>, OptionQuery>; + + // Asset id of AIUSD + #[pallet::storage] + #[pallet::getter(fn aiusd_asset_id)] + pub type AIUSDAssetId = + StorageValue<_, >::AssetId, OptionQuery>; + + // Asset id of CAN + #[pallet::storage] + #[pallet::getter(fn aiusd_asset_id)] + pub type CANAssetId = + StorageValue<_, >::AssetId, OptionQuery>; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + InvestingPoolCreated { + pool_id: InvestingPoolIndex, + admin: T::AccountId + start_time: BlockNumberFor, + epoch: u128, + epoch_range: BlockNumberFor, + setup_time: BlockNumberFor, + pool_cap: BalanceOf, + }, + /// New metadata has been set for a investing pool. + MetadataSet { + pool_id: InvestingPoolIndex, + name: Vec, + description: Vec, + }, + /// Metadata has been removed for a investing pool. + MetadataRemoved { + pool_id: InvestingPoolIndex, + }, + /// Reward updated + RewardUpdated { + pool_id: InvestingPoolIndex, + epoch: u128, + amount: BalanceOf, + }, + PendingInvestingSolved { + who: T::AccountId, + pool_id: InvestingPoolIndex, + effective_time: BlockNumberFor, + amount: BalanceOf, + }, + Staked { + who: T::AccountId, + pool_id: InvestingPoolIndex, + target_effective_time: BlockNumberFor, + amount: BalanceOf, + }, + NativeRewardClaimed { + who: T::AccountId, + until_time: BlockNumberFor, + reward_amount: BalanceOf, + }, + StableRewardClaimed { + who: T::AccountId, + pool_id: InvestingPoolIndex, + until_time: BlockNumberFor, + reward_amount: BalanceOf, + }, + Withdraw { + who: T::AccountId, + pool_id: InvestingPoolIndex, + time: BlockNumberFor, + amount: BalanceOf, + }, + AIUSDRegisted { + asset_id: >::AssetId, + }, + } + + #[pallet::error] + pub enum Error { + RewardAlreadyExisted, + PoolAlreadyStarted, + PoolAlreadyEnded, + PoolAlreadyExisted, + PoolCapLimit, + PoolNotEnded, + PoolNotExisted, + PoolNotStarted, + BadMetadata, + CannotClaimFuture, + EpochAlreadyEnded, + EpochNotExist, + NoAssetId, + TypeIncompatibleOrArithmeticError, + } + + #[pallet::hooks] + impl Hooks> for Pallet { + /// Weight: see `begin_block` + fn on_initialize(n: BlockNumberFor) -> Weight { + Self::begin_block(n) + } + } + + #[pallet::call] + impl Pallet { + /// Create a investing pool + /// Admin should be guardian multisig + #[pallet::call_index(0)] + #[pallet::weight({1000})] + #[transactional] + pub fn create_investing_pool( + origin: OriginFor, + pool_id: InvestingPoolIndex, + setting: PoolSetting, BalanceOf>, + admin: T::AccountId, + ) -> DispatchResult { + T::PoolProposalPalletOrigin::ensure_origin(origin)?; + + // Create all asset token categories + let asset_id_vec = InvestingPoolAssetIdGenerator::get_all_pool_token(pool_id, setting.epoch).ok_or(ArithmeticError::Overflow)? + for i in asset_id_vec.iter() { + ::AccountId>>::create(i, mutisig, true, One::one()); + } + + ensure!( + frame_system::Pallet::::block_number() <= setting.start_time, + Error::::PoolAlreadyStarted + ); + ensure!( + !InvestingPoolSetting::::contains_key(&pool_id), + Error::::PoolAlreadyExisted + ); + >::insert(pool_id.clone(), setting.clone()); + Self::deposit_event(Event::InvestingPoolCreated { + pool_id, + admin: setting.admin, + start_time: setting.start_time, + epoch: setting.epoch, + epoch_range: setting.epoch_range, + setup_time: setting.setup_time, + pool_cap: setting.pool_cap, + }); + Ok(()) + } + + /// Update a reward for an investing pool of specific epoch + /// Each epoch can be only updated once + #[pallet::call_index(1)] + #[pallet::weight({1000})] + #[transactional] + pub fn update_reward( + origin: OriginFor, + pool_id: InvestingPoolIndex, + epoch: u128, + reward: BalanceOf, + ) -> DispatchResult { + T::RewardUpdateOrigin::ensure_origin(origin)?; + + let setting = + >::get(pool_id.clone()).ok_or(Error::::PoolNotExisted)?; + ensure!(0 < epoch && epoch <= setting.epoch, Error::::EpochNotExist); + + >::try_mutate( + &pool_id, + &epoch, + |maybe_reward| -> DispatchResult { + ensure!(maybe_reward.is_none(), Error::::RewardAlreadyExisted); + + *maybe_reward = Some(reward); + Self::deposit_event(Event::::RewardUpdated { + pool_id: pool_id.clone(), + epoch, + amount: reward, + }); + Ok(()) + }, + )?; + + Ok(()) + } + + // Claim CAN and stable token reward, destroy/create corresponding pool token category + #[pallet::call_index(2)] + #[pallet::weight({1000})] + #[transactional] + pub fn claim( + origin: OriginFor, + pool_id: InvestingPoolIndex, + epoch: u128, + amount: AssetBalanceOf, + ) -> DispatchResult { + let source = ensure_signed(origin)?; + + Self::do_can_claim(source, asset_id, amount)?; + Self::do_stable_claim(source, asset_id, amount) + } + + // Registing AIUSD asset id + #[pallet::call_index(3)] + #[pallet::weight({1000})] + #[transactional] + pub fn regist_aiusd( + origin: OriginFor, + asset_id: >::AssetId, + ) -> DispatchResult { + T::InvestingPoolCommitteeOrigin::ensure_origin(origin)?; + >::put(asset_id.clone()); + Self::deposit_event(Event::::AIUSDRegisted { asset_id }); + Ok(()) + } + + // Registing CAN asset id + #[pallet::call_index(3)] + #[pallet::weight({1000})] + #[transactional] + pub fn regist_can( + origin: OriginFor, + asset_id: >::AssetId, + ) -> DispatchResult { + T::InvestingPoolCommitteeOrigin::ensure_origin(origin)?; + >::put(asset_id.clone()); + Self::deposit_event(Event::::AIUSDRegisted { asset_id }); + Ok(()) + } + } + + impl Pallet { + // Epoch starting from 1 + // return setting.epoch if time >= pool end_time + fn get_epoch_index( + pool_id: InvestingPoolIndex, + time: BlockNumberFor, + ) -> Result { + let setting = + >::get(pool_id).ok_or(Error::::PoolNotExisted)?; + // If start_time > time, means epoch 0 + let index_bn = time + .saturating_sub(setting.start_time) + .checked_div(&setting.epoch_range) + .ok_or(ArithmeticError::DivisionByZero)?; + let index: u128 = + index_bn.try_into().or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + if index >= setting.epoch { + return Ok(setting.epoch); + } else { + return index.checked_add(1u128).ok_or(ArithmeticError::Overflow); + } + } + + // return pool ending time if epoch > setting.epoch + // Epoch starting from 1 + fn get_epoch_begin_time( + pool_id: InvestingPoolIndex, + epoch: u128, + ) -> Result, sp_runtime::DispatchError> { + let setting = + >::get(pool_id).ok_or(Error::::PoolNotExisted)?; + // If epoch larger than setting + if epoch > setting.epoch { + return Ok(setting + .end_time() + .ok_or(Error::::TypeIncompatibleOrArithmeticError)?); + } + let epoch_bn: BlockNumberFor = + epoch.checked_sub(1u128).ok_or(ArithmeticError::Overflow)?.try_into().or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + let result = setting + .start_time + .checked_add( + &setting.epoch_range.checked_mul(&epoch_bn).ok_or(ArithmeticError::Overflow)?, + ) + .ok_or(ArithmeticError::Overflow)?; + return Ok(result) + } + + // return pool ending time if epoch >= setting.epoch + // Epoch starting from 1 + fn get_epoch_end_time( + pool_id: InvestingPoolIndex, + epoch: u128, + ) -> Result, sp_runtime::DispatchError> { + let setting = + >::get(pool_id).ok_or(Error::::PoolNotExisted)?; + // If epoch larger than setting + if epoch >= setting.epoch { + return Ok(setting + .end_time() + .ok_or(Error::::TypeIncompatibleOrArithmeticError)?); + } + let epoch_bn: BlockNumberFor = + epoch.try_into().or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + let result = setting + .start_time + .checked_add( + &setting.epoch_range.checked_mul(&epoch_bn).ok_or(ArithmeticError::Overflow)?, + ) + .ok_or(ArithmeticError::Overflow)?; + return Ok(result) + } + + // For can_investing + fn do_can_add( + who: T::AccountId, + amount: BalanceOf, + effective_time: BlockNumberFor, + ) -> DispatchResult { + >::try_mutate(|maybe_checkpoint| { + if let Some(checkpoint) = maybe_checkpoint { + checkpoint + .add(effective_time, amount) + .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; + } else { + *maybe_checkpoint = + Some(CANWeightedInfo { effective_time, amount, last_add_time: effective_time }); + } + Ok::<(), DispatchError>(()) + })?; + } + + // No category token effected + fn do_can_claim(who: T::AccountId, until_time: BlockNumberFor) -> DispatchResult { + let beneficiary_account: T::AccountId = Self::can_token_beneficiary_account(); + let current_block = frame_system::Pallet::::block_number(); + ensure!(until_time <= current_block, Error::::CannotClaimFuture); + let can_asset_id = >::get().ok_or(Error::::NoAssetId)?; + // BalanceOf + let reward_pool = T::Fungible::balance(&beneficiary_account); + + if let Some(mut ncp) = >::get() { + if let Some(mut user_ncp) = >::get(who.clone()) { + // get weight and update stake info + let user_claimed_weight = user_ncp + .claim(until_time) + .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; + let proportion = Perquintill::from_rational( + user_claimed_weight, + ncp.weight_force(until_time) + .ok_or(Error::::TypeIncompatibleOrArithmeticError)?, + ); + // Do not care what new Synthetic effective_time of investing pool + let _ = ncp + .claim_based_on_weight(user_claimed_weight) + .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; + + let reward_pool_u128: u128 = reward_pool + .try_into() + .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + let distributed_reward_u128: u128 = proportion * reward_pool_u128; + let distributed_reward: BalanceOf = distributed_reward_u128 + .try_into() + .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + T::Fungible::transfer( + &beneficiary_account, + &who, + distributed_reward, + Preservation::Expendable, + )?; + // Adjust checkpoint + >::put(ncp); + >::insert(&who, user_ncp); + Self::deposit_event(Event::::NativeRewardClaimed { + who, + until_time, + reward_amount: distributed_reward, + }); + } + } + Ok(()) + } + + // Category token effected + fn do_stable_claim( + who: T::AccountId, + asset_id: InvestingPoolIndex, + amount: BlockNumberFor, + ) -> DispatchResult { + let current_block = frame_system::Pallet::::block_number(); + ensure!(until_time <= current_block, Error::::CannotClaimFuture); + // BalanceOf + let reward_pool = >::get(pool_id.clone()); + let aiusd_asset_id = >::get().ok_or(Error::::NoAssetId)?; + ???? + + Ok(()) + } + + pub fn can_token_beneficiary_account() -> T::AccountId { + T::CANBeneficiaryId::get().into_account_truncating() + } + + pub fn stable_token_beneficiary_account() -> T::AccountId { + T::StableTokenBeneficiaryId::get().into_account_truncating() + } + + // Mint category token to user, record can token checkpoint accordingly + pub fn inject_investment(pool_id: InvestingPoolIndex, investments: Vec<(T::AccountId, BalanceOf)>) { + let setting = + >::get(pool_id).ok_or(Error::::PoolNotExisted)?; + let effective_time = Self::get_epoch_start_time(pool_id, One::one()); + + let debt_asset_id = InvestingPoolAssetIdGenerator::get_debt_token(pool_id, setting.epoch).ok_or(ArithmeticError::Overflow)?; + let initial_epoch_asset_id = InvestingPoolAssetIdGenerator::get_epoch_token(pool_id, setting.epoch).ok_or(ArithmeticError::Overflow)?; + for i in investments.iter() { + // Mint certification token to user + let _ = T::Fungibles::mint_into( + debt_asset_id, + &i.0, + i.1, + )?; + + let _ = T::Fungibles::mint_into( + initial_epoch_asset_id, + &i.0, + i.1, + )?; + + // Add CAN token checkpoint + Self::do_can_add(i.0, i.1, effective_time) + + } + } + } +} + +impl InvestmentInjector> for Pallet { + fn inject_investment(pool_id: InvestingPoolIndex, investments: Vec<(T::AccountId, BalanceOf)>) { + Self::inject_investment(pool_id, investments); + } +} \ No newline at end of file diff --git a/parachain/pallets/collab-ai/investing-pool/src/mock.rs b/parachain/pallets/collab-ai/investing-pool/src/mock.rs new file mode 100644 index 0000000000..d7ec1d8481 --- /dev/null +++ b/parachain/pallets/collab-ai/investing-pool/src/mock.rs @@ -0,0 +1,191 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate::{self as pallet_investing_pool}; +use frame_support::{ + assert_ok, derive_impl, ord_parameter_types, parameter_types, + traits::{AsEnsureOriginWithArg, ConstU32, ConstU64}, + PalletId, +}; +use frame_system::EnsureRoot; +use pallet_investing_pool::PoolSetting; +use sp_core::{ConstU16, H256}; +use sp_runtime::{ + traits::{AccountIdConversion, BlakeTwo256, IdentityLookup}, + BuildStorage, +}; + +type AccountId = u64; +type Block = frame_system::mocking::MockBlock; + +type Balance = u64; +/// Pool id +pub type PoolId = u128; +// Configure a mock runtime to test the pallet. +frame_support::construct_runtime!( + pub enum Test + { + System: frame_system, + Balances: pallet_balances, + Assets: pallet_assets, + InvestingPool: pallet_investing_pool, + } +); + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = ConstU16<42>; + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +ord_parameter_types! { + pub const One: u64 = 1; +} + +impl pallet_balances::Config for Test { + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ConstU64<1>; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = ConstU32<100>; + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxHolds = (); + type MaxFreezes = (); + type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); +} + +impl pallet_assets::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = u32; + type AssetIdParameter = u32; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type AssetDeposit = ConstU64<1>; + type AssetAccountDeposit = ConstU64<10>; + type MetadataDepositBase = ConstU64<1>; + type MetadataDepositPerByte = ConstU64<1>; + type ApprovalDeposit = ConstU64<1>; + type StringLimit = ConstU32<50>; + type Freezer = (); + type WeightInfo = (); + type CallbackHandle = (); + type Extra = (); + type RemoveItemsLimit = ConstU32<5>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + +parameter_types! { + pub const InvestingPoolId: PalletId = PalletId(*b"can/stpl"); + pub const HavlingMintId: PalletId = PalletId(*b"can/hlvm"); +} + +impl pallet_investing_pool::Config for Test { + type RuntimeEvent = RuntimeEvent; + type InvestingPoolCommitteeOrigin = EnsureRoot; + type PoolId = PoolId; + type Fungibles = Assets; + type Fungible = Balances; + type StableTokenBeneficiaryId = InvestingPoolId; + type CANBeneficiaryId = HavlingMintId; + type PoolStringLimit = ConstU32<100>; +} + +pub const ENDOWED_BALANCE: u64 = 100_000_000; +pub const USER_A: AccountId = 0x2; +pub const USER_B: AccountId = 0x3; +pub const USER_C: AccountId = 0x4; + +pub fn new_test_ext() -> sp_io::TestExternalities { + let native_token_pool: u64 = HavlingMintId::get().into_account_truncating(); + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + pallet_balances::GenesisConfig:: { + balances: vec![ + (native_token_pool, ENDOWED_BALANCE), + (USER_A, ENDOWED_BALANCE), + (USER_B, ENDOWED_BALANCE), + (USER_C, ENDOWED_BALANCE), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + frame_system::Pallet::::set_block_number(1); + + // Regist AIUSD + // asset_id = 1, admin = USER_A + assert_ok!(Assets::create(RuntimeOrigin::signed(USER_A), 1u32, USER_A, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(USER_A), 1u32, USER_A, ENDOWED_BALANCE)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(USER_A), 1u32, USER_B, ENDOWED_BALANCE)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(USER_A), 1u32, USER_C, ENDOWED_BALANCE)); + // Setup stable investing pallet + assert_ok!(InvestingPool::regist_aiusd(RuntimeOrigin::root(), 1u32)); + assert_eq!(InvestingPool::aiusd_asset_id(), Some(1u32)); + // Create stable investing pool + let pool_setup: PoolSetting = PoolSetting { + start_time: 100u64, + epoch: 10u128, + epoch_range: 100u64, + setup_time: 200u64, + pool_cap: 50_000_000u64, + }; + assert_ok!(InvestingPool::create_investing_pool(RuntimeOrigin::root(), 1u128, pool_setup)); + }); + ext +} + +// Checks events against the latest. A contiguous set of events must be provided. They must +// include the most recent event, but do not have to include every past event. +pub fn assert_events(mut expected: Vec) { + let mut actual: Vec = + frame_system::Pallet::::events().iter().map(|e| e.event.clone()).collect(); + + expected.reverse(); + + for evt in expected { + let next = actual.pop().expect("event expected"); + assert_eq!(next, evt, "Events don't match"); + } +} \ No newline at end of file diff --git a/parachain/pallets/collab-ai/investing-pool/src/test.rs b/parachain/pallets/collab-ai/investing-pool/src/test.rs new file mode 100644 index 0000000000..447aa80271 --- /dev/null +++ b/parachain/pallets/collab-ai/investing-pool/src/test.rs @@ -0,0 +1,580 @@ +use super::{ + mock::{ + assert_events, new_test_ext, Assets, Balances, HavlingMintId, RuntimeEvent, RuntimeOrigin, + InvestingPool, InvestingPoolId, System, Test, ENDOWED_BALANCE, USER_A, USER_B, USER_C, + }, + *, +}; +use frame_support::{assert_noop, assert_ok}; + +fn next_block() { + System::set_block_number(System::block_number() + 1); + InvestingPool::begin_block(System::block_number()); +} + +fn fast_forward_to(n: u64) { + while System::block_number() < n { + next_block(); + } +} + +#[test] +fn can_not_create_pool_already_started_or_existed() { + new_test_ext().execute_with(|| { + // Create stable investing pool + let pool_setup: PoolSetting = PoolSetting { + start_time: 100u64, + epoch: 10u128, + epoch_range: 100u64, + setup_time: 200u64, + pool_cap: 1_000_000_000u64, + }; + assert_noop!( + InvestingPool::create_investing_pool(RuntimeOrigin::root(), 1u128, pool_setup.clone()), + Error::::PoolAlreadyExisted + ); + // Transfer and check result + fast_forward_to(101); + assert_noop!( + InvestingPool::create_investing_pool(RuntimeOrigin::root(), 2u128, pool_setup.clone()), + Error::::PoolAlreadyStarted + ); + // Create another pool is fine + let another_pool_setup: PoolSetting = PoolSetting { + start_time: 150u64, + epoch: 10u128, + epoch_range: 100u64, + setup_time: 200u64, + pool_cap: 1_000_000_000u64, + }; + assert_ok!(InvestingPool::create_investing_pool( + RuntimeOrigin::root(), + 2u128, + another_pool_setup + )); + assert_events(vec![RuntimeEvent::InvestingPool(Event::InvestingPoolCreated { + pool_id: 2u128, + start_time: 150u64, + epoch: 10u128, + epoch_range: 100u64, + setup_time: 200u64, + pool_cap: 1_000_000_000u64, + })]); + }) +} + +// TODO: update_metadata test +// Currently metadata does nothing but description + +#[test] +fn update_reward_successful_and_failed() { + new_test_ext().execute_with(|| { + let stable_token_pool: u64 = InvestingPoolId::get().into_account_truncating(); + + // update epoch 0 reward with amount of 2000 + assert_ok!(InvestingPool::update_reward(RuntimeOrigin::root(), 1u128, 0u128, 2000u64)); + assert_events(vec![RuntimeEvent::InvestingPool(Event::RewardUpdated { + pool_id: 1u128, + epoch: 0u128, + amount: 2000u64, + })]); + // Investing pool reward storage efffective + assert_eq!(InvestingPool::stable_investing_pool_reward(1u128), 2000u64); + assert_eq!(InvestingPool::stable_investing_pool_epoch_reward(1u128, 0u128), Some(2000u64)); + assert_eq!(InvestingPool::stable_investing_pool_epoch_reward(1u128, 1u128), None); + // Investing pool balance effective + assert_eq!(Assets::balance(1u32, stable_token_pool), 2000u64); + + // Can not update epoch reward twice + assert_noop!( + InvestingPool::update_reward(RuntimeOrigin::root(), 1u128, 0u128, 1000u64), + Error::::RewardAlreadyExisted + ); + + // Pool started at 100, epoch range = 100, epoch = 10 + // So Blocknumber 301 => Epoch 2 started/Epoch 1 ended + System::set_block_number(301u64); + // Can not update epoch already ended + assert_noop!( + InvestingPool::update_reward(RuntimeOrigin::root(), 1u128, 1u128, 1000u64), + Error::::EpochAlreadyEnded + ); + + // Epoch reward can not be updated to non-existing pool + assert_noop!( + InvestingPool::update_reward(RuntimeOrigin::root(), 9999u128, 1u128, 1000u64), + Error::::PoolNotExisted + ); + // Epoch reward can not be updated to epoch index not existing + assert_noop!( + InvestingPool::update_reward(RuntimeOrigin::root(), 1u128, 11u128, 1000u64), + Error::::EpochNotExist + ); + + // Epoch reward update for "last epoch" (pool end time's next epoch) always success + // Pool epoch = 10 + System::set_block_number(9999999u64); + assert_ok!(InvestingPool::update_reward(RuntimeOrigin::root(), 1u128, 10u128, 2000u64)); + assert_events(vec![RuntimeEvent::InvestingPool(Event::RewardUpdated { + pool_id: 1u128, + epoch: 10u128, + amount: 2000u64, + })]); + + // Can not update reward if no AIUSD registed + System::set_block_number(301u64); + >::kill(); + assert_noop!( + InvestingPool::update_reward(RuntimeOrigin::root(), 1u128, 5u128, 2000u64), + Error::::NoAssetId + ); + }) +} + +#[test] +fn stake_successful_and_failed() { + new_test_ext().execute_with(|| { + let stable_token_pool: u64 = InvestingPoolId::get().into_account_truncating(); + + // Can not stake non-exist pool + assert_noop!( + InvestingPool::stake(RuntimeOrigin::signed(USER_A), 2u128, 2000u64), + Error::::PoolNotExisted + ); + + // Can not stake non-started pool + assert_noop!( + InvestingPool::stake(RuntimeOrigin::signed(USER_A), 1u128, 2000u64), + Error::::PoolNotStarted + ); + + // Can not stake ended pool + System::set_block_number(9999999u64); + assert_noop!( + InvestingPool::stake(RuntimeOrigin::signed(USER_A), 1u128, 2000u64), + Error::::PoolAlreadyEnded + ); + + // Success, check user/global native checkpoint storage + // check pending set up storage + System::set_block_number(301u64); + // Can not stake oversized + assert_noop!( + InvestingPool::stake(RuntimeOrigin::signed(USER_A), 1u128, 50_000_001u64), + Error::::PoolCapLimit + ); + + assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_A), 1u128, 2000u64)); + assert_events(vec![RuntimeEvent::InvestingPool(Event::Staked { + who: USER_A, + pool_id: 1u128, + target_effective_time: 600u64, + amount: 2000u64, + })]); + assert_eq!(Assets::balance(1u32, USER_A), ENDOWED_BALANCE - 2000u64); + assert_eq!(Assets::balance(1u32, stable_token_pool), 2000u64); + let global_investing_info = InvestingPool::native_checkpoint().unwrap(); + assert_eq!( + global_investing_info, + CANWeightedInfo { effective_time: 301u64, amount: 2000u64, last_add_time: 301u64 } + ); + let user_a_investing_info = InvestingPool::user_native_checkpoint(USER_A).unwrap(); + assert_eq!( + user_a_investing_info, + CANWeightedInfo { effective_time: 301u64, amount: 2000u64, last_add_time: 301u64 } + ); + let pending_set_up = InvestingPool::pending_setup(); + assert_eq!(pending_set_up.len(), 1); + let pending_set_up_element = pending_set_up.get(0).unwrap(); + // Pool set up time = 200 + // So user enter at 301 need to wait till 600 to make it effective and receiving Stable + // investing reward + assert_eq!( + *pending_set_up_element, + CANWeightedInfoWithOwner { + who: USER_A, + pool_id: 1u128, + investing_info: CANWeightedInfo { + effective_time: 600u64, + amount: 2000u64, + last_add_time: 600u64 + } + } + ); + + // Second user B stake + System::set_block_number(399u64); + fast_forward_to(411u64); + assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_B), 1u128, 1000u64)); + assert_events(vec![RuntimeEvent::InvestingPool(Event::Staked { + who: USER_B, + pool_id: 1u128, + target_effective_time: 700u64, + amount: 1000u64, + })]); + + assert_eq!(Assets::balance(1u32, USER_B), ENDOWED_BALANCE - 1000u64); + assert_eq!(Assets::balance(1u32, stable_token_pool), 2000u64 + 1000u64); + let global_investing_info = InvestingPool::native_checkpoint().unwrap(); + // Synthetic (301, 2000), (411, 1000) = (337.6666, 3000) + assert_eq!( + global_investing_info, + CANWeightedInfo { effective_time: 337u64, amount: 3000u64, last_add_time: 411u64 } + ); + // user a unchanged + let user_a_investing_info = InvestingPool::user_native_checkpoint(USER_A).unwrap(); + assert_eq!( + user_a_investing_info, + CANWeightedInfo { effective_time: 301u64, amount: 2000u64, last_add_time: 301u64 } + ); + // user b + let user_b_investing_info = InvestingPool::user_native_checkpoint(USER_B).unwrap(); + assert_eq!( + user_b_investing_info, + CANWeightedInfo { effective_time: 411u64, amount: 1000u64, last_add_time: 411u64 } + ); + // Pending set up storage change + let pending_set_up = InvestingPool::pending_setup(); + assert_eq!(pending_set_up.len(), 2); + // pending set up is ordered by effective time, so user_b's request is at index 1 while + // user_a is at index 0 + let pending_set_up_element = pending_set_up.get(1).unwrap(); + // Pool set up time = 200 + // So user enter at 411 need to wait till 700 to make it effective and receiving Stable + // investing reward + assert_eq!( + *pending_set_up_element, + CANWeightedInfoWithOwner { + who: USER_B, + pool_id: 1u128, + investing_info: CANWeightedInfo { + effective_time: 700u64, + amount: 1000u64, + last_add_time: 700u64 + } + } + ); + + // Can not stake if no AIUSD registed + >::kill(); + assert_noop!( + InvestingPool::stake(RuntimeOrigin::signed(USER_C), 1u128, 3000u64), + Error::::NoAssetId + ); + assert_ok!(InvestingPool::regist_aiusd(RuntimeOrigin::root(), 1u32)); + + // Can not stake oversized + assert_noop!( + InvestingPool::stake( + RuntimeOrigin::signed(USER_A), + 1u128, + 50_000_001u64 - 2000u64 - 1000u64 + ), + Error::::PoolCapLimit + ); + assert_ok!(InvestingPool::stake( + RuntimeOrigin::signed(USER_A), + 1u128, + 50_000_000u64 - 2000u64 - 1000u64 + )); + }) +} + +#[test] +fn solve_pending_stake_and_hook_works() { + new_test_ext().execute_with(|| { + // Success, check user/global native checkpoint storage + // check pending set up storage + System::set_block_number(301u64); + assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_A), 1u128, 2000u64)); + // Pool set up time = 200 + // So user enter at 301 need to wait till 600 to make it effective and receiving Stable + System::set_block_number(590u64); + // Try trigger hook + fast_forward_to(610u64); + assert_events(vec![RuntimeEvent::InvestingPool(Event::PendingInvestingSolved { + who: USER_A, + pool_id: 1u128, + effective_time: 600u64, + amount: 2000u64, + })]); + // No more pending + let pending_set_up = InvestingPool::pending_setup(); + assert_eq!(pending_set_up.len(), 0); + // Check stable investing checkpoint + let global_investing_info = InvestingPool::stable_investing_pool_checkpoint(1u128).unwrap(); + assert_eq!( + global_investing_info, + CANWeightedInfo { effective_time: 600u64, amount: 2000u64, last_add_time: 600u64 } + ); + let user_a_investing_info = + InvestingPool::user_stable_investing_pool_checkpoint(USER_A, 1u128).unwrap(); + assert_eq!( + user_a_investing_info, + CANWeightedInfo { effective_time: 600u64, amount: 2000u64, last_add_time: 600u64 } + ); + + // Second user B stake + assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_B), 1u128, 1000u64)); + // Any one can trigger manual, but right now no effect + let pending_set_up = InvestingPool::pending_setup(); + assert_eq!(pending_set_up.len(), 1); + assert_ok!(InvestingPool::solve_pending_stake(RuntimeOrigin::signed(USER_C))); + let pending_set_up = InvestingPool::pending_setup(); + assert_eq!(pending_set_up.len(), 1); + + // Pool set up time = 200, current block = 610 + // So user enter at 301 need to wait till 900 to make it effective and receiving Stable + // set block number without triggering hook + System::set_block_number(910u64); + // Global investing no changed + let global_investing_info = InvestingPool::stable_investing_pool_checkpoint(1u128).unwrap(); + assert_eq!( + global_investing_info, + CANWeightedInfo { effective_time: 600u64, amount: 2000u64, last_add_time: 600u64 } + ); + // User b investing is still none + assert!(InvestingPool::user_stable_investing_pool_checkpoint(USER_B, 1u128).is_none()); + + // Any one can trigger manual + // But effective time will be the time when triggered, which is 910 + assert_ok!(InvestingPool::solve_pending_stake(RuntimeOrigin::signed(USER_C))); + assert_events(vec![RuntimeEvent::InvestingPool(Event::PendingInvestingSolved { + who: USER_B, + pool_id: 1u128, + effective_time: 910u64, + amount: 1000u64, + })]); + let pending_set_up = InvestingPool::pending_setup(); + // Pending solved + assert_eq!(pending_set_up.len(), 0); + // User B stable investing checkpoint updated + let user_b_investing_info = + InvestingPool::user_stable_investing_pool_checkpoint(USER_B, 1u128).unwrap(); + // The effective time is delayed accordingly + assert_eq!( + user_b_investing_info, + CANWeightedInfo { effective_time: 910u64, amount: 1000u64, last_add_time: 910u64 } + ); + // Global investing check + // (600, 2000), (910, 1000) -> (703.333, 3000) + let global_investing_info = InvestingPool::stable_investing_pool_checkpoint(1u128).unwrap(); + assert_eq!( + global_investing_info, + CANWeightedInfo { effective_time: 703u64, amount: 3000u64, last_add_time: 910u64 } + ); + }) +} + +#[test] +fn claim_native_successful_and_failed() { + new_test_ext().execute_with(|| { + let native_token_pool: u64 = HavlingMintId::get().into_account_truncating(); + + System::set_block_number(301u64); + assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_A), 1u128, 2000u64)); + System::set_block_number(401u64); + assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_A), 1u128, 2000u64)); + assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_B), 1u128, 1000u64)); + // at block 401: + // User_A : (351, 4000) with last_add_time = 401 + // User_B : (401, 1000) with last_add_time = 401 + // Global : (361 ,5000) with last_add_time = 401 + + // Just for convenience, suppose there are already 100 times ENDOWED_BALANCE native token + // reward + assert_eq!( + Balances::set_balance(&native_token_pool, 100 * ENDOWED_BALANCE), + 100 * ENDOWED_BALANCE + ); + + System::set_block_number(601u64); + // User_a try claim before 401, failed since it is not allowed to claim before last_add_time + // TODO:: TypeIncompatibleOrArithmeticError is not specific enough + assert_noop!( + InvestingPool::claim_native(RuntimeOrigin::signed(USER_A), 400u64), + Error::::TypeIncompatibleOrArithmeticError + ); + + // A normal claim until 501 at time 601 + assert_ok!(InvestingPool::claim_native(RuntimeOrigin::signed(USER_A), 501u64)); + // total weight = 5000 * (501 - 361) = 700,000 + // claim weight = 4000 * (501 - 351) = 600,000 + // reward = 100 * ENDOWED_BALANCE * claim weight / total weight + // 8571428571.428 + assert_events(vec![ + RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: native_token_pool, + to: USER_A, + amount: 8_571_428_571u64, + }), + RuntimeEvent::InvestingPool(Event::NativeRewardClaimed { + who: USER_A, + until_time: 501u64, + reward_amount: 8_571_428_571u64, + }), + ]); + // After claim + // User_A : (501, 4000) with last_add_time = 401 + // User_B : (401, 1000) with last_add_time = 401 + // Global : weight before = (501 - 361) * 5000 = 700,000 + // Global : weight after = 700,000 - 600,000 = 100,000 + // Global : synthetic (501 - (100,000 / 5000), 5000) = (481, 5000) + // check user a + let user_a_investing_info = InvestingPool::user_native_checkpoint(USER_A).unwrap(); + assert_eq!( + user_a_investing_info, + CANWeightedInfo { effective_time: 501u64, amount: 4000u64, last_add_time: 401u64 } + ); + // check global + let global_investing_info = InvestingPool::native_checkpoint().unwrap(); + assert_eq!( + global_investing_info, + CANWeightedInfo { effective_time: 481u64, amount: 5000u64, last_add_time: 401u64 } + ); + + // Can not claim future + assert_noop!( + InvestingPool::claim_native(RuntimeOrigin::signed(USER_A), 602u64), + Error::::CannotClaimFuture + ); + }) +} + +#[test] +fn claim_stable_successful_and_failed() { + new_test_ext().execute_with(|| { + let stable_token_pool: u64 = InvestingPoolId::get().into_account_truncating(); + + System::set_block_number(301u64); + // effective time = 600 + assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_A), 1u128, 2000u64)); + System::set_block_number(401u64); + // effective time = 700 + assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_A), 1u128, 2000u64)); + assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_B), 1u128, 1000u64)); + + // triggering pending by hook + System::set_block_number(599u64); + fast_forward_to(610u64); + + // Notice: Can not update reward if EpochAlreadyEnded + // Pool: start_time: 100u64, + // epoch: 10u128, + // epoch_range: 100u64, + // setup_time: 200u64, + // 610 => current epoch 5 + let stable_token_pool_balance = Assets::balance(1u32, stable_token_pool); + assert_ok!(InvestingPool::update_reward(RuntimeOrigin::root(), 1u128, 5u128, 2000u64)); + assert_eq!(Assets::balance(1u32, stable_token_pool), stable_token_pool_balance + 2000u64); + + // Only user a yet, claiming from 600 to 650 + // Stable investing + // User_A : (600, 2000) with last_add_time = 600 + // Global : (600 ,2000) with last_add_time = 600 + // claimed weight: 100% out of total! + System::set_block_number(699u64); + assert_ok!(InvestingPool::claim_stable(RuntimeOrigin::signed(USER_A), 1u128, 650u64)); + assert_eq!(Assets::balance(1u32, stable_token_pool), stable_token_pool_balance); + assert_events(vec![ + RuntimeEvent::Assets(pallet_assets::Event::Transferred { + asset_id: 1u32, + from: stable_token_pool, + to: USER_A, + amount: 2000u64, + }), + RuntimeEvent::InvestingPool(Event::StableRewardClaimed { + who: USER_A, + pool_id: 1u128, + until_time: 650u64, + reward_amount: 2000u64, + }), + ]); + // Check stable investing checkpoint storage + // check user + let user_a_investing_info = + InvestingPool::user_stable_investing_pool_checkpoint(USER_A, 1u128).unwrap(); + assert_eq!( + user_a_investing_info, + CANWeightedInfo { effective_time: 650u64, amount: 2000u64, last_add_time: 600u64 } + ); + // check global + let global_investing_info = InvestingPool::stable_investing_pool_checkpoint(1u128).unwrap(); + assert_eq!( + global_investing_info, + CANWeightedInfo { effective_time: 650u64, amount: 2000u64, last_add_time: 600u64 } + ); + + fast_forward_to(710u64); + // 710 => current epoch 6 + assert_ok!(InvestingPool::update_reward(RuntimeOrigin::root(), 1u128, 6u128, 4000u64)); + assert_eq!(Assets::balance(1u32, stable_token_pool), stable_token_pool_balance + 4000u64); + System::set_block_number(799u64); + // Stable investing + // User_A : (650, 2000) + (700, 2000) = (675, 4000) with last_add_time = 700 + // User_B : (700, 1000) with last_add_time = 700 + // Global : (650, 2000) + (700, 2000) + (700, 1000) = (680, 5000) with last_add_time = 600 + // Claimed weight: (750 - 675) * 4000 = 300_000 + // Total weight: (750 - 680) * 5000 = 350_000 + // claimed reward = 4000 * 300_000 / 350_000 = 3428.571 + assert_ok!(InvestingPool::claim_stable(RuntimeOrigin::signed(USER_A), 1u128, 750u64)); + + assert_events(vec![ + RuntimeEvent::Assets(pallet_assets::Event::Transferred { + asset_id: 1u32, + from: stable_token_pool, + to: USER_A, + amount: 3429u64, + }), + RuntimeEvent::InvestingPool(Event::StableRewardClaimed { + who: USER_A, + pool_id: 1u128, + until_time: 750u64, + reward_amount: 3429u64, + }), + ]); + + // Check stable investing checkpoint storage + // check user + let user_a_investing_info = + InvestingPool::user_stable_investing_pool_checkpoint(USER_A, 1u128).unwrap(); + assert_eq!( + user_a_investing_info, + CANWeightedInfo { effective_time: 750u64, amount: 4000u64, last_add_time: 700u64 } + ); + // check global + let global_investing_info = InvestingPool::stable_investing_pool_checkpoint(1u128).unwrap(); + assert_eq!( + global_investing_info, + CANWeightedInfo { effective_time: 740u64, amount: 5000u64, last_add_time: 700u64 } + ); + }) +} + +#[test] +fn withdraw_works() { + new_test_ext().execute_with(|| {}) +} + +#[test] +fn regist_aiusd_works() { + new_test_ext().execute_with(|| {}) +} + +#[test] +fn get_epoch_index() { + new_test_ext().execute_with(|| {}) +} + +#[test] +fn get_epoch_begin_time() { + new_test_ext().execute_with(|| {}) +} + +// pending swap storage does get a proper order for multiple pools and can handle multiple pending +// orders double add at same time behavior of (native) stable checkpoint +// if user does not claim reward, and reward update is percentage fair, user is impact +// if user does not claim reward, and reward update is percentage improved in future, user is +// benefited if user does not claim reward, and reward update is percentage downgraded in future, +// user is harmed claim reward behavior of native and stable checkpoint +// withdraw behavior of native and stable checkingpoint \ No newline at end of file diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index e1c2ea459c..c131a48b96 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -146,7 +146,7 @@ where let result = index .iter() .map(|&i| { - if let Ok(tmp_index) = i.try_into() { + if let Ok(tmp_index) = >::try_into(i) { if let Some((info_hash, update_block, curator, status)) = pallet_curator::Pallet::::curator_index_to_info(tmp_index) { From 0b3148cf8c0fb672dc5135670235d659aaa0e729 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 14:20:05 +0800 Subject: [PATCH 103/215] chore: fix --- .../collab-ai/investing-pool/Cargo.toml | 44 +++++++++---------- .../precompiles/collab-ai/curator/Curator.sol | 9 ++-- .../precompiles/collab-ai/curator/src/lib.rs | 20 +++++++-- .../collab-ai/curator/src/tests.rs | 4 +- .../collab-ai/guardian/Guardian.sol | 16 +++++++ .../precompiles/collab-ai/guardian/src/lib.rs | 9 ++++ 6 files changed, 69 insertions(+), 33 deletions(-) diff --git a/parachain/pallets/collab-ai/investing-pool/Cargo.toml b/parachain/pallets/collab-ai/investing-pool/Cargo.toml index 15bb21e2b2..0014785cf4 100644 --- a/parachain/pallets/collab-ai/investing-pool/Cargo.toml +++ b/parachain/pallets/collab-ai/investing-pool/Cargo.toml @@ -23,9 +23,9 @@ serde = { workspace = true } frame-benchmarking = { workspace = true, optional = true } frame-support = { workspace = true } frame-system = { workspace = true } -sp-std = { workspace = true } -sp-runtime = { workspace = true, features = ["serde"] } pallet-assets = { workspace = true } +sp-runtime = { workspace = true, features = ["serde"] } +sp-std = { workspace = true } pallet-collab-ai-common = { workspace = true } @@ -37,29 +37,29 @@ pallet-balances = { workspace = true } [features] default = ["std"] std = [ - "codec/std", - "serde/std", - "frame-benchmarking?/std", - "frame-support/std", - "frame-system/std", - "scale-info/std", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", - "sp-std/std", - "pallet-balances/std", - "pallet-assets/std", + "codec/std", + "serde/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", + "pallet-balances/std", + "pallet-assets/std", "pallet-collab-ai-common/std", ] runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", "pallet-collab-ai-common/runtime-benchmarks", ] try-runtime = [ - "frame-support/try-runtime", - "frame-system/try-runtime", - "sp-runtime/try-runtime", -] \ No newline at end of file + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/parachain/precompiles/collab-ai/curator/Curator.sol b/parachain/precompiles/collab-ai/curator/Curator.sol index af4e1a0084..2f631b0932 100644 --- a/parachain/precompiles/collab-ai/curator/Curator.sol +++ b/parachain/precompiles/collab-ai/curator/Curator.sol @@ -53,9 +53,10 @@ interface ICurator { function curatorIndexToInfo(uint256 index) external view returns (bool exist, bytes32 info_hash, uint256 update_block, bytes32 curator, CandidateStatus status); /// @notice Curator index to curator info, bool represents if such info exists - /// @param index: Curator index - /// @custom:selector 0xa84c8d74 - /// batchCuratorIndexToInfo(uint256[]) - function batchCuratorIndexToInfo(uint256[] calldata index) external view returns (CuratorQueryResult[] memory result); + /// @param start_id: Guardian index start_id, included + /// @param end_id: Guardian index end id, excluded + /// @custom:selector 0xf2e508c7 + /// batchCuratorIndexToInfo(uint256,uint256) + function batchCuratorIndexToInfo(uint256 start_id, uint256 end_id) external view returns (CuratorQueryResult[] memory result); } \ No newline at end of file diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index c131a48b96..65ecaf2c3f 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -133,17 +133,28 @@ where } } - #[precompile::public("batchCuratorIndexToInfo(uint256[])")] + #[precompile::public("batchCuratorIndexToInfo(uint256,uint256)")] #[precompile::view] fn batch_curator_index_to_info( handle: &mut impl PrecompileHandle, - index: Vec, + start_id: U256, + end_id: U256, ) -> EvmResult> { + let start_id: u128 = start_id.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + let end_id: u128 = end_id.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + + let length: u128 = end_id.checked_sub(start_id).ok_or(Into::::into( + RevertReason::value_is_too_large("id overflow"), + ))?; // Storage item: CuratorIndex u128: // Twox64Concat(8) + CuratorIndex(16) + InfoHash(32) + BlockNumber(4) + T::AccountId(32) + CandidateStatus(1) - handle.record_db_read::(93 * index.len())?; + handle.record_db_read::(93 * length)?; - let result = index + let result = vec![start_id..end_id] .iter() .map(|&i| { if let Ok(tmp_index) = >::try_into(i) { @@ -168,6 +179,7 @@ where } } } else { + // Impossible here, but // If value_is_too_large error from U256 to u128 // return default CuratorQueryResult { diff --git a/parachain/precompiles/collab-ai/curator/src/tests.rs b/parachain/precompiles/collab-ai/curator/src/tests.rs index 41b81cedd2..f6f6fa78c9 100644 --- a/parachain/precompiles/collab-ai/curator/src/tests.rs +++ b/parachain/precompiles/collab-ai/curator/src/tests.rs @@ -215,13 +215,11 @@ fn test_batch_curator_index_to_info() { let curator_account: [u8; 32] = curator_account.into(); let curator_account: H256 = curator_account.into(); - let mut tmp_index_vec = Vec::::new(); - tmp_index_vec.push(0.into()); PrecompilesValue::get() .prepare_test( curator, H160::from_low_u64_be(1000), - PCall::::batch_curator_index_to_info { index: tmp_index_vec }, + PCall::::batch_curator_index_to_info { start_id: 0.into(), end_id: 1.into() }, ) .execute_returns(vec![crate::CuratorQueryResult { exist: true, diff --git a/parachain/precompiles/collab-ai/guardian/Guardian.sol b/parachain/precompiles/collab-ai/guardian/Guardian.sol index 4f171a134c..33bc3446fb 100644 --- a/parachain/precompiles/collab-ai/guardian/Guardian.sol +++ b/parachain/precompiles/collab-ai/guardian/Guardian.sol @@ -8,6 +8,15 @@ interface IGuardian { Verified, Banned } + + /// @dev A structure for Guardian query result + struct GuardianQueryResult { + bool exist; + bytes32 info_hash; + uint256 update_block; + bytes32 guardian; + CandidateStatus status; + } /// @dev Defines GuardianVote type enum GuardianVote { @@ -59,6 +68,13 @@ interface IGuardian { /// @custom:selector 0x59c95743 /// guardianIndexToInfo(address) function guardianIndexToInfo(uint256 index) external view returns (bool exist, bytes32 info_hash, uint256 update_block, bytes32 guardian, CandidateStatus status); + + /// @notice Guardian index to guardian info, bool represents if such info exists + /// @param start_id: Guardian index start_id, included + /// @param end_id: Guardian index end id, excluded + /// @custom:selector 0x92bd7975 + /// batchGuardianIndexToInfo(uint256,uint256) + function batchGuardianIndexToInfo(uint256 start_id, uint256 end_id) external view returns (GuardianQueryResult[] memory result); /// @notice Query voter's vote of one specific guardian given its guardian index, substrate /// @param voter: voter address, substrate diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index bc44300254..86c6749d63 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -228,3 +228,12 @@ where Ok(result) } } + +#[derive(Default, Debug, solidity::Codec)] +struct GuardianQueryResult { + exist: bool, + info_hash: H256, + update_block: U256, + guardian: H256, + status: u8, +} From d754350d59106338037714f858a59bb1925d8abb Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 14:32:22 +0800 Subject: [PATCH 104/215] chore: fix --- .../precompiles/collab-ai/curator/src/lib.rs | 44 +++++++------------ 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index 65ecaf2c3f..cfe2e32bdb 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -152,36 +152,22 @@ where ))?; // Storage item: CuratorIndex u128: // Twox64Concat(8) + CuratorIndex(16) + InfoHash(32) + BlockNumber(4) + T::AccountId(32) + CandidateStatus(1) - handle.record_db_read::(93 * length)?; - - let result = vec![start_id..end_id] - .iter() - .map(|&i| { - if let Ok(tmp_index) = >::try_into(i) { - if let Some((info_hash, update_block, curator, status)) = - pallet_curator::Pallet::::curator_index_to_info(tmp_index) - { - let update_block: U256 = update_block.into(); - - let curator: [u8; 32] = curator.into(); - let curator: H256 = curator.into(); - - let status: u8 = Self::candidate_status_to_u8(status).unwrap_or_default(); - - CuratorQueryResult { exist: true, info_hash, update_block, curator, status } - } else { - CuratorQueryResult { - exist: false, - info_hash: Default::default(), - update_block: Default::default(), - curator: Default::default(), - status: Default::default(), - } - } + handle.record_db_read::(93 * length.into())?; + + let result = (start_id..end_id) + .map(|i| { + if let Some((info_hash, update_block, curator, status)) = + pallet_curator::Pallet::::curator_index_to_info(i) + { + let update_block: U256 = update_block.into(); + + let curator: [u8; 32] = curator.into(); + let curator: H256 = curator.into(); + + let status: u8 = Self::candidate_status_to_u8(status).unwrap_or_default(); + + CuratorQueryResult { exist: true, info_hash, update_block, curator, status } } else { - // Impossible here, but - // If value_is_too_large error from U256 to u128 - // return default CuratorQueryResult { exist: false, info_hash: Default::default(), From 705f58cccbce874b9e16bd4c764a9cb8cb4f1203 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 14:44:21 +0800 Subject: [PATCH 105/215] chore: fix --- parachain/precompiles/collab-ai/curator/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index cfe2e32bdb..8617571cd8 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -152,7 +152,7 @@ where ))?; // Storage item: CuratorIndex u128: // Twox64Concat(8) + CuratorIndex(16) + InfoHash(32) + BlockNumber(4) + T::AccountId(32) + CandidateStatus(1) - handle.record_db_read::(93 * length.into())?; + handle.record_db_read::(93 * >::into(length))?; let result = (start_id..end_id) .map(|i| { From 278b34aef6b53782d336f8b952dd04e2fa610a18 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 15:04:44 +0800 Subject: [PATCH 106/215] chore: fix --- parachain/precompiles/collab-ai/curator/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index 8617571cd8..1f311f43e2 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -152,7 +152,10 @@ where ))?; // Storage item: CuratorIndex u128: // Twox64Concat(8) + CuratorIndex(16) + InfoHash(32) + BlockNumber(4) + T::AccountId(32) + CandidateStatus(1) - handle.record_db_read::(93 * >::into(length))?; + let length_usize: usize = length.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + handle.record_db_read::(93 * length_usize)?; let result = (start_id..end_id) .map(|i| { From d3bd9999064895fff84e10d11fb92898b59fda1d Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 15:29:58 +0800 Subject: [PATCH 107/215] chore: add guardian batch method --- .../precompiles/collab-ai/guardian/src/lib.rs | 51 +++++++++++++++++++ .../collab-ai/guardian/src/tests.rs | 40 +++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index 86c6749d63..6ebd45ea29 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -203,6 +203,57 @@ where } } + #[precompile::public("batchGuardianIndexToInfo(uint256,uint256)")] + #[precompile::view] + fn batch_guardian_index_to_info( + handle: &mut impl PrecompileHandle, + start_id: U256, + end_id: U256, + ) -> EvmResult> { + let start_id: u128 = start_id.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + let end_id: u128 = end_id.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + + let length: u128 = end_id.checked_sub(start_id).ok_or(Into::::into( + RevertReason::value_is_too_large("id overflow"), + ))?; + // Storage item: GuardianIndex u128: + // Twox64Concat(8) + GuardianIndex(16) + InfoHash(32) + BlockNumber(4) + T::AccountId(32) + CandidateStatus(1) + let length_usize: usize = length.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + handle.record_db_read::(93 * length_usize)?; + + let result = (start_id..end_id) + .map(|i| { + if let Some((info_hash, update_block, curator, status)) = + pallet_guardian::Pallet::::guardian_index_to_info(i) + { + let update_block: U256 = update_block.into(); + + let guardian: [u8; 32] = guardian.into(); + let guardian: H256 = guardian.into(); + + let status: u8 = Self::candidate_status_to_u8(status).unwrap_or_default(); + + GuardianQueryResult { exist: true, info_hash, update_block, guardian, status } + } else { + GuardianQueryResult { + exist: false, + info_hash: Default::default(), + update_block: Default::default(), + guardian: Default::default(), + status: Default::default(), + } + } + }) + .collect(); + Ok(result) + } + #[precompile::public("guardianVotes(bytes32,uint256)")] #[precompile::view] fn guardian_votes( diff --git a/parachain/precompiles/collab-ai/guardian/src/tests.rs b/parachain/precompiles/collab-ai/guardian/src/tests.rs index ed39451913..f097c71dd4 100644 --- a/parachain/precompiles/collab-ai/guardian/src/tests.rs +++ b/parachain/precompiles/collab-ai/guardian/src/tests.rs @@ -340,3 +340,43 @@ fn test_guardian_votes() { .execute_returns((1u8, U256::from(0))); // Aye vote }); } + +#[test] +fn test_batch_guardian_index_to_info() { + new_test_ext().execute_with(|| { + let guardian: H160 = H160::from_low_u64_be(1001); + let info_hash: H256 = H256::from([1u8; 32]); + + // Register the guardian + PrecompilesValue::get() + .prepare_test( + guardian, + H160::from_low_u64_be(1000), + PCall::::regist_guardian { info_hash }, + ) + .execute_returns(()); + + // Query the guardian info by index + + let guardian_account = TruncatedAddressMapping::into_account_id(guardian); + let guardian_account: [u8; 32] = guardian_account.into(); + let guardian_account: H256 = guardian_account.into(); + + PrecompilesValue::get() + .prepare_test( + guardian, + H160::from_low_u64_be(1000), + PCall::::batch_guardian_index_to_info { + start_id: 0.into(), + end_id: 1.into(), + }, + ) + .execute_returns(vec![crate::GuardianQueryResult { + exist: true, + info_hash, + update_block: U256::from(1), + guardian: guardian_account, + status: 0u8, + }]); + }); +} From 1a4af9e094b7771e6eadee83177ab1c830ae0741 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 16:02:09 +0800 Subject: [PATCH 108/215] chore: add batch method for pool proposal --- .../precompiles/collab-ai/curator/Curator.sol | 2 +- .../precompiles/collab-ai/curator/src/lib.rs | 20 +- .../collab-ai/curator/src/tests.rs | 8 +- .../collab-ai/guardian/Guardian.sol | 2 +- .../precompiles/collab-ai/guardian/src/lib.rs | 22 +- .../collab-ai/guardian/src/tests.rs | 8 +- .../collab-ai/pool-proposal/PoolProposal.sol | 32 ++- .../collab-ai/pool-proposal/src/lib.rs | 218 +++++++++++++----- 8 files changed, 219 insertions(+), 93 deletions(-) diff --git a/parachain/precompiles/collab-ai/curator/Curator.sol b/parachain/precompiles/collab-ai/curator/Curator.sol index 2f631b0932..f1d4785e50 100644 --- a/parachain/precompiles/collab-ai/curator/Curator.sol +++ b/parachain/precompiles/collab-ai/curator/Curator.sol @@ -50,7 +50,7 @@ interface ICurator { /// @param index: Curator index /// @custom:selector 0x74cded61 /// curatorIndexToInfo(uint256) - function curatorIndexToInfo(uint256 index) external view returns (bool exist, bytes32 info_hash, uint256 update_block, bytes32 curator, CandidateStatus status); + function curatorIndexToInfo(uint256 index) external view returns (CuratorQueryResult memory result); /// @notice Curator index to curator info, bool represents if such info exists /// @param start_id: Guardian index start_id, included diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index 1f311f43e2..deeed9ca23 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -103,7 +103,7 @@ where fn curator_index_to_info( handle: &mut impl PrecompileHandle, index: U256, - ) -> EvmResult<(bool, H256, U256, H256, u8)> { + ) -> EvmResult { // Storage item: CuratorIndex u128: // Twox64Concat(8) + CuratorIndex(16) + InfoHash(32) + BlockNumber(4) + T::AccountId(32) + CandidateStatus(1) handle.record_db_read::(93)?; @@ -121,15 +121,15 @@ where let status = Self::candidate_status_to_u8(status).in_field("candidateStatus")?; - Ok((true, info_hash, update_block, curator, status)) + Ok(CuratorQueryResult { exist: true, info_hash, update_block, curator, status }) } else { - Ok(( - false, - Default::default(), - Default::default(), - Default::default(), - Default::default(), - )) + Ok(CuratorQueryResult { + exist: false, + info_hash: Default::default(), + update_block: Default::default(), + curator: Default::default(), + status: Default::default(), + }) } } @@ -155,7 +155,7 @@ where let length_usize: usize = length.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; - handle.record_db_read::(93 * length_usize)?; + handle.record_db_read::(93.saturating_mul(length_usize))?; let result = (start_id..end_id) .map(|i| { diff --git a/parachain/precompiles/collab-ai/curator/src/tests.rs b/parachain/precompiles/collab-ai/curator/src/tests.rs index f6f6fa78c9..a72fcfc12f 100644 --- a/parachain/precompiles/collab-ai/curator/src/tests.rs +++ b/parachain/precompiles/collab-ai/curator/src/tests.rs @@ -191,7 +191,13 @@ fn test_curator_index_to_info() { H160::from_low_u64_be(1000), PCall::::curator_index_to_info { index: 0.into() }, ) - .execute_returns((true, info_hash, U256::from(1), curator_account, 0u8)); + .execute_returns(crate::CuratorQueryResult { + exist: true, + info_hash, + update_block: U256::from(1), + curator: curator_account, + status: 0u8, + }); }); } diff --git a/parachain/precompiles/collab-ai/guardian/Guardian.sol b/parachain/precompiles/collab-ai/guardian/Guardian.sol index 33bc3446fb..342e01bd43 100644 --- a/parachain/precompiles/collab-ai/guardian/Guardian.sol +++ b/parachain/precompiles/collab-ai/guardian/Guardian.sol @@ -67,7 +67,7 @@ interface IGuardian { /// @param index: Guardian index /// @custom:selector 0x59c95743 /// guardianIndexToInfo(address) - function guardianIndexToInfo(uint256 index) external view returns (bool exist, bytes32 info_hash, uint256 update_block, bytes32 guardian, CandidateStatus status); + function guardianIndexToInfo(uint256 index) external view returns (GuardianQueryResult memory result); /// @notice Guardian index to guardian info, bool represents if such info exists /// @param start_id: Guardian index start_id, included diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index 6ebd45ea29..b8ea813458 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -173,7 +173,7 @@ where fn guardian_index_to_info( handle: &mut impl PrecompileHandle, index: U256, - ) -> EvmResult<(bool, H256, U256, H256, u8)> { + ) -> EvmResult { // Storage item: GuardianIndex u128: // Twox64Concat(8) + GuardianIndex(16) + InfoHash(32) + BlockNumber(4) + T::AccountId(32) + CandidateStatus(1) handle.record_db_read::(93)?; @@ -191,15 +191,15 @@ where let status = Self::candidate_status_to_u8(status).in_field("candidateStatus")?; - Ok((true, info_hash, update_block, guardian, status)) + Ok(GuardianQueryResult { exist: true, info_hash, update_block, guardian, status }) } else { - Ok(( - false, - Default::default(), - Default::default(), - Default::default(), - Default::default(), - )) + Ok(GuardianQueryResult { + exist: false, + info_hash: Default::default(), + update_block: Default::default(), + guardian: Default::default(), + status: Default::default(), + }) } } @@ -209,7 +209,7 @@ where handle: &mut impl PrecompileHandle, start_id: U256, end_id: U256, - ) -> EvmResult> { + ) -> EvmResult> { let start_id: u128 = start_id.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; @@ -225,7 +225,7 @@ where let length_usize: usize = length.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; - handle.record_db_read::(93 * length_usize)?; + handle.record_db_read::(93.saturating_mul(length_usize))?; let result = (start_id..end_id) .map(|i| { diff --git a/parachain/precompiles/collab-ai/guardian/src/tests.rs b/parachain/precompiles/collab-ai/guardian/src/tests.rs index f097c71dd4..6fc000be5d 100644 --- a/parachain/precompiles/collab-ai/guardian/src/tests.rs +++ b/parachain/precompiles/collab-ai/guardian/src/tests.rs @@ -290,7 +290,13 @@ fn test_guardian_index_to_info() { H160::from_low_u64_be(1000), PCall::::guardian_index_to_info { index: 0.into() }, ) - .execute_returns((true, info_hash, U256::from(1), guardian_account, 0u8)); + .execute_returns(crate::GuardianQueryResult { + exist: true, + info_hash, + update_block: U256::from(1), + guardian: guardian_account, + status: 0u8, + }); }); } diff --git a/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol b/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol index df1fed979a..7db315cfe5 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol +++ b/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol @@ -10,12 +10,14 @@ interface IPoolProposal { /// @dev A structure for bonding of user's official pre-staking struct StakingBond { + uint256 poolIndex; bytes32 owner; uint256 amount; } /// @dev A structure for bonding of user's queued pre-staking struct QueuedStakingBond { + uint256 poolIndex; bytes32 owner; uint256 amount; uint256 queuedTime; @@ -29,6 +31,7 @@ interface IPoolProposal { /// @dev A strcuture for proposal details struct PoolProposalInfo { + bool exist; // Proposer/Curator bytes32 proposer; // Hash of pool info like legal files etc. @@ -64,6 +67,8 @@ interface IPoolProposal { uint8 proposalStatusFlags; } + struct GuardianQueryResult + /// @notice Propose an investing pool proposal /// @param max_pool_size: At most this amount of raised money curator/investing pool willing to take /// @param proposal_last_time: How does the proposal lasts for voting/preinvesting. @@ -114,19 +119,28 @@ interface IPoolProposal { /// @param pool_proposal_index: Index of pool proposal /// @custom:selector 0x18afd9ad /// poolProposal(uint256) - function poolProposal(uint256 pool_proposal_index) external view returns (bool exist, PoolProposalInfo memory proposal_info); + function poolProposal(uint256 pool_proposal_index) external view returns (PoolProposalInfo memory proposal_info); + + /// @notice Query a batch of pool proposal and their details, bool represents if such info exists + /// @param start_id: Proposal index start_id, included + /// @param end_id: Proposal index end id, excluded + /// @custom:selector 0x1b3fb27c + /// batchPoolProposal(uint256,uint256) + function batchPoolProposal(uint256 start_id, uint256 end_id) external view returns (PoolProposalInfo[] memory proposal_info); /// @notice Query a single pool proposal and its existing included pre staking - /// @param pool_proposal_index: Index of pool proposal - /// @custom:selector 0xf081aa73 - /// poolPreInvestings(uint256) - function poolPreInvestings(uint256 pool_proposal_index) external view returns (StakingBond[] memory pre_investing_bond); + /// @param start_id: Proposal index start_id, included + /// @param end_id: Proposal index end id, excluded + /// @custom:selector 0x49dc251a + /// poolPreInvestings(uint256,uint256) + function poolPreInvestings(uint256 start_id, uint256 end_id) external view returns (StakingBond[] memory pre_investing_bond); /// @notice Query a single pool proposal and its queued pre staking - /// @param pool_proposal_index: Index of pool proposal - /// @custom:selector 0x884df5eb - /// poolPreInvestingsQueued(uint256) - function poolPreInvestingsQueued(uint256 pool_proposal_index) external view returns (QueuedStakingBond[] memory queued_bond); + /// @param start_id: Proposal index start_id, included + /// @param end_id: Proposal index end id, excluded + /// @custom:selector 0x201be573 + /// poolPreInvestingsQueued(uint256,uint256) + function poolPreInvestingsQueued(uint256 start_id, uint256 end_id) external view returns (QueuedStakingBond[] memory queued_bond); /// @notice Query a single pool proposal and its potential guardian detail /// @param pool_proposal_index: Index of pool proposal diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index 812da8d70d..77034a77bf 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -223,7 +223,7 @@ where fn pool_proposal( handle: &mut impl PrecompileHandle, pool_proposal_index: U256, - ) -> EvmResult<(bool, PoolProposalInfo)> { + ) -> EvmResult { // Storage item: PoolProposal -> // PoolProposalInfo, BlockNumberFor, T::AccountId> handle.record_db_read::(PalletPoolProposalInfo::< @@ -243,7 +243,8 @@ where let proposer: [u8; 32] = info.proposer.into(); let proposer = proposer.into(); - let info = PoolProposalInfo { + Ok(PoolProposalInfo { + exist: true, proposer, info_hash: info.pool_info_hash, max_pool_size: info.max_pool_size.into(), @@ -251,90 +252,186 @@ where pool_end_time: info.pool_end_time.into(), estimated_epoch_reward: info.estimated_epoch_reward.into(), proposal_status_flags: info.proposal_status_flags.bits(), - }; - - Ok((true, info)) + }) } else { - Ok((false, Default::default())) + Ok(PoolProposalInfo { + exist: false, + proposer, + info_hash: Default::default(), + max_pool_size: Default::default(), + pool_start_time: Default::default(), + pool_end_time: Default::default(), + estimated_epoch_reward: Default::default(), + proposal_status_flags: Default::default(), + }) } } - #[precompile::public("poolPreInvestings(uint256)")] + #[precompile::public("batchPoolProposal(uint256,uint256)")] + #[precompile::view] + fn batch_pool_proposal( + handle: &mut impl PrecompileHandle, + start_id: U256, + end_id: U256, + ) -> EvmResult> { + let start_id: u128 = start_id.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + let end_id: u128 = end_id.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + + let length: u128 = end_id.checked_sub(start_id).ok_or(Into::::into( + RevertReason::value_is_too_large("id overflow"), + ))?; + // Storage item: PoolProposal -> + // PoolProposalInfo, BlockNumberFor, T::AccountId> + let length_usize: usize = length.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + handle.record_db_read::( + PalletPoolProposalInfo::< + H256, + AssetBalanceOf, + BlockNumberFor, + Runtime::AccountId, + >::max_encoded_len() + .saturating_mul(length_usize), + )?; + + let result = (start_id..end_id) + .map(|i| { + if let Some(info) = pallet_pool_proposal::Pallet::::pool_proposal(i) { + let proposer: [u8; 32] = info.proposer.into(); + let proposer = proposer.into(); + + PoolProposalInfo { + exist: true, + proposer, + info_hash: info.pool_info_hash, + max_pool_size: info.max_pool_size.into(), + pool_start_time: info.pool_start_time.into(), + pool_end_time: info.pool_end_time.into(), + estimated_epoch_reward: info.estimated_epoch_reward.into(), + proposal_status_flags: info.proposal_status_flags.bits(), + } + } else { + PoolProposalInfo { + exist: false, + proposer, + info_hash: Default::default(), + max_pool_size: Default::default(), + pool_start_time: Default::default(), + pool_end_time: Default::default(), + estimated_epoch_reward: Default::default(), + proposal_status_flags: Default::default(), + } + } + }) + .collect(); + + Ok(result) + } + + #[precompile::public("poolPreInvestings(uint256,uint256)")] #[precompile::view] fn pool_pre_investings( handle: &mut impl PrecompileHandle, - pool_proposal_index: U256, + start_id: U256, + end_id: U256, ) -> EvmResult> { + let start_id: u128 = start_id.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + let end_id: u128 = end_id.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + + let length: u128 = end_id.checked_sub(start_id).ok_or(Into::::into( + RevertReason::value_is_too_large("id overflow"), + ))?; // Storage item: PoolPreInvestings -> // PoolProposalPreInvesting, BlockNumberFor, T::MaximumPoolProposed> + let length_usize: usize = length.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; handle.record_db_read::( PalletBond::>::max_encoded_len() - .saturating_mul(Runtime::MaximumPoolProposed::get() as usize), + .saturating_mul(Runtime::MaximumPoolProposed::get() as usize) + .saturating_mul(length_usize), )?; - - let pool_proposal_index: u128 = pool_proposal_index.try_into().map_err(|_| { - Into::::into(RevertReason::value_is_too_large("index type")) - })?; - - if let Some(result) = - pallet_pool_proposal::Pallet::::pool_pre_investings(pool_proposal_index) - { - let bond_vec = result - .pre_investings - .into_iter() - .enumerate() - .map(|(_index, bond)| { - let owner: [u8; 32] = bond.owner.into(); - let owner = owner.into(); - StakingBond { owner, amount: bond.amount.into() } - }) - .collect(); - - Ok(bond_vec) - } else { - Ok(Default::default()) + let mut bond_result = Vec::::new(); + for n in start_id..end_id { + if let Some(result) = pallet_pool_proposal::Pallet::::pool_pre_investings(n) { + let bond_vec = result + .pre_investings + .into_iter() + .enumerate() + .map(|(_index, bond)| { + let owner: [u8; 32] = bond.owner.into(); + let owner = owner.into(); + StakingBond { pool_index: n, owner, amount: bond.amount.into() } + }) + .collect(); + + bond_result.extend(bond_vec); + } } + + Ok(bond_result) } - #[precompile::public("poolPreInvestingsQueued(uint256)")] + #[precompile::public("poolPreInvestingsQueued(uint256,uint256)")] #[precompile::view] fn pool_pre_investings_queued( handle: &mut impl PrecompileHandle, - pool_proposal_index: U256, + start_id: U256, + end_id: U256, ) -> EvmResult> { + let start_id: u128 = start_id.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + let end_id: u128 = end_id.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + + let length: u128 = end_id.checked_sub(start_id).ok_or(Into::::into( + RevertReason::value_is_too_large("id overflow"), + ))?; // Storage item: PoolPreInvestings -> // PoolProposalPreInvesting, BlockNumberFor, T::MaximumPoolProposed> + let length_usize: usize = length.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; handle.record_db_read::( PalletBond::>::max_encoded_len() - .saturating_mul(Runtime::MaximumPoolProposed::get() as usize), + .saturating_mul(Runtime::MaximumPoolProposed::get() as usize) + .saturating_mul(length_usize), )?; - let pool_proposal_index: u128 = pool_proposal_index.try_into().map_err(|_| { - Into::::into(RevertReason::value_is_too_large("index type")) - })?; - - if let Some(result) = - pallet_pool_proposal::Pallet::::pool_pre_investings(pool_proposal_index) - { - let bond_vec = result - .queued_pre_investings - .into_iter() - .enumerate() - .map(|(_index, bond)| { - let owner: [u8; 32] = bond.0.owner.into(); - let owner = owner.into(); - QueuedStakingBond { - owner, - amount: bond.0.amount.into(), - queued_time: bond.1.into(), - } - }) - .collect(); - - Ok(bond_vec) - } else { - Ok(Default::default()) + let mut bond_result = Vec::::new(); + for n in start_id..end_id { + if let Some(result) = pallet_pool_proposal::Pallet::::pool_pre_investings(n) { + let bond_vec = result + .queued_pre_investings + .into_iter() + .enumerate() + .map(|(_index, bond)| { + let owner: [u8; 32] = bond.0.owner.into(); + let owner = owner.into(); + QueuedStakingBond { + owner, + amount: bond.0.amount.into(), + queued_time: bond.1.into(), + } + }) + .collect(); + + bond_result.extend(bond_vec); + } } + + Ok(bond_result) } #[precompile::public("poolGuardian(uint256)")] @@ -381,12 +478,14 @@ pub struct DepositBond { #[derive(Default, Debug, solidity::Codec)] pub struct StakingBond { + pool_index: U256, owner: H256, amount: U256, } #[derive(Default, Debug, solidity::Codec)] pub struct QueuedStakingBond { + pool_index: U256, owner: H256, amount: U256, queued_time: U256, @@ -400,6 +499,7 @@ pub struct PoolProposalStatus { #[derive(Default, Debug, solidity::Codec)] struct PoolProposalInfo { + exist: bool, proposer: H256, info_hash: H256, max_pool_size: U256, From 96b74b8112b7450d47462992e4e8a46b1e207464 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 16:16:12 +0800 Subject: [PATCH 109/215] chore: fix --- parachain/precompiles/collab-ai/curator/src/lib.rs | 2 +- parachain/precompiles/collab-ai/guardian/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index deeed9ca23..7910547691 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -155,7 +155,7 @@ where let length_usize: usize = length.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; - handle.record_db_read::(93.saturating_mul(length_usize))?; + handle.record_db_read::(length_usize.saturating_mul(93_usize))?; let result = (start_id..end_id) .map(|i| { diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index b8ea813458..c5e2e298df 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -225,7 +225,7 @@ where let length_usize: usize = length.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; - handle.record_db_read::(93.saturating_mul(length_usize))?; + handle.record_db_read::(length_usize.saturating_mul(93_usize))?; let result = (start_id..end_id) .map(|i| { From a68eb4a3229393d4ad12b12a7ece9c68d47af1a9 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 16:28:31 +0800 Subject: [PATCH 110/215] chore: fix --- parachain/precompiles/collab-ai/guardian/src/lib.rs | 2 +- .../precompiles/collab-ai/pool-proposal/PoolProposal.sol | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index c5e2e298df..541ec0326a 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -229,7 +229,7 @@ where let result = (start_id..end_id) .map(|i| { - if let Some((info_hash, update_block, curator, status)) = + if let Some((info_hash, update_block, guardian, status)) = pallet_guardian::Pallet::::guardian_index_to_info(i) { let update_block: U256 = update_block.into(); diff --git a/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol b/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol index 7db315cfe5..aed6060dce 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol +++ b/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol @@ -128,14 +128,14 @@ interface IPoolProposal { /// batchPoolProposal(uint256,uint256) function batchPoolProposal(uint256 start_id, uint256 end_id) external view returns (PoolProposalInfo[] memory proposal_info); - /// @notice Query a single pool proposal and its existing included pre staking + /// @notice Batch query pool proposals and their existing included pre stakings /// @param start_id: Proposal index start_id, included /// @param end_id: Proposal index end id, excluded /// @custom:selector 0x49dc251a /// poolPreInvestings(uint256,uint256) function poolPreInvestings(uint256 start_id, uint256 end_id) external view returns (StakingBond[] memory pre_investing_bond); - /// @notice Query a single pool proposal and its queued pre staking + /// @notice Batch query pool proposals and their queued pre stakings /// @param start_id: Proposal index start_id, included /// @param end_id: Proposal index end id, excluded /// @custom:selector 0x201be573 From f51249aaf0c47cf9a1dbd0187897945f86d3abdf Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 16:40:55 +0800 Subject: [PATCH 111/215] chore: fix --- parachain/precompiles/collab-ai/pool-proposal/src/lib.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index 77034a77bf..bd671baf7b 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -256,7 +256,7 @@ where } else { Ok(PoolProposalInfo { exist: false, - proposer, + proposer: Default::default(), info_hash: Default::default(), max_pool_size: Default::default(), pool_start_time: Default::default(), @@ -318,7 +318,7 @@ where } else { PoolProposalInfo { exist: false, - proposer, + proposer: Default::default(), info_hash: Default::default(), max_pool_size: Default::default(), pool_start_time: Default::default(), @@ -370,7 +370,7 @@ where .map(|(_index, bond)| { let owner: [u8; 32] = bond.owner.into(); let owner = owner.into(); - StakingBond { pool_index: n, owner, amount: bond.amount.into() } + StakingBond { pool_index: n.into(), owner, amount: bond.amount.into() } }) .collect(); @@ -409,7 +409,7 @@ where .saturating_mul(length_usize), )?; - let mut bond_result = Vec::::new(); + let mut bond_result = Vec::::new(); for n in start_id..end_id { if let Some(result) = pallet_pool_proposal::Pallet::::pool_pre_investings(n) { let bond_vec = result @@ -420,6 +420,7 @@ where let owner: [u8; 32] = bond.0.owner.into(); let owner = owner.into(); QueuedStakingBond { + pool_index: n.into(), owner, amount: bond.0.amount.into(), queued_time: bond.1.into(), From e28d29b3e76a59f703411654c8ca8061a89ae5cf Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 24 Oct 2024 17:02:19 +0800 Subject: [PATCH 112/215] chore: fix --- .../precompiles/collab-ai/pool-proposal/PoolProposal.sol | 2 -- parachain/precompiles/collab-ai/pool-proposal/src/lib.rs | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol b/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol index aed6060dce..5a692fb9da 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol +++ b/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol @@ -67,8 +67,6 @@ interface IPoolProposal { uint8 proposalStatusFlags; } - struct GuardianQueryResult - /// @notice Propose an investing pool proposal /// @param max_pool_size: At most this amount of raised money curator/investing pool willing to take /// @param proposal_last_time: How does the proposal lasts for voting/preinvesting. diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index bd671baf7b..246dc1dda8 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -363,7 +363,7 @@ where let mut bond_result = Vec::::new(); for n in start_id..end_id { if let Some(result) = pallet_pool_proposal::Pallet::::pool_pre_investings(n) { - let bond_vec = result + let bond_vec: Vec = result .pre_investings .into_iter() .enumerate() @@ -412,7 +412,7 @@ where let mut bond_result = Vec::::new(); for n in start_id..end_id { if let Some(result) = pallet_pool_proposal::Pallet::::pool_pre_investings(n) { - let bond_vec = result + let bond_vec: Vec = result .queued_pre_investings .into_iter() .enumerate() From dbb483b6bc7fff66f1ea681efdf2d631d11ad99f Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 28 Oct 2024 14:28:03 +0800 Subject: [PATCH 113/215] chore: temp submit --- parachain/pallets/collab-ai/common/src/lib.rs | 18 +++++- .../collab-ai/investing-pool/src/lib.rs | 62 ++++++++++++++----- .../collab-ai/pool-proposal/src/lib.rs | 9 ++- 3 files changed, 70 insertions(+), 19 deletions(-) diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index b7947b53a3..f6767ea081 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -170,7 +170,7 @@ pub const INVESTING_POOL_START_EPOCH_SHIFTER: u128 = 1_000; pub const INVESTING_POOL_END_EPOCH_SHIFTER: u128 = 1; pub struct InvestingPoolAssetIdGenerator(PhantomData); -impl> InvestingPoolAssetIdGenerator { +impl + Into> InvestingPoolAssetIdGenerator { /// Create a series of new asset id based on pool index and reward epoch /// Return None if impossible to generate. e.g. overflow pub fn get_all_pool_token(pool_index: InvestingPoolIndex, epoch: u128) -> Option> { @@ -199,6 +199,22 @@ impl> InvestingPoolAssetIdGenerator { let end_epoch_suffix = epoch.checked_mul(INVESTING_POOL_END_EPOCH_SHIFTER)?; Some(pool_index_prefix.checked_add(end_epoch_suffix)?.into()) } + + pub fn get_token_pool_index(asset_id: AssetId) -> u128 { + let asset_id_u128: u128 = asset_id.into(); + asset_id_u128 / INVESTING_POOL_INDEX_SHIFTER + } + + pub fn get_token_start_epoch(asset_id: AssetId) -> u128 { + let asset_id_u128: u128 = asset_id.into(); + (asset_id_u128 % INVESTING_POOL_INDEX_SHIFTER) / INVESTING_POOL_START_EPOCH_SHIFTER + } + + pub fn get_token_end_epoch(asset_id: AssetId) -> u128 { + let asset_id_u128: u128 = asset_id.into(); + ((asset_id_u128 % INVESTING_POOL_INDEX_SHIFTER) % INVESTING_POOL_START_EPOCH_SHIFTER) + / INVESTING_POOL_END_EPOCH_SHIFTER + } } /// Some sort of check on the account is from some group. diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index c67c3d172c..6b8611b9b1 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -180,6 +180,7 @@ pub mod pallet { pub type BalanceOf = <::Fungibles as FsInspect<::AccountId>>::Balance; + pub type AssetIdOf = <::Fungibles as FsInspect<::AccountId>>::AssetId; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -246,13 +247,13 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn aiusd_asset_id)] pub type AIUSDAssetId = - StorageValue<_, >::AssetId, OptionQuery>; + StorageValue<_, AssetIdOf, OptionQuery>; // Asset id of CAN #[pallet::storage] #[pallet::getter(fn aiusd_asset_id)] pub type CANAssetId = - StorageValue<_, >::AssetId, OptionQuery>; + StorageValue<_, AssetIdOf, OptionQuery>; #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] @@ -428,12 +429,15 @@ pub mod pallet { origin: OriginFor, pool_id: InvestingPoolIndex, epoch: u128, - amount: AssetBalanceOf, + amount: BalanceOf, ) -> DispatchResult { let source = ensure_signed(origin)?; Self::do_can_claim(source, asset_id, amount)?; - Self::do_stable_claim(source, asset_id, amount) + Self::do_stable_claim(source, asset_id, amount)?; + + //destroy/create corresponding pool token category + ??? } // Registing AIUSD asset id @@ -442,7 +446,7 @@ pub mod pallet { #[transactional] pub fn regist_aiusd( origin: OriginFor, - asset_id: >::AssetId, + asset_id: AssetIdOf, ) -> DispatchResult { T::InvestingPoolCommitteeOrigin::ensure_origin(origin)?; >::put(asset_id.clone()); @@ -456,7 +460,7 @@ pub mod pallet { #[transactional] pub fn regist_can( origin: OriginFor, - asset_id: >::AssetId, + asset_id: AssetIdOf, ) -> DispatchResult { T::InvestingPoolCommitteeOrigin::ensure_origin(origin)?; >::put(asset_id.clone()); @@ -467,6 +471,7 @@ pub mod pallet { impl Pallet { // Epoch starting from 1 + // The undergoing epoch index if at "time" // return setting.epoch if time >= pool end_time fn get_epoch_index( pool_id: InvestingPoolIndex, @@ -490,7 +495,7 @@ pub mod pallet { // return pool ending time if epoch > setting.epoch // Epoch starting from 1 - fn get_epoch_begin_time( + fn get_epoch_start_time( pool_id: InvestingPoolIndex, epoch: u128, ) -> Result, sp_runtime::DispatchError> { @@ -540,7 +545,6 @@ pub mod pallet { // For can_investing fn do_can_add( - who: T::AccountId, amount: BalanceOf, effective_time: BlockNumberFor, ) -> DispatchResult { @@ -558,13 +562,40 @@ pub mod pallet { } // No category token effected - fn do_can_claim(who: T::AccountId, until_time: BlockNumberFor) -> DispatchResult { + fn do_can_claim(who: T::AccountId, asset_id: AssetIdOf, amount: BalanceOf) -> DispatchResult { let beneficiary_account: T::AccountId = Self::can_token_beneficiary_account(); let current_block = frame_system::Pallet::::block_number(); - ensure!(until_time <= current_block, Error::::CannotClaimFuture); let can_asset_id = >::get().ok_or(Error::::NoAssetId)?; // BalanceOf - let reward_pool = T::Fungible::balance(&beneficiary_account); + let reward_pool = T::Fungibles::balance(can_asset_id, &beneficiary_account); + let pool_id = InvestingPoolAssetIdGenerator::get_token_pool_index(asset_id); + // Current latest end epoch + let latest_ended_epoch = self::get_epoch_index(pool_id, current_block).checed_sub(1u128).ok_or(ArithmeticError::Overflow)?; + let token_start_epoch = InvestingPoolAssetIdGenerator::get_token_start_epoch(asset_id); + + if token_start_epoch > latest_ended_epoch { + // Nothing to claim + // Do nothing + return Ok(()) + } else { + // Claim until the latest_ended_epoch + let until_time = get_epoch_end_time(pool_id, latest_ended_epoch); + let claim_duration = until_time - get_epoch_start_time(pool_id, token_start_epoch); + let claim_weight = claim_duration.checked_mul(amount).ok_or(ArithmeticError::Overflow)?; + + if let Some(mut ncp) = >::get() { + let proportion = Perquintill::from_rational( + claim_weight, + ncp.weight_force(until_time) + .ok_or(Error::::TypeIncompatibleOrArithmeticError)?, + ); + } + + + + + ... + } if let Some(mut ncp) = >::get() { if let Some(mut user_ncp) = >::get(who.clone()) { @@ -597,7 +628,6 @@ pub mod pallet { )?; // Adjust checkpoint >::put(ncp); - >::insert(&who, user_ncp); Self::deposit_event(Event::::NativeRewardClaimed { who, until_time, @@ -611,8 +641,8 @@ pub mod pallet { // Category token effected fn do_stable_claim( who: T::AccountId, - asset_id: InvestingPoolIndex, - amount: BlockNumberFor, + asset_id: AssetIdOf, + amount: BalanceOf, ) -> DispatchResult { let current_block = frame_system::Pallet::::block_number(); ensure!(until_time <= current_block, Error::::CannotClaimFuture); @@ -654,8 +684,8 @@ pub mod pallet { i.1, )?; - // Add CAN token checkpoint - Self::do_can_add(i.0, i.1, effective_time) + // Add CAN token global checkpoint + Self::do_can_add(i.1, effective_time) } } diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index db8d66b25d..a9b67d0e6d 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -198,7 +198,11 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// A motion has been proposed by a public account. - PoolProposed { proposer: T::AccountId, pool_proposal_index: PoolProposalIndex }, + PoolProposed { + proposer: T::AccountId, + pool_proposal_index: PoolProposalIndex, + info_hash: InfoHash, + }, /// A pre investing becomes valid PoolPreInvested { user: T::AccountId, @@ -293,7 +297,7 @@ pub mod pallet { let new_proposal_info = PoolProposalInfo { proposer: who.clone(), - pool_info_hash, + pool_info_hash: pool_info_hash.clone(), max_pool_size, pool_start_time, pool_end_time: pool_start_time @@ -355,6 +359,7 @@ pub mod pallet { Self::deposit_event(Event::PoolProposed { proposer: who, pool_proposal_index: next_proposal_index, + info_hash: pool_info_hash, }); Ok(()) } From 65ff430690588d00aa2dd382c8a116689cd8d296 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 28 Oct 2024 16:24:32 +0800 Subject: [PATCH 114/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index a9b67d0e6d..0fca746de5 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -297,7 +297,7 @@ pub mod pallet { let new_proposal_info = PoolProposalInfo { proposer: who.clone(), - pool_info_hash: pool_info_hash.clone(), + pool_info_hash, max_pool_size, pool_start_time, pool_end_time: pool_start_time From 9080a77900cdb211890da9f062d6a61260ec8480 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 31 Oct 2024 11:50:58 +0800 Subject: [PATCH 115/215] chore: add investing pool / test not fix --- parachain/pallets/collab-ai/common/src/lib.rs | 14 +- .../collab-ai/investing-pool/src/lib.rs | 292 ++++++++++++++---- .../collab-ai/investing-pool/src/test.rs | 42 +-- 3 files changed, 262 insertions(+), 86 deletions(-) diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index f6767ea081..0693836540 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -185,7 +185,7 @@ impl + Into> InvestingPoolAssetIdGenerator { Some(vec) } - pub fn get_epoch_token(pool_index: InvestingPoolIndex, epoch: u128) -> Option { + pub fn get_initial_epoch_token(pool_index: InvestingPoolIndex, epoch: u128) -> Option { let pool_index_prefix = pool_index.checked_mul(INVESTING_POOL_INDEX_SHIFTER)?; let end_epoch_suffix = epoch.checked_mul(INVESTING_POOL_END_EPOCH_SHIFTER)?; @@ -193,6 +193,18 @@ impl + Into> InvestingPoolAssetIdGenerator { Some(pool_index_prefix.checked_add(infix)?.checked_add(end_epoch_suffix)?.into()) } + pub fn get_intermediate_epoch_token( + pool_index: InvestingPoolIndex, + start_epoch: u128, + end_epoch: u128, + ) -> Option { + let pool_index_prefix = pool_index.checked_mul(INVESTING_POOL_INDEX_SHIFTER)?; + + let end_epoch_suffix = end_epoch.checked_mul(INVESTING_POOL_END_EPOCH_SHIFTER)?; + let infix = start_epoch.checked_mul(INVESTING_POOL_START_EPOCH_SHIFTER)?; + Some(pool_index_prefix.checked_add(infix)?.checked_add(end_epoch_suffix)?.into()) + } + pub fn get_debt_token(pool_index: InvestingPoolIndex, epoch: u128) -> Option { let pool_index_prefix = pool_index.checked_mul(INVESTING_POOL_INDEX_SHIFTER)?; diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index 6b8611b9b1..32369eb592 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -47,7 +47,7 @@ mod mock; mod tests; #[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] -pub struct CANWeightedInfo { +pub struct InvestingWeightInfo { // For a single position or // Synthetic overall average effective_time weighted by staked amount pub effective_time: BlockNumber, @@ -58,7 +58,7 @@ pub struct CANWeightedInfo { pub last_add_time: BlockNumber, } -impl CANWeightedInfo +impl InvestingWeightInfo where Balance: AtLeast32BitUnsigned + Copy, BlockNumber: AtLeast32BitUnsigned + Copy, @@ -88,6 +88,27 @@ where Some(()) } + // Mixing a new investing position removed, replace the checkpoint with Synthetic new one + // Notice: The logic will be wrong if weight calculated time is before any single added + // effective_time + // None means TypeIncompatible Or Overflow Or Division Zero + fn remove(&mut self, effective_time: BlockNumber, amount: Balance) -> Option<()> { + // We try force all types into u128, then convert it back + let e: u128 = effective_time.try_into().ok()?; + let s: u128 = amount.try_into().ok()?; + + let oe: u128 = self.effective_time.try_into().ok()?; + let os: u128 = self.amount.try_into().ok()?; + + let new_amount: u128 = os.checked_sub(s)?; + // (oe * os - e * s) / (os - s) + let new_effective_time: u128 = + (oe.checked_mul(os)?.checked_sub(e.checked_mul(s)?)?).checked_div(new_amount)?; + self.amount = new_amount.try_into().ok()?; + self.effective_time = new_effective_time.try_into().ok()?; + Some(()) + } + // Claim/Update weighted info based on target until-block and return the consumed weight // None means TypeIncompatible Or Overflow fn claim(&mut self, n: BlockNumber) -> Option { @@ -230,18 +251,30 @@ pub mod pallet { >; // investing pools' stable token reward waiting claiming - // Pool id, epcoh index => unclaimed total reward + // Pool id, epcoh index => epoch reward #[pallet::storage] #[pallet::getter(fn stable_investing_pool_epoch_reward)] pub type StableInvestingPoolEpochReward = StorageDoubleMap<_, Twox64Concat, InvestingPoolIndex, Twox64Concat, u128, BalanceOf, OptionQuery>; + + // Checkpoint of single stable staking pool + // For stable token reward distribution + #[pallet::storage] + #[pallet::getter(fn stable_investing_pool_checkpoint)] + pub type StableIvestingPoolCheckpoint = StorageMap< + _, + Twox64Concat, + T::PoolId, + InvestingWeightInfo, BalanceOf>, + OptionQuery, + >; // Checkpoint of overall investing condition synthetic by tracking all investing pools // For CAN token reward distribution #[pallet::storage] #[pallet::getter(fn native_checkpoint)] pub type CANCheckpoint = - StorageValue<_, CANWeightedInfo, BalanceOf>, OptionQuery>; + StorageValue<_, InvestingWeightInfo, BalanceOf>, OptionQuery>; // Asset id of AIUSD #[pallet::storage] @@ -328,8 +361,8 @@ pub mod pallet { PoolNotExisted, PoolNotStarted, BadMetadata, - CannotClaimFuture, EpochAlreadyEnded, + EpochRewardNotUpdated, EpochNotExist, NoAssetId, TypeIncompatibleOrArithmeticError, @@ -418,6 +451,15 @@ pub mod pallet { }, )?; + // Mint AIUSD into reward pool + let aiusd_asset_id = >::get().ok_or(Error::::NoAssetId)?; + let beneficiary_account: T::AccountId = Self::stable_token_beneficiary_account(); + let _ = T::Fungibles::mint_into( + aiusd_asset_id, + beneficiary_account, + reward, + )?; + Ok(()) } @@ -427,17 +469,51 @@ pub mod pallet { #[transactional] pub fn claim( origin: OriginFor, - pool_id: InvestingPoolIndex, - epoch: u128, + asset_id: InvestingPoolIndex, amount: BalanceOf, ) -> DispatchResult { let source = ensure_signed(origin)?; - Self::do_can_claim(source, asset_id, amount)?; - Self::do_stable_claim(source, asset_id, amount)?; + let current_block = frame_system::Pallet::::block_number(); + // Epoch reward may update before epoch ends, which is also fine to claim early + let mut claimed_until_epoch = self::get_epoch_index_with_reward_updated_before(pool_id, current_block); + let pool_id = InvestingPoolAssetIdGenerator::get_token_pool_index(asset_id); + let token_start_epoch = InvestingPoolAssetIdGenerator::get_token_start_epoch(asset_id); + let token_end_epoch = InvestingPoolAssetIdGenerator::get_token_end_epoch(asset_id); + + // Technically speaking, start_epoch <= end_epoch + if token_start_epoch > claimed_until_epoch { + // Nothing to claim + return Ok(()); + } + + // Burn old category token + T::Fungibles::burn_from( + asset_id, + &source, + amount, + Precision::Exact, + // Seem to be no effect + Fortitude::Polite, + )?; + // Whether this claim leads to termination of investing procedure + let mut terminated: bool = false; + if token_end_epoch <= claimed_until_epoch { + // We simply destroy the category token without minting new + claimed_until_epoch = token_end_epoch; + terminated = true; + } else { + // Mint new category token + let new_asset_id = InvestingPoolAssetIdGenerator::get_intermediate_epoch_token(pool_id, (claimed_until_epoch + 1), token_end_epoch); + T::Fungibles::mint_into( + new_asset_id, + &source, + amount, + )?; + } + Self::do_can_claim(source, pool_id, amount, Self::get_epoch_start_time(token_start_epoch)?, Self::get_epoch_end_time(claimed_until_epoch)?, terminated)?; + Self::do_stable_claim(source, pool_id, amount, token_start_epoch, claimed_until_epoch)?; - //destroy/create corresponding pool token category - ??? } // Registing AIUSD asset id @@ -470,7 +546,7 @@ pub mod pallet { } impl Pallet { - // Epoch starting from 1 + // Epoch starting from 1, epoch 0 means not start // The undergoing epoch index if at "time" // return setting.epoch if time >= pool end_time fn get_epoch_index( @@ -480,6 +556,9 @@ pub mod pallet { let setting = >::get(pool_id).ok_or(Error::::PoolNotExisted)?; // If start_time > time, means epoch 0 + if setting.start_time > time { + return Ok(0); + } let index_bn = time .saturating_sub(setting.start_time) .checked_div(&setting.epoch_range) @@ -493,6 +572,23 @@ pub mod pallet { } } + // Epoch starting from 1 + // The largest epoch index with reward updated before "time" (including epoch during that time) + // return setting.epoch if all epoch reward updated and time >= pool end_time + fn get_epoch_index_with_reward_updated_before( + pool_id: InvestingPoolIndex, + time: BlockNumberFor, + ) -> Result { + let epoch_index: u128 = self::get_epoch_index(pool_id, time)?; + + for i in 1u128..(epoch_index+1u128) { + if >::get(pool_id, i).is_none() { + return Ok(i); + } + } + Ok(epoch_index) + } + // return pool ending time if epoch > setting.epoch // Epoch starting from 1 fn get_epoch_start_time( @@ -555,82 +651,100 @@ pub mod pallet { .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; } else { *maybe_checkpoint = - Some(CANWeightedInfo { effective_time, amount, last_add_time: effective_time }); + Some(InvestingWeightInfo { effective_time, amount, last_add_time: effective_time }); } Ok::<(), DispatchError>(()) })?; } - // No category token effected - fn do_can_claim(who: T::AccountId, asset_id: AssetIdOf, amount: BalanceOf) -> DispatchResult { + // For stable_investing + fn do_stable_add( + pool_id: T::PoolId, + amount: BalanceOf, + effective_time: BlockNumberFor, + ) -> DispatchResult { + >::try_mutate(&pool_id, |maybe_checkpoint| { + if let Some(checkpoint) = maybe_checkpoint { + checkpoint + .add(effective_time, amount) + .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; + } else { + *maybe_checkpoint = + Some(StakingInfo { effective_time, amount, last_add_time: effective_time }); + } + Ok::<(), DispatchError>(()) + })?; + Ok(()) + } + + // Distribute can reward + // No category token destroyed/created + fn do_can_claim(who: T::AccountId, pool_id: InvestingPoolIndex, amount: BalanceOf, start_time: BlockNumberFor, end_time: BlockNumberFor, terminated: bool) -> DispatchResult { let beneficiary_account: T::AccountId = Self::can_token_beneficiary_account(); - let current_block = frame_system::Pallet::::block_number(); let can_asset_id = >::get().ok_or(Error::::NoAssetId)?; // BalanceOf let reward_pool = T::Fungibles::balance(can_asset_id, &beneficiary_account); - let pool_id = InvestingPoolAssetIdGenerator::get_token_pool_index(asset_id); - // Current latest end epoch - let latest_ended_epoch = self::get_epoch_index(pool_id, current_block).checed_sub(1u128).ok_or(ArithmeticError::Overflow)?; - let token_start_epoch = InvestingPoolAssetIdGenerator::get_token_start_epoch(asset_id); + let current_block = frame_system::Pallet::::block_number(); + - if token_start_epoch > latest_ended_epoch { + if start_time > end_time { // Nothing to claim // Do nothing return Ok(()) } else { - // Claim until the latest_ended_epoch - let until_time = get_epoch_end_time(pool_id, latest_ended_epoch); - let claim_duration = until_time - get_epoch_start_time(pool_id, token_start_epoch); - let claim_weight = claim_duration.checked_mul(amount).ok_or(ArithmeticError::Overflow)?; - if let Some(mut ncp) = >::get() { + let mut claim_duration: BlockNumberFor; + if terminated { + // This means the effective investing duration is beyond the pool lifespan + // i.e. users who do not claim reward after the pool end are still considering as in-pool contributing their weights + claim_duration = current_block - start_time; + } else { + // Only counting the investing weight during the epoch + // Claim from start_time until the end_time + claim_duration = end_time - start_time; + } + + let claim_weight = claim_duration.checked_mul(amount).ok_or(ArithmeticError::Overflow)?; let proportion = Perquintill::from_rational( claim_weight, - ncp.weight_force(until_time) + ncp.weight_force(current_block) .ok_or(Error::::TypeIncompatibleOrArithmeticError)?, ); - } - - - - - ... - } - - if let Some(mut ncp) = >::get() { - if let Some(mut user_ncp) = >::get(who.clone()) { - // get weight and update stake info - let user_claimed_weight = user_ncp - .claim(until_time) - .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; - let proportion = Perquintill::from_rational( - user_claimed_weight, - ncp.weight_force(until_time) - .ok_or(Error::::TypeIncompatibleOrArithmeticError)?, - ); - // Do not care what new Synthetic effective_time of investing pool - let _ = ncp - .claim_based_on_weight(user_claimed_weight) - .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; let reward_pool_u128: u128 = reward_pool - .try_into() - .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + .try_into() + .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; let distributed_reward_u128: u128 = proportion * reward_pool_u128; let distributed_reward: BalanceOf = distributed_reward_u128 .try_into() .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; - T::Fungible::transfer( + // Transfer CAN reward + T::Fungibles::transfer( + can_asset_id, &beneficiary_account, &who, distributed_reward, Preservation::Expendable, )?; + + // Update gloabl investing status + if terminated { + let _ = ncp + .remove(start_time, amount) + .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; + } else { + // Do not care what new Synthetic effective_time of investing pool + let _ = ncp + .claim_based_on_weight(claim_weight) + .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; + } + // Adjust checkpoint >::put(ncp); - Self::deposit_event(Event::::NativeRewardClaimed { + Self::deposit_event(Event::::CANRewardClaimed { who, - until_time, + claim_duration, + amount, reward_amount: distributed_reward, }); } @@ -638,18 +752,68 @@ pub mod pallet { Ok(()) } - // Category token effected + // Distribute stable reward + // No category token destroyed/created + // Claim epoch between start_epoch - end_epoch (included) fn do_stable_claim( who: T::AccountId, - asset_id: AssetIdOf, + pool_id: InvestingPoolIndex, amount: BalanceOf, + start_epoch: u128, + end_epoch: u128, ) -> DispatchResult { let current_block = frame_system::Pallet::::block_number(); - ensure!(until_time <= current_block, Error::::CannotClaimFuture); - // BalanceOf - let reward_pool = >::get(pool_id.clone()); + let beneficiary_account: T::AccountId = Self::stable_token_beneficiary_account(); let aiusd_asset_id = >::get().ok_or(Error::::NoAssetId)?; - ???? + + let total_distributed_reward: BalanceOf = Zero::zero(); + + if start_epoch > end_epoch { + // Nothing to claim + // Do nothing + return Ok(()) + } else { + if let Some(mut scp) = >::get(pool_id) { + // Must exist + let total_investing = scp.amount; + // Claim until the claimed_until_epoch + // loop through each epoch + for i in start_epoch..(end_epoch+1) { + let reward_pool = >::get(pool_id, i).ok_or(Error::::EpochRewardNotUpdated)?; + + let proportion = Perquintill::from_rational( + amount, + total_investing, + ); + + let reward_pool_u128: u128 = reward_pool + .try_into() + .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + let distributed_reward_u128: u128 = proportion * reward_pool_u128; + let distributed_reward: BalanceOf = distributed_reward_u128 + .try_into() + .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + total_distributed_reward = total_distributed_reward.checked_add(distributed_reward).ok_or(ArithmeticError::Overflow)?; + + Self::deposit_event(Event::::StableRewardClaimed { + who, + pool_id, + i, + reward_amount: distributed_reward, + }); + } + } + } + + // Stable token reward + // Will fail if insufficient balance + T::Fungibles::transfer( + aiusd_asset_id, + &beneficiary_account, + &who, + total_distributed_reward, + Preservation::Expendable, + )?; Ok(()) } @@ -669,7 +833,7 @@ pub mod pallet { let effective_time = Self::get_epoch_start_time(pool_id, One::one()); let debt_asset_id = InvestingPoolAssetIdGenerator::get_debt_token(pool_id, setting.epoch).ok_or(ArithmeticError::Overflow)?; - let initial_epoch_asset_id = InvestingPoolAssetIdGenerator::get_epoch_token(pool_id, setting.epoch).ok_or(ArithmeticError::Overflow)?; + let initial_epoch_asset_id = InvestingPoolAssetIdGenerator::get_initial_epoch_token(pool_id, setting.epoch).ok_or(ArithmeticError::Overflow)?; for i in investments.iter() { // Mint certification token to user let _ = T::Fungibles::mint_into( @@ -685,8 +849,8 @@ pub mod pallet { )?; // Add CAN token global checkpoint - Self::do_can_add(i.1, effective_time) - + Self::do_can_add(i.1, effective_time)?; + Self::do_stable_add(pool_id, i.1, effective_time) } } } diff --git a/parachain/pallets/collab-ai/investing-pool/src/test.rs b/parachain/pallets/collab-ai/investing-pool/src/test.rs index 447aa80271..1236817d26 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/test.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/test.rs @@ -176,12 +176,12 @@ fn stake_successful_and_failed() { let global_investing_info = InvestingPool::native_checkpoint().unwrap(); assert_eq!( global_investing_info, - CANWeightedInfo { effective_time: 301u64, amount: 2000u64, last_add_time: 301u64 } + InvestingWeightInfo { effective_time: 301u64, amount: 2000u64, last_add_time: 301u64 } ); let user_a_investing_info = InvestingPool::user_native_checkpoint(USER_A).unwrap(); assert_eq!( user_a_investing_info, - CANWeightedInfo { effective_time: 301u64, amount: 2000u64, last_add_time: 301u64 } + InvestingWeightInfo { effective_time: 301u64, amount: 2000u64, last_add_time: 301u64 } ); let pending_set_up = InvestingPool::pending_setup(); assert_eq!(pending_set_up.len(), 1); @@ -191,10 +191,10 @@ fn stake_successful_and_failed() { // investing reward assert_eq!( *pending_set_up_element, - CANWeightedInfoWithOwner { + InvestingWeightInfoWithOwner { who: USER_A, pool_id: 1u128, - investing_info: CANWeightedInfo { + investing_info: InvestingWeightInfo { effective_time: 600u64, amount: 2000u64, last_add_time: 600u64 @@ -219,19 +219,19 @@ fn stake_successful_and_failed() { // Synthetic (301, 2000), (411, 1000) = (337.6666, 3000) assert_eq!( global_investing_info, - CANWeightedInfo { effective_time: 337u64, amount: 3000u64, last_add_time: 411u64 } + InvestingWeightInfo { effective_time: 337u64, amount: 3000u64, last_add_time: 411u64 } ); // user a unchanged let user_a_investing_info = InvestingPool::user_native_checkpoint(USER_A).unwrap(); assert_eq!( user_a_investing_info, - CANWeightedInfo { effective_time: 301u64, amount: 2000u64, last_add_time: 301u64 } + InvestingWeightInfo { effective_time: 301u64, amount: 2000u64, last_add_time: 301u64 } ); // user b let user_b_investing_info = InvestingPool::user_native_checkpoint(USER_B).unwrap(); assert_eq!( user_b_investing_info, - CANWeightedInfo { effective_time: 411u64, amount: 1000u64, last_add_time: 411u64 } + InvestingWeightInfo { effective_time: 411u64, amount: 1000u64, last_add_time: 411u64 } ); // Pending set up storage change let pending_set_up = InvestingPool::pending_setup(); @@ -244,10 +244,10 @@ fn stake_successful_and_failed() { // investing reward assert_eq!( *pending_set_up_element, - CANWeightedInfoWithOwner { + InvestingWeightInfoWithOwner { who: USER_B, pool_id: 1u128, - investing_info: CANWeightedInfo { + investing_info: InvestingWeightInfo { effective_time: 700u64, amount: 1000u64, last_add_time: 700u64 @@ -305,13 +305,13 @@ fn solve_pending_stake_and_hook_works() { let global_investing_info = InvestingPool::stable_investing_pool_checkpoint(1u128).unwrap(); assert_eq!( global_investing_info, - CANWeightedInfo { effective_time: 600u64, amount: 2000u64, last_add_time: 600u64 } + InvestingWeightInfo { effective_time: 600u64, amount: 2000u64, last_add_time: 600u64 } ); let user_a_investing_info = InvestingPool::user_stable_investing_pool_checkpoint(USER_A, 1u128).unwrap(); assert_eq!( user_a_investing_info, - CANWeightedInfo { effective_time: 600u64, amount: 2000u64, last_add_time: 600u64 } + InvestingWeightInfo { effective_time: 600u64, amount: 2000u64, last_add_time: 600u64 } ); // Second user B stake @@ -331,7 +331,7 @@ fn solve_pending_stake_and_hook_works() { let global_investing_info = InvestingPool::stable_investing_pool_checkpoint(1u128).unwrap(); assert_eq!( global_investing_info, - CANWeightedInfo { effective_time: 600u64, amount: 2000u64, last_add_time: 600u64 } + InvestingWeightInfo { effective_time: 600u64, amount: 2000u64, last_add_time: 600u64 } ); // User b investing is still none assert!(InvestingPool::user_stable_investing_pool_checkpoint(USER_B, 1u128).is_none()); @@ -354,14 +354,14 @@ fn solve_pending_stake_and_hook_works() { // The effective time is delayed accordingly assert_eq!( user_b_investing_info, - CANWeightedInfo { effective_time: 910u64, amount: 1000u64, last_add_time: 910u64 } + InvestingWeightInfo { effective_time: 910u64, amount: 1000u64, last_add_time: 910u64 } ); // Global investing check // (600, 2000), (910, 1000) -> (703.333, 3000) let global_investing_info = InvestingPool::stable_investing_pool_checkpoint(1u128).unwrap(); assert_eq!( global_investing_info, - CANWeightedInfo { effective_time: 703u64, amount: 3000u64, last_add_time: 910u64 } + InvestingWeightInfo { effective_time: 703u64, amount: 3000u64, last_add_time: 910u64 } ); }) } @@ -424,19 +424,19 @@ fn claim_native_successful_and_failed() { let user_a_investing_info = InvestingPool::user_native_checkpoint(USER_A).unwrap(); assert_eq!( user_a_investing_info, - CANWeightedInfo { effective_time: 501u64, amount: 4000u64, last_add_time: 401u64 } + InvestingWeightInfo { effective_time: 501u64, amount: 4000u64, last_add_time: 401u64 } ); // check global let global_investing_info = InvestingPool::native_checkpoint().unwrap(); assert_eq!( global_investing_info, - CANWeightedInfo { effective_time: 481u64, amount: 5000u64, last_add_time: 401u64 } + InvestingWeightInfo { effective_time: 481u64, amount: 5000u64, last_add_time: 401u64 } ); // Can not claim future assert_noop!( InvestingPool::claim_native(RuntimeOrigin::signed(USER_A), 602u64), - Error::::CannotClaimFuture + Error::::EpochRewardNotUpdated ); }) } @@ -496,13 +496,13 @@ fn claim_stable_successful_and_failed() { InvestingPool::user_stable_investing_pool_checkpoint(USER_A, 1u128).unwrap(); assert_eq!( user_a_investing_info, - CANWeightedInfo { effective_time: 650u64, amount: 2000u64, last_add_time: 600u64 } + InvestingWeightInfo { effective_time: 650u64, amount: 2000u64, last_add_time: 600u64 } ); // check global let global_investing_info = InvestingPool::stable_investing_pool_checkpoint(1u128).unwrap(); assert_eq!( global_investing_info, - CANWeightedInfo { effective_time: 650u64, amount: 2000u64, last_add_time: 600u64 } + InvestingWeightInfo { effective_time: 650u64, amount: 2000u64, last_add_time: 600u64 } ); fast_forward_to(710u64); @@ -540,13 +540,13 @@ fn claim_stable_successful_and_failed() { InvestingPool::user_stable_investing_pool_checkpoint(USER_A, 1u128).unwrap(); assert_eq!( user_a_investing_info, - CANWeightedInfo { effective_time: 750u64, amount: 4000u64, last_add_time: 700u64 } + InvestingWeightInfo { effective_time: 750u64, amount: 4000u64, last_add_time: 700u64 } ); // check global let global_investing_info = InvestingPool::stable_investing_pool_checkpoint(1u128).unwrap(); assert_eq!( global_investing_info, - CANWeightedInfo { effective_time: 740u64, amount: 5000u64, last_add_time: 700u64 } + InvestingWeightInfo { effective_time: 740u64, amount: 5000u64, last_add_time: 700u64 } ); }) } From 9e801f0b4ba93b173c9da5cd633990d0ef1be083 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 31 Oct 2024 13:48:06 +0800 Subject: [PATCH 116/215] chore: remove invalid test --- .../collab-ai/investing-pool/src/lib.rs | 6 - .../collab-ai/investing-pool/src/mock.rs | 191 ------ .../collab-ai/investing-pool/src/test.rs | 580 ------------------ 3 files changed, 777 deletions(-) delete mode 100644 parachain/pallets/collab-ai/investing-pool/src/mock.rs delete mode 100644 parachain/pallets/collab-ai/investing-pool/src/test.rs diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index 32369eb592..d3147bf6cf 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -40,12 +40,6 @@ use sp_std::{collections::vec_deque::VecDeque, fmt::Debug, prelude::*}; use pallet_collab_ai_common::*; -#[cfg(test)] -mod mock; - -#[cfg(test)] -mod tests; - #[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] pub struct InvestingWeightInfo { // For a single position or diff --git a/parachain/pallets/collab-ai/investing-pool/src/mock.rs b/parachain/pallets/collab-ai/investing-pool/src/mock.rs deleted file mode 100644 index d7ec1d8481..0000000000 --- a/parachain/pallets/collab-ai/investing-pool/src/mock.rs +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright 2020-2024 Trust Computing GmbH. -// This file is part of Litentry. -// -// Litentry is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Litentry is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Litentry. If not, see . - -use crate::{self as pallet_investing_pool}; -use frame_support::{ - assert_ok, derive_impl, ord_parameter_types, parameter_types, - traits::{AsEnsureOriginWithArg, ConstU32, ConstU64}, - PalletId, -}; -use frame_system::EnsureRoot; -use pallet_investing_pool::PoolSetting; -use sp_core::{ConstU16, H256}; -use sp_runtime::{ - traits::{AccountIdConversion, BlakeTwo256, IdentityLookup}, - BuildStorage, -}; - -type AccountId = u64; -type Block = frame_system::mocking::MockBlock; - -type Balance = u64; -/// Pool id -pub type PoolId = u128; -// Configure a mock runtime to test the pallet. -frame_support::construct_runtime!( - pub enum Test - { - System: frame_system, - Balances: pallet_balances, - Assets: pallet_assets, - InvestingPool: pallet_investing_pool, - } -); - -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] -impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = ConstU16<42>; - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -ord_parameter_types! { - pub const One: u64 = 1; -} - -impl pallet_balances::Config for Test { - type Balance = Balance; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ConstU64<1>; - type AccountStore = System; - type WeightInfo = (); - type MaxLocks = ConstU32<100>; - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type FreezeIdentifier = (); - type MaxHolds = (); - type MaxFreezes = (); - type RuntimeHoldReason = (); - type RuntimeFreezeReason = (); -} - -impl pallet_assets::Config for Test { - type RuntimeEvent = RuntimeEvent; - type Balance = Balance; - type AssetId = u32; - type AssetIdParameter = u32; - type Currency = Balances; - type CreateOrigin = AsEnsureOriginWithArg>; - type ForceOrigin = frame_system::EnsureRoot; - type AssetDeposit = ConstU64<1>; - type AssetAccountDeposit = ConstU64<10>; - type MetadataDepositBase = ConstU64<1>; - type MetadataDepositPerByte = ConstU64<1>; - type ApprovalDeposit = ConstU64<1>; - type StringLimit = ConstU32<50>; - type Freezer = (); - type WeightInfo = (); - type CallbackHandle = (); - type Extra = (); - type RemoveItemsLimit = ConstU32<5>; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); -} - -parameter_types! { - pub const InvestingPoolId: PalletId = PalletId(*b"can/stpl"); - pub const HavlingMintId: PalletId = PalletId(*b"can/hlvm"); -} - -impl pallet_investing_pool::Config for Test { - type RuntimeEvent = RuntimeEvent; - type InvestingPoolCommitteeOrigin = EnsureRoot; - type PoolId = PoolId; - type Fungibles = Assets; - type Fungible = Balances; - type StableTokenBeneficiaryId = InvestingPoolId; - type CANBeneficiaryId = HavlingMintId; - type PoolStringLimit = ConstU32<100>; -} - -pub const ENDOWED_BALANCE: u64 = 100_000_000; -pub const USER_A: AccountId = 0x2; -pub const USER_B: AccountId = 0x3; -pub const USER_C: AccountId = 0x4; - -pub fn new_test_ext() -> sp_io::TestExternalities { - let native_token_pool: u64 = HavlingMintId::get().into_account_truncating(); - let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - pallet_balances::GenesisConfig:: { - balances: vec![ - (native_token_pool, ENDOWED_BALANCE), - (USER_A, ENDOWED_BALANCE), - (USER_B, ENDOWED_BALANCE), - (USER_C, ENDOWED_BALANCE), - ], - } - .assimilate_storage(&mut t) - .unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| { - frame_system::Pallet::::set_block_number(1); - - // Regist AIUSD - // asset_id = 1, admin = USER_A - assert_ok!(Assets::create(RuntimeOrigin::signed(USER_A), 1u32, USER_A, 1)); - assert_ok!(Assets::mint(RuntimeOrigin::signed(USER_A), 1u32, USER_A, ENDOWED_BALANCE)); - assert_ok!(Assets::mint(RuntimeOrigin::signed(USER_A), 1u32, USER_B, ENDOWED_BALANCE)); - assert_ok!(Assets::mint(RuntimeOrigin::signed(USER_A), 1u32, USER_C, ENDOWED_BALANCE)); - // Setup stable investing pallet - assert_ok!(InvestingPool::regist_aiusd(RuntimeOrigin::root(), 1u32)); - assert_eq!(InvestingPool::aiusd_asset_id(), Some(1u32)); - // Create stable investing pool - let pool_setup: PoolSetting = PoolSetting { - start_time: 100u64, - epoch: 10u128, - epoch_range: 100u64, - setup_time: 200u64, - pool_cap: 50_000_000u64, - }; - assert_ok!(InvestingPool::create_investing_pool(RuntimeOrigin::root(), 1u128, pool_setup)); - }); - ext -} - -// Checks events against the latest. A contiguous set of events must be provided. They must -// include the most recent event, but do not have to include every past event. -pub fn assert_events(mut expected: Vec) { - let mut actual: Vec = - frame_system::Pallet::::events().iter().map(|e| e.event.clone()).collect(); - - expected.reverse(); - - for evt in expected { - let next = actual.pop().expect("event expected"); - assert_eq!(next, evt, "Events don't match"); - } -} \ No newline at end of file diff --git a/parachain/pallets/collab-ai/investing-pool/src/test.rs b/parachain/pallets/collab-ai/investing-pool/src/test.rs deleted file mode 100644 index 1236817d26..0000000000 --- a/parachain/pallets/collab-ai/investing-pool/src/test.rs +++ /dev/null @@ -1,580 +0,0 @@ -use super::{ - mock::{ - assert_events, new_test_ext, Assets, Balances, HavlingMintId, RuntimeEvent, RuntimeOrigin, - InvestingPool, InvestingPoolId, System, Test, ENDOWED_BALANCE, USER_A, USER_B, USER_C, - }, - *, -}; -use frame_support::{assert_noop, assert_ok}; - -fn next_block() { - System::set_block_number(System::block_number() + 1); - InvestingPool::begin_block(System::block_number()); -} - -fn fast_forward_to(n: u64) { - while System::block_number() < n { - next_block(); - } -} - -#[test] -fn can_not_create_pool_already_started_or_existed() { - new_test_ext().execute_with(|| { - // Create stable investing pool - let pool_setup: PoolSetting = PoolSetting { - start_time: 100u64, - epoch: 10u128, - epoch_range: 100u64, - setup_time: 200u64, - pool_cap: 1_000_000_000u64, - }; - assert_noop!( - InvestingPool::create_investing_pool(RuntimeOrigin::root(), 1u128, pool_setup.clone()), - Error::::PoolAlreadyExisted - ); - // Transfer and check result - fast_forward_to(101); - assert_noop!( - InvestingPool::create_investing_pool(RuntimeOrigin::root(), 2u128, pool_setup.clone()), - Error::::PoolAlreadyStarted - ); - // Create another pool is fine - let another_pool_setup: PoolSetting = PoolSetting { - start_time: 150u64, - epoch: 10u128, - epoch_range: 100u64, - setup_time: 200u64, - pool_cap: 1_000_000_000u64, - }; - assert_ok!(InvestingPool::create_investing_pool( - RuntimeOrigin::root(), - 2u128, - another_pool_setup - )); - assert_events(vec![RuntimeEvent::InvestingPool(Event::InvestingPoolCreated { - pool_id: 2u128, - start_time: 150u64, - epoch: 10u128, - epoch_range: 100u64, - setup_time: 200u64, - pool_cap: 1_000_000_000u64, - })]); - }) -} - -// TODO: update_metadata test -// Currently metadata does nothing but description - -#[test] -fn update_reward_successful_and_failed() { - new_test_ext().execute_with(|| { - let stable_token_pool: u64 = InvestingPoolId::get().into_account_truncating(); - - // update epoch 0 reward with amount of 2000 - assert_ok!(InvestingPool::update_reward(RuntimeOrigin::root(), 1u128, 0u128, 2000u64)); - assert_events(vec![RuntimeEvent::InvestingPool(Event::RewardUpdated { - pool_id: 1u128, - epoch: 0u128, - amount: 2000u64, - })]); - // Investing pool reward storage efffective - assert_eq!(InvestingPool::stable_investing_pool_reward(1u128), 2000u64); - assert_eq!(InvestingPool::stable_investing_pool_epoch_reward(1u128, 0u128), Some(2000u64)); - assert_eq!(InvestingPool::stable_investing_pool_epoch_reward(1u128, 1u128), None); - // Investing pool balance effective - assert_eq!(Assets::balance(1u32, stable_token_pool), 2000u64); - - // Can not update epoch reward twice - assert_noop!( - InvestingPool::update_reward(RuntimeOrigin::root(), 1u128, 0u128, 1000u64), - Error::::RewardAlreadyExisted - ); - - // Pool started at 100, epoch range = 100, epoch = 10 - // So Blocknumber 301 => Epoch 2 started/Epoch 1 ended - System::set_block_number(301u64); - // Can not update epoch already ended - assert_noop!( - InvestingPool::update_reward(RuntimeOrigin::root(), 1u128, 1u128, 1000u64), - Error::::EpochAlreadyEnded - ); - - // Epoch reward can not be updated to non-existing pool - assert_noop!( - InvestingPool::update_reward(RuntimeOrigin::root(), 9999u128, 1u128, 1000u64), - Error::::PoolNotExisted - ); - // Epoch reward can not be updated to epoch index not existing - assert_noop!( - InvestingPool::update_reward(RuntimeOrigin::root(), 1u128, 11u128, 1000u64), - Error::::EpochNotExist - ); - - // Epoch reward update for "last epoch" (pool end time's next epoch) always success - // Pool epoch = 10 - System::set_block_number(9999999u64); - assert_ok!(InvestingPool::update_reward(RuntimeOrigin::root(), 1u128, 10u128, 2000u64)); - assert_events(vec![RuntimeEvent::InvestingPool(Event::RewardUpdated { - pool_id: 1u128, - epoch: 10u128, - amount: 2000u64, - })]); - - // Can not update reward if no AIUSD registed - System::set_block_number(301u64); - >::kill(); - assert_noop!( - InvestingPool::update_reward(RuntimeOrigin::root(), 1u128, 5u128, 2000u64), - Error::::NoAssetId - ); - }) -} - -#[test] -fn stake_successful_and_failed() { - new_test_ext().execute_with(|| { - let stable_token_pool: u64 = InvestingPoolId::get().into_account_truncating(); - - // Can not stake non-exist pool - assert_noop!( - InvestingPool::stake(RuntimeOrigin::signed(USER_A), 2u128, 2000u64), - Error::::PoolNotExisted - ); - - // Can not stake non-started pool - assert_noop!( - InvestingPool::stake(RuntimeOrigin::signed(USER_A), 1u128, 2000u64), - Error::::PoolNotStarted - ); - - // Can not stake ended pool - System::set_block_number(9999999u64); - assert_noop!( - InvestingPool::stake(RuntimeOrigin::signed(USER_A), 1u128, 2000u64), - Error::::PoolAlreadyEnded - ); - - // Success, check user/global native checkpoint storage - // check pending set up storage - System::set_block_number(301u64); - // Can not stake oversized - assert_noop!( - InvestingPool::stake(RuntimeOrigin::signed(USER_A), 1u128, 50_000_001u64), - Error::::PoolCapLimit - ); - - assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_A), 1u128, 2000u64)); - assert_events(vec![RuntimeEvent::InvestingPool(Event::Staked { - who: USER_A, - pool_id: 1u128, - target_effective_time: 600u64, - amount: 2000u64, - })]); - assert_eq!(Assets::balance(1u32, USER_A), ENDOWED_BALANCE - 2000u64); - assert_eq!(Assets::balance(1u32, stable_token_pool), 2000u64); - let global_investing_info = InvestingPool::native_checkpoint().unwrap(); - assert_eq!( - global_investing_info, - InvestingWeightInfo { effective_time: 301u64, amount: 2000u64, last_add_time: 301u64 } - ); - let user_a_investing_info = InvestingPool::user_native_checkpoint(USER_A).unwrap(); - assert_eq!( - user_a_investing_info, - InvestingWeightInfo { effective_time: 301u64, amount: 2000u64, last_add_time: 301u64 } - ); - let pending_set_up = InvestingPool::pending_setup(); - assert_eq!(pending_set_up.len(), 1); - let pending_set_up_element = pending_set_up.get(0).unwrap(); - // Pool set up time = 200 - // So user enter at 301 need to wait till 600 to make it effective and receiving Stable - // investing reward - assert_eq!( - *pending_set_up_element, - InvestingWeightInfoWithOwner { - who: USER_A, - pool_id: 1u128, - investing_info: InvestingWeightInfo { - effective_time: 600u64, - amount: 2000u64, - last_add_time: 600u64 - } - } - ); - - // Second user B stake - System::set_block_number(399u64); - fast_forward_to(411u64); - assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_B), 1u128, 1000u64)); - assert_events(vec![RuntimeEvent::InvestingPool(Event::Staked { - who: USER_B, - pool_id: 1u128, - target_effective_time: 700u64, - amount: 1000u64, - })]); - - assert_eq!(Assets::balance(1u32, USER_B), ENDOWED_BALANCE - 1000u64); - assert_eq!(Assets::balance(1u32, stable_token_pool), 2000u64 + 1000u64); - let global_investing_info = InvestingPool::native_checkpoint().unwrap(); - // Synthetic (301, 2000), (411, 1000) = (337.6666, 3000) - assert_eq!( - global_investing_info, - InvestingWeightInfo { effective_time: 337u64, amount: 3000u64, last_add_time: 411u64 } - ); - // user a unchanged - let user_a_investing_info = InvestingPool::user_native_checkpoint(USER_A).unwrap(); - assert_eq!( - user_a_investing_info, - InvestingWeightInfo { effective_time: 301u64, amount: 2000u64, last_add_time: 301u64 } - ); - // user b - let user_b_investing_info = InvestingPool::user_native_checkpoint(USER_B).unwrap(); - assert_eq!( - user_b_investing_info, - InvestingWeightInfo { effective_time: 411u64, amount: 1000u64, last_add_time: 411u64 } - ); - // Pending set up storage change - let pending_set_up = InvestingPool::pending_setup(); - assert_eq!(pending_set_up.len(), 2); - // pending set up is ordered by effective time, so user_b's request is at index 1 while - // user_a is at index 0 - let pending_set_up_element = pending_set_up.get(1).unwrap(); - // Pool set up time = 200 - // So user enter at 411 need to wait till 700 to make it effective and receiving Stable - // investing reward - assert_eq!( - *pending_set_up_element, - InvestingWeightInfoWithOwner { - who: USER_B, - pool_id: 1u128, - investing_info: InvestingWeightInfo { - effective_time: 700u64, - amount: 1000u64, - last_add_time: 700u64 - } - } - ); - - // Can not stake if no AIUSD registed - >::kill(); - assert_noop!( - InvestingPool::stake(RuntimeOrigin::signed(USER_C), 1u128, 3000u64), - Error::::NoAssetId - ); - assert_ok!(InvestingPool::regist_aiusd(RuntimeOrigin::root(), 1u32)); - - // Can not stake oversized - assert_noop!( - InvestingPool::stake( - RuntimeOrigin::signed(USER_A), - 1u128, - 50_000_001u64 - 2000u64 - 1000u64 - ), - Error::::PoolCapLimit - ); - assert_ok!(InvestingPool::stake( - RuntimeOrigin::signed(USER_A), - 1u128, - 50_000_000u64 - 2000u64 - 1000u64 - )); - }) -} - -#[test] -fn solve_pending_stake_and_hook_works() { - new_test_ext().execute_with(|| { - // Success, check user/global native checkpoint storage - // check pending set up storage - System::set_block_number(301u64); - assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_A), 1u128, 2000u64)); - // Pool set up time = 200 - // So user enter at 301 need to wait till 600 to make it effective and receiving Stable - System::set_block_number(590u64); - // Try trigger hook - fast_forward_to(610u64); - assert_events(vec![RuntimeEvent::InvestingPool(Event::PendingInvestingSolved { - who: USER_A, - pool_id: 1u128, - effective_time: 600u64, - amount: 2000u64, - })]); - // No more pending - let pending_set_up = InvestingPool::pending_setup(); - assert_eq!(pending_set_up.len(), 0); - // Check stable investing checkpoint - let global_investing_info = InvestingPool::stable_investing_pool_checkpoint(1u128).unwrap(); - assert_eq!( - global_investing_info, - InvestingWeightInfo { effective_time: 600u64, amount: 2000u64, last_add_time: 600u64 } - ); - let user_a_investing_info = - InvestingPool::user_stable_investing_pool_checkpoint(USER_A, 1u128).unwrap(); - assert_eq!( - user_a_investing_info, - InvestingWeightInfo { effective_time: 600u64, amount: 2000u64, last_add_time: 600u64 } - ); - - // Second user B stake - assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_B), 1u128, 1000u64)); - // Any one can trigger manual, but right now no effect - let pending_set_up = InvestingPool::pending_setup(); - assert_eq!(pending_set_up.len(), 1); - assert_ok!(InvestingPool::solve_pending_stake(RuntimeOrigin::signed(USER_C))); - let pending_set_up = InvestingPool::pending_setup(); - assert_eq!(pending_set_up.len(), 1); - - // Pool set up time = 200, current block = 610 - // So user enter at 301 need to wait till 900 to make it effective and receiving Stable - // set block number without triggering hook - System::set_block_number(910u64); - // Global investing no changed - let global_investing_info = InvestingPool::stable_investing_pool_checkpoint(1u128).unwrap(); - assert_eq!( - global_investing_info, - InvestingWeightInfo { effective_time: 600u64, amount: 2000u64, last_add_time: 600u64 } - ); - // User b investing is still none - assert!(InvestingPool::user_stable_investing_pool_checkpoint(USER_B, 1u128).is_none()); - - // Any one can trigger manual - // But effective time will be the time when triggered, which is 910 - assert_ok!(InvestingPool::solve_pending_stake(RuntimeOrigin::signed(USER_C))); - assert_events(vec![RuntimeEvent::InvestingPool(Event::PendingInvestingSolved { - who: USER_B, - pool_id: 1u128, - effective_time: 910u64, - amount: 1000u64, - })]); - let pending_set_up = InvestingPool::pending_setup(); - // Pending solved - assert_eq!(pending_set_up.len(), 0); - // User B stable investing checkpoint updated - let user_b_investing_info = - InvestingPool::user_stable_investing_pool_checkpoint(USER_B, 1u128).unwrap(); - // The effective time is delayed accordingly - assert_eq!( - user_b_investing_info, - InvestingWeightInfo { effective_time: 910u64, amount: 1000u64, last_add_time: 910u64 } - ); - // Global investing check - // (600, 2000), (910, 1000) -> (703.333, 3000) - let global_investing_info = InvestingPool::stable_investing_pool_checkpoint(1u128).unwrap(); - assert_eq!( - global_investing_info, - InvestingWeightInfo { effective_time: 703u64, amount: 3000u64, last_add_time: 910u64 } - ); - }) -} - -#[test] -fn claim_native_successful_and_failed() { - new_test_ext().execute_with(|| { - let native_token_pool: u64 = HavlingMintId::get().into_account_truncating(); - - System::set_block_number(301u64); - assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_A), 1u128, 2000u64)); - System::set_block_number(401u64); - assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_A), 1u128, 2000u64)); - assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_B), 1u128, 1000u64)); - // at block 401: - // User_A : (351, 4000) with last_add_time = 401 - // User_B : (401, 1000) with last_add_time = 401 - // Global : (361 ,5000) with last_add_time = 401 - - // Just for convenience, suppose there are already 100 times ENDOWED_BALANCE native token - // reward - assert_eq!( - Balances::set_balance(&native_token_pool, 100 * ENDOWED_BALANCE), - 100 * ENDOWED_BALANCE - ); - - System::set_block_number(601u64); - // User_a try claim before 401, failed since it is not allowed to claim before last_add_time - // TODO:: TypeIncompatibleOrArithmeticError is not specific enough - assert_noop!( - InvestingPool::claim_native(RuntimeOrigin::signed(USER_A), 400u64), - Error::::TypeIncompatibleOrArithmeticError - ); - - // A normal claim until 501 at time 601 - assert_ok!(InvestingPool::claim_native(RuntimeOrigin::signed(USER_A), 501u64)); - // total weight = 5000 * (501 - 361) = 700,000 - // claim weight = 4000 * (501 - 351) = 600,000 - // reward = 100 * ENDOWED_BALANCE * claim weight / total weight - // 8571428571.428 - assert_events(vec![ - RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: native_token_pool, - to: USER_A, - amount: 8_571_428_571u64, - }), - RuntimeEvent::InvestingPool(Event::NativeRewardClaimed { - who: USER_A, - until_time: 501u64, - reward_amount: 8_571_428_571u64, - }), - ]); - // After claim - // User_A : (501, 4000) with last_add_time = 401 - // User_B : (401, 1000) with last_add_time = 401 - // Global : weight before = (501 - 361) * 5000 = 700,000 - // Global : weight after = 700,000 - 600,000 = 100,000 - // Global : synthetic (501 - (100,000 / 5000), 5000) = (481, 5000) - // check user a - let user_a_investing_info = InvestingPool::user_native_checkpoint(USER_A).unwrap(); - assert_eq!( - user_a_investing_info, - InvestingWeightInfo { effective_time: 501u64, amount: 4000u64, last_add_time: 401u64 } - ); - // check global - let global_investing_info = InvestingPool::native_checkpoint().unwrap(); - assert_eq!( - global_investing_info, - InvestingWeightInfo { effective_time: 481u64, amount: 5000u64, last_add_time: 401u64 } - ); - - // Can not claim future - assert_noop!( - InvestingPool::claim_native(RuntimeOrigin::signed(USER_A), 602u64), - Error::::EpochRewardNotUpdated - ); - }) -} - -#[test] -fn claim_stable_successful_and_failed() { - new_test_ext().execute_with(|| { - let stable_token_pool: u64 = InvestingPoolId::get().into_account_truncating(); - - System::set_block_number(301u64); - // effective time = 600 - assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_A), 1u128, 2000u64)); - System::set_block_number(401u64); - // effective time = 700 - assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_A), 1u128, 2000u64)); - assert_ok!(InvestingPool::stake(RuntimeOrigin::signed(USER_B), 1u128, 1000u64)); - - // triggering pending by hook - System::set_block_number(599u64); - fast_forward_to(610u64); - - // Notice: Can not update reward if EpochAlreadyEnded - // Pool: start_time: 100u64, - // epoch: 10u128, - // epoch_range: 100u64, - // setup_time: 200u64, - // 610 => current epoch 5 - let stable_token_pool_balance = Assets::balance(1u32, stable_token_pool); - assert_ok!(InvestingPool::update_reward(RuntimeOrigin::root(), 1u128, 5u128, 2000u64)); - assert_eq!(Assets::balance(1u32, stable_token_pool), stable_token_pool_balance + 2000u64); - - // Only user a yet, claiming from 600 to 650 - // Stable investing - // User_A : (600, 2000) with last_add_time = 600 - // Global : (600 ,2000) with last_add_time = 600 - // claimed weight: 100% out of total! - System::set_block_number(699u64); - assert_ok!(InvestingPool::claim_stable(RuntimeOrigin::signed(USER_A), 1u128, 650u64)); - assert_eq!(Assets::balance(1u32, stable_token_pool), stable_token_pool_balance); - assert_events(vec![ - RuntimeEvent::Assets(pallet_assets::Event::Transferred { - asset_id: 1u32, - from: stable_token_pool, - to: USER_A, - amount: 2000u64, - }), - RuntimeEvent::InvestingPool(Event::StableRewardClaimed { - who: USER_A, - pool_id: 1u128, - until_time: 650u64, - reward_amount: 2000u64, - }), - ]); - // Check stable investing checkpoint storage - // check user - let user_a_investing_info = - InvestingPool::user_stable_investing_pool_checkpoint(USER_A, 1u128).unwrap(); - assert_eq!( - user_a_investing_info, - InvestingWeightInfo { effective_time: 650u64, amount: 2000u64, last_add_time: 600u64 } - ); - // check global - let global_investing_info = InvestingPool::stable_investing_pool_checkpoint(1u128).unwrap(); - assert_eq!( - global_investing_info, - InvestingWeightInfo { effective_time: 650u64, amount: 2000u64, last_add_time: 600u64 } - ); - - fast_forward_to(710u64); - // 710 => current epoch 6 - assert_ok!(InvestingPool::update_reward(RuntimeOrigin::root(), 1u128, 6u128, 4000u64)); - assert_eq!(Assets::balance(1u32, stable_token_pool), stable_token_pool_balance + 4000u64); - System::set_block_number(799u64); - // Stable investing - // User_A : (650, 2000) + (700, 2000) = (675, 4000) with last_add_time = 700 - // User_B : (700, 1000) with last_add_time = 700 - // Global : (650, 2000) + (700, 2000) + (700, 1000) = (680, 5000) with last_add_time = 600 - // Claimed weight: (750 - 675) * 4000 = 300_000 - // Total weight: (750 - 680) * 5000 = 350_000 - // claimed reward = 4000 * 300_000 / 350_000 = 3428.571 - assert_ok!(InvestingPool::claim_stable(RuntimeOrigin::signed(USER_A), 1u128, 750u64)); - - assert_events(vec![ - RuntimeEvent::Assets(pallet_assets::Event::Transferred { - asset_id: 1u32, - from: stable_token_pool, - to: USER_A, - amount: 3429u64, - }), - RuntimeEvent::InvestingPool(Event::StableRewardClaimed { - who: USER_A, - pool_id: 1u128, - until_time: 750u64, - reward_amount: 3429u64, - }), - ]); - - // Check stable investing checkpoint storage - // check user - let user_a_investing_info = - InvestingPool::user_stable_investing_pool_checkpoint(USER_A, 1u128).unwrap(); - assert_eq!( - user_a_investing_info, - InvestingWeightInfo { effective_time: 750u64, amount: 4000u64, last_add_time: 700u64 } - ); - // check global - let global_investing_info = InvestingPool::stable_investing_pool_checkpoint(1u128).unwrap(); - assert_eq!( - global_investing_info, - InvestingWeightInfo { effective_time: 740u64, amount: 5000u64, last_add_time: 700u64 } - ); - }) -} - -#[test] -fn withdraw_works() { - new_test_ext().execute_with(|| {}) -} - -#[test] -fn regist_aiusd_works() { - new_test_ext().execute_with(|| {}) -} - -#[test] -fn get_epoch_index() { - new_test_ext().execute_with(|| {}) -} - -#[test] -fn get_epoch_begin_time() { - new_test_ext().execute_with(|| {}) -} - -// pending swap storage does get a proper order for multiple pools and can handle multiple pending -// orders double add at same time behavior of (native) stable checkpoint -// if user does not claim reward, and reward update is percentage fair, user is impact -// if user does not claim reward, and reward update is percentage improved in future, user is -// benefited if user does not claim reward, and reward update is percentage downgraded in future, -// user is harmed claim reward behavior of native and stable checkpoint -// withdraw behavior of native and stable checkingpoint \ No newline at end of file From ef4e66120709f3435c59e7b3fcfadb42811bd85a Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 31 Oct 2024 13:52:59 +0800 Subject: [PATCH 117/215] chore: temp update --- parachain/Cargo.lock | 19 ++ parachain/Cargo.toml | 2 + .../collab-ai/investing-pool/Cargo.toml | 20 +- .../collab-ai/investing-pool/src/lib.rs | 205 ++++++++++-------- 4 files changed, 142 insertions(+), 104 deletions(-) diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index b3a93c4fa6..af81a81045 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -7804,6 +7804,25 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-investing-pool" +version = "0.1.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-assets", + "pallet-balances", + "pallet-collab-ai-common", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-membership" version = "4.0.0-dev" diff --git a/parachain/Cargo.toml b/parachain/Cargo.toml index a0c0f4af33..1a819bde5f 100644 --- a/parachain/Cargo.toml +++ b/parachain/Cargo.toml @@ -13,6 +13,7 @@ members = [ 'pallets/collab-ai/curator', 'pallets/collab-ai/guardian', 'pallets/collab-ai/pool-proposal', + 'pallets/collab-ai/investing-pool', 'pallets/extrinsic-filter', 'pallets/evm-address', 'pallets/evm-assertions', @@ -295,6 +296,7 @@ pallet-collab-ai-common = { path = "pallets/collab-ai/common", default-features pallet-curator = { path = "pallets/collab-ai/curator", default-features = false } pallet-guardian = { path = "pallets/collab-ai/guardian", default-features = false } pallet-pool-proposal = { path = "pallets/collab-ai/pool-proposal", default-features = false } +pallet-investing-pool = { path = "pallets/collab-ai/investing-pool", default-features = false } [patch.crates-io] ring = { git = "https://github.com/betrusted-io/ring-xous", branch = "0.16.20-cleanup" } diff --git a/parachain/pallets/collab-ai/investing-pool/Cargo.toml b/parachain/pallets/collab-ai/investing-pool/Cargo.toml index 0014785cf4..88929fe13f 100644 --- a/parachain/pallets/collab-ai/investing-pool/Cargo.toml +++ b/parachain/pallets/collab-ai/investing-pool/Cargo.toml @@ -1,22 +1,18 @@ [package] +authors = ['Litentry Dev'] +description = 'Pallet for managing investing pool' +edition = '2021' +homepage = 'https://litentry.com/' +license = 'GPL-3.0' name = 'pallet-investing-pool' -description = 'pallet for creating and interacting with investing pool' +repository = 'https://github.com/litentry/litentry-parachain' version = '0.1.0' -license = 'GPL-3.0' -authors.workspace = true -homepage.workspace = true -repository.workspace = true -edition.workspace = true -publish = false - -[lints] -workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { workspace = true } +parity-scale-codec = { workspace = true } scale-info = { workspace = true } serde = { workspace = true } @@ -37,7 +33,7 @@ pallet-balances = { workspace = true } [features] default = ["std"] std = [ - "codec/std", + "parity-scale-codec/std", "serde/std", "frame-benchmarking?/std", "frame-support/std", diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index d3147bf6cf..6015c7dc16 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -20,7 +20,7 @@ use frame_support::{ traits::{ tokens::{ fungible::{Inspect as FInspect, Mutate as FMutate}, - fungibles::{Inspect as FsInspect, Mutate as FsMutate, Create as FsCreate}, + fungibles::{Create as FsCreate, Inspect as FsInspect, Mutate as FsMutate}, Preservation, }, StorageVersion, @@ -114,7 +114,7 @@ where } // consume corresponding weight, change effective time without changing staked amount, return - // the changed effective time + // the changed effective time // This function is mostly used for Synthetic checkpoint change // None means TypeIncompatible Or Division Zero fn claim_based_on_weight(&mut self, weight: u128) -> Option { @@ -195,7 +195,8 @@ pub mod pallet { pub type BalanceOf = <::Fungibles as FsInspect<::AccountId>>::Balance; - pub type AssetIdOf = <::Fungibles as FsInspect<::AccountId>>::AssetId; + pub type AssetIdOf = + <::Fungibles as FsInspect<::AccountId>>::AssetId; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -221,8 +222,6 @@ pub mod pallet { type Fungibles: FsMutate + FsCreate; - type Fungible: FMutate;???? - /// The beneficiary PalletId, used fro deriving its sovereign account to hold assets of reward #[pallet::constant] type StableTokenBeneficiaryId: Get; @@ -248,9 +247,16 @@ pub mod pallet { // Pool id, epcoh index => epoch reward #[pallet::storage] #[pallet::getter(fn stable_investing_pool_epoch_reward)] - pub type StableInvestingPoolEpochReward = - StorageDoubleMap<_, Twox64Concat, InvestingPoolIndex, Twox64Concat, u128, BalanceOf, OptionQuery>; - + pub type StableInvestingPoolEpochReward = StorageDoubleMap< + _, + Twox64Concat, + InvestingPoolIndex, + Twox64Concat, + u128, + BalanceOf, + OptionQuery, + >; + // Checkpoint of single stable staking pool // For stable token reward distribution #[pallet::storage] @@ -273,21 +279,19 @@ pub mod pallet { // Asset id of AIUSD #[pallet::storage] #[pallet::getter(fn aiusd_asset_id)] - pub type AIUSDAssetId = - StorageValue<_, AssetIdOf, OptionQuery>; - + pub type AIUSDAssetId = StorageValue<_, AssetIdOf, OptionQuery>; + // Asset id of CAN #[pallet::storage] #[pallet::getter(fn aiusd_asset_id)] - pub type CANAssetId = - StorageValue<_, AssetIdOf, OptionQuery>; + pub type CANAssetId = StorageValue<_, AssetIdOf, OptionQuery>; #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { InvestingPoolCreated { pool_id: InvestingPoolIndex, - admin: T::AccountId + admin: T::AccountId, start_time: BlockNumberFor, epoch: u128, epoch_range: BlockNumberFor, @@ -386,9 +390,16 @@ pub mod pallet { T::PoolProposalPalletOrigin::ensure_origin(origin)?; // Create all asset token categories - let asset_id_vec = InvestingPoolAssetIdGenerator::get_all_pool_token(pool_id, setting.epoch).ok_or(ArithmeticError::Overflow)? + let asset_id_vec = + InvestingPoolAssetIdGenerator::get_all_pool_token(pool_id, setting.epoch) + .ok_or(ArithmeticError::Overflow)?; for i in asset_id_vec.iter() { - ::AccountId>>::create(i, mutisig, true, One::one()); + ::AccountId>>::create( + i, + mutisig, + true, + One::one(), + ); } ensure!( @@ -425,8 +436,8 @@ pub mod pallet { ) -> DispatchResult { T::RewardUpdateOrigin::ensure_origin(origin)?; - let setting = - >::get(pool_id.clone()).ok_or(Error::::PoolNotExisted)?; + let setting = >::get(pool_id.clone()) + .ok_or(Error::::PoolNotExisted)?; ensure!(0 < epoch && epoch <= setting.epoch, Error::::EpochNotExist); >::try_mutate( @@ -448,11 +459,7 @@ pub mod pallet { // Mint AIUSD into reward pool let aiusd_asset_id = >::get().ok_or(Error::::NoAssetId)?; let beneficiary_account: T::AccountId = Self::stable_token_beneficiary_account(); - let _ = T::Fungibles::mint_into( - aiusd_asset_id, - beneficiary_account, - reward, - )?; + let _ = T::Fungibles::mint_into(aiusd_asset_id, beneficiary_account, reward)?; Ok(()) } @@ -470,7 +477,8 @@ pub mod pallet { let current_block = frame_system::Pallet::::block_number(); // Epoch reward may update before epoch ends, which is also fine to claim early - let mut claimed_until_epoch = self::get_epoch_index_with_reward_updated_before(pool_id, current_block); + let mut claimed_until_epoch = + self::get_epoch_index_with_reward_updated_before(pool_id, current_block); let pool_id = InvestingPoolAssetIdGenerator::get_token_pool_index(asset_id); let token_start_epoch = InvestingPoolAssetIdGenerator::get_token_start_epoch(asset_id); let token_end_epoch = InvestingPoolAssetIdGenerator::get_token_end_epoch(asset_id); @@ -498,26 +506,29 @@ pub mod pallet { terminated = true; } else { // Mint new category token - let new_asset_id = InvestingPoolAssetIdGenerator::get_intermediate_epoch_token(pool_id, (claimed_until_epoch + 1), token_end_epoch); - T::Fungibles::mint_into( - new_asset_id, - &source, - amount, - )?; + let new_asset_id = InvestingPoolAssetIdGenerator::get_intermediate_epoch_token( + pool_id, + (claimed_until_epoch + 1), + token_end_epoch, + ); + T::Fungibles::mint_into(new_asset_id, &source, amount)?; } - Self::do_can_claim(source, pool_id, amount, Self::get_epoch_start_time(token_start_epoch)?, Self::get_epoch_end_time(claimed_until_epoch)?, terminated)?; + Self::do_can_claim( + source, + pool_id, + amount, + Self::get_epoch_start_time(token_start_epoch)?, + Self::get_epoch_end_time(claimed_until_epoch)?, + terminated, + )?; Self::do_stable_claim(source, pool_id, amount, token_start_epoch, claimed_until_epoch)?; - } // Registing AIUSD asset id #[pallet::call_index(3)] #[pallet::weight({1000})] #[transactional] - pub fn regist_aiusd( - origin: OriginFor, - asset_id: AssetIdOf, - ) -> DispatchResult { + pub fn regist_aiusd(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResult { T::InvestingPoolCommitteeOrigin::ensure_origin(origin)?; >::put(asset_id.clone()); Self::deposit_event(Event::::AIUSDRegisted { asset_id }); @@ -528,10 +539,7 @@ pub mod pallet { #[pallet::call_index(3)] #[pallet::weight({1000})] #[transactional] - pub fn regist_can( - origin: OriginFor, - asset_id: AssetIdOf, - ) -> DispatchResult { + pub fn regist_can(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResult { T::InvestingPoolCommitteeOrigin::ensure_origin(origin)?; >::put(asset_id.clone()); Self::deposit_event(Event::::AIUSDRegisted { asset_id }); @@ -568,14 +576,14 @@ pub mod pallet { // Epoch starting from 1 // The largest epoch index with reward updated before "time" (including epoch during that time) - // return setting.epoch if all epoch reward updated and time >= pool end_time + // return setting.epoch if all epoch reward updated and time >= pool end_time fn get_epoch_index_with_reward_updated_before( pool_id: InvestingPoolIndex, time: BlockNumberFor, ) -> Result { let epoch_index: u128 = self::get_epoch_index(pool_id, time)?; - for i in 1u128..(epoch_index+1u128) { + for i in 1u128..(epoch_index + 1u128) { if >::get(pool_id, i).is_none() { return Ok(i); } @@ -597,15 +605,18 @@ pub mod pallet { .end_time() .ok_or(Error::::TypeIncompatibleOrArithmeticError)?); } - let epoch_bn: BlockNumberFor = - epoch.checked_sub(1u128).ok_or(ArithmeticError::Overflow)?.try_into().or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + let epoch_bn: BlockNumberFor = epoch + .checked_sub(1u128) + .ok_or(ArithmeticError::Overflow)? + .try_into() + .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; let result = setting .start_time .checked_add( &setting.epoch_range.checked_mul(&epoch_bn).ok_or(ArithmeticError::Overflow)?, ) .ok_or(ArithmeticError::Overflow)?; - return Ok(result) + return Ok(result); } // return pool ending time if epoch >= setting.epoch @@ -630,22 +641,22 @@ pub mod pallet { &setting.epoch_range.checked_mul(&epoch_bn).ok_or(ArithmeticError::Overflow)?, ) .ok_or(ArithmeticError::Overflow)?; - return Ok(result) + return Ok(result); } // For can_investing - fn do_can_add( - amount: BalanceOf, - effective_time: BlockNumberFor, - ) -> DispatchResult { + fn do_can_add(amount: BalanceOf, effective_time: BlockNumberFor) -> DispatchResult { >::try_mutate(|maybe_checkpoint| { if let Some(checkpoint) = maybe_checkpoint { checkpoint .add(effective_time, amount) .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; } else { - *maybe_checkpoint = - Some(InvestingWeightInfo { effective_time, amount, last_add_time: effective_time }); + *maybe_checkpoint = Some(InvestingWeightInfo { + effective_time, + amount, + last_add_time: effective_time, + }); } Ok::<(), DispatchError>(()) })?; @@ -671,20 +682,26 @@ pub mod pallet { Ok(()) } - // Distribute can reward + // Distribute can reward // No category token destroyed/created - fn do_can_claim(who: T::AccountId, pool_id: InvestingPoolIndex, amount: BalanceOf, start_time: BlockNumberFor, end_time: BlockNumberFor, terminated: bool) -> DispatchResult { + fn do_can_claim( + who: T::AccountId, + pool_id: InvestingPoolIndex, + amount: BalanceOf, + start_time: BlockNumberFor, + end_time: BlockNumberFor, + terminated: bool, + ) -> DispatchResult { let beneficiary_account: T::AccountId = Self::can_token_beneficiary_account(); let can_asset_id = >::get().ok_or(Error::::NoAssetId)?; // BalanceOf let reward_pool = T::Fungibles::balance(can_asset_id, &beneficiary_account); let current_block = frame_system::Pallet::::block_number(); - if start_time > end_time { // Nothing to claim // Do nothing - return Ok(()) + return Ok(()); } else { if let Some(mut ncp) = >::get() { let mut claim_duration: BlockNumberFor; @@ -698,7 +715,8 @@ pub mod pallet { claim_duration = end_time - start_time; } - let claim_weight = claim_duration.checked_mul(amount).ok_or(ArithmeticError::Overflow)?; + let claim_weight = + claim_duration.checked_mul(amount).ok_or(ArithmeticError::Overflow)?; let proportion = Perquintill::from_rational( claim_weight, ncp.weight_force(current_block) @@ -706,8 +724,8 @@ pub mod pallet { ); let reward_pool_u128: u128 = reward_pool - .try_into() - .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + .try_into() + .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; let distributed_reward_u128: u128 = proportion * reward_pool_u128; let distributed_reward: BalanceOf = distributed_reward_u128 .try_into() @@ -746,7 +764,7 @@ pub mod pallet { Ok(()) } - // Distribute stable reward + // Distribute stable reward // No category token destroyed/created // Claim epoch between start_epoch - end_epoch (included) fn do_stable_claim( @@ -760,34 +778,35 @@ pub mod pallet { let beneficiary_account: T::AccountId = Self::stable_token_beneficiary_account(); let aiusd_asset_id = >::get().ok_or(Error::::NoAssetId)?; - let total_distributed_reward: BalanceOf = Zero::zero(); + let total_distributed_reward: BalanceOf = Zero::zero(); if start_epoch > end_epoch { // Nothing to claim // Do nothing - return Ok(()) + return Ok(()); } else { if let Some(mut scp) = >::get(pool_id) { // Must exist let total_investing = scp.amount; // Claim until the claimed_until_epoch // loop through each epoch - for i in start_epoch..(end_epoch+1) { - let reward_pool = >::get(pool_id, i).ok_or(Error::::EpochRewardNotUpdated)?; - - let proportion = Perquintill::from_rational( - amount, - total_investing, - ); - + for i in start_epoch..(end_epoch + 1) { + let reward_pool = >::get(pool_id, i) + .ok_or(Error::::EpochRewardNotUpdated)?; + + let proportion = Perquintill::from_rational(amount, total_investing); + let reward_pool_u128: u128 = reward_pool - .try_into() - .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; - let distributed_reward_u128: u128 = proportion * reward_pool_u128; - let distributed_reward: BalanceOf = distributed_reward_u128 .try_into() .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; - total_distributed_reward = total_distributed_reward.checked_add(distributed_reward).ok_or(ArithmeticError::Overflow)?; + let distributed_reward_u128: u128 = proportion * reward_pool_u128; + let distributed_reward: BalanceOf = + distributed_reward_u128 + .try_into() + .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + total_distributed_reward = total_distributed_reward + .checked_add(distributed_reward) + .ok_or(ArithmeticError::Overflow)?; Self::deposit_event(Event::::StableRewardClaimed { who, @@ -808,7 +827,7 @@ pub mod pallet { total_distributed_reward, Preservation::Expendable, )?; - + Ok(()) } @@ -821,26 +840,25 @@ pub mod pallet { } // Mint category token to user, record can token checkpoint accordingly - pub fn inject_investment(pool_id: InvestingPoolIndex, investments: Vec<(T::AccountId, BalanceOf)>) { + pub fn inject_investment( + pool_id: InvestingPoolIndex, + investments: Vec<(T::AccountId, BalanceOf)>, + ) { let setting = >::get(pool_id).ok_or(Error::::PoolNotExisted)?; let effective_time = Self::get_epoch_start_time(pool_id, One::one()); - let debt_asset_id = InvestingPoolAssetIdGenerator::get_debt_token(pool_id, setting.epoch).ok_or(ArithmeticError::Overflow)?; - let initial_epoch_asset_id = InvestingPoolAssetIdGenerator::get_initial_epoch_token(pool_id, setting.epoch).ok_or(ArithmeticError::Overflow)?; + let debt_asset_id = + InvestingPoolAssetIdGenerator::get_debt_token(pool_id, setting.epoch) + .ok_or(ArithmeticError::Overflow)?; + let initial_epoch_asset_id = + InvestingPoolAssetIdGenerator::get_initial_epoch_token(pool_id, setting.epoch) + .ok_or(ArithmeticError::Overflow)?; for i in investments.iter() { // Mint certification token to user - let _ = T::Fungibles::mint_into( - debt_asset_id, - &i.0, - i.1, - )?; - - let _ = T::Fungibles::mint_into( - initial_epoch_asset_id, - &i.0, - i.1, - )?; + let _ = T::Fungibles::mint_into(debt_asset_id, &i.0, i.1)?; + + let _ = T::Fungibles::mint_into(initial_epoch_asset_id, &i.0, i.1)?; // Add CAN token global checkpoint Self::do_can_add(i.1, effective_time)?; @@ -851,7 +869,10 @@ pub mod pallet { } impl InvestmentInjector> for Pallet { - fn inject_investment(pool_id: InvestingPoolIndex, investments: Vec<(T::AccountId, BalanceOf)>) { + fn inject_investment( + pool_id: InvestingPoolIndex, + investments: Vec<(T::AccountId, BalanceOf)>, + ) { Self::inject_investment(pool_id, investments); } -} \ No newline at end of file +} From fed020b5b9b58ff5cc9165d10cb78a6a64990f63 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 31 Oct 2024 13:58:35 +0800 Subject: [PATCH 118/215] chore: fix --- parachain/Cargo.toml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/parachain/Cargo.toml b/parachain/Cargo.toml index 5a82970d64..2aec779792 100644 --- a/parachain/Cargo.toml +++ b/parachain/Cargo.toml @@ -26,7 +26,14 @@ members = [ 'pallets/xcm-asset-manager', 'pallets/omni-account', 'pallets/omni-account/runtime-api', - 'precompiles/*', + 'precompiles/assets-erc20', + 'precompiles/bridge-transfer', + 'precompiles/collab-ai/aiusd-convertor', + 'precompiles/collab-ai/curator', + 'precompiles/collab-ai/guardian', + 'precompiles/collab-ai/pool-proposal', + 'precompiles/parachain-staking', + 'precompiles/score-staking', 'runtime/litentry', 'runtime/rococo', 'runtime/paseo', From 2b7b7d00fb880ea33d0d669fc0fcba70230ac9f1 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 31 Oct 2024 14:32:44 +0800 Subject: [PATCH 119/215] chore: fix --- .../collab-ai/investing-pool/src/lib.rs | 18 +++++++++--------- .../pallets/collab-ai/pool-proposal/src/lib.rs | 8 +++++--- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index 6015c7dc16..b49f1fe1e0 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -173,7 +173,7 @@ pub struct PoolSetting { pub admin: AccountId, } -impl PoolSetting +impl PoolSetting where Balance: AtLeast32BitUnsigned + Copy, BlockNumber: AtLeast32BitUnsigned + Copy, @@ -536,7 +536,7 @@ pub mod pallet { } // Registing CAN asset id - #[pallet::call_index(3)] + #[pallet::call_index(4)] #[pallet::weight({1000})] #[transactional] pub fn regist_can(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResult { @@ -866,13 +866,13 @@ pub mod pallet { } } } -} -impl InvestmentInjector> for Pallet { - fn inject_investment( - pool_id: InvestingPoolIndex, - investments: Vec<(T::AccountId, BalanceOf)>, - ) { - Self::inject_investment(pool_id, investments); + impl InvestmentInjector> for Pallet { + fn inject_investment( + pool_id: InvestingPoolIndex, + investments: Vec<(T::AccountId, BalanceOf)>, + ) { + Self::inject_investment(pool_id, investments); + } } } diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 0fca746de5..696bb82bf2 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -67,6 +67,11 @@ pub type AssetBalanceOf = pub type AssetIdOf = as FsInspect<::AccountId>>::AssetId; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + #[frame_support::pallet] pub mod pallet { use frame_support::{dispatch::DispatchResult, pallet_prelude::OptionQuery}; @@ -87,9 +92,6 @@ pub mod pallet { pub trait Config: frame_system::Config + pallet_assets::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// The Make pool mature. - // type Scheduler: ScheduleNamed, CallOf, Self::PalletsOrigin>; - /// Currency type for this pallet. type Currency: ReservableCurrency + LockableCurrency>; From 1974e726412107ce37ed5d124a230aba8c6156bc Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 31 Oct 2024 14:39:37 +0800 Subject: [PATCH 120/215] chore: temp remove mock and test --- .../collab-ai/pool-proposal/src/lib.rs | 8 +- .../collab-ai/pool-proposal/src/mock.rs | 173 ++++++++++++++++++ .../collab-ai/pool-proposal/src/tests.rs | 32 ++++ 3 files changed, 209 insertions(+), 4 deletions(-) create mode 100644 parachain/pallets/collab-ai/pool-proposal/src/mock.rs create mode 100644 parachain/pallets/collab-ai/pool-proposal/src/tests.rs diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 696bb82bf2..e9c932b1df 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -67,10 +67,10 @@ pub type AssetBalanceOf = pub type AssetIdOf = as FsInspect<::AccountId>>::AssetId; -#[cfg(test)] -mod mock; -#[cfg(test)] -mod tests; +// #[cfg(test)] +// mod mock; +// #[cfg(test)] +// mod tests; #[frame_support::pallet] pub mod pallet { diff --git a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs new file mode 100644 index 0000000000..01547378cc --- /dev/null +++ b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs @@ -0,0 +1,173 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate as pallet_pool_proposal; +use frame_support::{ + assert_ok, construct_runtime, parameter_types, + traits::{ + tokens::fungibles::{Inspect, Mutate}, + AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, Everything, + }, +}; +use sp_core::{Get, H256}; +use sp_runtime::{ + traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, + AccountId32, BuildStorage, +}; + +pub type Signature = sp_runtime::MultiSignature; +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + +pub type Balance = u128; + +// Configure a mock runtime to test the pallet. +construct_runtime!( + pub enum Test { + System: frame_system, + Assets: pallet_assets, + Balances: pallet_balances, + PoolProposal: pallet_pool_proposal, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const AIUSDAssetId: u32 = 1; + pub const OfficialGapPeriod: u32 = 10; + pub const MinimumProposalLastTime: u32 = 10; + pub const MinimumPoolDeposit: Balance = 100; + pub const MaxGuardianPerProposal: u32 = 2; + pub const MaximumPoolProposed: u32 = 2; +} + +impl frame_system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type Block = frame_system::mocking::MockBlock; + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = ConstU16<31>; + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl pallet_assets::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = u32; + type AssetIdParameter = u32; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type AssetDeposit = ConstU128<1>; + type AssetAccountDeposit = ConstU128<10>; + type MetadataDepositBase = ConstU128<1>; + type MetadataDepositPerByte = ConstU128<1>; + type ApprovalDeposit = ConstU128<1>; + type StringLimit = ConstU32<50>; + type Freezer = (); + type WeightInfo = (); + type CallbackHandle = (); + type Extra = (); + type RemoveItemsLimit = ConstU32<5>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + +impl pallet_balances::Config for Test { + type MaxLocks = (); + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ConstU128<1>; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = (); + type ReserveIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = (); + type MaxFreezes = (); + type RuntimeHoldReason = (); +} + +pub struct PreInvestingPool; +impl Get for PreInvestingPool { + fn get() -> AccountId32 { + AccountId32::new([1u8; 32]) + } +} + +impl pallet_pool_proposal::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type AIUSDAssetId = AIUSDAssetId; + tpye OfficialGapPeriod = OfficialGapPeriod; + type MinimumProposalLastTime = MinimumProposalLastTime; + type MinimumPoolDeposit = MinimumPoolDeposit; + type MaximumPoolProposed = MaxGuardianPerProposal; + type ProposalOrigin = frame_system::EnsureRoot; + type PublicVotingOrigin = frame_system::EnsureRoot; + type GuardianVoteResource = ; + type MaxGuardianPerProposal = MaxGuardianPerProposal; + type PreInvestingPool = PreInvestingPool; +} + +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + + let owner = AccountId32::from([2u8; 32]); + let origin = RuntimeOrigin::root(); + + // Create the AIUSD asset + assert_ok!(pallet_assets::Pallet::::force_create( + origin.clone(), + 1, // AIUSD asset id + owner.clone(), + true, + 1, + )); + + // Check if these assets exists + assert!(pallet_aiusd::InspectFungibles::::asset_exists(1)); + + // Set total supply + assert_ok!(pallet_aiusd::InspectFungibles::::mint_into( + target_asset_id, + &owner, + 1_000_000_000 // 1000 (10^6 * 1000) + )); + }); + ext +} diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs new file mode 100644 index 0000000000..6188cdf3df --- /dev/null +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -0,0 +1,32 @@ +use crate::mock::*; +use frame_support::assert_ok; +use sp_runtime::AccountId32; + +#[test] +fn test_propose_investing_pool_ok() { + new_test_ext().execute_with(|| { + let curator: AccountId32 = AccountId32::from([1u8; 32]); + let info_hash: [u8; 32] = [1; 32]; + let curator_index = PublicCuratorCount::::get(); + + // Register curator + assert_ok!(Curator::regist_curator( + RuntimeOrigin::signed(curator.clone()), + sp_core::H256(info_hash) + )); + + // Check if curator is stored correctly + assert_eq!(PublicCuratorToIndex::::get(&curator), Some(curator_index)); + assert_eq!(PublicCuratorCount::::get(), curator_index + 1); + assert_eq!( + CuratorIndexToInfo::::get(curator_index), + Some((sp_core::H256(info_hash), 1, curator.clone(), CandidateStatus::Unverified)) + ); + + System::assert_last_event(RuntimeEvent::Curator(crate::Event::CuratorRegisted { + curator, + curator_index, + info_hash: sp_core::H256(info_hash), + })); + }) +} \ No newline at end of file From 9a6a9af46db2f03b173c72f2f8f7876f6a1980bc Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 31 Oct 2024 15:47:30 +0800 Subject: [PATCH 121/215] chore: fix --- parachain/pallets/collab-ai/common/src/lib.rs | 10 ++- .../collab-ai/investing-pool/src/lib.rs | 86 +++++++++++-------- 2 files changed, 56 insertions(+), 40 deletions(-) diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index 0693836540..a02590ed95 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -20,7 +20,10 @@ use scale_info::TypeInfo; use sp_core::{RuntimeDebug, H256}; use sp_std::marker::PhantomData; -use frame_support::{pallet_prelude::EnsureOrigin, traits::EitherOfDiverse}; +use frame_support::{ + pallet_prelude::{DispatchResult, EnsureOrigin}, + traits::EitherOfDiverse, +}; use frame_system::{EnsureRoot, RawOrigin}; pub type InfoHash = H256; @@ -243,5 +246,8 @@ pub trait GuardianQuery { /// Inject investment into pool pub trait InvestmentInjector { - fn inject_investment(pool_id: InvestingPoolIndex, investments: Vec<(AccountId, Balance)>); + fn inject_investment( + pool_id: InvestingPoolIndex, + investments: Vec<(AccountId, Balance)>, + ) -> DispatchResult; } diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index b49f1fe1e0..c0edc9c857 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -21,7 +21,7 @@ use frame_support::{ tokens::{ fungible::{Inspect as FInspect, Mutate as FMutate}, fungibles::{Create as FsCreate, Inspect as FsInspect, Mutate as FsMutate}, - Preservation, + Fortitude, Precision, Preservation, }, StorageVersion, }, @@ -32,7 +32,7 @@ pub use pallet::*; use sp_runtime::{ traits::{ AccountIdConversion, AtLeast32BitUnsigned, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, - One, + One, Zero, }, ArithmeticError, Perquintill, Saturating, }; @@ -261,10 +261,10 @@ pub mod pallet { // For stable token reward distribution #[pallet::storage] #[pallet::getter(fn stable_investing_pool_checkpoint)] - pub type StableIvestingPoolCheckpoint = StorageMap< + pub type StableInvestingPoolCheckpoint = StorageMap< _, Twox64Concat, - T::PoolId, + InvestingPoolIndex, InvestingWeightInfo, BalanceOf>, OptionQuery, >; @@ -272,7 +272,7 @@ pub mod pallet { // Checkpoint of overall investing condition synthetic by tracking all investing pools // For CAN token reward distribution #[pallet::storage] - #[pallet::getter(fn native_checkpoint)] + #[pallet::getter(fn can_checkpoint)] pub type CANCheckpoint = StorageValue<_, InvestingWeightInfo, BalanceOf>, OptionQuery>; @@ -283,7 +283,7 @@ pub mod pallet { // Asset id of CAN #[pallet::storage] - #[pallet::getter(fn aiusd_asset_id)] + #[pallet::getter(fn can_asset_id)] pub type CANAssetId = StorageValue<_, AssetIdOf, OptionQuery>; #[pallet::event] @@ -295,7 +295,6 @@ pub mod pallet { start_time: BlockNumberFor, epoch: u128, epoch_range: BlockNumberFor, - setup_time: BlockNumberFor, pool_cap: BalanceOf, }, /// New metadata has been set for a investing pool. @@ -369,9 +368,7 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { /// Weight: see `begin_block` - fn on_initialize(n: BlockNumberFor) -> Weight { - Self::begin_block(n) - } + fn on_initialize(n: BlockNumberFor) -> Weight {} } #[pallet::call] @@ -395,8 +392,8 @@ pub mod pallet { .ok_or(ArithmeticError::Overflow)?; for i in asset_id_vec.iter() { ::AccountId>>::create( - i, - mutisig, + i.clone(), + admin, true, One::one(), ); @@ -417,7 +414,6 @@ pub mod pallet { start_time: setting.start_time, epoch: setting.epoch, epoch_range: setting.epoch_range, - setup_time: setting.setup_time, pool_cap: setting.pool_cap, }); Ok(()) @@ -459,7 +455,7 @@ pub mod pallet { // Mint AIUSD into reward pool let aiusd_asset_id = >::get().ok_or(Error::::NoAssetId)?; let beneficiary_account: T::AccountId = Self::stable_token_beneficiary_account(); - let _ = T::Fungibles::mint_into(aiusd_asset_id, beneficiary_account, reward)?; + let _ = T::Fungibles::mint_into(aiusd_asset_id, &beneficiary_account, reward)?; Ok(()) } @@ -470,16 +466,16 @@ pub mod pallet { #[transactional] pub fn claim( origin: OriginFor, - asset_id: InvestingPoolIndex, + asset_id: AssetIdOf, amount: BalanceOf, ) -> DispatchResult { let source = ensure_signed(origin)?; let current_block = frame_system::Pallet::::block_number(); + let pool_id = InvestingPoolAssetIdGenerator::get_token_pool_index(asset_id); // Epoch reward may update before epoch ends, which is also fine to claim early let mut claimed_until_epoch = - self::get_epoch_index_with_reward_updated_before(pool_id, current_block); - let pool_id = InvestingPoolAssetIdGenerator::get_token_pool_index(asset_id); + Self::get_epoch_index_with_reward_updated_before(pool_id, current_block); let token_start_epoch = InvestingPoolAssetIdGenerator::get_token_start_epoch(asset_id); let token_end_epoch = InvestingPoolAssetIdGenerator::get_token_end_epoch(asset_id); @@ -508,20 +504,21 @@ pub mod pallet { // Mint new category token let new_asset_id = InvestingPoolAssetIdGenerator::get_intermediate_epoch_token( pool_id, - (claimed_until_epoch + 1), + claimed_until_epoch + 1, token_end_epoch, - ); + ) + .ok_or(ArithmeticError::Overflow)?; T::Fungibles::mint_into(new_asset_id, &source, amount)?; } Self::do_can_claim( source, pool_id, amount, - Self::get_epoch_start_time(token_start_epoch)?, - Self::get_epoch_end_time(claimed_until_epoch)?, + Self::get_epoch_start_time(pool_id, token_start_epoch)?, + Self::get_epoch_end_time(pool_id, claimed_until_epoch)?, terminated, )?; - Self::do_stable_claim(source, pool_id, amount, token_start_epoch, claimed_until_epoch)?; + Self::do_stable_claim(source, pool_id, amount, token_start_epoch, claimed_until_epoch)? } // Registing AIUSD asset id @@ -529,7 +526,7 @@ pub mod pallet { #[pallet::weight({1000})] #[transactional] pub fn regist_aiusd(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResult { - T::InvestingPoolCommitteeOrigin::ensure_origin(origin)?; + T::InvestingPoolAdminOrigin::ensure_origin(origin)?; >::put(asset_id.clone()); Self::deposit_event(Event::::AIUSDRegisted { asset_id }); Ok(()) @@ -540,7 +537,7 @@ pub mod pallet { #[pallet::weight({1000})] #[transactional] pub fn regist_can(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResult { - T::InvestingPoolCommitteeOrigin::ensure_origin(origin)?; + T::InvestingPoolAdminOrigin::ensure_origin(origin)?; >::put(asset_id.clone()); Self::deposit_event(Event::::AIUSDRegisted { asset_id }); Ok(()) @@ -570,7 +567,7 @@ pub mod pallet { if index >= setting.epoch { return Ok(setting.epoch); } else { - return index.checked_add(1u128).ok_or(ArithmeticError::Overflow); + return index.checked_add(1u128).ok_or(ArithmeticError::Overflow)?; } } @@ -581,7 +578,7 @@ pub mod pallet { pool_id: InvestingPoolIndex, time: BlockNumberFor, ) -> Result { - let epoch_index: u128 = self::get_epoch_index(pool_id, time)?; + let epoch_index: u128 = Self::get_epoch_index(pool_id, time)?; for i in 1u128..(epoch_index + 1u128) { if >::get(pool_id, i).is_none() { @@ -664,7 +661,7 @@ pub mod pallet { // For stable_investing fn do_stable_add( - pool_id: T::PoolId, + pool_id: InvestingPoolIndex, amount: BalanceOf, effective_time: BlockNumberFor, ) -> DispatchResult { @@ -674,8 +671,11 @@ pub mod pallet { .add(effective_time, amount) .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; } else { - *maybe_checkpoint = - Some(StakingInfo { effective_time, amount, last_add_time: effective_time }); + *maybe_checkpoint = Some(InvestingWeightInfo { + effective_time, + amount, + last_add_time: effective_time, + }); } Ok::<(), DispatchError>(()) })?; @@ -704,19 +704,28 @@ pub mod pallet { return Ok(()); } else { if let Some(mut ncp) = >::get() { - let mut claim_duration: BlockNumberFor; + let mut claim_duration: u128; if terminated { // This means the effective investing duration is beyond the pool lifespan // i.e. users who do not claim reward after the pool end are still considering as in-pool contributing their weights - claim_duration = current_block - start_time; + claim_duration = (current_block - start_time) + .try_into() + .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; } else { // Only counting the investing weight during the epoch // Claim from start_time until the end_time - claim_duration = end_time - start_time; + claim_duration = (end_time - start_time) + .try_into() + .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; } - let claim_weight = - claim_duration.checked_mul(amount).ok_or(ArithmeticError::Overflow)?; + let claim_weight: u128 = claim_duration + .checked_mul( + &amount + .try_into() + .ok_or(Error::::TypeIncompatibleOrArithmeticError)?, + ) + .ok_or(ArithmeticError::Overflow)?; let proportion = Perquintill::from_rational( claim_weight, ncp.weight_force(current_block) @@ -785,7 +794,7 @@ pub mod pallet { // Do nothing return Ok(()); } else { - if let Some(mut scp) = >::get(pool_id) { + if let Some(mut scp) = >::get(pool_id) { // Must exist let total_investing = scp.amount; // Claim until the claimed_until_epoch @@ -843,7 +852,7 @@ pub mod pallet { pub fn inject_investment( pool_id: InvestingPoolIndex, investments: Vec<(T::AccountId, BalanceOf)>, - ) { + ) -> DispatchResult { let setting = >::get(pool_id).ok_or(Error::::PoolNotExisted)?; let effective_time = Self::get_epoch_start_time(pool_id, One::one()); @@ -864,6 +873,7 @@ pub mod pallet { Self::do_can_add(i.1, effective_time)?; Self::do_stable_add(pool_id, i.1, effective_time) } + Ok(()) } } @@ -871,8 +881,8 @@ pub mod pallet { fn inject_investment( pool_id: InvestingPoolIndex, investments: Vec<(T::AccountId, BalanceOf)>, - ) { - Self::inject_investment(pool_id, investments); + ) -> DispatchResult { + Self::inject_investment(pool_id, investments) } } } From 39d514c45016ee3c37bc681eb3d70818042d6b1e Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 31 Oct 2024 16:02:34 +0800 Subject: [PATCH 122/215] chore: fix --- .../pallets/collab-ai/investing-pool/src/lib.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index c0edc9c857..38608536d4 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -207,7 +207,9 @@ pub mod pallet { pub struct Pallet(_); #[pallet::config] - pub trait Config: frame_system::Config + pallet_assets::Config { + pub trait Config: + frame_system::Config + pallet_assets::Config + Into> + { /// Overarching event type type RuntimeEvent: From> + IsType<::RuntimeEvent>; @@ -387,7 +389,7 @@ pub mod pallet { T::PoolProposalPalletOrigin::ensure_origin(origin)?; // Create all asset token categories - let asset_id_vec = + let asset_id_vec: Vec> = InvestingPoolAssetIdGenerator::get_all_pool_token(pool_id, setting.epoch) .ok_or(ArithmeticError::Overflow)?; for i in asset_id_vec.iter() { @@ -567,7 +569,7 @@ pub mod pallet { if index >= setting.epoch { return Ok(setting.epoch); } else { - return index.checked_add(1u128).ok_or(ArithmeticError::Overflow)?; + return Ok(index.checked_add(1u128).ok_or(ArithmeticError::Overflow)?); } } @@ -814,7 +816,7 @@ pub mod pallet { .try_into() .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; total_distributed_reward = total_distributed_reward - .checked_add(distributed_reward) + .checked_add(&distributed_reward) .ok_or(ArithmeticError::Overflow)?; Self::deposit_event(Event::::StableRewardClaimed { @@ -855,7 +857,7 @@ pub mod pallet { ) -> DispatchResult { let setting = >::get(pool_id).ok_or(Error::::PoolNotExisted)?; - let effective_time = Self::get_epoch_start_time(pool_id, One::one()); + let effective_time = Self::get_epoch_start_time(pool_id, One::one())?; let debt_asset_id = InvestingPoolAssetIdGenerator::get_debt_token(pool_id, setting.epoch) @@ -871,7 +873,7 @@ pub mod pallet { // Add CAN token global checkpoint Self::do_can_add(i.1, effective_time)?; - Self::do_stable_add(pool_id, i.1, effective_time) + Self::do_stable_add(pool_id, i.1, effective_time)?; } Ok(()) } From e0082c5c4e0e04666e9bba20548b77f649632946 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 31 Oct 2024 16:23:44 +0800 Subject: [PATCH 123/215] chore: fix --- .../pallets/collab-ai/investing-pool/src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index 38608536d4..212262d793 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -207,9 +207,7 @@ pub mod pallet { pub struct Pallet(_); #[pallet::config] - pub trait Config: - frame_system::Config + pallet_assets::Config + Into> - { + pub trait Config: frame_system::Config + pallet_assets::Config { /// Overarching event type type RuntimeEvent: From> + IsType<::RuntimeEvent>; @@ -370,7 +368,9 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { /// Weight: see `begin_block` - fn on_initialize(n: BlockNumberFor) -> Weight {} + fn on_initialize(n: BlockNumberFor) -> Weight { + Weight::zero() + } } #[pallet::call] @@ -477,7 +477,7 @@ pub mod pallet { let pool_id = InvestingPoolAssetIdGenerator::get_token_pool_index(asset_id); // Epoch reward may update before epoch ends, which is also fine to claim early let mut claimed_until_epoch = - Self::get_epoch_index_with_reward_updated_before(pool_id, current_block); + Self::get_epoch_index_with_reward_updated_before(pool_id, current_block)?; let token_start_epoch = InvestingPoolAssetIdGenerator::get_token_start_epoch(asset_id); let token_end_epoch = InvestingPoolAssetIdGenerator::get_token_end_epoch(asset_id); @@ -520,7 +520,7 @@ pub mod pallet { Self::get_epoch_end_time(pool_id, claimed_until_epoch)?, terminated, )?; - Self::do_stable_claim(source, pool_id, amount, token_start_epoch, claimed_until_epoch)? + Self::do_stable_claim(source, pool_id, amount, token_start_epoch, claimed_until_epoch) } // Registing AIUSD asset id From 1b8ea38afd3031bd87eb56a43ed4065db1d9754d Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 31 Oct 2024 16:59:30 +0800 Subject: [PATCH 124/215] chore: fix --- parachain/pallets/collab-ai/investing-pool/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index 212262d793..189b793253 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -207,7 +207,7 @@ pub mod pallet { pub struct Pallet(_); #[pallet::config] - pub trait Config: frame_system::Config + pallet_assets::Config { + pub trait Config: frame_system::Config { /// Overarching event type type RuntimeEvent: From> + IsType<::RuntimeEvent>; @@ -220,7 +220,9 @@ pub mod pallet { /// Origin used to administer the investing pool type InvestingPoolAdminOrigin: EnsureOrigin; - type Fungibles: FsMutate + FsCreate; + type Fungibles: FsMutate + FsCreate + where + FsMutate::AssetId = u128; /// The beneficiary PalletId, used fro deriving its sovereign account to hold assets of reward #[pallet::constant] From caa6eb760ed063a1b58d256b8cae72d8bb604731 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 31 Oct 2024 17:20:37 +0800 Subject: [PATCH 125/215] chore: fix --- parachain/pallets/collab-ai/investing-pool/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index 189b793253..28c98c63d8 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -220,9 +220,7 @@ pub mod pallet { /// Origin used to administer the investing pool type InvestingPoolAdminOrigin: EnsureOrigin; - type Fungibles: FsMutate + FsCreate - where - FsMutate::AssetId = u128; + type Fungibles: FsMutate + FsCreate; /// The beneficiary PalletId, used fro deriving its sovereign account to hold assets of reward #[pallet::constant] From 8b66aeea6e9f22d50f45daf80140e212543eced1 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 31 Oct 2024 17:46:09 +0800 Subject: [PATCH 126/215] chore: fix --- .../collab-ai/investing-pool/src/lib.rs | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index 28c98c63d8..3a943d90c4 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -325,9 +325,12 @@ pub mod pallet { target_effective_time: BlockNumberFor, amount: BalanceOf, }, - NativeRewardClaimed { + CANRewardClaimed { who: T::AccountId, - until_time: BlockNumberFor, + claim_duration: BlockNumberFor, + // Investing amount related of claim + invest_amount: BalanceOf, + // Amount of reward reward_amount: BalanceOf, }, StableRewardClaimed { @@ -395,7 +398,7 @@ pub mod pallet { for i in asset_id_vec.iter() { ::AccountId>>::create( i.clone(), - admin, + admin.clone(), true, One::one(), ); @@ -513,7 +516,7 @@ pub mod pallet { T::Fungibles::mint_into(new_asset_id, &source, amount)?; } Self::do_can_claim( - source, + source.clone(), pool_id, amount, Self::get_epoch_start_time(pool_id, token_start_epoch)?, @@ -659,6 +662,7 @@ pub mod pallet { } Ok::<(), DispatchError>(()) })?; + Ok(()) } // For stable_investing @@ -706,26 +710,22 @@ pub mod pallet { return Ok(()); } else { if let Some(mut ncp) = >::get() { - let mut claim_duration: u128; + let mut claim_duration: BlockNumberFor; if terminated { // This means the effective investing duration is beyond the pool lifespan // i.e. users who do not claim reward after the pool end are still considering as in-pool contributing their weights - claim_duration = (current_block - start_time) - .try_into() - .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; + claim_duration = current_block - start_time; } else { // Only counting the investing weight during the epoch // Claim from start_time until the end_time - claim_duration = (end_time - start_time) - .try_into() - .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; + claim_duration = end_time - start_time; } let claim_weight: u128 = claim_duration + .try_into() + .or(Error::::TypeIncompatibleOrArithmeticError)? .checked_mul( - &amount - .try_into() - .ok_or(Error::::TypeIncompatibleOrArithmeticError)?, + &amount.try_into().or(Error::::TypeIncompatibleOrArithmeticError)?, ) .ok_or(ArithmeticError::Overflow)?; let proportion = Perquintill::from_rational( @@ -767,7 +767,7 @@ pub mod pallet { Self::deposit_event(Event::::CANRewardClaimed { who, claim_duration, - amount, + invest_amount: amount, reward_amount: distributed_reward, }); } @@ -788,6 +788,8 @@ pub mod pallet { let current_block = frame_system::Pallet::::block_number(); let beneficiary_account: T::AccountId = Self::stable_token_beneficiary_account(); let aiusd_asset_id = >::get().ok_or(Error::::NoAssetId)?; + let amount_u128 = + amount.try_into().or(Err(Error::::TypeIncompatibleOrArithmeticError))?; let total_distributed_reward: BalanceOf = Zero::zero(); @@ -798,14 +800,17 @@ pub mod pallet { } else { if let Some(mut scp) = >::get(pool_id) { // Must exist - let total_investing = scp.amount; + let total_investing: u128 = scp + .amount + .try_into() + .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; // Claim until the claimed_until_epoch // loop through each epoch for i in start_epoch..(end_epoch + 1) { let reward_pool = >::get(pool_id, i) .ok_or(Error::::EpochRewardNotUpdated)?; - let proportion = Perquintill::from_rational(amount, total_investing); + let proportion = Perquintill::from_rational(amount_u128, total_investing); let reward_pool_u128: u128 = reward_pool .try_into() From 34eba612d9840fcbcca1331faaaf9731ff5884a4 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Thu, 31 Oct 2024 17:58:57 +0800 Subject: [PATCH 127/215] chore: fix --- .../collab-ai/investing-pool/src/lib.rs | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index 3a943d90c4..cccb139766 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -19,7 +19,6 @@ use frame_support::{ pallet_prelude::*, traits::{ tokens::{ - fungible::{Inspect as FInspect, Mutate as FMutate}, fungibles::{Create as FsCreate, Inspect as FsInspect, Mutate as FsMutate}, Fortitude, Precision, Preservation, }, @@ -31,12 +30,11 @@ use frame_system::pallet_prelude::*; pub use pallet::*; use sp_runtime::{ traits::{ - AccountIdConversion, AtLeast32BitUnsigned, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, - One, Zero, + AccountIdConversion, AtLeast32BitUnsigned, CheckedAdd, CheckedDiv, CheckedMul, One, Zero, }, ArithmeticError, Perquintill, Saturating, }; -use sp_std::{collections::vec_deque::VecDeque, fmt::Debug, prelude::*}; +use sp_std::{fmt::Debug, prelude::*}; use pallet_collab_ai_common::*; @@ -371,7 +369,7 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { /// Weight: see `begin_block` - fn on_initialize(n: BlockNumberFor) -> Weight { + fn on_initialize(_n: BlockNumberFor) -> Weight { Weight::zero() } } @@ -721,12 +719,15 @@ pub mod pallet { claim_duration = end_time - start_time; } - let claim_weight: u128 = claim_duration + let claim_duration_u128 = claim_duration .try_into() - .or(Error::::TypeIncompatibleOrArithmeticError)? - .checked_mul( - &amount.try_into().or(Error::::TypeIncompatibleOrArithmeticError)?, - ) + .or(Error::::TypeIncompatibleOrArithmeticError)?; + let amount_u128 = amount + .clone() + .try_into() + .or(Error::::TypeIncompatibleOrArithmeticError)?; + let claim_weight: u128 = claim_duration_u128 + .checked_mul(amount_u128) .ok_or(ArithmeticError::Overflow)?; let proportion = Perquintill::from_rational( claim_weight, From 2984dfe40d488123f965dd861f3a522fa3768f40 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 1 Nov 2024 09:42:55 +0800 Subject: [PATCH 128/215] chore: fix --- parachain/pallets/collab-ai/investing-pool/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index cccb139766..0cf92700b1 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -719,13 +719,13 @@ pub mod pallet { claim_duration = end_time - start_time; } - let claim_duration_u128 = claim_duration + let claim_duration_u128: u128 = claim_duration .try_into() - .or(Error::::TypeIncompatibleOrArithmeticError)?; + .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; let amount_u128 = amount .clone() .try_into() - .or(Error::::TypeIncompatibleOrArithmeticError)?; + .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; let claim_weight: u128 = claim_duration_u128 .checked_mul(amount_u128) .ok_or(ArithmeticError::Overflow)?; From 94b302c7ef803b09867d33902aa24c00fcb4191d Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 1 Nov 2024 09:46:35 +0800 Subject: [PATCH 129/215] chore: fix --- parachain/pallets/collab-ai/investing-pool/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index 0cf92700b1..9a57cfca84 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -334,7 +334,7 @@ pub mod pallet { StableRewardClaimed { who: T::AccountId, pool_id: InvestingPoolIndex, - until_time: BlockNumberFor, + epoch: u128, reward_amount: BalanceOf, }, Withdraw { @@ -828,7 +828,7 @@ pub mod pallet { Self::deposit_event(Event::::StableRewardClaimed { who, pool_id, - i, + epoch: i, reward_amount: distributed_reward, }); } From 6c4d6ed8a8ebd248b8a774aa61e96c377355bb23 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 1 Nov 2024 10:10:01 +0800 Subject: [PATCH 130/215] chore: fix --- parachain/pallets/collab-ai/investing-pool/src/lib.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index 9a57cfca84..6043deba9f 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -515,7 +515,6 @@ pub mod pallet { } Self::do_can_claim( source.clone(), - pool_id, amount, Self::get_epoch_start_time(pool_id, token_start_epoch)?, Self::get_epoch_end_time(pool_id, claimed_until_epoch)?, @@ -690,7 +689,6 @@ pub mod pallet { // No category token destroyed/created fn do_can_claim( who: T::AccountId, - pool_id: InvestingPoolIndex, amount: BalanceOf, start_time: BlockNumberFor, end_time: BlockNumberFor, @@ -708,7 +706,7 @@ pub mod pallet { return Ok(()); } else { if let Some(mut ncp) = >::get() { - let mut claim_duration: BlockNumberFor; + let claim_duration: BlockNumberFor; if terminated { // This means the effective investing duration is beyond the pool lifespan // i.e. users who do not claim reward after the pool end are still considering as in-pool contributing their weights @@ -786,20 +784,19 @@ pub mod pallet { start_epoch: u128, end_epoch: u128, ) -> DispatchResult { - let current_block = frame_system::Pallet::::block_number(); let beneficiary_account: T::AccountId = Self::stable_token_beneficiary_account(); let aiusd_asset_id = >::get().ok_or(Error::::NoAssetId)?; let amount_u128 = amount.try_into().or(Err(Error::::TypeIncompatibleOrArithmeticError))?; - let total_distributed_reward: BalanceOf = Zero::zero(); + let mut total_distributed_reward: BalanceOf = Zero::zero(); if start_epoch > end_epoch { // Nothing to claim // Do nothing return Ok(()); } else { - if let Some(mut scp) = >::get(pool_id) { + if let Some(scp) = >::get(pool_id) { // Must exist let total_investing: u128 = scp .amount @@ -826,7 +823,7 @@ pub mod pallet { .ok_or(ArithmeticError::Overflow)?; Self::deposit_event(Event::::StableRewardClaimed { - who, + who: who.clone(), pool_id, epoch: i, reward_amount: distributed_reward, From 096265698c73fe6acedd51a31d9b2f7141ddcea8 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 1 Nov 2024 10:37:25 +0800 Subject: [PATCH 131/215] chore: fix --- .../collab-ai/investing-pool/src/lib.rs | 211 +++++++++--------- 1 file changed, 100 insertions(+), 111 deletions(-) diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index 6043deba9f..a97c54210c 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -15,6 +15,7 @@ // along with Litentry. If not, see . #![cfg_attr(not(feature = "std"), no_std)] +#![allow(dead_code)] use frame_support::{ pallet_prelude::*, traits::{ @@ -395,11 +396,11 @@ pub mod pallet { .ok_or(ArithmeticError::Overflow)?; for i in asset_id_vec.iter() { ::AccountId>>::create( - i.clone(), + *i, admin.clone(), true, One::one(), - ); + )?; } ensure!( @@ -407,10 +408,10 @@ pub mod pallet { Error::::PoolAlreadyStarted ); ensure!( - !InvestingPoolSetting::::contains_key(&pool_id), + !InvestingPoolSetting::::contains_key(pool_id), Error::::PoolAlreadyExisted ); - >::insert(pool_id.clone(), setting.clone()); + >::insert(pool_id, setting.clone()); Self::deposit_event(Event::InvestingPoolCreated { pool_id, admin: setting.admin, @@ -435,19 +436,19 @@ pub mod pallet { ) -> DispatchResult { T::RewardUpdateOrigin::ensure_origin(origin)?; - let setting = >::get(pool_id.clone()) - .ok_or(Error::::PoolNotExisted)?; + let setting = + >::get(pool_id).ok_or(Error::::PoolNotExisted)?; ensure!(0 < epoch && epoch <= setting.epoch, Error::::EpochNotExist); >::try_mutate( - &pool_id, - &epoch, + pool_id, + epoch, |maybe_reward| -> DispatchResult { ensure!(maybe_reward.is_none(), Error::::RewardAlreadyExisted); *maybe_reward = Some(reward); Self::deposit_event(Event::::RewardUpdated { - pool_id: pool_id.clone(), + pool_id, epoch, amount: reward, }); @@ -529,7 +530,7 @@ pub mod pallet { #[transactional] pub fn regist_aiusd(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResult { T::InvestingPoolAdminOrigin::ensure_origin(origin)?; - >::put(asset_id.clone()); + >::put(asset_id); Self::deposit_event(Event::::AIUSDRegisted { asset_id }); Ok(()) } @@ -567,9 +568,9 @@ pub mod pallet { let index: u128 = index_bn.try_into().or(Err(Error::::TypeIncompatibleOrArithmeticError))?; if index >= setting.epoch { - return Ok(setting.epoch); + Ok(setting.epoch) } else { - return Ok(index.checked_add(1u128).ok_or(ArithmeticError::Overflow)?); + Ok(index.checked_add(1u128).ok_or(ArithmeticError::Overflow)?) } } @@ -615,7 +616,7 @@ pub mod pallet { &setting.epoch_range.checked_mul(&epoch_bn).ok_or(ArithmeticError::Overflow)?, ) .ok_or(ArithmeticError::Overflow)?; - return Ok(result); + Ok(result) } // return pool ending time if epoch >= setting.epoch @@ -640,7 +641,7 @@ pub mod pallet { &setting.epoch_range.checked_mul(&epoch_bn).ok_or(ArithmeticError::Overflow)?, ) .ok_or(ArithmeticError::Overflow)?; - return Ok(result); + Ok(result) } // For can_investing @@ -668,7 +669,7 @@ pub mod pallet { amount: BalanceOf, effective_time: BlockNumberFor, ) -> DispatchResult { - >::try_mutate(&pool_id, |maybe_checkpoint| { + >::try_mutate(pool_id, |maybe_checkpoint| { if let Some(checkpoint) = maybe_checkpoint { checkpoint .add(effective_time, amount) @@ -704,72 +705,65 @@ pub mod pallet { // Nothing to claim // Do nothing return Ok(()); - } else { - if let Some(mut ncp) = >::get() { - let claim_duration: BlockNumberFor; - if terminated { - // This means the effective investing duration is beyond the pool lifespan - // i.e. users who do not claim reward after the pool end are still considering as in-pool contributing their weights - claim_duration = current_block - start_time; - } else { - // Only counting the investing weight during the epoch - // Claim from start_time until the end_time - claim_duration = end_time - start_time; - } - - let claim_duration_u128: u128 = claim_duration - .try_into() - .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; - let amount_u128 = amount - .clone() - .try_into() - .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; - let claim_weight: u128 = claim_duration_u128 - .checked_mul(amount_u128) - .ok_or(ArithmeticError::Overflow)?; - let proportion = Perquintill::from_rational( - claim_weight, - ncp.weight_force(current_block) - .ok_or(Error::::TypeIncompatibleOrArithmeticError)?, - ); + } else if let Some(mut ncp) = >::get() { + let claim_duration: BlockNumberFor = if terminated { + // This means the effective investing duration is beyond the pool lifespan + // i.e. users who do not claim reward after the pool end are still considering as in-pool contributing their weights + claim_duration = current_block - start_time + } else { + // Only counting the investing weight during the epoch + // Claim from start_time until the end_time + claim_duration = end_time - start_time + }; + + let claim_duration_u128: u128 = claim_duration + .try_into() + .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + let amount_u128 = + amount.try_into().or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + let claim_weight: u128 = claim_duration_u128 + .checked_mul(amount_u128) + .ok_or(ArithmeticError::Overflow)?; + let proportion = Perquintill::from_rational( + claim_weight, + ncp.weight_force(current_block) + .ok_or(Error::::TypeIncompatibleOrArithmeticError)?, + ); - let reward_pool_u128: u128 = reward_pool - .try_into() - .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; - let distributed_reward_u128: u128 = proportion * reward_pool_u128; - let distributed_reward: BalanceOf = distributed_reward_u128 - .try_into() - .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; - // Transfer CAN reward - T::Fungibles::transfer( - can_asset_id, - &beneficiary_account, - &who, - distributed_reward, - Preservation::Expendable, - )?; - - // Update gloabl investing status - if terminated { - let _ = ncp - .remove(start_time, amount) - .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; - } else { - // Do not care what new Synthetic effective_time of investing pool - let _ = ncp - .claim_based_on_weight(claim_weight) - .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; - } - - // Adjust checkpoint - >::put(ncp); - Self::deposit_event(Event::::CANRewardClaimed { - who, - claim_duration, - invest_amount: amount, - reward_amount: distributed_reward, - }); + let reward_pool_u128: u128 = reward_pool + .try_into() + .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + let distributed_reward_u128: u128 = proportion * reward_pool_u128; + let distributed_reward: BalanceOf = distributed_reward_u128 + .try_into() + .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + // Transfer CAN reward + T::Fungibles::transfer( + can_asset_id, + &beneficiary_account, + &who, + distributed_reward, + Preservation::Expendable, + )?; + + // Update gloabl investing status + if terminated { + ncp.remove(start_time, amount) + .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; + } else { + // Do not care what new Synthetic effective_time of investing pool + ncp.claim_based_on_weight(claim_weight) + .ok_or(Error::::TypeIncompatibleOrArithmeticError)?; } + + // Adjust checkpoint + >::put(ncp); + Self::deposit_event(Event::::CANRewardClaimed { + who, + claim_duration, + invest_amount: amount, + reward_amount: distributed_reward, + }); } Ok(()) } @@ -795,40 +789,35 @@ pub mod pallet { // Nothing to claim // Do nothing return Ok(()); - } else { - if let Some(scp) = >::get(pool_id) { - // Must exist - let total_investing: u128 = scp - .amount + } else if let Some(scp) = >::get(pool_id) { + // Must exist + let total_investing: u128 = + scp.amount.try_into().or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + // Claim until the claimed_until_epoch + // loop through each epoch + for i in start_epoch..(end_epoch + 1) { + let reward_pool = >::get(pool_id, i) + .ok_or(Error::::EpochRewardNotUpdated)?; + + let proportion = Perquintill::from_rational(amount_u128, total_investing); + + let reward_pool_u128: u128 = reward_pool + .try_into() + .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + let distributed_reward_u128: u128 = proportion * reward_pool_u128; + let distributed_reward: BalanceOf = distributed_reward_u128 .try_into() .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; - // Claim until the claimed_until_epoch - // loop through each epoch - for i in start_epoch..(end_epoch + 1) { - let reward_pool = >::get(pool_id, i) - .ok_or(Error::::EpochRewardNotUpdated)?; - - let proportion = Perquintill::from_rational(amount_u128, total_investing); - - let reward_pool_u128: u128 = reward_pool - .try_into() - .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; - let distributed_reward_u128: u128 = proportion * reward_pool_u128; - let distributed_reward: BalanceOf = - distributed_reward_u128 - .try_into() - .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; - total_distributed_reward = total_distributed_reward - .checked_add(&distributed_reward) - .ok_or(ArithmeticError::Overflow)?; - - Self::deposit_event(Event::::StableRewardClaimed { - who: who.clone(), - pool_id, - epoch: i, - reward_amount: distributed_reward, - }); - } + total_distributed_reward = total_distributed_reward + .checked_add(&distributed_reward) + .ok_or(ArithmeticError::Overflow)?; + + Self::deposit_event(Event::::StableRewardClaimed { + who: who.clone(), + pool_id, + epoch: i, + reward_amount: distributed_reward, + }); } } From 3ac018b91083b2183f5047c354b58f266bf7f4d4 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 1 Nov 2024 10:53:44 +0800 Subject: [PATCH 132/215] chore: fix --- parachain/pallets/collab-ai/investing-pool/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index a97c54210c..e711e77edc 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -709,11 +709,11 @@ pub mod pallet { let claim_duration: BlockNumberFor = if terminated { // This means the effective investing duration is beyond the pool lifespan // i.e. users who do not claim reward after the pool end are still considering as in-pool contributing their weights - claim_duration = current_block - start_time + current_block - start_time } else { // Only counting the investing weight during the epoch // Claim from start_time until the end_time - claim_duration = end_time - start_time + end_time - start_time }; let claim_duration_u128: u128 = claim_duration From cc393e82cb3ba11c8d4e1075ec6a8eed5f4f7b82 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 1 Nov 2024 11:15:56 +0800 Subject: [PATCH 133/215] chore: fix --- parachain/pallets/collab-ai/investing-pool/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index e711e77edc..c0c34ae222 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -541,7 +541,7 @@ pub mod pallet { #[transactional] pub fn regist_can(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResult { T::InvestingPoolAdminOrigin::ensure_origin(origin)?; - >::put(asset_id.clone()); + >::put(asset_id); Self::deposit_event(Event::::AIUSDRegisted { asset_id }); Ok(()) } From 08111e109d7e792275539c01eb140b5f86be840c Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 1 Nov 2024 16:20:38 +0800 Subject: [PATCH 134/215] chore: add first pool proposal test case --- .../collab-ai/pool-proposal/src/lib.rs | 14 +-- .../collab-ai/pool-proposal/src/mock.rs | 44 +++++++- .../collab-ai/pool-proposal/src/tests.rs | 100 ++++++++++++++---- .../collab-ai/pool-proposal/src/types.rs | 2 +- .../collab-ai/pool-proposal/PoolProposal.sol | 4 +- .../collab-ai/pool-proposal/src/lib.rs | 18 ++-- 6 files changed, 136 insertions(+), 46 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index e9c932b1df..4828f3d0f9 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -67,10 +67,10 @@ pub type AssetBalanceOf = pub type AssetIdOf = as FsInspect<::AccountId>>::AssetId; -// #[cfg(test)] -// mod mock; -// #[cfg(test)] -// mod tests; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; #[frame_support::pallet] pub mod pallet { @@ -268,7 +268,7 @@ pub mod pallet { /// All ProposalStatusFlags must be satisfied after this period passed, which is also /// the approximate date when pool begins. /// pool_last_time: How long does the investing pool last if passed - /// estimated_epoch_reward: This number is only for displaying purpose without any techinical meaning + /// estimated_pool_reward: This number is only for displaying purpose without any techinical meaning /// pool_info_hash: Hash of pool info for including pool details #[pallet::call_index(0)] #[pallet::weight({195_000_000})] @@ -278,7 +278,7 @@ pub mod pallet { max_pool_size: AssetBalanceOf, proposal_last_time: BlockNumberFor, pool_last_time: BlockNumberFor, - estimated_epoch_reward: AssetBalanceOf, + estimated_pool_reward: AssetBalanceOf, pool_info_hash: InfoHash, ) -> DispatchResult { let who = T::ProposalOrigin::ensure_origin(origin)?; @@ -305,7 +305,7 @@ pub mod pallet { pool_end_time: pool_start_time .checked_add(&pool_last_time) .ok_or(ArithmeticError::Overflow)?, - estimated_epoch_reward, + estimated_pool_reward, proposal_status_flags: ProposalStatusFlags::empty(), }; diff --git a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs index 01547378cc..23992f575b 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs @@ -28,6 +28,8 @@ use sp_runtime::{ AccountId32, BuildStorage, }; +use pallet_collab_ai_common::*; + pub type Signature = sp_runtime::MultiSignature; pub type AccountId = <::Signer as IdentifyAccount>::AccountId; @@ -50,7 +52,7 @@ parameter_types! { pub const MinimumProposalLastTime: u32 = 10; pub const MinimumPoolDeposit: Balance = 100; pub const MaxGuardianPerProposal: u32 = 2; - pub const MaximumPoolProposed: u32 = 2; + pub const MaximumPoolProposed: u32 = 1; } impl frame_system::Config for Test { @@ -125,17 +127,35 @@ impl Get for PreInvestingPool { } } +pub struct MockGuardianQuery; +impl GuardianQuery for MockGuardianQuery { + /// All guardian but banned ones + fn is_guardian(_account: AccountId) -> bool { + true + } + + /// Only verified one + fn is_verified_guardian(_account: AccountId) -> bool { + true + } + + /// Get vote + fn get_vote(voter: AccountId, guardian: AccountId) -> Option { + Some(GuardianVote::Aye) + } +} + impl pallet_pool_proposal::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type AIUSDAssetId = AIUSDAssetId; - tpye OfficialGapPeriod = OfficialGapPeriod; + type OfficialGapPeriod = OfficialGapPeriod; type MinimumProposalLastTime = MinimumProposalLastTime; type MinimumPoolDeposit = MinimumPoolDeposit; type MaximumPoolProposed = MaxGuardianPerProposal; type ProposalOrigin = frame_system::EnsureRoot; type PublicVotingOrigin = frame_system::EnsureRoot; - type GuardianVoteResource = ; + type GuardianVoteResource = MockGuardianQuery; type MaxGuardianPerProposal = MaxGuardianPerProposal; type PreInvestingPool = PreInvestingPool; } @@ -147,7 +167,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { ext.execute_with(|| { System::set_block_number(1); - let owner = AccountId32::from([2u8; 32]); + let owner = AccountId32::from([1u8; 32]); let origin = RuntimeOrigin::root(); // Create the AIUSD asset @@ -166,8 +186,22 @@ pub fn new_test_ext() -> sp_io::TestExternalities { assert_ok!(pallet_aiusd::InspectFungibles::::mint_into( target_asset_id, &owner, - 1_000_000_000 // 1000 (10^6 * 1000) + 1_000_000_000_000_000_000_000_000 // 1 000 000 (10^18 * 1000) )); }); ext } + +// Checks events against the latest. A contiguous set of events must be provided. They must +// include the most recent event, but do not have to include every past event. +pub fn assert_events(mut expected: Vec) { + let mut actual: Vec = + frame_system::Pallet::::events().iter().map(|e| e.event.clone()).collect(); + + expected.reverse(); + + for evt in expected { + let next = actual.pop().expect("event expected"); + assert_eq!(next, evt, "Events don't match"); + } +} diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 6188cdf3df..6e4fdbd259 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -1,32 +1,88 @@ -use crate::mock::*; -use frame_support::assert_ok; +use crate::mock::{Error, *}; +use frame_support::{assert_err, assert_noop, assert_ok}; use sp_runtime::AccountId32; #[test] fn test_propose_investing_pool_ok() { new_test_ext().execute_with(|| { - let curator: AccountId32 = AccountId32::from([1u8; 32]); - let info_hash: [u8; 32] = [1; 32]; - let curator_index = PublicCuratorCount::::get(); + let user_a: AccountId32 = AccountId32::from([1u8; 32]); + let user_b: AccountId32 = AccountId32::from([2u8; 32]); + Balances::make_free_balance_be(&user_a, 100_000_000_000_000_000_000); - // Register curator - assert_ok!(Curator::regist_curator( - RuntimeOrigin::signed(curator.clone()), - sp_core::H256(info_hash) - )); + let max_pool_size = 1_000_000_000_000_000_000_000u128; + let proposal_last_time = 100; + let pool_last_time = 10000; + let estimated_pool_reward = 2_000_000_000_000_000_000_000u128; + let pool_info_hash: [u8; 32] = [2; 32]; + let pool_info_hash_2: [u8; 32] = [3; 32]; + + // Bad origin + assert_noop!( + PoolProposal::propose_investing_pool( + RuntimeOrigin::signed(user_a.clone()), + max_pool_size, + proposal_last_time, + pool_last_time, + estimated_pool_reward, + pool_info_hash + ), + sp_runtime::DispatchError::BadOrigin + ); + // ProposalPublicTimeTooShort + assert_noop!( + PoolProposal::propose_investing_pool( + RuntimeOrigin::signed(user_a.clone()), + max_pool_size, + 1, + pool_last_time, + estimated_pool_reward, + pool_info_hash + ), + Error::::ProposalPublicTimeTooShort + ); - // Check if curator is stored correctly - assert_eq!(PublicCuratorToIndex::::get(&curator), Some(curator_index)); - assert_eq!(PublicCuratorCount::::get(), curator_index + 1); - assert_eq!( - CuratorIndexToInfo::::get(curator_index), - Some((sp_core::H256(info_hash), 1, curator.clone(), CandidateStatus::Unverified)) + // No enough reserve token + assert_err!( + PoolProposal::propose_investing_pool( + RuntimeOrigin::signed(user_b.clone()), + max_pool_size, + proposal_last_time, + pool_last_time, + estimated_pool_reward, + pool_info_hash + ), + TokenError::FundsUnavailable ); - System::assert_last_event(RuntimeEvent::Curator(crate::Event::CuratorRegisted { - curator, - curator_index, - info_hash: sp_core::H256(info_hash), - })); + // Worked + assert_ok!(PoolProposal::propose_investing_pool( + RuntimeOrigin::signed(user_a.clone()), + max_pool_size, + proposal_last_time, + pool_last_time, + estimated_pool_reward, + pool_info_hash + )); + + assert_events(vec![RuntimeEvent::PoolProposal( + pallet_pool_proposal::Event::PoolProposed { + proposer: user_a.clone(), + pool_proposal_index: 1u128, + info_hash: pool_info_hash, + }, + )]); + + // Oversized + assert_noop!( + PoolProposal::propose_investing_pool( + RuntimeOrigin::signed(user_a), + max_pool_size, + proposal_last_time, + pool_last_time, + estimated_pool_reward, + pool_info_hash + ), + Error::::ProposalDepositDuplicatedOrOversized + ); }) -} \ No newline at end of file +} diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index f13dbec3b4..fc185517a3 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -79,7 +79,7 @@ pub struct PoolProposalInfo { pub pool_end_time: BlockNumber, // estimated APR, but in percentage form // i.e. 100 => 100% - pub estimated_epoch_reward: Balance, + pub estimated_pool_reward: Balance, // Proposal status flags pub proposal_status_flags: ProposalStatusFlags, } diff --git a/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol b/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol index 5a692fb9da..43b1ad7b16 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol +++ b/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol @@ -71,11 +71,11 @@ interface IPoolProposal { /// @param max_pool_size: At most this amount of raised money curator/investing pool willing to take /// @param proposal_last_time: How does the proposal lasts for voting/preinvesting. /// @param pool_last_time: How long does the investing pool last if passed - /// @param estimated_epoch_reward: This number is only for displaying purpose without any techinical meaning + /// @param estimated_pool_reward: This number is only for displaying purpose without any techinical meaning /// @param pool_info_hash: H256 hash of pool info for including pool details /// @custom:selector 0x7bc55add /// proposeInvestingPool(uint256,uint256,uint256,uint256,bytes32) - function proposeInvestingPool(uint256 max_pool_size, uint256 proposal_last_time, uint256 pool_last_time, uint256 estimated_epoch_reward, bytes32 pool_info_hash) external; + function proposeInvestingPool(uint256 max_pool_size, uint256 proposal_last_time, uint256 pool_last_time, uint256 estimated_pool_reward, bytes32 pool_info_hash) external; /// @notice Prestake the pool proposal /// @param pool_proposal_index: Index of pool proposal diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index 246dc1dda8..89f89bcd9d 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -43,7 +43,7 @@ where max_pool_size: U256, proposal_last_time: U256, pool_last_time: U256, - estimated_epoch_reward: U256, + estimated_pool_reward: U256, pool_info_hash: H256, ) -> EvmResult { let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); @@ -63,8 +63,8 @@ where Into::::into(RevertReason::value_is_too_large("block number type")) })?; - let estimated_epoch_reward: AssetBalanceOf = - estimated_epoch_reward.try_into().map_err(|_| { + let estimated_pool_reward: AssetBalanceOf = + estimated_pool_reward.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("balance type")) })?; @@ -72,7 +72,7 @@ where max_pool_size, proposal_last_time, pool_last_time, - estimated_epoch_reward, + estimated_pool_reward, pool_info_hash, }; RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; @@ -250,7 +250,7 @@ where max_pool_size: info.max_pool_size.into(), pool_start_time: info.pool_start_time.into(), pool_end_time: info.pool_end_time.into(), - estimated_epoch_reward: info.estimated_epoch_reward.into(), + estimated_pool_reward: info.estimated_pool_reward.into(), proposal_status_flags: info.proposal_status_flags.bits(), }) } else { @@ -261,7 +261,7 @@ where max_pool_size: Default::default(), pool_start_time: Default::default(), pool_end_time: Default::default(), - estimated_epoch_reward: Default::default(), + estimated_pool_reward: Default::default(), proposal_status_flags: Default::default(), }) } @@ -312,7 +312,7 @@ where max_pool_size: info.max_pool_size.into(), pool_start_time: info.pool_start_time.into(), pool_end_time: info.pool_end_time.into(), - estimated_epoch_reward: info.estimated_epoch_reward.into(), + estimated_pool_reward: info.estimated_pool_reward.into(), proposal_status_flags: info.proposal_status_flags.bits(), } } else { @@ -323,7 +323,7 @@ where max_pool_size: Default::default(), pool_start_time: Default::default(), pool_end_time: Default::default(), - estimated_epoch_reward: Default::default(), + estimated_pool_reward: Default::default(), proposal_status_flags: Default::default(), } } @@ -506,6 +506,6 @@ struct PoolProposalInfo { max_pool_size: U256, pool_start_time: U256, pool_end_time: U256, - estimated_epoch_reward: U256, + estimated_pool_reward: U256, proposal_status_flags: u8, } From 40a2187d0baea5e3d64867e5f752693682470d75 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 1 Nov 2024 16:47:12 +0800 Subject: [PATCH 135/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/Cargo.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/parachain/pallets/collab-ai/pool-proposal/Cargo.toml b/parachain/pallets/collab-ai/pool-proposal/Cargo.toml index d70002998a..a1fa39ed43 100644 --- a/parachain/pallets/collab-ai/pool-proposal/Cargo.toml +++ b/parachain/pallets/collab-ai/pool-proposal/Cargo.toml @@ -22,6 +22,12 @@ sp-std = { workspace = true } pallet-collab-ai-common = { workspace = true } +[dev-dependencies] +sp-core = { workspace = true } +sp-io = { workspace = true } +pallet-balances = { workspace = true } +pallet-assets = { workspace = true } + [features] default = ["std"] runtime-benchmarks = [ From ca3fa0e1ba552ec46e1069b34a9331f5641e958e Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 1 Nov 2024 16:51:07 +0800 Subject: [PATCH 136/215] chore: fix lock --- parachain/Cargo.lock | 3 +++ 1 file changed, 3 insertions(+) diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index 8239778317..52f88bea95 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -8064,9 +8064,12 @@ dependencies = [ "frame-system", "orml-utilities", "pallet-assets", + "pallet-balances", "pallet-collab-ai-common", "parity-scale-codec", "scale-info", + "sp-core", + "sp-io", "sp-runtime", "sp-std", ] From 8b036adf7cc84d8fea58b507283c2e573291f049 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 1 Nov 2024 17:14:03 +0800 Subject: [PATCH 137/215] chore: fix --- .../collab-ai/investing-pool/Cargo.toml | 3 +-- .../collab-ai/pool-proposal/Cargo.toml | 1 - .../collab-ai/pool-proposal/src/mock.rs | 12 +++++------- .../collab-ai/pool-proposal/src/tests.rs | 19 +++++++++---------- 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/parachain/pallets/collab-ai/investing-pool/Cargo.toml b/parachain/pallets/collab-ai/investing-pool/Cargo.toml index 88929fe13f..fe3aab37ee 100644 --- a/parachain/pallets/collab-ai/investing-pool/Cargo.toml +++ b/parachain/pallets/collab-ai/investing-pool/Cargo.toml @@ -19,7 +19,6 @@ serde = { workspace = true } frame-benchmarking = { workspace = true, optional = true } frame-support = { workspace = true } frame-system = { workspace = true } -pallet-assets = { workspace = true } sp-runtime = { workspace = true, features = ["serde"] } sp-std = { workspace = true } @@ -28,6 +27,7 @@ pallet-collab-ai-common = { workspace = true } [dev-dependencies] sp-core = { workspace = true } sp-io = { workspace = true } +pallet-assets = { workspace = true } pallet-balances = { workspace = true } [features] @@ -44,7 +44,6 @@ std = [ "sp-runtime/std", "sp-std/std", "pallet-balances/std", - "pallet-assets/std", "pallet-collab-ai-common/std", ] runtime-benchmarks = [ diff --git a/parachain/pallets/collab-ai/pool-proposal/Cargo.toml b/parachain/pallets/collab-ai/pool-proposal/Cargo.toml index a1fa39ed43..96e316ea5e 100644 --- a/parachain/pallets/collab-ai/pool-proposal/Cargo.toml +++ b/parachain/pallets/collab-ai/pool-proposal/Cargo.toml @@ -26,7 +26,6 @@ pallet-collab-ai-common = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } pallet-balances = { workspace = true } -pallet-assets = { workspace = true } [features] default = ["std"] diff --git a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs index 23992f575b..322ad999c3 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs @@ -179,14 +179,12 @@ pub fn new_test_ext() -> sp_io::TestExternalities { 1, )); - // Check if these assets exists - assert!(pallet_aiusd::InspectFungibles::::asset_exists(1)); - // Set total supply - assert_ok!(pallet_aiusd::InspectFungibles::::mint_into( - target_asset_id, - &owner, - 1_000_000_000_000_000_000_000_000 // 1 000 000 (10^18 * 1000) + assert_ok!(pallet_assets::Pallet::::mint( + owner.clone(), + 1, // AIUSD asset id + owner.clone(), + 1_000_000_000_000_000_000_000_000, // 1 000 000 (10^18 * 1000) )); }); ext diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 6e4fdbd259..1920634e80 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -1,5 +1,6 @@ use crate::mock::{Error, *}; -use frame_support::{assert_err, assert_noop, assert_ok}; +use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; +use sp_core::H256; use sp_runtime::AccountId32; #[test] @@ -13,8 +14,8 @@ fn test_propose_investing_pool_ok() { let proposal_last_time = 100; let pool_last_time = 10000; let estimated_pool_reward = 2_000_000_000_000_000_000_000u128; - let pool_info_hash: [u8; 32] = [2; 32]; - let pool_info_hash_2: [u8; 32] = [3; 32]; + let pool_info_hash: H256 = H256([2; 32]); + let pool_info_hash_2: H256 = H256([3; 32]); // Bad origin assert_noop!( @@ -64,13 +65,11 @@ fn test_propose_investing_pool_ok() { pool_info_hash )); - assert_events(vec![RuntimeEvent::PoolProposal( - pallet_pool_proposal::Event::PoolProposed { - proposer: user_a.clone(), - pool_proposal_index: 1u128, - info_hash: pool_info_hash, - }, - )]); + assert_events(vec![RuntimeEvent::PoolProposal(crate::Event::PoolProposed { + proposer: user_a.clone(), + pool_proposal_index: 1u128, + info_hash: pool_info_hash, + })]); // Oversized assert_noop!( From 4b79a98e6095442e21b98552f3c85cf0887adc24 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Fri, 1 Nov 2024 17:31:41 +0800 Subject: [PATCH 138/215] chore: fix --- .../pallets/collab-ai/pool-proposal/src/mock.rs | 17 +++++++++++++++-- .../collab-ai/pool-proposal/src/tests.rs | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs index 322ad999c3..d30703a737 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs @@ -127,6 +127,19 @@ impl Get for PreInvestingPool { } } +pub struct MockCuratorQuery; +impl CuratorQuery for MockCuratorQuery { + /// All curator but banned ones + fn is_curator(account: AccountId) -> bool { + true + } + + /// Only verified one + fn is_verified_curator(account: AccountId) -> bool { + true + } +} + pub struct MockGuardianQuery; impl GuardianQuery for MockGuardianQuery { /// All guardian but banned ones @@ -153,7 +166,7 @@ impl pallet_pool_proposal::Config for Test { type MinimumProposalLastTime = MinimumProposalLastTime; type MinimumPoolDeposit = MinimumPoolDeposit; type MaximumPoolProposed = MaxGuardianPerProposal; - type ProposalOrigin = frame_system::EnsureRoot; + type ProposalOrigin = EnsureSignedAndCurator; type PublicVotingOrigin = frame_system::EnsureRoot; type GuardianVoteResource = MockGuardianQuery; type MaxGuardianPerProposal = MaxGuardianPerProposal; @@ -181,7 +194,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { // Set total supply assert_ok!(pallet_assets::Pallet::::mint( - owner.clone(), + RuntimeOrigin::signed(owner.clone()), 1, // AIUSD asset id owner.clone(), 1_000_000_000_000_000_000_000_000, // 1 000 000 (10^18 * 1000) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 1920634e80..eb8bef0f87 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -1,7 +1,7 @@ use crate::mock::{Error, *}; use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; use sp_core::H256; -use sp_runtime::AccountId32; +use sp_runtime::{AccountId32, TokenError}; #[test] fn test_propose_investing_pool_ok() { From d42414cf7c98fe8b63bdcec5381467b2f1388308 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sat, 2 Nov 2024 01:01:41 +0800 Subject: [PATCH 139/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/tests.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index eb8bef0f87..0c3f34a013 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -1,4 +1,4 @@ -use crate::mock::{Error, *}; +use crate::mock::*; use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; use sp_core::H256; use sp_runtime::{AccountId32, TokenError}; @@ -39,7 +39,7 @@ fn test_propose_investing_pool_ok() { estimated_pool_reward, pool_info_hash ), - Error::::ProposalPublicTimeTooShort + crate::Error::::ProposalPublicTimeTooShort ); // No enough reserve token @@ -81,7 +81,7 @@ fn test_propose_investing_pool_ok() { estimated_pool_reward, pool_info_hash ), - Error::::ProposalDepositDuplicatedOrOversized + crate::Error::::ProposalDepositDuplicatedOrOversized ); }) } From e853fdb93891f3bc6fe7c8d3f7d6e245da1edfca Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sat, 2 Nov 2024 01:15:26 +0800 Subject: [PATCH 140/215] chore: fix --- .../pallets/collab-ai/pool-proposal/src/mock.rs | 11 ++++------- .../pallets/collab-ai/pool-proposal/src/tests.rs | 14 +------------- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs index d30703a737..671f21cfb4 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs @@ -17,10 +17,7 @@ use crate as pallet_pool_proposal; use frame_support::{ assert_ok, construct_runtime, parameter_types, - traits::{ - tokens::fungibles::{Inspect, Mutate}, - AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, Everything, - }, + traits::{AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, Everything}, }; use sp_core::{Get, H256}; use sp_runtime::{ @@ -130,12 +127,12 @@ impl Get for PreInvestingPool { pub struct MockCuratorQuery; impl CuratorQuery for MockCuratorQuery { /// All curator but banned ones - fn is_curator(account: AccountId) -> bool { + fn is_curator(_account: AccountId) -> bool { true } /// Only verified one - fn is_verified_curator(account: AccountId) -> bool { + fn is_verified_curator(_account: AccountId) -> bool { true } } @@ -153,7 +150,7 @@ impl GuardianQuery for MockGuardianQuery { } /// Get vote - fn get_vote(voter: AccountId, guardian: AccountId) -> Option { + fn get_vote(_voter: AccountId, _guardian: AccountId) -> Option { Some(GuardianVote::Aye) } } diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 0c3f34a013..124a7e553b 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -17,18 +17,6 @@ fn test_propose_investing_pool_ok() { let pool_info_hash: H256 = H256([2; 32]); let pool_info_hash_2: H256 = H256([3; 32]); - // Bad origin - assert_noop!( - PoolProposal::propose_investing_pool( - RuntimeOrigin::signed(user_a.clone()), - max_pool_size, - proposal_last_time, - pool_last_time, - estimated_pool_reward, - pool_info_hash - ), - sp_runtime::DispatchError::BadOrigin - ); // ProposalPublicTimeTooShort assert_noop!( PoolProposal::propose_investing_pool( @@ -79,7 +67,7 @@ fn test_propose_investing_pool_ok() { proposal_last_time, pool_last_time, estimated_pool_reward, - pool_info_hash + pool_info_hash_2 ), crate::Error::::ProposalDepositDuplicatedOrOversized ); From 711ad3eaf3e98e5939bdc21b2494766395918e7b Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sat, 2 Nov 2024 01:26:22 +0800 Subject: [PATCH 141/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/tests.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 124a7e553b..c70858316f 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -1,5 +1,6 @@ use crate::mock::*; use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; +use pallet_balances::Error as BalanceError; use sp_core::H256; use sp_runtime::{AccountId32, TokenError}; @@ -40,7 +41,7 @@ fn test_propose_investing_pool_ok() { estimated_pool_reward, pool_info_hash ), - TokenError::FundsUnavailable + BalanceError::::InsufficientBalance ); // Worked From 795c2052c60782d9fd620560d7b44ff1bfad9db6 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sat, 2 Nov 2024 01:53:46 +0800 Subject: [PATCH 142/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index c70858316f..93c4f07a11 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -56,7 +56,7 @@ fn test_propose_investing_pool_ok() { assert_events(vec![RuntimeEvent::PoolProposal(crate::Event::PoolProposed { proposer: user_a.clone(), - pool_proposal_index: 1u128, + pool_proposal_index: 0u128, info_hash: pool_info_hash, })]); From bebce1af0bc25a2e02093696fccd8731f2aec467 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sat, 2 Nov 2024 01:59:00 +0800 Subject: [PATCH 143/215] chore: fix --- parachain/pallets/collab-ai/curator/src/lib.rs | 8 +++++++- parachain/pallets/collab-ai/guardian/src/lib.rs | 8 +++++++- parachain/pallets/collab-ai/guardian/src/tests.rs | 8 ++++---- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 8 +++++++- parachain/pallets/collab-ai/pool-proposal/src/tests.rs | 2 +- 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/parachain/pallets/collab-ai/curator/src/lib.rs b/parachain/pallets/collab-ai/curator/src/lib.rs index 974791dedf..a0271e6c8a 100644 --- a/parachain/pallets/collab-ai/curator/src/lib.rs +++ b/parachain/pallets/collab-ai/curator/src/lib.rs @@ -74,10 +74,16 @@ pub mod pallet { type CuratorJudgeOrigin: EnsureOrigin; } + #[pallet::type_value] + pub(super) fn DefaultForCuratorIndex() -> CuratorIndex { + 1.into() + } + /// The number of (public) curator that have been made so far. #[pallet::storage] #[pallet::getter(fn public_curator_count)] - pub type PublicCuratorCount = StorageValue<_, CuratorIndex, ValueQuery>; + pub type PublicCuratorCount = + StorageValue<_, CuratorIndex, ValueQuery, DefaultForCuratorIndex>; /// The public curator to index #[pallet::storage] diff --git a/parachain/pallets/collab-ai/guardian/src/lib.rs b/parachain/pallets/collab-ai/guardian/src/lib.rs index c958f34083..e5ce4bcbfa 100644 --- a/parachain/pallets/collab-ai/guardian/src/lib.rs +++ b/parachain/pallets/collab-ai/guardian/src/lib.rs @@ -78,10 +78,16 @@ pub mod pallet { type GuardianJudgeOrigin: EnsureOrigin; } + #[pallet::type_value] + pub(super) fn DefaultForGuardianIndex() -> GuardianIndex { + 1.into() + } + /// The number of (public) guardian that have been made so far. #[pallet::storage] #[pallet::getter(fn public_guardian_count)] - pub type PublicGuardianCount = StorageValue<_, GuardianIndex, ValueQuery>; + pub type PublicGuardianCount = + StorageValue<_, GuardianIndex, ValueQuery, DefaultForGuardianIndex>; /// The public guardian to index #[pallet::storage] diff --git a/parachain/pallets/collab-ai/guardian/src/tests.rs b/parachain/pallets/collab-ai/guardian/src/tests.rs index 08dcc69c33..10b44a0986 100644 --- a/parachain/pallets/collab-ai/guardian/src/tests.rs +++ b/parachain/pallets/collab-ai/guardian/src/tests.rs @@ -36,7 +36,7 @@ fn test_regist_guardian() { assert_eq!(Guardian::public_guardian_to_index(&guardian), Some(0)); System::assert_last_event(RuntimeEvent::Guardian(crate::Event::GuardianRegisted { guardian, - guardian_index: 0, + guardian_index: 1, info_hash: sp_core::H256(info_hash), })); }); @@ -66,7 +66,7 @@ fn test_update_guardian() { assert_eq!(guardian_info.0, sp_core::H256(updated_hash)); System::assert_last_event(RuntimeEvent::Guardian(crate::Event::GuardianUpdated { guardian, - guardian_index: 0, + guardian_index: 1, info_hash: sp_core::H256(updated_hash), })); }); @@ -89,7 +89,7 @@ fn test_clean_guardian() { assert_eq!(Guardian::public_guardian_to_index(&guardian), None); System::assert_last_event(RuntimeEvent::Guardian(crate::Event::GuardianCleaned { guardian, - guardian_index: 0, + guardian_index: 1, })); }); } @@ -121,7 +121,7 @@ fn test_vote_for_guardian() { ); System::assert_last_event(RuntimeEvent::Guardian(crate::Event::VoteGuardian { voter, - guardian_index: 0, + guardian_index: 1, guardian, status: Some(GuardianVote::Specific(1)), })); diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 4828f3d0f9..41ce94befb 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -132,10 +132,16 @@ pub mod pallet { type PreInvestingPool: Get; } + #[pallet::type_value] + pub(super) fn DefaultForProposalIndex() -> PoolProposalIndex { + 1.into() + } + /// The next free Pool Proposal index, aka the number of pool proposed so far. #[pallet::storage] #[pallet::getter(fn pool_proposal_count)] - pub type PoolProposalCount = StorageValue<_, PoolProposalIndex, ValueQuery>; + pub type PoolProposalCount = + StorageValue<_, PoolProposalIndex, ValueQuery, DefaultForProposalIndex>; /// Those who have a reserve for his pool proposal. #[pallet::storage] diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 93c4f07a11..c70858316f 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -56,7 +56,7 @@ fn test_propose_investing_pool_ok() { assert_events(vec![RuntimeEvent::PoolProposal(crate::Event::PoolProposed { proposer: user_a.clone(), - pool_proposal_index: 0u128, + pool_proposal_index: 1u128, info_hash: pool_info_hash, })]); From cbc41577eb44db2cb5bdbe08a74b7fb6d6b62b7d Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sat, 2 Nov 2024 03:05:54 +0800 Subject: [PATCH 144/215] chore: fix --- parachain/pallets/collab-ai/curator/src/lib.rs | 2 +- parachain/pallets/collab-ai/guardian/src/lib.rs | 2 +- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/parachain/pallets/collab-ai/curator/src/lib.rs b/parachain/pallets/collab-ai/curator/src/lib.rs index a0271e6c8a..30c09942fa 100644 --- a/parachain/pallets/collab-ai/curator/src/lib.rs +++ b/parachain/pallets/collab-ai/curator/src/lib.rs @@ -76,7 +76,7 @@ pub mod pallet { #[pallet::type_value] pub(super) fn DefaultForCuratorIndex() -> CuratorIndex { - 1.into() + 1u128 } /// The number of (public) curator that have been made so far. diff --git a/parachain/pallets/collab-ai/guardian/src/lib.rs b/parachain/pallets/collab-ai/guardian/src/lib.rs index e5ce4bcbfa..8f652be5c5 100644 --- a/parachain/pallets/collab-ai/guardian/src/lib.rs +++ b/parachain/pallets/collab-ai/guardian/src/lib.rs @@ -80,7 +80,7 @@ pub mod pallet { #[pallet::type_value] pub(super) fn DefaultForGuardianIndex() -> GuardianIndex { - 1.into() + 1u128 } /// The number of (public) guardian that have been made so far. diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 41ce94befb..dc95630934 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -134,7 +134,7 @@ pub mod pallet { #[pallet::type_value] pub(super) fn DefaultForProposalIndex() -> PoolProposalIndex { - 1.into() + 1u128 } /// The next free Pool Proposal index, aka the number of pool proposed so far. From f804b22982f888f04fa46d06e5bfc932d5572519 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sat, 2 Nov 2024 12:13:53 +0800 Subject: [PATCH 145/215] chore: fix --- parachain/precompiles/collab-ai/curator/src/tests.rs | 8 ++++---- .../precompiles/collab-ai/guardian/src/tests.rs | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/parachain/precompiles/collab-ai/curator/src/tests.rs b/parachain/precompiles/collab-ai/curator/src/tests.rs index a72fcfc12f..ed1c282752 100644 --- a/parachain/precompiles/collab-ai/curator/src/tests.rs +++ b/parachain/precompiles/collab-ai/curator/src/tests.rs @@ -42,7 +42,7 @@ fn test_regist_curator() { System::assert_last_event(RuntimeEvent::Curator(Event::CuratorRegisted { curator: TruncatedAddressMapping::into_account_id(curator), - curator_index: 0, + curator_index: 1, info_hash, })); }); @@ -73,7 +73,7 @@ fn test_update_curator() { System::assert_last_event(RuntimeEvent::Curator(Event::CuratorUpdated { curator: TruncatedAddressMapping::into_account_id(curator), - curator_index: 0, + curator_index: 1, info_hash: updated_hash, })); }); @@ -99,7 +99,7 @@ fn test_clean_curator() { System::assert_last_event(RuntimeEvent::Curator(Event::CuratorCleaned { curator: TruncatedAddressMapping::into_account_id(curator), - curator_index: 0, + curator_index: 1, })); }); } @@ -189,7 +189,7 @@ fn test_curator_index_to_info() { .prepare_test( curator, H160::from_low_u64_be(1000), - PCall::::curator_index_to_info { index: 0.into() }, + PCall::::curator_index_to_info { index: 1.into() }, ) .execute_returns(crate::CuratorQueryResult { exist: true, diff --git a/parachain/precompiles/collab-ai/guardian/src/tests.rs b/parachain/precompiles/collab-ai/guardian/src/tests.rs index 6fc000be5d..1111f92f3b 100644 --- a/parachain/precompiles/collab-ai/guardian/src/tests.rs +++ b/parachain/precompiles/collab-ai/guardian/src/tests.rs @@ -43,7 +43,7 @@ fn test_regist_guardian() { System::assert_last_event(RuntimeEvent::Guardian(Event::GuardianRegisted { guardian: TruncatedAddressMapping::into_account_id(guardian), - guardian_index: 0, + guardian_index: 1, info_hash, })); }); @@ -74,7 +74,7 @@ fn test_update_guardian() { System::assert_last_event(RuntimeEvent::Guardian(Event::GuardianUpdated { guardian: TruncatedAddressMapping::into_account_id(guardian), - guardian_index: 0, + guardian_index: 1, info_hash: updated_hash, })); }); @@ -100,7 +100,7 @@ fn test_clean_guardian() { System::assert_last_event(RuntimeEvent::Guardian(Event::GuardianCleaned { guardian: TruncatedAddressMapping::into_account_id(guardian), - guardian_index: 0, + guardian_index: 1, })); }); } @@ -145,7 +145,7 @@ fn test_vote_for_guardian() { System::assert_last_event(RuntimeEvent::Guardian(Event::VoteGuardian { voter: TruncatedAddressMapping::into_account_id(voter), - guardian_index: 0, + guardian_index: 1, guardian: TruncatedAddressMapping::into_account_id(guardian), status: Some(GuardianVote::Aye), })); @@ -288,7 +288,7 @@ fn test_guardian_index_to_info() { .prepare_test( guardian, H160::from_low_u64_be(1000), - PCall::::guardian_index_to_info { index: 0.into() }, + PCall::::guardian_index_to_info { index: 1.into() }, ) .execute_returns(crate::GuardianQueryResult { exist: true, @@ -341,7 +341,7 @@ fn test_guardian_votes() { .prepare_test( voter, H160::from_low_u64_be(1000), - PCall::::guardian_votes { voter: voter_account, guardian_index: 0.into() }, + PCall::::guardian_votes { voter: voter_account, guardian_index: 1.into() }, ) .execute_returns((1u8, U256::from(0))); // Aye vote }); From bfc786ce8bf5780bece2a70af28924f3c34630a9 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sat, 2 Nov 2024 13:39:16 +0800 Subject: [PATCH 146/215] chore: fix --- parachain/pallets/collab-ai/curator/src/lib.rs | 2 +- parachain/pallets/collab-ai/guardian/src/lib.rs | 2 +- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 2 +- parachain/precompiles/collab-ai/curator/src/tests.rs | 8 ++++---- parachain/precompiles/collab-ai/guardian/src/tests.rs | 10 +++++----- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/parachain/pallets/collab-ai/curator/src/lib.rs b/parachain/pallets/collab-ai/curator/src/lib.rs index 30c09942fa..cc89a190b1 100644 --- a/parachain/pallets/collab-ai/curator/src/lib.rs +++ b/parachain/pallets/collab-ai/curator/src/lib.rs @@ -79,7 +79,7 @@ pub mod pallet { 1u128 } - /// The number of (public) curator that have been made so far. + /// The next curator index, the number of (public) curator that have been made so far + 1. #[pallet::storage] #[pallet::getter(fn public_curator_count)] pub type PublicCuratorCount = diff --git a/parachain/pallets/collab-ai/guardian/src/lib.rs b/parachain/pallets/collab-ai/guardian/src/lib.rs index 8f652be5c5..57dfe3d868 100644 --- a/parachain/pallets/collab-ai/guardian/src/lib.rs +++ b/parachain/pallets/collab-ai/guardian/src/lib.rs @@ -83,7 +83,7 @@ pub mod pallet { 1u128 } - /// The number of (public) guardian that have been made so far. + /// Next guardian index, the number of (public) guardian that have been made so far + 1. #[pallet::storage] #[pallet::getter(fn public_guardian_count)] pub type PublicGuardianCount = diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index dc95630934..e029cbde1c 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -137,7 +137,7 @@ pub mod pallet { 1u128 } - /// The next free Pool Proposal index, aka the number of pool proposed so far. + /// The next free Pool Proposal index, aka the number of pool proposed so far + 1. #[pallet::storage] #[pallet::getter(fn pool_proposal_count)] pub type PoolProposalCount = diff --git a/parachain/precompiles/collab-ai/curator/src/tests.rs b/parachain/precompiles/collab-ai/curator/src/tests.rs index ed1c282752..71dadcde70 100644 --- a/parachain/precompiles/collab-ai/curator/src/tests.rs +++ b/parachain/precompiles/collab-ai/curator/src/tests.rs @@ -114,7 +114,7 @@ fn test_public_curator_count() { H160::from_low_u64_be(1000), PCall::::public_curator_count {}, ) - .execute_returns(U256::from(0)); // Provide expected result + .execute_returns(U256::from(1)); // Provide expected result // Register a curator to increase the count let info_hash: H256 = H256::from([1u8; 32]); @@ -133,7 +133,7 @@ fn test_public_curator_count() { H160::from_low_u64_be(1000), PCall::::public_curator_count {}, ) - .execute_returns(U256::from(1)); + .execute_returns(U256::from(2)); }); } @@ -162,7 +162,7 @@ fn test_public_curator_to_index() { H160::from_low_u64_be(1000), PCall::::public_curator_to_index { curator: curator_account }, ) - .execute_returns((true, U256::from(0))); + .execute_returns((true, U256::from(1))); }); } @@ -225,7 +225,7 @@ fn test_batch_curator_index_to_info() { .prepare_test( curator, H160::from_low_u64_be(1000), - PCall::::batch_curator_index_to_info { start_id: 0.into(), end_id: 1.into() }, + PCall::::batch_curator_index_to_info { start_id: 1.into(), end_id: 2.into() }, ) .execute_returns(vec![crate::CuratorQueryResult { exist: true, diff --git a/parachain/precompiles/collab-ai/guardian/src/tests.rs b/parachain/precompiles/collab-ai/guardian/src/tests.rs index 1111f92f3b..d49e300f0d 100644 --- a/parachain/precompiles/collab-ai/guardian/src/tests.rs +++ b/parachain/precompiles/collab-ai/guardian/src/tests.rs @@ -138,7 +138,7 @@ fn test_vote_for_guardian() { PCall::::vote { guardian: guardian_account, status: 1, - potential_proposal_index: 0.into(), + potential_proposal_index: 1.into(), }, ) .execute_returns(()); @@ -185,7 +185,7 @@ fn test_remove_all_votes() { PCall::::vote { guardian: guardian_account, status: 1, - potential_proposal_index: 0.into(), + potential_proposal_index: 1.into(), }, ) .execute_returns(()); @@ -211,7 +211,7 @@ fn test_public_guardian_count() { H160::from_low_u64_be(1000), PCall::::public_guardian_count {}, ) - .execute_returns(U256::from(0)); // Provide expected result + .execute_returns(U256::from(1)); // Provide expected result // Register a guardian to increase the count let info_hash: H256 = H256::from([1u8; 32]); @@ -223,14 +223,14 @@ fn test_public_guardian_count() { ) .execute_returns(()); - // Check the guardian count again, should be 1 + // Check the guardian count again, should be 2 PrecompilesValue::get() .prepare_test( H160::from_low_u64_be(1001), H160::from_low_u64_be(1000), PCall::::public_guardian_count {}, ) - .execute_returns(U256::from(1)); + .execute_returns(U256::from(2)); }); } From 85bef01dac1f07e90565d0a26930141f7e4d67a1 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sat, 2 Nov 2024 14:07:01 +0800 Subject: [PATCH 147/215] chore: fix --- parachain/pallets/collab-ai/curator/src/lib.rs | 2 +- parachain/pallets/collab-ai/guardian/src/lib.rs | 2 +- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 2 +- parachain/pallets/collab-ai/pool-proposal/src/tests.rs | 2 +- parachain/precompiles/collab-ai/guardian/src/tests.rs | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/parachain/pallets/collab-ai/curator/src/lib.rs b/parachain/pallets/collab-ai/curator/src/lib.rs index cc89a190b1..6e0803213e 100644 --- a/parachain/pallets/collab-ai/curator/src/lib.rs +++ b/parachain/pallets/collab-ai/curator/src/lib.rs @@ -75,7 +75,7 @@ pub mod pallet { } #[pallet::type_value] - pub(super) fn DefaultForCuratorIndex() -> CuratorIndex { + pub fn DefaultForCuratorIndex() -> CuratorIndex { 1u128 } diff --git a/parachain/pallets/collab-ai/guardian/src/lib.rs b/parachain/pallets/collab-ai/guardian/src/lib.rs index 57dfe3d868..8d6ff7d8be 100644 --- a/parachain/pallets/collab-ai/guardian/src/lib.rs +++ b/parachain/pallets/collab-ai/guardian/src/lib.rs @@ -79,7 +79,7 @@ pub mod pallet { } #[pallet::type_value] - pub(super) fn DefaultForGuardianIndex() -> GuardianIndex { + pub fn DefaultForGuardianIndex() -> GuardianIndex { 1u128 } diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index e029cbde1c..578142310a 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -133,7 +133,7 @@ pub mod pallet { } #[pallet::type_value] - pub(super) fn DefaultForProposalIndex() -> PoolProposalIndex { + pub fn DefaultForProposalIndex() -> PoolProposalIndex { 1u128 } diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index c70858316f..0b36865cca 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -2,7 +2,7 @@ use crate::mock::*; use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; use pallet_balances::Error as BalanceError; use sp_core::H256; -use sp_runtime::{AccountId32, TokenError}; +use sp_runtime::AccountId32; #[test] fn test_propose_investing_pool_ok() { diff --git a/parachain/precompiles/collab-ai/guardian/src/tests.rs b/parachain/precompiles/collab-ai/guardian/src/tests.rs index d49e300f0d..b37f55646a 100644 --- a/parachain/precompiles/collab-ai/guardian/src/tests.rs +++ b/parachain/precompiles/collab-ai/guardian/src/tests.rs @@ -260,7 +260,7 @@ fn test_public_guardian_to_index() { H160::from_low_u64_be(1000), PCall::::public_guardian_to_index { guardian: guardian_account }, ) - .execute_returns((true, U256::from(0))); + .execute_returns((true, U256::from(1))); }); } @@ -373,8 +373,8 @@ fn test_batch_guardian_index_to_info() { guardian, H160::from_low_u64_be(1000), PCall::::batch_guardian_index_to_info { - start_id: 0.into(), - end_id: 1.into(), + start_id: 1.into(), + end_id: 2.into(), }, ) .execute_returns(vec![crate::GuardianQueryResult { From 0707667d54a0386a67c2450c671017aab0250430 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sat, 2 Nov 2024 14:46:40 +0800 Subject: [PATCH 148/215] chore: fix test --- parachain/pallets/collab-ai/guardian/src/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/pallets/collab-ai/guardian/src/tests.rs b/parachain/pallets/collab-ai/guardian/src/tests.rs index 10b44a0986..8886406a92 100644 --- a/parachain/pallets/collab-ai/guardian/src/tests.rs +++ b/parachain/pallets/collab-ai/guardian/src/tests.rs @@ -33,7 +33,7 @@ fn test_regist_guardian() { )); // Check if guardian is stored correctly - assert_eq!(Guardian::public_guardian_to_index(&guardian), Some(0)); + assert_eq!(Guardian::public_guardian_to_index(&guardian), Some(1)); System::assert_last_event(RuntimeEvent::Guardian(crate::Event::GuardianRegisted { guardian, guardian_index: 1, @@ -62,7 +62,7 @@ fn test_update_guardian() { )); // Check if guardian info is updated correctly - let guardian_info = Guardian::guardian_index_to_info(0).unwrap(); + let guardian_info = Guardian::guardian_index_to_info(1).unwrap(); assert_eq!(guardian_info.0, sp_core::H256(updated_hash)); System::assert_last_event(RuntimeEvent::Guardian(crate::Event::GuardianUpdated { guardian, From 44ce078b2950aef4455e2a9cd3a7bd7f6915e2f0 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sat, 2 Nov 2024 15:00:47 +0800 Subject: [PATCH 149/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/mock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs index 671f21cfb4..a5d346177b 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs @@ -162,7 +162,7 @@ impl pallet_pool_proposal::Config for Test { type OfficialGapPeriod = OfficialGapPeriod; type MinimumProposalLastTime = MinimumProposalLastTime; type MinimumPoolDeposit = MinimumPoolDeposit; - type MaximumPoolProposed = MaxGuardianPerProposal; + type MaximumPoolProposed = MaximumPoolProposed; type ProposalOrigin = EnsureSignedAndCurator; type PublicVotingOrigin = frame_system::EnsureRoot; type GuardianVoteResource = MockGuardianQuery; From bd9401d48b858a63ab2e19bc7f35106ac56f6b32 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sat, 2 Nov 2024 22:23:05 +0800 Subject: [PATCH 150/215] feat: add test and baking proposal logic --- .../collab-ai/aiusd-convertor/src/lib.rs | 42 +++--- .../collab-ai/aiusd-convertor/src/mock.rs | 6 +- .../collab-ai/aiusd-convertor/src/tests.rs | 44 +++--- parachain/pallets/collab-ai/common/src/lib.rs | 17 --- .../collab-ai/investing-pool/src/lib.rs | 17 +-- .../collab-ai/pool-proposal/Cargo.toml | 3 +- .../collab-ai/pool-proposal/src/lib.rs | 134 ++++++++++++++++-- .../collab-ai/pool-proposal/src/mock.rs | 1 + .../collab-ai/pool-proposal/src/tests.rs | 59 ++++++++ .../collab-ai/aiusd-convertor/src/lib.rs | 4 +- .../collab-ai/aiusd-convertor/src/mock.rs | 8 +- .../collab-ai/aiusd-convertor/src/tests.rs | 16 +-- 12 files changed, 247 insertions(+), 104 deletions(-) diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index b7cce3f4e7..053cc92b7b 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -117,28 +117,24 @@ pub mod pallet { #[pallet::call] impl Pallet { - // Lock target_asset_id token and mint AIUSD + // Lock source_asset_id token and mint AIUSD #[pallet::call_index(0)] #[pallet::weight({195_000_000})] #[transactional] pub fn mint_aiusd( origin: OriginFor, - target_asset_id: AssetIdOf, + source_asset_id: AssetIdOf, aiusd_amount: AssetBalanceOf, ) -> DispatchResult { let beneficiary = ensure_signed(origin)?; - if let Some(ratio) = EnabledTokens::::get(&target_asset_id) { - ensure!( - EnabledTokens::::contains_key(&target_asset_id), - Error::::AssetNotEnabled - ); + if let Some(ratio) = EnabledTokens::::get(&source_asset_id) { let aiusd_id = T::AIUSDAssetId::get(); ensure!( InspectFungibles::::asset_exists(aiusd_id.clone()) - && InspectFungibles::::asset_exists(target_asset_id.clone()), + && InspectFungibles::::asset_exists(source_asset_id.clone()), Error::::InvalidAssetId ); - // It will fail if insufficient fund + let aiusd_minted_amount: AssetBalanceOf = >::mint_into(aiusd_id, &beneficiary, aiusd_amount)?; @@ -152,7 +148,7 @@ pub mod pallet { .ok_or(Error::::Overflow)?; let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( - target_asset_id.clone(), + source_asset_id.clone(), &beneficiary, &T::ConvertingFeeAccount::get(), asset_target_transfer_amount, @@ -162,7 +158,7 @@ pub mod pallet { Self::deposit_event(Event::AIUSDCreated { beneficiary, aiusd_amount: aiusd_minted_amount, - asset_id: target_asset_id, + asset_id: source_asset_id, asset_amount: asset_actual_transfer_amount, }); @@ -172,22 +168,22 @@ pub mod pallet { } } - // Burn aiusd and get target_asset_id token released + // Burn aiusd and get source_asset_id token released // Failed if pool does not have enough token of one type #[pallet::call_index(1)] #[pallet::weight({195_000_000})] #[transactional] pub fn burn_aiusd( origin: OriginFor, - target_asset_id: AssetIdOf, + source_asset_id: AssetIdOf, aiusd_amount: AssetBalanceOf, ) -> DispatchResult { let beneficiary = ensure_signed(origin)?; - if let Some(ratio) = EnabledTokens::::get(&target_asset_id) { + if let Some(ratio) = EnabledTokens::::get(&source_asset_id) { let aiusd_id = T::AIUSDAssetId::get(); ensure!( InspectFungibles::::asset_exists(aiusd_id.clone()) - && InspectFungibles::::asset_exists(target_asset_id.clone()), + && InspectFungibles::::asset_exists(source_asset_id.clone()), Error::::InvalidAssetId ); // It will fail if insufficient fund @@ -209,7 +205,7 @@ pub mod pallet { .ok_or(Error::::Overflow)?; let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( - target_asset_id.clone(), + source_asset_id.clone(), &T::ConvertingFeeAccount::get(), &beneficiary, asset_target_transfer_amount, @@ -219,7 +215,7 @@ pub mod pallet { Self::deposit_event(Event::AIUSDDestroyed { beneficiary, aiusd_amount: aiusd_destroyed_amount, - asset_id: target_asset_id, + asset_id: source_asset_id, asset_amount: asset_actual_transfer_amount, }); Ok(()) @@ -233,12 +229,12 @@ pub mod pallet { #[pallet::weight({195_000_000})] pub fn enable_token( origin: OriginFor, - target_asset_id: AssetIdOf, + source_asset_id: AssetIdOf, decimal_ratio: AssetBalanceOf, ) -> DispatchResultWithPostInfo { T::ManagerOrigin::ensure_origin(origin)?; - EnabledTokens::::insert(&target_asset_id, decimal_ratio); - Self::deposit_event(Event::AssetEnabled { asset_id: target_asset_id, decimal_ratio }); + EnabledTokens::::insert(&source_asset_id, decimal_ratio); + Self::deposit_event(Event::AssetEnabled { asset_id: source_asset_id, decimal_ratio }); Ok(Pays::No.into()) } @@ -247,11 +243,11 @@ pub mod pallet { #[pallet::weight({195_000_000})] pub fn disable_token( origin: OriginFor, - target_asset_id: AssetIdOf, + source_asset_id: AssetIdOf, ) -> DispatchResultWithPostInfo { T::ManagerOrigin::ensure_origin(origin)?; - EnabledTokens::::remove(&target_asset_id); - Self::deposit_event(Event::AssetDisabled { asset_id: target_asset_id }); + EnabledTokens::::remove(&source_asset_id); + Self::deposit_event(Event::AssetDisabled { asset_id: source_asset_id }); Ok(Pays::No.into()) } } diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/mock.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/mock.rs index 393dcb4e03..bda5e43ce4 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/mock.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/mock.rs @@ -146,10 +146,10 @@ pub fn new_test_ext() -> sp_io::TestExternalities { 1, )); // Create the target asset - let target_asset_id = 2; + let source_asset_id = 2; assert_ok!(pallet_assets::Pallet::::force_create( origin, - target_asset_id, + source_asset_id, owner.clone(), true, 1, @@ -161,7 +161,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { // Set total supply assert_ok!(pallet_aiusd::InspectFungibles::::mint_into( - target_asset_id, + source_asset_id, &owner, 1_000_000_000 // 1000 (10^6 * 1000) )); diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/tests.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/tests.rs index 1e32ed76dc..8cc3fd0406 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/tests.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/tests.rs @@ -24,7 +24,7 @@ fn test_mint_aiusd() { new_test_ext().execute_with(|| { let beneficiary: AccountId32 = AccountId32::from([2u8; 32]); let aiusd_asset_id: u32 = 1; - let target_asset_id: u32 = 2; + let source_asset_id: u32 = 2; let target_decimal_ratio = 1_000_000; let target_asset_supply_amount: u128 = target_decimal_ratio * 1000; let mint_amount: u128 = 2_000_000_000_000_000_000; // 2 AIUSD (10^18 * 2) @@ -32,12 +32,12 @@ fn test_mint_aiusd() { // Check balance let aiusd_balance = InspectFungibles::::balance(aiusd_asset_id, &beneficiary); assert_eq!(aiusd_balance, 0); - let target_balance = InspectFungibles::::balance(target_asset_id, &beneficiary); + let target_balance = InspectFungibles::::balance(source_asset_id, &beneficiary); assert_eq!(target_balance, target_asset_supply_amount); assert_ok!(AIUSD::enable_token( RuntimeOrigin::root(), - target_asset_id, + source_asset_id, target_decimal_ratio )); @@ -48,20 +48,20 @@ fn test_mint_aiusd() { assert_ok!(AIUSD::mint_aiusd( RuntimeOrigin::signed(beneficiary.clone()), - target_asset_id, + source_asset_id, mint_amount )); // Check balance after mint let asset_amount = target_decimal_ratio * 2; let aiusd_balance = InspectFungibles::::balance(aiusd_asset_id, &beneficiary); assert_eq!(aiusd_balance, mint_amount); - let target_balance = InspectFungibles::::balance(target_asset_id, &beneficiary); + let target_balance = InspectFungibles::::balance(source_asset_id, &beneficiary); assert_eq!(target_balance, target_asset_supply_amount - asset_amount); System::assert_last_event(RuntimeEvent::AIUSD(Event::AIUSDCreated { beneficiary, aiusd_amount: mint_amount, - asset_id: target_asset_id, + asset_id: source_asset_id, asset_amount, })); }); @@ -72,7 +72,7 @@ fn test_burn_aiusd() { new_test_ext().execute_with(|| { let beneficiary: AccountId32 = AccountId32::from([2u8; 32]); let aiusd_asset_id: u32 = 1; - let target_asset_id: u32 = 2; + let source_asset_id: u32 = 2; let target_decimal_ratio = 1_000_000; let target_asset_supply_amount: u128 = target_decimal_ratio * 1000; let aiusd_amount: u128 = 2_000_000_000_000_000_000; // 2 AIUSD (10^18 * 2) @@ -80,12 +80,12 @@ fn test_burn_aiusd() { // Check balance let aiusd_balance = InspectFungibles::::balance(aiusd_asset_id, &beneficiary); assert_eq!(aiusd_balance, 0); - let target_balance = InspectFungibles::::balance(target_asset_id, &beneficiary); + let target_balance = InspectFungibles::::balance(source_asset_id, &beneficiary); assert_eq!(target_balance, target_asset_supply_amount); assert_ok!(AIUSD::enable_token( RuntimeOrigin::root(), - target_asset_id, + source_asset_id, target_decimal_ratio )); @@ -93,7 +93,7 @@ fn test_burn_aiusd() { assert_err!( AIUSD::burn_aiusd( RuntimeOrigin::signed(beneficiary.clone()), - target_asset_id, + source_asset_id, aiusd_amount ), TokenError::FundsUnavailable @@ -101,30 +101,30 @@ fn test_burn_aiusd() { assert_ok!(AIUSD::mint_aiusd( RuntimeOrigin::signed(beneficiary.clone()), - target_asset_id, + source_asset_id, aiusd_amount )); // Check balance after mint let aiusd_balance = InspectFungibles::::balance(aiusd_asset_id, &beneficiary); assert_eq!(aiusd_balance, aiusd_amount); - let target_balance = InspectFungibles::::balance(target_asset_id, &beneficiary); + let target_balance = InspectFungibles::::balance(source_asset_id, &beneficiary); assert_eq!(target_balance, target_asset_supply_amount - target_decimal_ratio * 2); assert_ok!(AIUSD::burn_aiusd( RuntimeOrigin::signed(beneficiary.clone()), - target_asset_id, + source_asset_id, aiusd_amount )); // Check balance after burn let aiusd_balance = InspectFungibles::::balance(aiusd_asset_id, &beneficiary); assert_eq!(aiusd_balance, 0); - let target_balance = InspectFungibles::::balance(target_asset_id, &beneficiary); + let target_balance = InspectFungibles::::balance(source_asset_id, &beneficiary); assert_eq!(target_balance, target_asset_supply_amount); System::assert_last_event(RuntimeEvent::AIUSD(Event::AIUSDDestroyed { beneficiary, aiusd_amount, - asset_id: target_asset_id, + asset_id: source_asset_id, asset_amount: target_decimal_ratio * 2, })); }); @@ -133,23 +133,23 @@ fn test_burn_aiusd() { #[test] fn test_enable_disable_token() { new_test_ext().execute_with(|| { - let target_asset_id: u32 = 2; + let source_asset_id: u32 = 2; let decimal_ratio: u128 = 1_000_000; // enable - assert_ok!(AIUSD::enable_token(RuntimeOrigin::root(), target_asset_id, decimal_ratio)); - assert!(AIUSD::enabled_tokens(target_asset_id).is_some()); + assert_ok!(AIUSD::enable_token(RuntimeOrigin::root(), source_asset_id, decimal_ratio)); + assert!(AIUSD::enabled_tokens(source_asset_id).is_some()); System::assert_last_event(RuntimeEvent::AIUSD(Event::AssetEnabled { - asset_id: target_asset_id, + asset_id: source_asset_id, decimal_ratio, })); // disable - assert_ok!(AIUSD::disable_token(RuntimeOrigin::root(), target_asset_id)); - assert!(AIUSD::enabled_tokens(target_asset_id).is_none()); + assert_ok!(AIUSD::disable_token(RuntimeOrigin::root(), source_asset_id)); + assert!(AIUSD::enabled_tokens(source_asset_id).is_none()); System::assert_last_event(RuntimeEvent::AIUSD(Event::AssetDisabled { - asset_id: target_asset_id, + asset_id: source_asset_id, })); }); } diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index a02590ed95..97c2f34fb8 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -32,23 +32,6 @@ pub type GuardianIndex = u128; pub type PoolProposalIndex = u128; pub type InvestingPoolIndex = PoolProposalIndex; -#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] -pub struct PoolSetting { - // The start time of staking pool - pub start_time: BlockNumber, - // How many epoch will staking pool last, n > 0, valid epoch index :[0..n) - pub epoch: u128, - // How many blocks each epoch consist - pub epoch_range: BlockNumber, - // The number of block regarding setup for purchasing hardware which deliver no non-native - // token reward - pub setup_time: BlockNumber, - // Max staked amount of pool - pub pool_cap: Balance, - // Minimum amount of token required for pool starting - pub minimum_cap: Balance, -} - #[derive(Clone, Encode, Decode, Eq, PartialEq, Default, RuntimeDebug, MaxEncodedLen, TypeInfo)] pub struct PoolMetadata { /// The user friendly name of this staking pool. Limited in length by `PoolStringLimit`. diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index c0c34ae222..7b1979e4b2 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -390,6 +390,15 @@ pub mod pallet { ) -> DispatchResult { T::PoolProposalPalletOrigin::ensure_origin(origin)?; + ensure!( + frame_system::Pallet::::block_number() <= setting.start_time, + Error::::PoolAlreadyStarted + ); + ensure!( + !InvestingPoolSetting::::contains_key(pool_id), + Error::::PoolAlreadyExisted + ); + // Create all asset token categories let asset_id_vec: Vec> = InvestingPoolAssetIdGenerator::get_all_pool_token(pool_id, setting.epoch) @@ -403,14 +412,6 @@ pub mod pallet { )?; } - ensure!( - frame_system::Pallet::::block_number() <= setting.start_time, - Error::::PoolAlreadyStarted - ); - ensure!( - !InvestingPoolSetting::::contains_key(pool_id), - Error::::PoolAlreadyExisted - ); >::insert(pool_id, setting.clone()); Self::deposit_event(Event::InvestingPoolCreated { pool_id, diff --git a/parachain/pallets/collab-ai/pool-proposal/Cargo.toml b/parachain/pallets/collab-ai/pool-proposal/Cargo.toml index 96e316ea5e..89f6b9092d 100644 --- a/parachain/pallets/collab-ai/pool-proposal/Cargo.toml +++ b/parachain/pallets/collab-ai/pool-proposal/Cargo.toml @@ -16,7 +16,6 @@ scale-info = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } orml-utilities = { workspace = true } -pallet-assets = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } @@ -25,6 +24,7 @@ pallet-collab-ai-common = { workspace = true } [dev-dependencies] sp-core = { workspace = true } sp-io = { workspace = true } +pallet-assets = { workspace = true } pallet-balances = { workspace = true } [features] @@ -42,7 +42,6 @@ std = [ "frame-support/std", "frame-system/std", "orml-utilities/std", - "pallet-assets/std", "pallet-collab-ai-common/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 578142310a..b2c0f4f114 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -56,17 +56,6 @@ use sp_std::collections::vec_deque::VecDeque; pub use types::*; -pub(crate) type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; - -pub(crate) type InspectFungibles = pallet_assets::Pallet; -/// Balance type alias for balances of assets that implement the `fungibles` trait. -pub type AssetBalanceOf = - as FsInspect<::AccountId>>::Balance; -/// Type alias for Asset IDs. -pub type AssetIdOf = - as FsInspect<::AccountId>>::AssetId; - #[cfg(test)] mod mock; #[cfg(test)] @@ -83,19 +72,29 @@ pub mod pallet { /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + pub type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + + pub type AssetBalanceOf = + <::Fungibles as FsInspect<::AccountId>>::Balance; + pub type AssetIdOf = + <::Fungibles as FsInspect<::AccountId>>::AssetId; + #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] - pub trait Config: frame_system::Config + pallet_assets::Config { + pub trait Config: frame_system::Config + pallet_investing_pool::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Currency type for this pallet. type Currency: ReservableCurrency + LockableCurrency>; + type Fungibles: FsMutate + FsCreate; + // Declare the asset id of AIUSD type AIUSDAssetId: Get>; @@ -128,6 +127,10 @@ pub mod pallet { #[pallet::constant] type MaxGuardianPerProposal: Get; + /// The maximum amount of guardian allowed for a proposal + #[pallet::constant] + type MaxGuardianSelectedPerProposal: Get; + /// System Account holding pre-investing assets type PreInvestingPool: Get; } @@ -255,7 +258,8 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { fn on_initialize(_n: BlockNumberFor) -> Weight { - // Check proposal expire by order + // Check proposal expire + // curator must be verified by this time // check epoch number not too large so asset id will not overflow @@ -382,7 +386,7 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin)?; - let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( + let asset_actual_transfer_amount: AssetBalanceOf = T::Fungibles::transfer( T::AIUSDAssetId::get(), &who, &T::PreInvestingPool::get(), @@ -527,7 +531,7 @@ pub mod pallet { } // Return funds - let _asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( + let _asset_actual_transfer_amount: AssetBalanceOf = T::Fungibles::transfer( T::AIUSDAssetId::get(), &T::PreInvestingPool::get(), &who, @@ -606,6 +610,87 @@ pub mod pallet { } } + impl Pallet { + fn solve_pending(n: BlockNumberFor) -> DispatchResult { + let mut pending_setup = >::take(); + loop { + match pending_setup.pop_front() { + // Latest Pending tx effective + Some(x) if x.proposal_expire_time <= n => { + // Mature the proposal + let mut pool_proposal = + >::get(pool_proposal_index).ok_or(Error::::ProposalNotExist)?; + pool_proposal.proposal_status_flags |= ProposalStatusFlags::PROPOSAL_EXPIRED; + >::insert(pool_proposal_index, pool_proposal.clone()); + + let mut pre_investments: Vec<(T::AccountId, AssetBalanceOf)> = Default::default(); + let mut queued_investments: Vec<(T::AccountId, AssetBalanceOf)> = Default::default(); + + // ignored if return none + if let Some(pool_bonds) = >::get(pool_proposal_index) { + pre_investments = pool_bonds.pre_investings.into_iter().map(|x| (x.owner, x.amount)).collect(); + queued_investments = pool_bonds.queued_pre_investings.into_iter().map(|x| (x.0.owner, x.0.amount)).collect(); + } + + // Judege guardian + let mut best_guardians: Vec<(T::AccountId, AssetBalanceOf)> = Default::default(); + if let Some(pool_guardians) = >::get(pool_proposal_index) { + for guardian_candidate in pool_guardians.0.into_iter() { + for investor in pre_investments.iter() { + T::GuardianVoteResource::get_vote(investor.0, guardian_candidate) + } + + } + + } + + if best_guardians.0.len > 0 { + pool_proposal.proposal_status_flags |= ProposalStatusFlags::PUBLIC_VOTE_PASSED; + } else { + pool_proposal.proposal_status_flags &= !ProposalStatusFlags::PUBLIC_VOTE_PASSED; + } + + pool_proposal.proposal_status_flags |= ProposalStatusFlags::PROPOSAL_EXPIRED; + + + + + + + + // If all satisfied, baked into investing pool + if pool_proposal.proposal_status_flags.is_all() + + // Otherwise return bonding + ??? + Self::deposit_event(Event::::??? { + who: x.who, + pool_id: x.pool_id.clone(), + effective_time: n, + amount: x.staking_info.amount, + }); + // Loop through investing bond + ??? + + >::insert(pool_proposal_index, pool_proposal); + }, + // Latest Pending tx not effective + Some(x) => { + // Put it back + pending_setup.push_front(x); + break; + }, + // No pending tx + _ => { + break; + }, + } + } + >::put(pending_setup); + Ok(()) + } + } + /// Simple ensure origin from pallet pool proposal pub struct EnsurePoolProposal(sp_std::marker::PhantomData); impl EnsureOrigin for EnsurePoolProposal { @@ -635,4 +720,23 @@ pub mod pallet { } } } + + /// Simple ensure origin for the applet pool proposal + pub struct EnsurePoolProposal(sp_std::marker::PhantomData); + impl EnsureOrigin for EnsureBridge { + type Success = T::AccountId; + fn try_origin(o: T::RuntimeOrigin) -> Result { + let pallet_id = MODULE_ID.into_account_truncating(); + o.into().and_then(|o| match o { + system::RawOrigin::Signed(who) if who == pallet_id => Ok(pallet_id), + r => Err(T::RuntimeOrigin::from(r)), + }) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + let pallet_id = MODULE_ID.into_account_truncating(); + Ok(T::RuntimeOrigin::from(system::RawOrigin::Signed(pallet_id))) + } + } } diff --git a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs index a5d346177b..6396f1d299 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs @@ -158,6 +158,7 @@ impl GuardianQuery for MockGuardianQuery { impl pallet_pool_proposal::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; + type Fungibles = Assets; type AIUSDAssetId = AIUSDAssetId; type OfficialGapPeriod = OfficialGapPeriod; type MinimumProposalLastTime = MinimumProposalLastTime; diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 0b36865cca..c5241617fb 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -1,6 +1,7 @@ use crate::mock::*; use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; use pallet_balances::Error as BalanceError; +use pallet_assets::Error as AssetError; use sp_core::H256; use sp_runtime::AccountId32; @@ -74,3 +75,61 @@ fn test_propose_investing_pool_ok() { ); }) } + +#[test] +fn test_pre_stake_proposal_ok() { + new_test_ext().execute_with(|| { + let user_a: AccountId32 = AccountId32::from([1u8; 32]); + let user_b: AccountId32 = AccountId32::from([2u8; 32]); + Balances::make_free_balance_be(&user_a, 100_000_000_000_000_000_000); + Balances::make_free_balance_be(&user_b, 100_000_000_000_000_000_000); + + let max_pool_size = 1_000_000_000_000_000_000_000u128; + let proposal_last_time = 100; + let pool_last_time = 10000; + let estimated_pool_reward = 2_000_000_000_000_000_000_000u128; + let pool_info_hash: H256 = H256([2; 32]); + let pool_info_hash_2: H256 = H256([3; 32]); + + // Worked + assert_ok!(PoolProposal::propose_investing_pool( + RuntimeOrigin::signed(user_a.clone()), + max_pool_size, + proposal_last_time, + pool_last_time, + estimated_pool_reward, + pool_info_hash + )); + + // Not enough token + assert_noop!( + PoolProposal::pre_stake_proposal( + RuntimeOrigin::signed(user_a), + 1.into(), + 2_000_000_000_000_000_000_000_000, + ), + AssetError::::BalanceLow + ); + + // Pool not exist + assert_noop!( + PoolProposal::pre_stake_proposal( + RuntimeOrigin::signed(user_a), + 2.into(), + 500_000_000_000_000_000_000u128, + ), + crate::Error::::ProposalNotExist + ); + + // // Proposal Expired + // assert_noop!( + // PoolProposal::pre_stake_proposal( + // RuntimeOrigin::signed(user_a), + // 2.into(), + // 500_000_000_000_000_000_000u128, + // ), + // crate::Error::::ProposalExpired + // ); + + }) +} \ No newline at end of file diff --git a/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs b/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs index 20909c94c3..31ff97e4fb 100644 --- a/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs @@ -41,7 +41,7 @@ where })?; let call = pallet_aiusd_convertor::Call::::mint_aiusd { - target_asset_id: asset_id, + source_asset_id: asset_id, aiusd_amount: amount, }; RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; @@ -61,7 +61,7 @@ where })?; let call = pallet_aiusd_convertor::Call::::burn_aiusd { - target_asset_id: asset_id, + source_asset_id: asset_id, aiusd_amount: amount, }; RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; diff --git a/parachain/precompiles/collab-ai/aiusd-convertor/src/mock.rs b/parachain/precompiles/collab-ai/aiusd-convertor/src/mock.rs index db7f1f88fc..48c53efd13 100644 --- a/parachain/precompiles/collab-ai/aiusd-convertor/src/mock.rs +++ b/parachain/precompiles/collab-ai/aiusd-convertor/src/mock.rs @@ -212,10 +212,10 @@ pub fn new_test_ext() -> sp_io::TestExternalities { 1, )); // Create the target asset - let target_asset_id = 2; + let source_asset_id = 2; assert_ok!(pallet_assets::Pallet::::force_create( origin, - target_asset_id, + source_asset_id, owner.clone(), true, 1, @@ -227,13 +227,13 @@ pub fn new_test_ext() -> sp_io::TestExternalities { // Set total supply assert_ok!(pallet_aiusd::InspectFungibles::::mint_into( - target_asset_id, + source_asset_id, &owner, 1_000_000_000 // 1000 (10^6 * 1000) )); // Enable assert - assert_ok!(AIUSD::enable_token(RuntimeOrigin::root(), target_asset_id, 1_000_000)); + assert_ok!(AIUSD::enable_token(RuntimeOrigin::root(), source_asset_id, 1_000_000)); }); ext } diff --git a/parachain/precompiles/collab-ai/aiusd-convertor/src/tests.rs b/parachain/precompiles/collab-ai/aiusd-convertor/src/tests.rs index dea5598600..d6de7512a5 100644 --- a/parachain/precompiles/collab-ai/aiusd-convertor/src/tests.rs +++ b/parachain/precompiles/collab-ai/aiusd-convertor/src/tests.rs @@ -25,7 +25,7 @@ use sp_runtime::AccountId32; fn test_mint_and_burn_aiusd() { new_test_ext().execute_with(|| { let aiusd_asset_id = 1; - let target_asset_id = 2; + let source_asset_id = 2; let target_decimal_ratio = 1_000_000; let target_asset_supply_amount: u128 = target_decimal_ratio * 1000; let h160_address: H160 = H160::from_low_u64_be(1001); @@ -35,7 +35,7 @@ fn test_mint_and_burn_aiusd() { // Check balance let aiusd_balance = InspectFungibles::::balance(aiusd_asset_id, &beneficiary); assert_eq!(aiusd_balance, 0); - let target_balance = InspectFungibles::::balance(target_asset_id, &beneficiary); + let target_balance = InspectFungibles::::balance(source_asset_id, &beneficiary); assert_eq!(target_balance, target_asset_supply_amount); // mint @@ -45,7 +45,7 @@ fn test_mint_and_burn_aiusd() { h160_address, precompile_address(), PCall::::mint_aiusd { - asset_id: target_asset_id.into(), + asset_id: source_asset_id.into(), amount: mint_amount.into(), }, ) @@ -56,12 +56,12 @@ fn test_mint_and_burn_aiusd() { // Check balance after mint let aiusd_balance = InspectFungibles::::balance(aiusd_asset_id, &beneficiary); assert_eq!(aiusd_balance, mint_amount); - let target_balance = InspectFungibles::::balance(target_asset_id, &beneficiary); + let target_balance = InspectFungibles::::balance(source_asset_id, &beneficiary); assert_eq!(target_balance, target_asset_supply_amount - mint_asset_amount); System::assert_last_event(RuntimeEvent::AIUSD(Event::AIUSDCreated { beneficiary: beneficiary.clone(), aiusd_amount: mint_amount, - asset_id: target_asset_id, + asset_id: source_asset_id, asset_amount: mint_asset_amount, })); @@ -72,7 +72,7 @@ fn test_mint_and_burn_aiusd() { h160_address, precompile_address(), PCall::::burn_aiusd { - asset_id: target_asset_id.into(), + asset_id: source_asset_id.into(), amount: burn_amount.into(), }, ) @@ -83,7 +83,7 @@ fn test_mint_and_burn_aiusd() { // Check balance after burn let aiusd_balance = InspectFungibles::::balance(aiusd_asset_id, &beneficiary); assert_eq!(aiusd_balance, mint_amount - burn_amount); - let target_balance = InspectFungibles::::balance(target_asset_id, &beneficiary); + let target_balance = InspectFungibles::::balance(source_asset_id, &beneficiary); assert_eq!( target_balance, target_asset_supply_amount - mint_asset_amount + burn_asset_amount @@ -91,7 +91,7 @@ fn test_mint_and_burn_aiusd() { System::assert_last_event(RuntimeEvent::AIUSD(Event::AIUSDDestroyed { beneficiary, aiusd_amount: burn_amount, - asset_id: target_asset_id, + asset_id: source_asset_id, asset_amount: burn_asset_amount, })); }); From 27e0ad87df4540cddb1b2c2959aad3ea052f21d4 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sat, 2 Nov 2024 22:26:41 +0800 Subject: [PATCH 151/215] chore: rename ConvertingFeeAccount --- parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs | 6 +++--- parachain/pallets/collab-ai/aiusd-convertor/src/mock.rs | 6 +++--- parachain/precompiles/collab-ai/aiusd-convertor/src/mock.rs | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs index 053cc92b7b..7fa376264e 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/lib.rs @@ -62,7 +62,7 @@ pub mod pallet { // This is not a treasury account // Balance of all types in this account record the // available stable coin for AIUSD to switch back - type ConvertingFeeAccount: Get; + type ConvertingPool: Get; // Declare the asset id of AIUSD type AIUSDAssetId: Get>; @@ -150,7 +150,7 @@ pub mod pallet { as FsMutate<::AccountId>>::transfer( source_asset_id.clone(), &beneficiary, - &T::ConvertingFeeAccount::get(), + &T::ConvertingPool::get(), asset_target_transfer_amount, Preservation::Expendable, )?; @@ -206,7 +206,7 @@ pub mod pallet { let asset_actual_transfer_amount: AssetBalanceOf = as FsMutate<::AccountId>>::transfer( source_asset_id.clone(), - &T::ConvertingFeeAccount::get(), + &T::ConvertingPool::get(), &beneficiary, asset_target_transfer_amount, Preservation::Expendable, diff --git a/parachain/pallets/collab-ai/aiusd-convertor/src/mock.rs b/parachain/pallets/collab-ai/aiusd-convertor/src/mock.rs index bda5e43ce4..9f6b077f50 100644 --- a/parachain/pallets/collab-ai/aiusd-convertor/src/mock.rs +++ b/parachain/pallets/collab-ai/aiusd-convertor/src/mock.rs @@ -113,8 +113,8 @@ impl pallet_balances::Config for Test { type RuntimeHoldReason = (); } -pub struct ConvertingFeeAccount; -impl Get for ConvertingFeeAccount { +pub struct ConvertingPool; +impl Get for ConvertingPool { fn get() -> AccountId32 { AccountId32::new([1u8; 32]) } @@ -122,7 +122,7 @@ impl Get for ConvertingFeeAccount { impl pallet_aiusd::Config for Test { type RuntimeEvent = RuntimeEvent; - type ConvertingFeeAccount = ConvertingFeeAccount; + type ConvertingPool = ConvertingPool; type AIUSDAssetId = AIUSDAssetId; type ManagerOrigin = frame_system::EnsureRoot<::AccountId>; } diff --git a/parachain/precompiles/collab-ai/aiusd-convertor/src/mock.rs b/parachain/precompiles/collab-ai/aiusd-convertor/src/mock.rs index 48c53efd13..579b9a374c 100644 --- a/parachain/precompiles/collab-ai/aiusd-convertor/src/mock.rs +++ b/parachain/precompiles/collab-ai/aiusd-convertor/src/mock.rs @@ -119,8 +119,8 @@ impl pallet_balances::Config for Test { type MaxFreezes = (); type RuntimeHoldReason = (); } -pub struct ConvertingFeeAccount; -impl Get for ConvertingFeeAccount { +pub struct ConvertingPool; +impl Get for ConvertingPool { fn get() -> AccountId32 { let h160_address: H160 = H160::from_low_u64_be(1000); TruncatedAddressMapping::into_account_id(h160_address) @@ -129,7 +129,7 @@ impl Get for ConvertingFeeAccount { impl pallet_aiusd::Config for Test { type RuntimeEvent = RuntimeEvent; - type ConvertingFeeAccount = ConvertingFeeAccount; + type ConvertingPool = ConvertingPool; type AIUSDAssetId = AIUSDAssetId; type ManagerOrigin = frame_system::EnsureRoot<::AccountId>; } From e3fcb3ccfdfec2ce7eb346ad129a9a36cd5b3dee Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 14:07:54 +0800 Subject: [PATCH 152/215] feat: add baking logic --- parachain/pallets/collab-ai/common/src/lib.rs | 35 ++- .../collab-ai/investing-pool/src/lib.rs | 128 ++++++----- .../collab-ai/pool-proposal/Cargo.toml | 2 + .../collab-ai/pool-proposal/src/lib.rs | 205 ++++++++++++++---- .../collab-ai/pool-proposal/src/mock.rs | 37 ++++ .../collab-ai/pool-proposal/src/tests.rs | 5 +- 6 files changed, 304 insertions(+), 108 deletions(-) diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index 97c2f34fb8..44c8c7406e 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -88,6 +88,34 @@ pub trait ProposerQuery { fn is_proposer(account: AccountId, proposal_index: PoolProposalIndex) -> bool; } +#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] +pub struct PoolSetting { + // The start time of investing pool + pub start_time: BlockNumber, + // How many epoch will investing pool last, n > 0, valid epoch index :[0..n) + pub epoch: u128, + // How many blocks each epoch consist + pub epoch_range: BlockNumber, + // Max staked amount of pool + pub pool_cap: Balance, + // Curator + pub admin: AccountId, +} + +impl PoolSetting +where + Balance: AtLeast32BitUnsigned + Copy, + BlockNumber: AtLeast32BitUnsigned + Copy, +{ + // None means TypeIncompatible Or Overflow + pub fn end_time(&self) -> Option { + let er: u128 = self.epoch_range.try_into().ok()?; + let st: u128 = self.start_time.try_into().ok()?; + let result = st.checked_add(er.checked_mul(self.epoch)?)?; + result.try_into().ok() + } +} + pub struct EnsureSignedAndCurator(PhantomData<(AccountId, EC)>); impl< O: Into, O>> + From>, @@ -228,7 +256,12 @@ pub trait GuardianQuery { } /// Inject investment into pool -pub trait InvestmentInjector { +pub trait InvestmentInjector { + fn create_investing_pool( + pool_id: InvestingPoolIndex, + setting: PoolSetting, + admin: AccountId, + ) -> DispatchResult; fn inject_investment( pool_id: InvestingPoolIndex, investments: Vec<(AccountId, Balance)>, diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index 7b1979e4b2..2b574e8c8a 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -158,34 +158,6 @@ where } } -#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] -pub struct PoolSetting { - // The start time of investing pool - pub start_time: BlockNumber, - // How many epoch will investing pool last, n > 0, valid epoch index :[0..n) - pub epoch: u128, - // How many blocks each epoch consist - pub epoch_range: BlockNumber, - // Max staked amount of pool - pub pool_cap: Balance, - // Curator - pub admin: AccountId, -} - -impl PoolSetting -where - Balance: AtLeast32BitUnsigned + Copy, - BlockNumber: AtLeast32BitUnsigned + Copy, -{ - // None means TypeIncompatible Or Overflow - fn end_time(&self) -> Option { - let er: u128 = self.epoch_range.try_into().ok()?; - let st: u128 = self.start_time.try_into().ok()?; - let result = st.checked_add(er.checked_mul(self.epoch)?)?; - result.try_into().ok() - } -} - #[frame_support::pallet] pub mod pallet { use frame_support::transactional; @@ -243,7 +215,7 @@ pub mod pallet { >; // investing pools' stable token reward waiting claiming - // Pool id, epcoh index => epoch reward + // Pool id, epcoh index => (total epoch reward, claimed reward) #[pallet::storage] #[pallet::getter(fn stable_investing_pool_epoch_reward)] pub type StableInvestingPoolEpochReward = StorageDoubleMap< @@ -252,7 +224,7 @@ pub mod pallet { InvestingPoolIndex, Twox64Concat, u128, - BalanceOf, + (BalanceOf, BalanceOf), OptionQuery, >; @@ -356,6 +328,8 @@ pub mod pallet { PoolAlreadyEnded, PoolAlreadyExisted, PoolCapLimit, + // If this happens, asset manager might cheat + PoolRewardOverflow, PoolNotEnded, PoolNotExisted, PoolNotStarted, @@ -390,38 +364,7 @@ pub mod pallet { ) -> DispatchResult { T::PoolProposalPalletOrigin::ensure_origin(origin)?; - ensure!( - frame_system::Pallet::::block_number() <= setting.start_time, - Error::::PoolAlreadyStarted - ); - ensure!( - !InvestingPoolSetting::::contains_key(pool_id), - Error::::PoolAlreadyExisted - ); - - // Create all asset token categories - let asset_id_vec: Vec> = - InvestingPoolAssetIdGenerator::get_all_pool_token(pool_id, setting.epoch) - .ok_or(ArithmeticError::Overflow)?; - for i in asset_id_vec.iter() { - ::AccountId>>::create( - *i, - admin.clone(), - true, - One::one(), - )?; - } - - >::insert(pool_id, setting.clone()); - Self::deposit_event(Event::InvestingPoolCreated { - pool_id, - admin: setting.admin, - start_time: setting.start_time, - epoch: setting.epoch, - epoch_range: setting.epoch_range, - pool_cap: setting.pool_cap, - }); - Ok(()) + Self::do_create_investing_pool(pool_id, setting, admin) } /// Update a reward for an investing pool of specific epoch @@ -447,7 +390,7 @@ pub mod pallet { |maybe_reward| -> DispatchResult { ensure!(maybe_reward.is_none(), Error::::RewardAlreadyExisted); - *maybe_reward = Some(reward); + *maybe_reward = Some((reward, Zero::zero())); Self::deposit_event(Event::::RewardUpdated { pool_id, epoch, @@ -797,12 +740,13 @@ pub mod pallet { // Claim until the claimed_until_epoch // loop through each epoch for i in start_epoch..(end_epoch + 1) { - let reward_pool = >::get(pool_id, i) + let mut reward_pool = >::get(pool_id, i) .ok_or(Error::::EpochRewardNotUpdated)?; let proportion = Perquintill::from_rational(amount_u128, total_investing); let reward_pool_u128: u128 = reward_pool + .0 .try_into() .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; let distributed_reward_u128: u128 = proportion * reward_pool_u128; @@ -813,6 +757,14 @@ pub mod pallet { .checked_add(&distributed_reward) .ok_or(ArithmeticError::Overflow)?; + // Make sure no overflow of reward even if asset manager cheating + reward_pool.1 = reward_pool + .1 + .checked_add(&distributed_reward) + .ok_or(ArithmeticError::Overflow)?; + ensure!(reward_pool.1 < reward_pool.0, Error::::PoolRewardOverflow); + >::insert(pool_id, i, reward_pool); + Self::deposit_event(Event::::StableRewardClaimed { who: who.clone(), pool_id, @@ -843,6 +795,45 @@ pub mod pallet { T::StableTokenBeneficiaryId::get().into_account_truncating() } + pub fn do_create_investing_pool( + pool_id: InvestingPoolIndex, + setting: PoolSetting, BalanceOf>, + admin: T::AccountId, + ) -> DispatchResult { + ensure!( + frame_system::Pallet::::block_number() <= setting.start_time, + Error::::PoolAlreadyStarted + ); + ensure!( + !InvestingPoolSetting::::contains_key(pool_id), + Error::::PoolAlreadyExisted + ); + + // Create all asset token categories + let asset_id_vec: Vec> = + InvestingPoolAssetIdGenerator::get_all_pool_token(pool_id, setting.epoch) + .ok_or(ArithmeticError::Overflow)?; + for i in asset_id_vec.iter() { + ::AccountId>>::create( + *i, + admin.clone(), + true, + One::one(), + )?; + } + + >::insert(pool_id, setting.clone()); + Self::deposit_event(Event::InvestingPoolCreated { + pool_id, + admin: setting.admin, + start_time: setting.start_time, + epoch: setting.epoch, + epoch_range: setting.epoch_range, + pool_cap: setting.pool_cap, + }); + Ok(()) + } + // Mint category token to user, record can token checkpoint accordingly pub fn inject_investment( pool_id: InvestingPoolIndex, @@ -872,7 +863,14 @@ pub mod pallet { } } - impl InvestmentInjector> for Pallet { + impl InvestmentInjector, BalanceOf> for Pallet { + fn create_investing_pool( + pool_id: InvestingPoolIndex, + setting: PoolSetting, BalanceOf>, + admin: T::AccountId, + ) -> DispatchResult { + Self::do_create_investing_pool(pool_id, setting, admin) + } fn inject_investment( pool_id: InvestingPoolIndex, investments: Vec<(T::AccountId, BalanceOf)>, diff --git a/parachain/pallets/collab-ai/pool-proposal/Cargo.toml b/parachain/pallets/collab-ai/pool-proposal/Cargo.toml index 89f6b9092d..ca1ab5a31b 100644 --- a/parachain/pallets/collab-ai/pool-proposal/Cargo.toml +++ b/parachain/pallets/collab-ai/pool-proposal/Cargo.toml @@ -16,6 +16,7 @@ scale-info = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } orml-utilities = { workspace = true } +pallet-multisig = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } @@ -43,5 +44,6 @@ std = [ "frame-system/std", "orml-utilities/std", "pallet-collab-ai-common/std", + "pallet-multisig/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index b2c0f4f114..43dd1a31ff 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -86,7 +86,7 @@ pub mod pallet { pub struct Pallet(_); #[pallet::config] - pub trait Config: frame_system::Config + pallet_investing_pool::Config { + pub trait Config: frame_system::Config + pallet_multisig::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Currency type for this pallet. @@ -114,6 +114,10 @@ pub mod pallet { #[pallet::constant] type MaximumPoolProposed: Get; + /// The maximum amount of allowed pool proposed by a single curator + #[pallet::constant] + type StandardEpoch: Get>; + /// Origin who can make a pool proposal type ProposalOrigin: EnsureOrigin; @@ -123,7 +127,7 @@ pub mod pallet { /// Guardian vote resource type GuardianVoteResource: GuardianQuery; - /// The maximum amount of guardian allowed for a proposal + /// The maximum amount of guardian allowed for a proposal before expired #[pallet::constant] type MaxGuardianPerProposal: Get; @@ -133,6 +137,13 @@ pub mod pallet { /// System Account holding pre-investing assets type PreInvestingPool: Get; + + /// Baking the effect proposal into investing pool + type InvestmentInjector: InvestmentInjector< + Self::AccountId, + BlockNumberFor, + AssetBalanceOf, + >; } #[pallet::type_value] @@ -240,6 +251,8 @@ pub mod pallet { }, /// A public vote result of proposal get passed ProposalPublicVoted { pool_proposal_index: PoolProposalIndex, vote_result: bool }, + /// A proposal passed all checking and become a investing pool + ProposalBaked { pool_proposal_index: PoolProposalIndex, effective_time: n }, } #[pallet::error] @@ -259,7 +272,6 @@ pub mod pallet { impl Hooks> for Pallet { fn on_initialize(_n: BlockNumberFor) -> Weight { // Check proposal expire - // curator must be verified by this time // check epoch number not too large so asset id will not overflow @@ -504,6 +516,14 @@ pub mod pallet { Error::::ProposalPreInvestingLocked ); + // If proposal expired, all bondings should already be returned + ensure!( + !pool_proposal + .proposal_status_flags + .contains(ProposalStatusFlags::PROPOSAL_EXPIRED), + Error::::ProposalExpired + ); + pool_proposal_pre_investing.withdraw::(who.clone(), amount)?; Self::deposit_event(Event::PoolWithdrawed { user: who.clone(), @@ -618,59 +638,166 @@ pub mod pallet { // Latest Pending tx effective Some(x) if x.proposal_expire_time <= n => { // Mature the proposal - let mut pool_proposal = - >::get(pool_proposal_index).ok_or(Error::::ProposalNotExist)?; - pool_proposal.proposal_status_flags |= ProposalStatusFlags::PROPOSAL_EXPIRED; - >::insert(pool_proposal_index, pool_proposal.clone()); + let mut pool_proposal = >::get(x.pool_proposal_index) + .ok_or(Error::::ProposalNotExist)?; + pool_proposal.proposal_status_flags |= + ProposalStatusFlags::PROPOSAL_EXPIRED; + >::insert(x.pool_proposal_index, pool_proposal.clone()); - let mut pre_investments: Vec<(T::AccountId, AssetBalanceOf)> = Default::default(); - let mut queued_investments: Vec<(T::AccountId, AssetBalanceOf)> = Default::default(); + let mut pre_investments: Vec<(T::AccountId, AssetBalanceOf)> = + Default::default(); + let mut queued_investments: Vec<(T::AccountId, AssetBalanceOf)> = + Default::default(); // ignored if return none - if let Some(pool_bonds) = >::get(pool_proposal_index) { - pre_investments = pool_bonds.pre_investings.into_iter().map(|x| (x.owner, x.amount)).collect(); - queued_investments = pool_bonds.queued_pre_investings.into_iter().map(|x| (x.0.owner, x.0.amount)).collect(); + if let Some(pool_bonds) = >::get(x.pool_proposal_index) + { + pre_investments = pool_bonds + .pre_investings + .into_iter() + .map(|b| (b.owner, b.amount)) + .collect(); + queued_investments = pool_bonds + .queued_pre_investings + .into_iter() + .map(|b| (b.0.owner, b.0.amount)) + .collect(); } // Judege guardian - let mut best_guardians: Vec<(T::AccountId, AssetBalanceOf)> = Default::default(); - if let Some(pool_guardians) = >::get(pool_proposal_index) { + // guardian with aye > nye will be selected + // And select top N guardians with highest aye + let mut best_guardians: Vec<(T::AccountId, AssetBalanceOf)> = + Default::default(); + if let Some(pool_guardians) = >::get(x.pool_proposal_index) + { for guardian_candidate in pool_guardians.0.into_iter() { + // AccountId, Aye, Nye + let mut guardian: (T::AccountId, AssetBalanceOf) = + (guardian_candidate.clone(), Zero::zero(), Zero::zero()); for investor in pre_investments.iter() { - T::GuardianVoteResource::get_vote(investor.0, guardian_candidate) + match T::GuardianVoteResource::get_vote( + investor.0, + guardian_candidate, + ) { + None => _, + Some(GuardianVote::Neutral) => _, + Some(GuardianVote::Aye) => guardian.1 += investor.1, + Some(GuardianVote::Nay) => guardian.2 += investor.1, + }; + } + // As long as Aye > Nye and kyc passed, valid guardian + if guardian.1 >= guardian.2 + && T::GuardianVoteResource::is_verified_guardian(guardian.0) + { + best_guardians.push((guardian.0, guardian.1)); } - } + } + // Order best_guardians based on Aye + // temp sorted by Aye from largestsmallest to smallest + best_guardians.sort_by(|a, b| b.1.cmp(&a.1)); + if best_guardians.len > T::MaxGuardianSelectedPerProposal::get() { + best_guardians.split_off(T::MaxGuardianSelectedPerProposal::get()); } - if best_guardians.0.len > 0 { - pool_proposal.proposal_status_flags |= ProposalStatusFlags::PUBLIC_VOTE_PASSED; + // If existing one guardian + if best_guardians.len > 0 { + pool_proposal.proposal_status_flags |= + ProposalStatusFlags::GUARDIAN_SELECTED; } else { - pool_proposal.proposal_status_flags &= !ProposalStatusFlags::PUBLIC_VOTE_PASSED; + pool_proposal.proposal_status_flags &= + !ProposalStatusFlags::GUARDIAN_SELECTED; } - pool_proposal.proposal_status_flags |= ProposalStatusFlags::PROPOSAL_EXPIRED; - - - - - + pool_proposal.proposal_status_flags |= + ProposalStatusFlags::PROPOSAL_EXPIRED; - // If all satisfied, baked into investing pool - if pool_proposal.proposal_status_flags.is_all() - - // Otherwise return bonding - ??? - Self::deposit_event(Event::::??? { - who: x.who, - pool_id: x.pool_id.clone(), - effective_time: n, - amount: x.staking_info.amount, - }); - // Loop through investing bond - ??? + if pool_proposal.proposal_status_flags.is_all() { + let signatories: [T::AccountId] = + best_guardian.into_iter().map(|b| b.owner).collect(); + let guardian_multisig = pallet_multisig::Pallet::::multi_account_id( + &signatories, + signatories.len, + ); + let start_time_u128: u128 = pool_proposal + .start_time + .try_into() + .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + let end_time_u128: u128 = pool_proposal + .end_time + .try_into() + .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + let epoch_range_u128: u128 = T::StandardEpoch::get() + .try_into() + .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; + + let total_epoch: u128 = + ((end_time_u128 - start_time_u128) / epoch_range_u128) + 1; + let pool_setting: PoolSetting< + T::AccountId, + BlockNumberFor, + AssetBalanceOf, + > = PoolSetting { + start_time: pool_proposal.pool_start_time, + epoch: total_epoch, + epoch_range: T::StandardEpoch::get(), + pool_cap: pool_proposal.max_pool_size, + // Curator + admin: pool_proposal.proposer, + }; + + T::InvestmentInjector::create_investing_pool( + x.pool_proposal_index, + pool_setting, + guardian_multisig, + )?; + T::InvestmentInjector::inject_investment( + x.pool_proposal_index, + pre_investments, + )?; + Self::deposit_event(Event::::ProposalBaked { + pool_proposal_index: x.pool_proposal_index, + effective_time: n, + }); + } else { + // Otherwise return bonding + for investor in pre_investments.iter() { + let asset_refund_amount: AssetBalanceOf = + T::Fungibles::transfer( + T::AIUSDAssetId::get(), + &T::PreInvestingPool::get(), + &investor.0, + investor.1, + Preservation::Expendable, + )?; + Self::deposit_event(Event::::PoolWithdrawed { + who: investor.0, + pool_id: x.pool_proposal_index, + effective_time: n, + amount: investor.1, + }); + } + } + + // Return Queued queued_investments always + for investor in queued_investments.iter() { + let asset_refund_amount: AssetBalanceOf = T::Fungibles::transfer( + T::AIUSDAssetId::get(), + &T::PreInvestingPool::get(), + &investor.0, + investor.1, + Preservation::Expendable, + )?; + Self::deposit_event(Event::::PoolWithdrawed { + who: investor.0, + pool_id: x.pool_proposal_index, + effective_time: n, + amount: investor.1, + }); + } >::insert(pool_proposal_index, pool_proposal); }, @@ -721,7 +848,7 @@ pub mod pallet { } } - /// Simple ensure origin for the applet pool proposal + /// Simple ensure origin for the applet pool proposal pub struct EnsurePoolProposal(sp_std::marker::PhantomData); impl EnsureOrigin for EnsureBridge { type Success = T::AccountId; diff --git a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs index 6396f1d299..17bd2d7702 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs @@ -38,6 +38,7 @@ construct_runtime!( System: frame_system, Assets: pallet_assets, Balances: pallet_balances, + Multisig: pallet_multisig, PoolProposal: pallet_pool_proposal, } ); @@ -49,7 +50,23 @@ parameter_types! { pub const MinimumProposalLastTime: u32 = 10; pub const MinimumPoolDeposit: Balance = 100; pub const MaxGuardianPerProposal: u32 = 2; + pub const MaxGuardianSelectedPerProposal: u32 = 1; pub const MaximumPoolProposed: u32 = 1; + + pub const DepositBase: Balance = 1; + pub const DepositFactor: Balance = 1; + + pub const StandardEpoch: u32 = 10; +} + +impl Config for Test { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type DepositBase = DepositBase; + type DepositFactor = DepositFactor; + type MaxSignatories = ConstU32<3>; + type WeightInfo = (); } impl frame_system::Config for Test { @@ -155,6 +172,23 @@ impl GuardianQuery for MockGuardianQuery { } } +pub struct MockInvestmentInjector; +impl InvestmentInjector for MockInvestmentInjector { + fn create_investing_pool( + _pool_id: InvestingPoolIndex, + _setting: PoolSetting, + _admin: AccountId, + ) -> DispatchResult { + Ok(()) + } + fn inject_investment( + _pool_id: InvestingPoolIndex, + _investments: Vec<(AccountId, Balance)>, + ) -> DispatchResult { + Ok(()) + } +} + impl pallet_pool_proposal::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; @@ -164,11 +198,14 @@ impl pallet_pool_proposal::Config for Test { type MinimumProposalLastTime = MinimumProposalLastTime; type MinimumPoolDeposit = MinimumPoolDeposit; type MaximumPoolProposed = MaximumPoolProposed; + type StandardEpoch = StandardEpoch; type ProposalOrigin = EnsureSignedAndCurator; type PublicVotingOrigin = frame_system::EnsureRoot; type GuardianVoteResource = MockGuardianQuery; type MaxGuardianPerProposal = MaxGuardianPerProposal; + type MaxGuardianSelectedPerProposal = MaxGuardianSelectedPerProposal; type PreInvestingPool = PreInvestingPool; + type InvestmentInjector = MockInvestmentInjector; } pub fn new_test_ext() -> sp_io::TestExternalities { diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index c5241617fb..293da14663 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -1,7 +1,7 @@ use crate::mock::*; use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; -use pallet_balances::Error as BalanceError; use pallet_assets::Error as AssetError; +use pallet_balances::Error as BalanceError; use sp_core::H256; use sp_runtime::AccountId32; @@ -130,6 +130,5 @@ fn test_pre_stake_proposal_ok() { // ), // crate::Error::::ProposalExpired // ); - }) -} \ No newline at end of file +} From 803c519408574e1efc752b47fe04e92d80dd8816 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 14:08:51 +0800 Subject: [PATCH 153/215] chore: fix lock --- parachain/Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index 52f88bea95..993a71428e 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -8066,6 +8066,7 @@ dependencies = [ "pallet-assets", "pallet-balances", "pallet-collab-ai-common", + "pallet-multisig", "parity-scale-codec", "scale-info", "sp-core", From 33a111b063b3d9f27ce6dffe452a903e6a300e5b Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 14:19:39 +0800 Subject: [PATCH 154/215] chore: fix --- parachain/pallets/collab-ai/common/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index 44c8c7406e..d634aebb51 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -18,6 +18,7 @@ use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_core::{RuntimeDebug, H256}; +use sp_runtime::traits::AtLeast32BitUnsigned; use sp_std::marker::PhantomData; use frame_support::{ From a08506cabae59602326485a515213618ac3c7554 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 14:53:12 +0800 Subject: [PATCH 155/215] chore: fix --- .../collab-ai/pool-proposal/src/lib.rs | 85 ++++++++++--------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 43dd1a31ff..c7a4e66c35 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -31,7 +31,7 @@ use frame_support::{ pallet_prelude::*, traits::{ tokens::{ - fungibles::{Inspect as FsInspect, Mutate as FsMutate}, + fungibles::{Create as FsCreate, Inspect as FsInspect, Mutate as FsMutate}, Preservation, }, Currency, EnsureOrigin, Get, LockableCurrency, ReservableCurrency, @@ -49,7 +49,7 @@ use orml_utilities::OrderedSet; pub use pallet::*; use pallet_collab_ai_common::*; use sp_runtime::{ - traits::{AccountIdConversion, CheckedAdd, CheckedSub}, + traits::{AccountIdConversion, CheckedAdd, CheckedSub, Zero}, ArithmeticError, }; use sp_std::collections::vec_deque::VecDeque; @@ -252,7 +252,13 @@ pub mod pallet { /// A public vote result of proposal get passed ProposalPublicVoted { pool_proposal_index: PoolProposalIndex, vote_result: bool }, /// A proposal passed all checking and become a investing pool - ProposalBaked { pool_proposal_index: PoolProposalIndex, effective_time: n }, + ProposalBaked { pool_proposal_index: PoolProposalIndex, effective_time: BlockNumberFor }, + /// A proposal failed some checking or type error + ProposalFailed { + pool_proposal_index: PoolProposalIndex, + effective_time: BlockNumberFor, + type_error: bool, + }, } #[pallet::error] @@ -272,10 +278,13 @@ pub mod pallet { impl Hooks> for Pallet { fn on_initialize(_n: BlockNumberFor) -> Weight { // Check proposal expire + // Mature the pool by proposal if qualified, refund/transfer all money based on investing pool logic + Self::solve_pending(n); // curator must be verified by this time - // check epoch number not too large so asset id will not overflow - // Mature the pool by proposal if qualified, refund/transfer all money based on investing pool logic + // TODO::check epoch number not too large so asset id will not overflow + // curator must be verified by this time since there is committe vote + // TODO::make sure curator is verified by now Weight::zero() } @@ -631,7 +640,7 @@ pub mod pallet { } impl Pallet { - fn solve_pending(n: BlockNumberFor) -> DispatchResult { + fn solve_pending(n: BlockNumberFor) { let mut pending_setup = >::take(); loop { match pending_setup.pop_front() { @@ -680,8 +689,8 @@ pub mod pallet { investor.0, guardian_candidate, ) { - None => _, - Some(GuardianVote::Neutral) => _, + None => {}, + Some(GuardianVote::Neutral) => {}, Some(GuardianVote::Aye) => guardian.1 += investor.1, Some(GuardianVote::Nay) => guardian.2 += investor.1, }; @@ -714,25 +723,37 @@ pub mod pallet { pool_proposal.proposal_status_flags |= ProposalStatusFlags::PROPOSAL_EXPIRED; + let type_error: bool = false; + let start_time_u128: u128; + match as TryInto>::try_into( + pool_proposal.start_time, + ) { + Ok(x) => start_time_u128 = x, + Err(_) => type_error = true, + } + + let end_time_u128: u128; + match as TryInto>::try_into(pool_proposal.end_time) + { + Ok(x) => end_time_u128 = x, + Error => type_error = true, + } + + let epoch_range_u128: u128; + match as TryInto>::try_into(T::StandardEpoch::get()) + { + Ok(x) => end_time_u128 = x, + Error => type_error = true, + } + // If all satisfied, baked into investing pool - if pool_proposal.proposal_status_flags.is_all() { + if !type_error && pool_proposal.proposal_status_flags.is_all() { let signatories: [T::AccountId] = best_guardian.into_iter().map(|b| b.owner).collect(); let guardian_multisig = pallet_multisig::Pallet::::multi_account_id( &signatories, signatories.len, ); - let start_time_u128: u128 = pool_proposal - .start_time - .try_into() - .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; - let end_time_u128: u128 = pool_proposal - .end_time - .try_into() - .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; - let epoch_range_u128: u128 = T::StandardEpoch::get() - .try_into() - .or(Err(Error::::TypeIncompatibleOrArithmeticError))?; let total_epoch: u128 = ((end_time_u128 - start_time_u128) / epoch_range_u128) + 1; @@ -780,6 +801,11 @@ pub mod pallet { amount: investor.1, }); } + Self::deposit_event(Event::::ProposalFailed { + pool_proposal_index: x.pool_proposal_index, + effective_time: n, + type_error, + }); } // Return Queued queued_investments always @@ -847,23 +873,4 @@ pub mod pallet { } } } - - /// Simple ensure origin for the applet pool proposal - pub struct EnsurePoolProposal(sp_std::marker::PhantomData); - impl EnsureOrigin for EnsureBridge { - type Success = T::AccountId; - fn try_origin(o: T::RuntimeOrigin) -> Result { - let pallet_id = MODULE_ID.into_account_truncating(); - o.into().and_then(|o| match o { - system::RawOrigin::Signed(who) if who == pallet_id => Ok(pallet_id), - r => Err(T::RuntimeOrigin::from(r)), - }) - } - - #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { - let pallet_id = MODULE_ID.into_account_truncating(); - Ok(T::RuntimeOrigin::from(system::RawOrigin::Signed(pallet_id))) - } - } } From 6fd49ba40ccd12895bda0555de0c560d1e43b1b0 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 15:26:00 +0800 Subject: [PATCH 156/215] chore: fix --- .../collab-ai/pool-proposal/src/lib.rs | 365 ++++++++++-------- 1 file changed, 207 insertions(+), 158 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index c7a4e66c35..81f7f6f38a 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -253,12 +253,20 @@ pub mod pallet { ProposalPublicVoted { pool_proposal_index: PoolProposalIndex, vote_result: bool }, /// A proposal passed all checking and become a investing pool ProposalBaked { pool_proposal_index: PoolProposalIndex, effective_time: BlockNumberFor }, - /// A proposal failed some checking or type error + /// A proposal failed some checking or type error, but fund is returned ProposalFailed { pool_proposal_index: PoolProposalIndex, effective_time: BlockNumberFor, type_error: bool, }, + /// Something really bad happened, the fund is not returned and we do not know if investing pool storage broking + /// TODO: We must overcome this uncertainty + ProposalEmergencyFault { + pool_proposal_index: PoolProposalIndex, + effective_time: BlockNumberFor, + pool_created: bool, + investment_injected: bool, + }, } #[pallet::error] @@ -276,7 +284,7 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { - fn on_initialize(_n: BlockNumberFor) -> Weight { + fn on_initialize(n: BlockNumberFor) -> Weight { // Check proposal expire // Mature the pool by proposal if qualified, refund/transfer all money based on investing pool logic Self::solve_pending(n); @@ -646,146 +654,211 @@ pub mod pallet { match pending_setup.pop_front() { // Latest Pending tx effective Some(x) if x.proposal_expire_time <= n => { - // Mature the proposal - let mut pool_proposal = >::get(x.pool_proposal_index) - .ok_or(Error::::ProposalNotExist)?; - pool_proposal.proposal_status_flags |= - ProposalStatusFlags::PROPOSAL_EXPIRED; - >::insert(x.pool_proposal_index, pool_proposal.clone()); - - let mut pre_investments: Vec<(T::AccountId, AssetBalanceOf)> = - Default::default(); - let mut queued_investments: Vec<(T::AccountId, AssetBalanceOf)> = - Default::default(); - - // ignored if return none - if let Some(pool_bonds) = >::get(x.pool_proposal_index) + // Mature the proposal, ignore if no PoolProposal Storage + if let Some(mut pool_proposal) = + >::get(x.pool_proposal_index) { - pre_investments = pool_bonds - .pre_investings - .into_iter() - .map(|b| (b.owner, b.amount)) - .collect(); - queued_investments = pool_bonds - .queued_pre_investings - .into_iter() - .map(|b| (b.0.owner, b.0.amount)) - .collect(); - } + pool_proposal.proposal_status_flags |= + ProposalStatusFlags::PROPOSAL_EXPIRED; + >::insert(x.pool_proposal_index, pool_proposal.clone()); + + let mut pre_investments: Vec<(T::AccountId, AssetBalanceOf)> = + Default::default(); + let mut queued_investments: Vec<(T::AccountId, AssetBalanceOf)> = + Default::default(); + + // ignored if return none + if let Some(pool_bonds) = + >::get(x.pool_proposal_index) + { + pre_investments = pool_bonds + .pre_investings + .into_iter() + .map(|b| (b.owner, b.amount)) + .collect(); + queued_investments = pool_bonds + .queued_pre_investings + .into_iter() + .map(|b| (b.0.owner, b.0.amount)) + .collect(); + } - // Judege guardian - // guardian with aye > nye will be selected - // And select top N guardians with highest aye - let mut best_guardians: Vec<(T::AccountId, AssetBalanceOf)> = - Default::default(); - if let Some(pool_guardians) = >::get(x.pool_proposal_index) - { - for guardian_candidate in pool_guardians.0.into_iter() { - // AccountId, Aye, Nye - let mut guardian: (T::AccountId, AssetBalanceOf) = - (guardian_candidate.clone(), Zero::zero(), Zero::zero()); - for investor in pre_investments.iter() { - match T::GuardianVoteResource::get_vote( - investor.0, - guardian_candidate, - ) { - None => {}, - Some(GuardianVote::Neutral) => {}, - Some(GuardianVote::Aye) => guardian.1 += investor.1, - Some(GuardianVote::Nay) => guardian.2 += investor.1, - }; - } - // As long as Aye > Nye and kyc passed, valid guardian - if guardian.1 >= guardian.2 - && T::GuardianVoteResource::is_verified_guardian(guardian.0) - { - best_guardians.push((guardian.0, guardian.1)); + // Judege guardian + // guardian with aye > nye will be selected + // And select top N guardians with highest aye + let mut best_guardians: Vec<(T::AccountId, AssetBalanceOf)> = + Default::default(); + if let Some(pool_guardians) = + >::get(x.pool_proposal_index) + { + for guardian_candidate in pool_guardians.0.into_iter() { + // AccountId, Aye, Nye + let mut guardian: ( + T::AccountId, + AssetBalanceOf, + AssetBalanceOf, + ) = (guardian_candidate.clone(), Zero::zero(), Zero::zero()); + for investor in pre_investments.iter() { + match T::GuardianVoteResource::get_vote( + investor.0, + guardian_candidate, + ) { + None => {}, + Some(GuardianVote::Neutral) => {}, + Some(GuardianVote::Aye) => guardian.1 += investor.1, + Some(GuardianVote::Nay) => guardian.2 += investor.1, + }; + } + // As long as Aye > Nye and kyc passed, valid guardian + if guardian.1 >= guardian.2 + && T::GuardianVoteResource::is_verified_guardian(guardian.0) + { + best_guardians.push((guardian.0, guardian.1)); + } } } - } - // Order best_guardians based on Aye - // temp sorted by Aye from largestsmallest to smallest - best_guardians.sort_by(|a, b| b.1.cmp(&a.1)); - - if best_guardians.len > T::MaxGuardianSelectedPerProposal::get() { - best_guardians.split_off(T::MaxGuardianSelectedPerProposal::get()); - } + // Order best_guardians based on Aye + // temp sorted by Aye from largestsmallest to smallest + best_guardians.sort_by(|a, b| b.1.cmp(&a.1)); + + let type_error: bool = false; + let split_index: usize; + + match >::try_into( + T::MaxGuardianSelectedPerProposal::get(), + ) { + Ok(x) => split_index = x, + Err(_) => type_error = true, + } - // If existing one guardian - if best_guardians.len > 0 { - pool_proposal.proposal_status_flags |= - ProposalStatusFlags::GUARDIAN_SELECTED; - } else { - pool_proposal.proposal_status_flags &= - !ProposalStatusFlags::GUARDIAN_SELECTED; - } + if best_guardians.len() > T::MaxGuardianSelectedPerProposal::get() { + best_guardians.split_off(split_index); + } - pool_proposal.proposal_status_flags |= - ProposalStatusFlags::PROPOSAL_EXPIRED; + // If existing one guardian + if best_guardians.len() > 0 { + pool_proposal.proposal_status_flags |= + ProposalStatusFlags::GUARDIAN_SELECTED; + } else { + pool_proposal.proposal_status_flags &= + !ProposalStatusFlags::GUARDIAN_SELECTED; + } - let type_error: bool = false; - let start_time_u128: u128; - match as TryInto>::try_into( - pool_proposal.start_time, - ) { - Ok(x) => start_time_u128 = x, - Err(_) => type_error = true, - } + pool_proposal.proposal_status_flags |= + ProposalStatusFlags::PROPOSAL_EXPIRED; + + let start_time_u128: u128; + match as TryInto>::try_into( + pool_proposal.pool_start_time, + ) { + Ok(x) => start_time_u128 = x, + Err(_) => type_error = true, + } - let end_time_u128: u128; - match as TryInto>::try_into(pool_proposal.end_time) - { - Ok(x) => end_time_u128 = x, - Error => type_error = true, - } + let end_time_u128: u128; + match as TryInto>::try_into( + pool_proposal.pool_end_time, + ) { + Ok(x) => end_time_u128 = x, + Err(_) => type_error = true, + } - let epoch_range_u128: u128; - match as TryInto>::try_into(T::StandardEpoch::get()) - { - Ok(x) => end_time_u128 = x, - Error => type_error = true, - } + let epoch_range_u128: u128; + match as TryInto>::try_into( + T::StandardEpoch::get(), + ) { + Ok(x) => end_time_u128 = x, + Err(_) => type_error = true, + } - // If all satisfied, baked into investing pool - if !type_error && pool_proposal.proposal_status_flags.is_all() { - let signatories: [T::AccountId] = - best_guardian.into_iter().map(|b| b.owner).collect(); - let guardian_multisig = pallet_multisig::Pallet::::multi_account_id( - &signatories, - signatories.len, - ); + // If all satisfied, baked into investing pool + if !type_error && pool_proposal.proposal_status_flags.is_all() { + let signatories: [T::AccountId] = + best_guardians.into_iter().map(|b| b.owner).collect(); + let guardian_multisig = + pallet_multisig::Pallet::::multi_account_id( + &signatories, + signatories.len(), + ); + + let total_epoch: u128 = + ((end_time_u128 - start_time_u128) / epoch_range_u128) + 1; + let pool_setting: PoolSetting< + T::AccountId, + BlockNumberFor, + AssetBalanceOf, + > = PoolSetting { + start_time: pool_proposal.pool_start_time, + epoch: total_epoch, + epoch_range: T::StandardEpoch::get(), + pool_cap: pool_proposal.max_pool_size, + // Curator + admin: pool_proposal.proposer, + }; + + // If the below two failed + // stop the loop immediately + match T::InvestmentInjector::create_investing_pool( + x.pool_proposal_index, + pool_setting, + guardian_multisig, + ) { + Ok(_) => {}, + Err(_) => { + Self::deposit_event(Event::::ProposalEmergencyFault { + pool_proposal_index: x.pool_proposal_index, + effective_time: n, + pool_created: false, + investment_injected: false, + }); + break; + }, + } + match T::InvestmentInjector::inject_investment( + x.pool_proposal_index, + pre_investments, + ) { + Ok(_) => {}, + Err(_) => { + Self::deposit_event(Event::::ProposalEmergencyFault { + pool_proposal_index: x.pool_proposal_index, + effective_time: n, + pool_created: true, + investment_injected: false, + }); + break; + }, + } + Self::deposit_event(Event::::ProposalBaked { + pool_proposal_index: x.pool_proposal_index, + effective_time: n, + }); + } else { + // Otherwise return bonding + for investor in pre_investments.iter() { + let asset_refund_amount: AssetBalanceOf = + T::Fungibles::transfer( + T::AIUSDAssetId::get(), + &T::PreInvestingPool::get(), + &investor.0, + investor.1, + Preservation::Expendable, + )?; + Self::deposit_event(Event::::PoolWithdrawed { + user: investor.0, + pool_proposal_index: x.pool_proposal_index, + amount: investor.1, + }); + } + Self::deposit_event(Event::::ProposalFailed { + pool_proposal_index: x.pool_proposal_index, + effective_time: n, + type_error, + }); + } - let total_epoch: u128 = - ((end_time_u128 - start_time_u128) / epoch_range_u128) + 1; - let pool_setting: PoolSetting< - T::AccountId, - BlockNumberFor, - AssetBalanceOf, - > = PoolSetting { - start_time: pool_proposal.pool_start_time, - epoch: total_epoch, - epoch_range: T::StandardEpoch::get(), - pool_cap: pool_proposal.max_pool_size, - // Curator - admin: pool_proposal.proposer, - }; - - T::InvestmentInjector::create_investing_pool( - x.pool_proposal_index, - pool_setting, - guardian_multisig, - )?; - T::InvestmentInjector::inject_investment( - x.pool_proposal_index, - pre_investments, - )?; - Self::deposit_event(Event::::ProposalBaked { - pool_proposal_index: x.pool_proposal_index, - effective_time: n, - }); - } else { - // Otherwise return bonding - for investor in pre_investments.iter() { + // Return Queued queued_investments always + for investor in queued_investments.iter() { let asset_refund_amount: AssetBalanceOf = T::Fungibles::transfer( T::AIUSDAssetId::get(), @@ -795,37 +868,14 @@ pub mod pallet { Preservation::Expendable, )?; Self::deposit_event(Event::::PoolWithdrawed { - who: investor.0, - pool_id: x.pool_proposal_index, - effective_time: n, + user: investor.0, + pool_proposal_index: x.pool_proposal_index, amount: investor.1, }); } - Self::deposit_event(Event::::ProposalFailed { - pool_proposal_index: x.pool_proposal_index, - effective_time: n, - type_error, - }); - } - // Return Queued queued_investments always - for investor in queued_investments.iter() { - let asset_refund_amount: AssetBalanceOf = T::Fungibles::transfer( - T::AIUSDAssetId::get(), - &T::PreInvestingPool::get(), - &investor.0, - investor.1, - Preservation::Expendable, - )?; - Self::deposit_event(Event::::PoolWithdrawed { - who: investor.0, - pool_id: x.pool_proposal_index, - effective_time: n, - amount: investor.1, - }); + >::insert(x.pool_proposal_index, pool_proposal); } - - >::insert(pool_proposal_index, pool_proposal); }, // Latest Pending tx not effective Some(x) => { @@ -840,7 +890,6 @@ pub mod pallet { } } >::put(pending_setup); - Ok(()) } } From 48409efb589181517b0478cf6438755786b94f46 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 16:52:30 +0800 Subject: [PATCH 157/215] chore: fix --- .../collab-ai/pool-proposal/src/lib.rs | 388 +++++++++++------- 1 file changed, 235 insertions(+), 153 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 81f7f6f38a..d1e9b01329 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -216,6 +216,21 @@ pub mod pallet { OptionQuery, >; + // Proposal Failed to bake, or other reasons, ready to dissolve + #[pallet::storage] + #[pallet::getter(fn proposal_ready_for_dissolve)] + pub type ProposalReadyForDissolve = + StorageValue<_, VecDeque, ValueQuery>; + + // Proposal Succeed, ready to bake into investing pool, along with selected guardian info + #[pallet::storage] + #[pallet::getter(fn proposal_ready_for_bake)] + pub type ProposalReadyForBake = StorageValue< + _, + VecDeque<(PoolProposalIndex, BoundedVec)>, + ValueQuery, + >; + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -251,22 +266,14 @@ pub mod pallet { }, /// A public vote result of proposal get passed ProposalPublicVoted { pool_proposal_index: PoolProposalIndex, vote_result: bool }, + /// A proposal is ready for baking + ProposalReadyForBake { pool_proposal_index: PoolProposalIndex }, + /// A proposal is ready for full dissolve, since the proposal expired but not satisifed all requirement + ProposalReadyForDissolve { pool_proposal_index: PoolProposalIndex }, /// A proposal passed all checking and become a investing pool ProposalBaked { pool_proposal_index: PoolProposalIndex, effective_time: BlockNumberFor }, /// A proposal failed some checking or type error, but fund is returned - ProposalFailed { - pool_proposal_index: PoolProposalIndex, - effective_time: BlockNumberFor, - type_error: bool, - }, - /// Something really bad happened, the fund is not returned and we do not know if investing pool storage broking - /// TODO: We must overcome this uncertainty - ProposalEmergencyFault { - pool_proposal_index: PoolProposalIndex, - effective_time: BlockNumberFor, - pool_created: bool, - investment_injected: bool, - }, + ProposalDissolved { pool_proposal_index: PoolProposalIndex }, } #[pallet::error] @@ -285,11 +292,11 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { fn on_initialize(n: BlockNumberFor) -> Weight { - // Check proposal expire - // Mature the pool by proposal if qualified, refund/transfer all money based on investing pool logic + // Check proposal expire and status flag + // Mature the pool by proposal if qualified + // No money transfer/investing pool creating so far Self::solve_pending(n); - // curator must be verified by this time // TODO::check epoch number not too large so asset id will not overflow // curator must be verified by this time since there is committe vote // TODO::make sure curator is verified by now @@ -383,14 +390,14 @@ pub mod pallet { } }, )?; - >::mutate(|pending_porposals| { + >::mutate(|pending_proposals| { let new_proposal_status = PoolProposalStatus { pool_proposal_index: next_proposal_index, proposal_expire_time: proposal_end_time, }; - pending_porposals.push_back(new_proposal_status); + pending_proposals.push_back(new_proposal_status); // Make sure the first element has earlies effective time - pending_porposals + pending_proposals .make_contiguous() .sort_by(|a, b| a.proposal_expire_time.cmp(&b.proposal_expire_time)); }); @@ -645,6 +652,196 @@ pub mod pallet { }, ) } + + // Make all avaialable qualified proposal into investing pool + // Refund the queued + #[pallet::call_index(5)] + #[pallet::weight({195_000_000})] + #[transactional] + pub fn bake_proposal(_origin: OriginFor) -> DispatchResult { + let mut pending = >::take(); + loop { + match pending.pop_front() { + Some(x) => { + if let Some(pool_proposal) = >::get(x.pool_proposal_index) { + // Creating investing pool + let start_time_u128: u128 = pool_proposal + .pool_start_time + .try_into() + .or(Err(ArithmeticError::Overflow))?; + let end_time_u128: u128 = pool_proposal + .pool_end_time + .try_into() + .or(Err(ArithmeticError::Overflow))?; + let epoch_range_u128: u128 = T::StandardEpoch::get() + .try_into() + .or(Err(ArithmeticError::Overflow))?; + + let signatories: [T::AccountId] = + x.1.into_iter().map(|b| b.0).collect(); + let guardian_multisig = pallet_multisig::Pallet::::multi_account_id( + &signatories, + signatories.len(), + ); + + let total_epoch: u128 = + ((end_time_u128 - start_time_u128) / epoch_range_u128) + 1; + let pool_setting: PoolSetting< + T::AccountId, + BlockNumberFor, + AssetBalanceOf, + > = PoolSetting { + start_time: pool_proposal.pool_start_time, + epoch: total_epoch, + epoch_range: T::StandardEpoch::get(), + pool_cap: pool_proposal.max_pool_size, + // Curator + admin: pool_proposal.proposer, + }; + + T::InvestmentInjector::create_investing_pool( + x.pool_proposal_index, + pool_setting, + guardian_multisig, + )?; + + // Prepare Money related material + let mut pre_investments: Vec<(T::AccountId, AssetBalanceOf)> = + Default::default(); + let mut queued_investments: Vec<(T::AccountId, AssetBalanceOf)> = + Default::default(); + + let total_investment_amount: AssetBalanceOf; + + // ignored if return none, but technically it is impossible + if let Some(pool_bonds) = + >::get(x.pool_proposal_index) + { + pre_investments = pool_bonds + .pre_investings + .into_iter() + .map(|b| (b.owner, b.amount)) + .collect(); + queued_investments = pool_bonds + .queued_pre_investings + .into_iter() + .map(|b| (b.0.owner, b.0.amount)) + .collect(); + total_investment_amount = pool_bonds.total_pre_investing_amount; + } + + // Inject investment + T::InvestmentInjector::inject_investment( + x.pool_proposal_index, + pre_investments, + )?; + + // Do refund + // Return Queued queued_investments always + for investor in queued_investments.iter() { + let asset_refund_amount: AssetBalanceOf = + T::Fungibles::transfer( + T::AIUSDAssetId::get(), + &T::PreInvestingPool::get(), + &investor.0, + investor.1, + Preservation::Expendable, + )?; + Self::deposit_event(Event::::PoolWithdrawed { + user: investor.0, + pool_proposal_index: x.pool_proposal_index, + amount: asset_refund_amount, + }); + } + + // Transfer official investment money to curator + let proposal_settlement: AssetBalanceOf = T::Fungibles::transfer( + T::AIUSDAssetId::get(), + &T::PreInvestingPool::get(), + &pool_proposal.proposer, + total_investing_amount, + Preservation::Expendable, + )?; + + Self::deposit_event(Event::::ProposalBaked { + pool_proposal_index: x.pool_proposal_index, + curator: pool_proposal.proposer, + proposal_settlement, + }); + } + }, + // Nothing to bake + _ => { + break; + }, + } + } + >::put(pending); + Ok(()) + } + + // Make all avaialable failed proposal refund + #[pallet::call_index(6)] + #[pallet::weight({195_000_000})] + #[transactional] + pub fn dissolve_proposal( + origin: OriginFor, + pool_proposal_index: PoolProposalIndex, + ) -> DispatchResult { + let mut pending = >::take(); + loop { + match pending.pop_front() { + Some(x) => { + if let Some(pool_proposal) = >::get(x.pool_proposal_index) { + // Do Refund + // Return bonding + for investor in pre_investments.iter() { + let asset_refund_amount: AssetBalanceOf = + T::Fungibles::transfer( + T::AIUSDAssetId::get(), + &T::PreInvestingPool::get(), + &investor.0, + investor.1, + Preservation::Expendable, + )?; + Self::deposit_event(Event::::PoolWithdrawed { + user: investor.0, + pool_proposal_index: x.pool_proposal_index, + amount: asset_refund_amount, + }); + } + + // Return Queued queued_investments always + for investor in queued_investments.iter() { + let asset_refund_amount: AssetBalanceOf = + T::Fungibles::transfer( + T::AIUSDAssetId::get(), + &T::PreInvestingPool::get(), + &investor.0, + investor.1, + Preservation::Expendable, + )?; + Self::deposit_event(Event::::PoolWithdrawed { + user: investor.0, + pool_proposal_index: x.pool_proposal_index, + amount: asset_refund_amount, + }); + } + + Self::deposit_event(Event::::ProposalDissolved { + pool_proposal_index: x.pool_proposal_index, + }); + } + }, + // Nothing to dissolve + _ => { + break; + }, + } + } + >::put(pending); + Ok(()) + } } impl Pallet { @@ -664,9 +861,6 @@ pub mod pallet { let mut pre_investments: Vec<(T::AccountId, AssetBalanceOf)> = Default::default(); - let mut queued_investments: Vec<(T::AccountId, AssetBalanceOf)> = - Default::default(); - // ignored if return none if let Some(pool_bonds) = >::get(x.pool_proposal_index) @@ -676,11 +870,6 @@ pub mod pallet { .into_iter() .map(|b| (b.owner, b.amount)) .collect(); - queued_investments = pool_bonds - .queued_pre_investings - .into_iter() - .map(|b| (b.0.owner, b.0.amount)) - .collect(); } // Judege guardian @@ -707,6 +896,11 @@ pub mod pallet { Some(GuardianVote::Neutral) => {}, Some(GuardianVote::Aye) => guardian.1 += investor.1, Some(GuardianVote::Nay) => guardian.2 += investor.1, + Some(GuardianVote::Specific(t)) + if t == x.pool_proposal_index => + { + guardian.1 += investor.1 + }, }; } // As long as Aye > Nye and kyc passed, valid guardian @@ -721,17 +915,16 @@ pub mod pallet { // temp sorted by Aye from largestsmallest to smallest best_guardians.sort_by(|a, b| b.1.cmp(&a.1)); - let type_error: bool = false; let split_index: usize; match >::try_into( T::MaxGuardianSelectedPerProposal::get(), ) { Ok(x) => split_index = x, - Err(_) => type_error = true, + Err(_) => split_index = 0usize, } - if best_guardians.len() > T::MaxGuardianSelectedPerProposal::get() { + if best_guardians.len() > split_index { best_guardians.split_off(split_index); } @@ -744,136 +937,25 @@ pub mod pallet { !ProposalStatusFlags::GUARDIAN_SELECTED; } - pool_proposal.proposal_status_flags |= - ProposalStatusFlags::PROPOSAL_EXPIRED; - - let start_time_u128: u128; - match as TryInto>::try_into( - pool_proposal.pool_start_time, - ) { - Ok(x) => start_time_u128 = x, - Err(_) => type_error = true, - } - - let end_time_u128: u128; - match as TryInto>::try_into( - pool_proposal.pool_end_time, - ) { - Ok(x) => end_time_u128 = x, - Err(_) => type_error = true, - } - - let epoch_range_u128: u128; - match as TryInto>::try_into( - T::StandardEpoch::get(), - ) { - Ok(x) => end_time_u128 = x, - Err(_) => type_error = true, - } - - // If all satisfied, baked into investing pool - if !type_error && pool_proposal.proposal_status_flags.is_all() { - let signatories: [T::AccountId] = - best_guardians.into_iter().map(|b| b.owner).collect(); - let guardian_multisig = - pallet_multisig::Pallet::::multi_account_id( - &signatories, - signatories.len(), - ); - - let total_epoch: u128 = - ((end_time_u128 - start_time_u128) / epoch_range_u128) + 1; - let pool_setting: PoolSetting< - T::AccountId, - BlockNumberFor, - AssetBalanceOf, - > = PoolSetting { - start_time: pool_proposal.pool_start_time, - epoch: total_epoch, - epoch_range: T::StandardEpoch::get(), - pool_cap: pool_proposal.max_pool_size, - // Curator - admin: pool_proposal.proposer, - }; - - // If the below two failed - // stop the loop immediately - match T::InvestmentInjector::create_investing_pool( - x.pool_proposal_index, - pool_setting, - guardian_multisig, - ) { - Ok(_) => {}, - Err(_) => { - Self::deposit_event(Event::::ProposalEmergencyFault { - pool_proposal_index: x.pool_proposal_index, - effective_time: n, - pool_created: false, - investment_injected: false, - }); - break; - }, - } - match T::InvestmentInjector::inject_investment( - x.pool_proposal_index, - pre_investments, - ) { - Ok(_) => {}, - Err(_) => { - Self::deposit_event(Event::::ProposalEmergencyFault { - pool_proposal_index: x.pool_proposal_index, - effective_time: n, - pool_created: true, - investment_injected: false, - }); - break; - }, - } - Self::deposit_event(Event::::ProposalBaked { + if pool_proposal.proposal_status_flags.is_all() { + >::mutate(|proposal_rb| { + proposal_rb.push_back(( + x.pool_proposal_index, + best_guardians.into_iter().map(|b| b.0).collect(), + )); + }); + Self::deposit_event(Event::::ProposalReadyForBake { pool_proposal_index: x.pool_proposal_index, - effective_time: n, }); } else { - // Otherwise return bonding - for investor in pre_investments.iter() { - let asset_refund_amount: AssetBalanceOf = - T::Fungibles::transfer( - T::AIUSDAssetId::get(), - &T::PreInvestingPool::get(), - &investor.0, - investor.1, - Preservation::Expendable, - )?; - Self::deposit_event(Event::::PoolWithdrawed { - user: investor.0, - pool_proposal_index: x.pool_proposal_index, - amount: investor.1, - }); - } - Self::deposit_event(Event::::ProposalFailed { - pool_proposal_index: x.pool_proposal_index, - effective_time: n, - type_error, + >::mutate(|proposal_fb| { + proposal_fb.push_back(x.pool_proposal_index); }); - } - - // Return Queued queued_investments always - for investor in queued_investments.iter() { - let asset_refund_amount: AssetBalanceOf = - T::Fungibles::transfer( - T::AIUSDAssetId::get(), - &T::PreInvestingPool::get(), - &investor.0, - investor.1, - Preservation::Expendable, - )?; - Self::deposit_event(Event::::PoolWithdrawed { - user: investor.0, + Self::deposit_event(Event::::ProposalReadyForDissolve { pool_proposal_index: x.pool_proposal_index, - amount: investor.1, }); } - + // Put status flag updated >::insert(x.pool_proposal_index, pool_proposal); } }, From 0acc6228336106158da0aba7a7c59cb0b8efeb69 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 17:11:38 +0800 Subject: [PATCH 158/215] chore: fix --- .../collab-ai/pool-proposal/src/lib.rs | 57 ++++++++++++------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index d1e9b01329..e00d3acef0 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -114,7 +114,7 @@ pub mod pallet { #[pallet::constant] type MaximumPoolProposed: Get; - /// The maximum amount of allowed pool proposed by a single curator + /// Standard epoch length #[pallet::constant] type StandardEpoch: Get>; @@ -271,7 +271,11 @@ pub mod pallet { /// A proposal is ready for full dissolve, since the proposal expired but not satisifed all requirement ProposalReadyForDissolve { pool_proposal_index: PoolProposalIndex }, /// A proposal passed all checking and become a investing pool - ProposalBaked { pool_proposal_index: PoolProposalIndex, effective_time: BlockNumberFor }, + ProposalBaked { + pool_proposal_index: PoolProposalIndex, + curator: T::AccountId, + proposal_settlement: AssetBalanceOf, + }, /// A proposal failed some checking or type error, but fund is returned ProposalDissolved { pool_proposal_index: PoolProposalIndex }, } @@ -663,7 +667,7 @@ pub mod pallet { loop { match pending.pop_front() { Some(x) => { - if let Some(pool_proposal) = >::get(x.pool_proposal_index) { + if let Some(pool_proposal) = >::get(x.0) { // Creating investing pool let start_time_u128: u128 = pool_proposal .pool_start_time @@ -677,8 +681,7 @@ pub mod pallet { .try_into() .or(Err(ArithmeticError::Overflow))?; - let signatories: [T::AccountId] = - x.1.into_iter().map(|b| b.0).collect(); + let signatories: [T::AccountId] = x.1.into_iter().map(|b| b).collect(); let guardian_multisig = pallet_multisig::Pallet::::multi_account_id( &signatories, signatories.len(), @@ -700,7 +703,7 @@ pub mod pallet { }; T::InvestmentInjector::create_investing_pool( - x.pool_proposal_index, + x.0, pool_setting, guardian_multisig, )?; @@ -714,9 +717,7 @@ pub mod pallet { let total_investment_amount: AssetBalanceOf; // ignored if return none, but technically it is impossible - if let Some(pool_bonds) = - >::get(x.pool_proposal_index) - { + if let Some(pool_bonds) = >::get(x.0) { pre_investments = pool_bonds .pre_investings .into_iter() @@ -731,10 +732,7 @@ pub mod pallet { } // Inject investment - T::InvestmentInjector::inject_investment( - x.pool_proposal_index, - pre_investments, - )?; + T::InvestmentInjector::inject_investment(x.0, pre_investments)?; // Do refund // Return Queued queued_investments always @@ -749,7 +747,7 @@ pub mod pallet { )?; Self::deposit_event(Event::::PoolWithdrawed { user: investor.0, - pool_proposal_index: x.pool_proposal_index, + pool_proposal_index: x.0, amount: asset_refund_amount, }); } @@ -759,12 +757,12 @@ pub mod pallet { T::AIUSDAssetId::get(), &T::PreInvestingPool::get(), &pool_proposal.proposer, - total_investing_amount, + total_investment_amount, Preservation::Expendable, )?; Self::deposit_event(Event::::ProposalBaked { - pool_proposal_index: x.pool_proposal_index, + pool_proposal_index: x.0, curator: pool_proposal.proposer, proposal_settlement, }); @@ -792,7 +790,26 @@ pub mod pallet { loop { match pending.pop_front() { Some(x) => { - if let Some(pool_proposal) = >::get(x.pool_proposal_index) { + if let Some(pool_proposal) = >::get(x) { + // Prepare Money related material + let mut pre_investments: Vec<(T::AccountId, AssetBalanceOf)> = + Default::default(); + let mut queued_investments: Vec<(T::AccountId, AssetBalanceOf)> = + Default::default(); + + // ignored if return none, but technically it is impossible + if let Some(pool_bonds) = >::get(x) { + pre_investments = pool_bonds + .pre_investings + .into_iter() + .map(|b| (b.owner, b.amount)) + .collect(); + queued_investments = pool_bonds + .queued_pre_investings + .into_iter() + .map(|b| (b.0.owner, b.0.amount)) + .collect(); + } // Do Refund // Return bonding for investor in pre_investments.iter() { @@ -806,7 +823,7 @@ pub mod pallet { )?; Self::deposit_event(Event::::PoolWithdrawed { user: investor.0, - pool_proposal_index: x.pool_proposal_index, + pool_proposal_index: x, amount: asset_refund_amount, }); } @@ -823,13 +840,13 @@ pub mod pallet { )?; Self::deposit_event(Event::::PoolWithdrawed { user: investor.0, - pool_proposal_index: x.pool_proposal_index, + pool_proposal_index: x, amount: asset_refund_amount, }); } Self::deposit_event(Event::::ProposalDissolved { - pool_proposal_index: x.pool_proposal_index, + pool_proposal_index: x, }); } }, From 23b96a9aa4aa042e05cee304149c51d6295ebc69 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 17:34:20 +0800 Subject: [PATCH 159/215] chore: fix --- .../collab-ai/pool-proposal/src/lib.rs | 119 +++++++++--------- 1 file changed, 56 insertions(+), 63 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index e00d3acef0..5fc3c25abc 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -681,10 +681,10 @@ pub mod pallet { .try_into() .or(Err(ArithmeticError::Overflow))?; - let signatories: [T::AccountId] = x.1.into_iter().map(|b| b).collect(); + let signatories: &[T::AccountId] = x.1.into_inner().as_slice(); let guardian_multisig = pallet_multisig::Pallet::::multi_account_id( - &signatories, - signatories.len(), + signatories, + signatories.len().try_into().or(Err(ArithmeticError::Overflow))?, ); let total_epoch: u128 = @@ -782,73 +782,66 @@ pub mod pallet { #[pallet::call_index(6)] #[pallet::weight({195_000_000})] #[transactional] - pub fn dissolve_proposal( - origin: OriginFor, - pool_proposal_index: PoolProposalIndex, - ) -> DispatchResult { + pub fn dissolve_proposal(_origin: OriginFor) -> DispatchResult { let mut pending = >::take(); loop { match pending.pop_front() { Some(x) => { - if let Some(pool_proposal) = >::get(x) { - // Prepare Money related material - let mut pre_investments: Vec<(T::AccountId, AssetBalanceOf)> = - Default::default(); - let mut queued_investments: Vec<(T::AccountId, AssetBalanceOf)> = - Default::default(); - - // ignored if return none, but technically it is impossible - if let Some(pool_bonds) = >::get(x) { - pre_investments = pool_bonds - .pre_investings - .into_iter() - .map(|b| (b.owner, b.amount)) - .collect(); - queued_investments = pool_bonds - .queued_pre_investings - .into_iter() - .map(|b| (b.0.owner, b.0.amount)) - .collect(); - } - // Do Refund - // Return bonding - for investor in pre_investments.iter() { - let asset_refund_amount: AssetBalanceOf = - T::Fungibles::transfer( - T::AIUSDAssetId::get(), - &T::PreInvestingPool::get(), - &investor.0, - investor.1, - Preservation::Expendable, - )?; - Self::deposit_event(Event::::PoolWithdrawed { - user: investor.0, - pool_proposal_index: x, - amount: asset_refund_amount, - }); - } - - // Return Queued queued_investments always - for investor in queued_investments.iter() { - let asset_refund_amount: AssetBalanceOf = - T::Fungibles::transfer( - T::AIUSDAssetId::get(), - &T::PreInvestingPool::get(), - &investor.0, - investor.1, - Preservation::Expendable, - )?; - Self::deposit_event(Event::::PoolWithdrawed { - user: investor.0, - pool_proposal_index: x, - amount: asset_refund_amount, - }); - } + // Prepare Money related material + let mut pre_investments: Vec<(T::AccountId, AssetBalanceOf)> = + Default::default(); + let mut queued_investments: Vec<(T::AccountId, AssetBalanceOf)> = + Default::default(); + + // ignored if return none, but technically it is impossible + if let Some(pool_bonds) = >::get(x) { + pre_investments = pool_bonds + .pre_investings + .into_iter() + .map(|b| (b.owner, b.amount)) + .collect(); + queued_investments = pool_bonds + .queued_pre_investings + .into_iter() + .map(|b| (b.0.owner, b.0.amount)) + .collect(); + } + // Do Refund + // Return bonding + for investor in pre_investments.iter() { + let asset_refund_amount: AssetBalanceOf = T::Fungibles::transfer( + T::AIUSDAssetId::get(), + &T::PreInvestingPool::get(), + &investor.0, + investor.1, + Preservation::Expendable, + )?; + Self::deposit_event(Event::::PoolWithdrawed { + user: investor.clone().0, + pool_proposal_index: x, + amount: asset_refund_amount, + }); + } - Self::deposit_event(Event::::ProposalDissolved { + // Return Queued queued_investments always + for investor in queued_investments.iter() { + let asset_refund_amount: AssetBalanceOf = T::Fungibles::transfer( + T::AIUSDAssetId::get(), + &T::PreInvestingPool::get(), + &investor.0, + investor.1, + Preservation::Expendable, + )?; + Self::deposit_event(Event::::PoolWithdrawed { + user: investor.clone().0, pool_proposal_index: x, + amount: asset_refund_amount, }); } + + Self::deposit_event(Event::::ProposalDissolved { + pool_proposal_index: x, + }); }, // Nothing to dissolve _ => { @@ -958,7 +951,7 @@ pub mod pallet { >::mutate(|proposal_rb| { proposal_rb.push_back(( x.pool_proposal_index, - best_guardians.into_iter().map(|b| b.0).collect(), + best_guardians.into_iter().map(|b| b.0).collect().into(), )); }); Self::deposit_event(Event::::ProposalReadyForBake { From 642d2258b5a292d12d8ce957cb272f76301077b7 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 18:06:06 +0800 Subject: [PATCH 160/215] chore: fix --- .../pallets/collab-ai/pool-proposal/src/lib.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 5fc3c25abc..cb75daadf0 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -681,7 +681,8 @@ pub mod pallet { .try_into() .or(Err(ArithmeticError::Overflow))?; - let signatories: &[T::AccountId] = x.1.into_inner().as_slice(); + let vec_inner = x.1.into_inner(); + let signatories: &[T::AccountId] = vec_inner.as_slice(); let guardian_multisig = pallet_multisig::Pallet::::multi_account_id( signatories, signatories.len().try_into().or(Err(ArithmeticError::Overflow))?, @@ -699,7 +700,7 @@ pub mod pallet { epoch_range: T::StandardEpoch::get(), pool_cap: pool_proposal.max_pool_size, // Curator - admin: pool_proposal.proposer, + admin: pool_proposal.proposer.clone(), }; T::InvestmentInjector::create_investing_pool( @@ -714,7 +715,7 @@ pub mod pallet { let mut queued_investments: Vec<(T::AccountId, AssetBalanceOf)> = Default::default(); - let total_investment_amount: AssetBalanceOf; + let mut total_investment_amount: AssetBalanceOf = Default::default(); // ignored if return none, but technically it is impossible if let Some(pool_bonds) = >::get(x.0) { @@ -746,7 +747,7 @@ pub mod pallet { Preservation::Expendable, )?; Self::deposit_event(Event::::PoolWithdrawed { - user: investor.0, + user: investor.0.clone(), pool_proposal_index: x.0, amount: asset_refund_amount, }); @@ -911,6 +912,7 @@ pub mod pallet { { guardian.1 += investor.1 }, + _ => {}, }; } // As long as Aye > Nye and kyc passed, valid guardian @@ -951,7 +953,11 @@ pub mod pallet { >::mutate(|proposal_rb| { proposal_rb.push_back(( x.pool_proposal_index, - best_guardians.into_iter().map(|b| b.0).collect().into(), + best_guardians + .into_iter() + .map(|b| b.0) + .collect::>() + .into(), )); }); Self::deposit_event(Event::::ProposalReadyForBake { From 293a50b222c8d4640e33346f71e1b1a2b068f28c Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 18:18:13 +0800 Subject: [PATCH 161/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index cb75daadf0..1687cd1c80 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -957,7 +957,8 @@ pub mod pallet { .into_iter() .map(|b| b.0) .collect::>() - .into(), + .try_from() + .or(Err(Error::::GuardianDuplicatedOrOversized))?, )); }); Self::deposit_event(Event::::ProposalReadyForBake { From 908b740014ffad99e56887679c812e1fa7ff6dff Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 18:30:26 +0800 Subject: [PATCH 162/215] chore: fix --- .../collab-ai/pool-proposal/src/lib.rs | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 1687cd1c80..c9ec5effc0 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -951,15 +951,21 @@ pub mod pallet { if pool_proposal.proposal_status_flags.is_all() { >::mutate(|proposal_rb| { - proposal_rb.push_back(( - x.pool_proposal_index, - best_guardians - .into_iter() - .map(|b| b.0) - .collect::>() - .try_from() + proposal_rb.push_back( + ( + x.pool_proposal_index, + BoundedVec::< + T::AccountId, + T::MaxGuardianSelectedPerProposal, + >::try_from( + best_guardians + .into_iter() + .map(|b| b.0) + .collect::>(), + ) .or(Err(Error::::GuardianDuplicatedOrOversized))?, - )); + ), + ); }); Self::deposit_event(Event::::ProposalReadyForBake { pool_proposal_index: x.pool_proposal_index, From bacf948ded2d8a889326910ba311acdac86380da Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 18:40:58 +0800 Subject: [PATCH 163/215] chore: fix --- .../collab-ai/pool-proposal/src/lib.rs | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index c9ec5effc0..49fbdca21b 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -949,23 +949,21 @@ pub mod pallet { !ProposalStatusFlags::GUARDIAN_SELECTED; } + let best_guardian_bounded = BoundedVec::< + T::AccountId, + T::MaxGuardianSelectedPerProposal, + >::try_from( + best_guardians + .into_iter() + .map(|b| b.0) + .collect::>(), + ) + .or(Err(Error::::GuardianDuplicatedOrOversized))?; + if pool_proposal.proposal_status_flags.is_all() { >::mutate(|proposal_rb| { - proposal_rb.push_back( - ( - x.pool_proposal_index, - BoundedVec::< - T::AccountId, - T::MaxGuardianSelectedPerProposal, - >::try_from( - best_guardians - .into_iter() - .map(|b| b.0) - .collect::>(), - ) - .or(Err(Error::::GuardianDuplicatedOrOversized))?, - ), - ); + proposal_rb + .push_back((x.pool_proposal_index, best_guardian_bounded)); }); Self::deposit_event(Event::::ProposalReadyForBake { pool_proposal_index: x.pool_proposal_index, From 6c4d01bb3e8729b38a77f39826dca80d404880da Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 18:52:44 +0800 Subject: [PATCH 164/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 49fbdca21b..8022f22d27 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -949,7 +949,7 @@ pub mod pallet { !ProposalStatusFlags::GUARDIAN_SELECTED; } - let best_guardian_bounded = BoundedVec::< + if let Ok(best_guardian_bounded) = BoundedVec::< T::AccountId, T::MaxGuardianSelectedPerProposal, >::try_from( @@ -957,10 +957,8 @@ pub mod pallet { .into_iter() .map(|b| b.0) .collect::>(), - ) - .or(Err(Error::::GuardianDuplicatedOrOversized))?; - - if pool_proposal.proposal_status_flags.is_all() { + ) && pool_proposal.proposal_status_flags.is_all() + { >::mutate(|proposal_rb| { proposal_rb .push_back((x.pool_proposal_index, best_guardian_bounded)); From 3281a1a813622291ded2675e0cb0bde074f34f2d Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 19:10:51 +0800 Subject: [PATCH 165/215] chore: fix --- .../collab-ai/pool-proposal/src/lib.rs | 47 ++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 8022f22d27..6227f87eb5 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -900,8 +900,8 @@ pub mod pallet { ) = (guardian_candidate.clone(), Zero::zero(), Zero::zero()); for investor in pre_investments.iter() { match T::GuardianVoteResource::get_vote( - investor.0, - guardian_candidate, + investor.0.clone(), + guardian_candidat.clone(), ) { None => {}, Some(GuardianVote::Neutral) => {}, @@ -917,8 +917,9 @@ pub mod pallet { } // As long as Aye > Nye and kyc passed, valid guardian if guardian.1 >= guardian.2 - && T::GuardianVoteResource::is_verified_guardian(guardian.0) - { + && T::GuardianVoteResource::is_verified_guardian( + guardian.0.clone(), + ) { best_guardians.push((guardian.0, guardian.1)); } } @@ -949,7 +950,7 @@ pub mod pallet { !ProposalStatusFlags::GUARDIAN_SELECTED; } - if let Ok(best_guardian_bounded) = BoundedVec::< + match BoundedVec::< T::AccountId, T::MaxGuardianSelectedPerProposal, >::try_from( @@ -957,22 +958,26 @@ pub mod pallet { .into_iter() .map(|b| b.0) .collect::>(), - ) && pool_proposal.proposal_status_flags.is_all() - { - >::mutate(|proposal_rb| { - proposal_rb - .push_back((x.pool_proposal_index, best_guardian_bounded)); - }); - Self::deposit_event(Event::::ProposalReadyForBake { - pool_proposal_index: x.pool_proposal_index, - }); - } else { - >::mutate(|proposal_fb| { - proposal_fb.push_back(x.pool_proposal_index); - }); - Self::deposit_event(Event::::ProposalReadyForDissolve { - pool_proposal_index: x.pool_proposal_index, - }); + ) { + // guardian is bounded and status satisfied + // guardian bounded is technically for sure + Ok(best_guardian_bounded) if pool_proposal.proposal_status_flags.is_all() => { + >::mutate(|proposal_rb| { + proposal_rb + .push_back((x.pool_proposal_index, best_guardian_bounded)); + }); + Self::deposit_event(Event::::ProposalReadyForBake { + pool_proposal_index: x.pool_proposal_index, + }); + }, + _ => { + >::mutate(|proposal_fb| { + proposal_fb.push_back(x.pool_proposal_index); + }); + Self::deposit_event(Event::::ProposalReadyForDissolve { + pool_proposal_index: x.pool_proposal_index, + }); + } } // Put status flag updated >::insert(x.pool_proposal_index, pool_proposal); From 6bccc643aa2a29dfa3759ffd2e18ff9811dda969 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 19:19:46 +0800 Subject: [PATCH 166/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 6227f87eb5..dd2fad8522 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -901,7 +901,7 @@ pub mod pallet { for investor in pre_investments.iter() { match T::GuardianVoteResource::get_vote( investor.0.clone(), - guardian_candidat.clone(), + guardian_candidate.clone(), ) { None => {}, Some(GuardianVote::Neutral) => {}, From 3df0bd6970b3b21dfd76084ce18282dcbd69ddac Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 19:32:36 +0800 Subject: [PATCH 167/215] chore: fix --- parachain/precompiles/collab-ai/pool-proposal/src/lib.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index 89f89bcd9d..6ebd61c242 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -30,9 +30,11 @@ impl PoolProposalPrecompile where Runtime: pallet_pool_proposal::Config + pallet_evm::Config, Runtime::AccountId: From<[u8; 32]> + Into<[u8; 32]>, - Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, - Runtime::RuntimeCall: From>, - ::RuntimeOrigin: From>, + ::RuntimeCall: + Dispatchable + GetDispatchInfo, + ::RuntimeCall: From>, + <::RuntimeCall as Dispatchable>::RuntimeOrigin: + From>, AssetBalanceOf: TryFrom + Into, BlockNumberFor: TryFrom + Into, BalanceOf: TryFrom + Into, From a19eb9172c01862845373cde77db277bacbb628d Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 19:48:33 +0800 Subject: [PATCH 168/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/mock.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs index 17bd2d7702..6c30a8aeee 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs @@ -22,7 +22,7 @@ use frame_support::{ use sp_core::{Get, H256}; use sp_runtime::{ traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, - AccountId32, BuildStorage, + AccountId32, BuildStorage, DispatchResult, }; use pallet_collab_ai_common::*; @@ -59,7 +59,7 @@ parameter_types! { pub const StandardEpoch: u32 = 10; } -impl Config for Test { +impl pallet_multisig::Config for Test { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type Currency = Balances; From e43b5fa18d7339c0e110785288195d8b92927e0e Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 20:00:44 +0800 Subject: [PATCH 169/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/mock.rs | 2 +- parachain/pallets/collab-ai/pool-proposal/src/tests.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs index 6c30a8aeee..18f6e90b9c 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs @@ -98,7 +98,7 @@ impl frame_system::Config for Test { impl pallet_assets::Config for Test { type RuntimeEvent = RuntimeEvent; type Balance = Balance; - type AssetId = u32; + type AssetId = u128; type AssetIdParameter = u32; type Currency = Balances; type CreateOrigin = AsEnsureOriginWithArg>; diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 293da14663..1b632f21f7 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -105,7 +105,7 @@ fn test_pre_stake_proposal_ok() { assert_noop!( PoolProposal::pre_stake_proposal( RuntimeOrigin::signed(user_a), - 1.into(), + 1u128, 2_000_000_000_000_000_000_000_000, ), AssetError::::BalanceLow @@ -115,7 +115,7 @@ fn test_pre_stake_proposal_ok() { assert_noop!( PoolProposal::pre_stake_proposal( RuntimeOrigin::signed(user_a), - 2.into(), + 2u128, 500_000_000_000_000_000_000u128, ), crate::Error::::ProposalNotExist From 3629ac42eb2a516a5f20ec5f07949b987de3bdbe Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 20:12:59 +0800 Subject: [PATCH 170/215] chore: fix --- parachain/pallets/collab-ai/guardian/src/lib.rs | 4 ---- parachain/pallets/collab-ai/guardian/src/mock.rs | 2 -- parachain/pallets/collab-ai/pool-proposal/src/mock.rs | 2 +- parachain/pallets/collab-ai/pool-proposal/src/tests.rs | 2 +- 4 files changed, 2 insertions(+), 8 deletions(-) diff --git a/parachain/pallets/collab-ai/guardian/src/lib.rs b/parachain/pallets/collab-ai/guardian/src/lib.rs index 8d6ff7d8be..7bf8c860de 100644 --- a/parachain/pallets/collab-ai/guardian/src/lib.rs +++ b/parachain/pallets/collab-ai/guardian/src/lib.rs @@ -70,10 +70,6 @@ pub mod pallet { #[pallet::constant] type MinimumGuardianDeposit: Get>; - /// The maximum amount of guardian allowed for a proposal - #[pallet::constant] - type MaxProposalPerGuardian: Get; - /// Origin from guardian legal file verified by type GuardianJudgeOrigin: EnsureOrigin; } diff --git a/parachain/pallets/collab-ai/guardian/src/mock.rs b/parachain/pallets/collab-ai/guardian/src/mock.rs index 4299b2bc9d..aba4e9bbff 100644 --- a/parachain/pallets/collab-ai/guardian/src/mock.rs +++ b/parachain/pallets/collab-ai/guardian/src/mock.rs @@ -44,7 +44,6 @@ construct_runtime!( parameter_types! { pub const BlockHashCount: u64 = 250; pub const MinimumGuardianDeposit: Balance = 10; - pub const MaxProposalPerGuardian: u32 = 10; } // Implement frame_system config trait for mock runtime. @@ -98,7 +97,6 @@ impl pallet_guardian::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type MinimumGuardianDeposit = MinimumGuardianDeposit; - type MaxProposalPerGuardian = MaxProposalPerGuardian; type GuardianJudgeOrigin = frame_system::EnsureRoot; } diff --git a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs index 18f6e90b9c..f323bacc32 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs @@ -99,7 +99,7 @@ impl pallet_assets::Config for Test { type RuntimeEvent = RuntimeEvent; type Balance = Balance; type AssetId = u128; - type AssetIdParameter = u32; + type AssetIdParameter = u128; type Currency = Balances; type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = frame_system::EnsureRoot; diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 1b632f21f7..71c8e515d7 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -104,7 +104,7 @@ fn test_pre_stake_proposal_ok() { // Not enough token assert_noop!( PoolProposal::pre_stake_proposal( - RuntimeOrigin::signed(user_a), + RuntimeOrigin::signed(user_a.clone()), 1u128, 2_000_000_000_000_000_000_000_000, ), From a1dfc8bde9751382cda316d48089733c1a7b0d94 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 20:28:29 +0800 Subject: [PATCH 171/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 2 +- parachain/precompiles/collab-ai/guardian/src/mock.rs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index dd2fad8522..dc70768725 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -938,7 +938,7 @@ pub mod pallet { } if best_guardians.len() > split_index { - best_guardians.split_off(split_index); + let _ = best_guardians.split_off(split_index); } // If existing one guardian diff --git a/parachain/precompiles/collab-ai/guardian/src/mock.rs b/parachain/precompiles/collab-ai/guardian/src/mock.rs index 390092b1da..8ba5ee44b9 100644 --- a/parachain/precompiles/collab-ai/guardian/src/mock.rs +++ b/parachain/precompiles/collab-ai/guardian/src/mock.rs @@ -44,7 +44,6 @@ construct_runtime!( parameter_types! { pub const BlockHashCount: u64 = 250; pub const MinimumGuardianDeposit: Balance = 10; - pub const MaxProposalPerGuardian: u32 = 10; } impl frame_system::Config for Test { @@ -94,7 +93,6 @@ impl pallet_guardian::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type MinimumGuardianDeposit = MinimumGuardianDeposit; - type MaxProposalPerGuardian = MaxProposalPerGuardian; type GuardianJudgeOrigin = frame_system::EnsureRoot; } From 7bd7f4a0608882fea0cbb90f068fad02e301bf2f Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 20:44:35 +0800 Subject: [PATCH 172/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/mock.rs | 4 ++-- parachain/pallets/collab-ai/pool-proposal/src/tests.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs index f323bacc32..af0b6592f1 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs @@ -173,10 +173,10 @@ impl GuardianQuery for MockGuardianQuery { } pub struct MockInvestmentInjector; -impl InvestmentInjector for MockInvestmentInjector { +impl InvestmentInjector for MockInvestmentInjector { fn create_investing_pool( _pool_id: InvestingPoolIndex, - _setting: PoolSetting, + _setting: PoolSetting, _admin: AccountId, ) -> DispatchResult { Ok(()) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 71c8e515d7..f717ceb015 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -17,7 +17,7 @@ fn test_propose_investing_pool_ok() { let pool_last_time = 10000; let estimated_pool_reward = 2_000_000_000_000_000_000_000u128; let pool_info_hash: H256 = H256([2; 32]); - let pool_info_hash_2: H256 = H256([3; 32]); + let _pool_info_hash_2: H256 = H256([3; 32]); // ProposalPublicTimeTooShort assert_noop!( From ed1567229e4c054e3543accd3411a813e2f27662 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 20:53:25 +0800 Subject: [PATCH 173/215] feat: update into paseo --- parachain/Cargo.lock | 10 ++ .../collab-ai/pool-proposal/src/tests.rs | 4 +- parachain/runtime/paseo/Cargo.toml | 34 +++++++ parachain/runtime/paseo/src/lib.rs | 93 ++++++++++++++++++- parachain/runtime/paseo/src/precompiles.rs | 30 ++++++ 5 files changed, 168 insertions(+), 3 deletions(-) diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index 993a71428e..dbe613bfe0 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -8745,6 +8745,7 @@ dependencies = [ "orml-traits", "orml-xtokens", "pallet-account-fix", + "pallet-aiusd-convertor", "pallet-asset-manager", "pallet-assets", "pallet-assets-handler", @@ -8755,32 +8756,41 @@ dependencies = [ "pallet-bounties", "pallet-bridge-transfer", "pallet-chain-bridge", + "pallet-collab-ai-common", "pallet-collective", + "pallet-curator", "pallet-democracy", "pallet-ethereum", "pallet-evm", "pallet-evm-assertions", + "pallet-evm-precompile-aiusd-convertor", "pallet-evm-precompile-assets-erc20", "pallet-evm-precompile-blake2", "pallet-evm-precompile-bn128", "pallet-evm-precompile-bridge-transfer", + "pallet-evm-precompile-curator", "pallet-evm-precompile-dispatch", "pallet-evm-precompile-ed25519", + "pallet-evm-precompile-guardian", "pallet-evm-precompile-modexp", "pallet-evm-precompile-parachain-staking", + "pallet-evm-precompile-pool-proposal", "pallet-evm-precompile-score-staking", "pallet-evm-precompile-sha3fips", "pallet-evm-precompile-simple", "pallet-extrinsic-filter", "pallet-group", + "pallet-guardian", "pallet-identity", "pallet-identity-management", + "pallet-investing-pool", "pallet-membership", "pallet-message-queue", "pallet-multisig", "pallet-omni-account", "pallet-omni-account-runtime-api", "pallet-parachain-staking", + "pallet-pool-proposal", "pallet-preimage", "pallet-proxy", "pallet-scheduler", diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index f717ceb015..2922bc761e 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -17,7 +17,7 @@ fn test_propose_investing_pool_ok() { let pool_last_time = 10000; let estimated_pool_reward = 2_000_000_000_000_000_000_000u128; let pool_info_hash: H256 = H256([2; 32]); - let _pool_info_hash_2: H256 = H256([3; 32]); + let pool_info_hash_2: H256 = H256([3; 32]); // ProposalPublicTimeTooShort assert_noop!( @@ -89,7 +89,7 @@ fn test_pre_stake_proposal_ok() { let pool_last_time = 10000; let estimated_pool_reward = 2_000_000_000_000_000_000_000u128; let pool_info_hash: H256 = H256([2; 32]); - let pool_info_hash_2: H256 = H256([3; 32]); + let _pool_info_hash_2: H256 = H256([3; 32]); // Worked assert_ok!(PoolProposal::propose_investing_pool( diff --git a/parachain/runtime/paseo/Cargo.toml b/parachain/runtime/paseo/Cargo.toml index 774ade6e48..0655c85b2d 100644 --- a/parachain/runtime/paseo/Cargo.toml +++ b/parachain/runtime/paseo/Cargo.toml @@ -95,6 +95,13 @@ pallet-teebag = { workspace = true } pallet-vc-management = { workspace = true } runtime-common = { workspace = true } +pallet-aiusd-convertor = { workspace = true } +pallet-collab-ai-common = { workspace = true } +pallet-curator = { workspace = true } +pallet-guardian = { workspace = true } +pallet-pool-proposal = { workspace = true } +pallet-investing-pool = { workspace = true } + fp-evm = { workspace = true } fp-rpc = { workspace = true } fp-self-contained = { workspace = true, features = ["serde"] } @@ -113,6 +120,11 @@ pallet-evm-precompile-bridge-transfer = { workspace = true } pallet-evm-precompile-parachain-staking = { workspace = true } pallet-evm-precompile-score-staking = { workspace = true } +pallet-evm-precompile-aiusd-convertor = { workspace = true } +pallet-evm-precompile-curator = { workspace = true } +pallet-evm-precompile-guardian = { workspace = true } +pallet-evm-precompile-pool-proposal = { workspace = true } + moonbeam-evm-tracer = { workspace = true } moonbeam-rpc-primitives-debug = { workspace = true } moonbeam-rpc-primitives-txpool = { workspace = true } @@ -175,6 +187,12 @@ runtime-benchmarks = [ "pallet-account-fix/runtime-benchmarks", "pallet-score-staking/runtime-benchmarks", "pallet-omni-account/runtime-benchmarks", + "pallet-aiusd-convertor/runtime-benchmarks", + "pallet-collab-ai-common/runtime-benchmarks", + "pallet-curator/runtime-benchmarks", + "pallet-guardian/runtime-benchmarks", + "pallet-pool-proposal/runtime-benchmarks", + "pallet-investing-pool/runtime-benchmarks", ] std = [ "parity-scale-codec/std", @@ -222,6 +240,10 @@ std = [ "pallet-evm-precompile-bridge-transfer/std", "pallet-evm-precompile-parachain-staking/std", "pallet-evm-precompile-score-staking/std", + "pallet-evm-precompile-aiusd-convertor/std", + "pallet-evm-precompile-curator/std", + "pallet-evm-precompile-guardian/std", + "pallet-evm-precompile-pool-proposal/std", "pallet-identity/std", "pallet-membership/std", "pallet-message-queue/std", @@ -278,6 +300,12 @@ std = [ "moonbeam-rpc-primitives-txpool/std", "pallet-bitacross/std", "precompile-utils/std", + "pallet-aiusd-convertor/std", + "pallet-collab-ai-common/std", + "pallet-curator/std", + "pallet-guardian/std", + "pallet-pool-proposal/std", + "pallet-investing-pool/std", ] try-runtime = [ "cumulus-pallet-aura-ext/try-runtime", @@ -332,4 +360,10 @@ try-runtime = [ "pallet-xcm/try-runtime", "parachain-info/try-runtime", "pallet-omni-account/try-runtime", + "pallet-aiusd-convertor/try-runtime", + "pallet-collab-ai-common/try-runtime", + "pallet-curator/try-runtime", + "pallet-guardian/try-runtime", + "pallet-pool-proposal/try-runtime", + "pallet-investing-pool/try-runtime", ] diff --git a/parachain/runtime/paseo/src/lib.rs b/parachain/runtime/paseo/src/lib.rs index b2b7e740e1..69c2e8f7ab 100644 --- a/parachain/runtime/paseo/src/lib.rs +++ b/parachain/runtime/paseo/src/lib.rs @@ -1037,6 +1037,84 @@ impl pallet_group::Config for Runtime { type GroupManagerOrigin = EnsureRootOrAllCouncil; } +parameter_types! { + pub const MinimumCuratorDeposit: Balance = 100 * DOLLARS; + pub const MinimumGuardianDeposit: Balance = 20 * DOLLARS; + // Declare the official AIUSDAssetId + pub const AIUSDAssetId: u128 = 1000; + pub const OfficialGapPeriod: BlockNumber = prod_or_fast!(7 * DAYS, 10 * MINUTES, "ROCOCO_OFFICIALGAPPERIOD"); + pub const MinimumProposalLastTime: BlockNumber = prod_or_fast!(30 * DAYS, 10 * MINUTES, "ROCOCO_MINIMUMPROPOSALLASTTIME"); + pub const MinimumPoolDeposit: Balance = 1000 * DOLLARS; + pub const MaximumPoolProposed: u128 = 10000; + pub const StandardEpoch: BlockNumber = prod_or_fast!(30 * DAYS, 10 * MINUTES, "ROCOCO_STANDARDEPOCH"); + pub const MaxGuardianPerProposal: u32 = 1000; + pub const MaxGuardianSelectedPerProposal: u32 = 3; + + pub const PoolProposalPalletId: PalletId = PalletId(*b"cbai/ipp"); + pub PreInvestingPool: AccountId = PoolProposalPalletId::get().into_account_truncating(); +} + +impl pallet_curator::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type MinimumCuratorDeposit = MinimumCuratorDeposit; + type CuratorJudgeOrigin = EnsureRootOrHalfCouncil; +} + +impl pallet_guardian::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type MinimumGuardianDeposit = MinimumGuardianDeposit; + type GuardianJudgeOrigin = + pallet_collective::EnsureMember; +} + +impl pallet_pool_proposal::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type Fungibles = Assets; + type AIUSDAssetId = AIUSDAssetId; + type OfficialGapPeriod = OfficialGapPeriod; + type MinimumProposalLastTime = MinimumProposalLastTime; + type MinimumPoolDeposit = MinimumPoolDeposit; + type MaximumPoolProposed = MaximumPoolProposed; + type StandardEpoch = StandardEpoch; + type ProposalOrigin = Curator; + type PublicVotingOrigin = EnsureRootOrAllCouncil; + type GuardianVoteResource = Guardian; + type MaxGuardianPerProposal = MaxGuardianPerProposal; + type MaxGuardianSelectedPerProposal = MaxGuardianSelectedPerProposal; + type PreInvestingPool = PreInvestingPool; + type InvestmentInjector = InvestingPool; +} + +parameter_types! { + StableTokenBeneficiaryId: PalletId = PalletId(*b"cbai/sid"); + CANBenefiicaryId: PalletId = PalletId(*b"cbai/nid"); +} + +impl pallet_investing_pool::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type PoolProposalPalletOrigin = EnsureRoot; + type RewardUpdateOrigin = EnsureRootOrAllCouncil; + type InvestingPoolAdminOrigin = EnsureRoot; + type Fungibles: Assets; + type StableTokenBeneficiaryId: StableTokenBeneficiaryId; + type CANBenefiicaryId: CANBenefiicaryId; +} + +parameter_types! { + pub const AIUSDConvertorPalletId: PalletId = PalletId(*b"cbai/scv"); + pub ConvertingPool: AccountId = AIUSDConvertorPalletId::get().into_account_truncating(); +} + +impl pallet_aiusd_convertor::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ConvertingPool = ConvertingPool; + type AIUSDAssetId = AIUSDAssetId; + type ManagerOrigin = EnsureRoot; +} + // For OnChargeEVMTransaction implementation type CurrencyAccountId = ::AccountId; type BalanceFor = @@ -1274,6 +1352,13 @@ construct_runtime! { EVM: pallet_evm = 120, Ethereum: pallet_ethereum = 121, + // CollabAI + Curator: pallet_curator = 150, + Guardian: pallet_guardian = 151, + PoolProposal: pallet_pool_proposal = 152, + InvestingPool: pallet_investing_pool = 153, + AIUSDConvertor: pallet_aiusd_convertor = 154, + // TMP AccountFix: pallet_account_fix = 254, Sudo: pallet_sudo = 255, @@ -1374,7 +1459,13 @@ impl Contains for NormalModeFilter { RuntimeCall::Bitacross(_) | RuntimeCall::EvmAssertions(_) | RuntimeCall::ScoreStaking(_) | - RuntimeCall::OmniAccount(_) + RuntimeCall::OmniAccount(_) | + // CollabAI + RuntimeCall::Curator(_) | + RuntimeCall::Guardian(_) | + RuntimeCall::PoolProposal(_) | + RuntimeCall::InvestingPool(_) | + RuntimeCall::AIUSDConvertor(_) ) } } diff --git a/parachain/runtime/paseo/src/precompiles.rs b/parachain/runtime/paseo/src/precompiles.rs index ac873e8003..6a1815f5d1 100644 --- a/parachain/runtime/paseo/src/precompiles.rs +++ b/parachain/runtime/paseo/src/precompiles.rs @@ -37,6 +37,12 @@ use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripe use precompile_utils::precompile_set::*; use sp_std::fmt::Debug; +// CollabAI +use pallet_evm_precompile_aiusd_convertor::AIUSDConvertorPrecompile; +use pallet_evm_precompile_curator::CuratorPrecompile; +use pallet_evm_precompile_guardian::GuardianPrecompile; +use pallet_evm_precompile_pool_proposal::PoolProposalPrecompile; + /// The asset precompile address prefix. Addresses that match against this prefix will be routed /// to Erc20AssetsPrecompileSet pub const ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8; 4]; @@ -135,6 +141,30 @@ pub type PrecompilesSetAt = ( ScoreStakingPrecompile, (CallableByContract, CallableByPrecompile), >, + // Curator: pallet_curator = 150 + 20480 + PrecompileAt< + AddressU64<20630>, + CuratorPrecompile, + (CallableByContract, CallableByPrecompile), + >, + // Guardian: pallet_guardian = 151 + 20480 + PrecompileAt< + AddressU64<20631>, + GuardianPrecompile, + (CallableByContract, CallableByPrecompile), + >, + // PoolProposal: pallet_pool_proposal = 152 + 20480 + PrecompileAt< + AddressU64<20632>, + PoolProposalPrecompile, + (CallableByContract, CallableByPrecompile), + >, + // AIUSDConvertor: pallet_aiusd_convertor = 154 + 20480 + PrecompileAt< + AddressU64<20634>, + AIUSDConvertorPrecompile, + (CallableByContract, CallableByPrecompile), + >, ); pub type RococoNetworkPrecompiles = PrecompileSetBuilder< From 51c0bf80a7e81aef03bae3a8ced45fb6c0b4dec5 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 20:59:36 +0800 Subject: [PATCH 174/215] chore: fix --- parachain/runtime/paseo/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/runtime/paseo/Cargo.toml b/parachain/runtime/paseo/Cargo.toml index 0655c85b2d..c47e3fb2fc 100644 --- a/parachain/runtime/paseo/Cargo.toml +++ b/parachain/runtime/paseo/Cargo.toml @@ -99,8 +99,8 @@ pallet-aiusd-convertor = { workspace = true } pallet-collab-ai-common = { workspace = true } pallet-curator = { workspace = true } pallet-guardian = { workspace = true } -pallet-pool-proposal = { workspace = true } pallet-investing-pool = { workspace = true } +pallet-pool-proposal = { workspace = true } fp-evm = { workspace = true } fp-rpc = { workspace = true } From 9b522ff6ff476653c6b0f741506ce095e5cd6395 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 21:19:14 +0800 Subject: [PATCH 175/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 2922bc761e..e2e73efbec 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -3,7 +3,7 @@ use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; use pallet_assets::Error as AssetError; use pallet_balances::Error as BalanceError; use sp_core::H256; -use sp_runtime::AccountId32; +use sp_runtime::{AccountId32, ArithmeticError}; #[test] fn test_propose_investing_pool_ok() { @@ -108,7 +108,7 @@ fn test_pre_stake_proposal_ok() { 1u128, 2_000_000_000_000_000_000_000_000, ), - AssetError::::BalanceLow + ArithmeticError::Underflow ); // Pool not exist From 4e9caee1ba14d3f296d085b63560100907519942 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 21:42:59 +0800 Subject: [PATCH 176/215] chore: fix clippy --- .../collab-ai/pool-proposal/src/lib.rs | 329 +++++++++--------- 1 file changed, 155 insertions(+), 174 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index dc70768725..bb33cd8a80 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -664,115 +664,106 @@ pub mod pallet { #[transactional] pub fn bake_proposal(_origin: OriginFor) -> DispatchResult { let mut pending = >::take(); - loop { - match pending.pop_front() { - Some(x) => { - if let Some(pool_proposal) = >::get(x.0) { - // Creating investing pool - let start_time_u128: u128 = pool_proposal - .pool_start_time - .try_into() - .or(Err(ArithmeticError::Overflow))?; - let end_time_u128: u128 = pool_proposal - .pool_end_time - .try_into() - .or(Err(ArithmeticError::Overflow))?; - let epoch_range_u128: u128 = T::StandardEpoch::get() - .try_into() - .or(Err(ArithmeticError::Overflow))?; - - let vec_inner = x.1.into_inner(); - let signatories: &[T::AccountId] = vec_inner.as_slice(); - let guardian_multisig = pallet_multisig::Pallet::::multi_account_id( - signatories, - signatories.len().try_into().or(Err(ArithmeticError::Overflow))?, - ); - - let total_epoch: u128 = - ((end_time_u128 - start_time_u128) / epoch_range_u128) + 1; - let pool_setting: PoolSetting< - T::AccountId, - BlockNumberFor, - AssetBalanceOf, - > = PoolSetting { - start_time: pool_proposal.pool_start_time, - epoch: total_epoch, - epoch_range: T::StandardEpoch::get(), - pool_cap: pool_proposal.max_pool_size, - // Curator - admin: pool_proposal.proposer.clone(), - }; - - T::InvestmentInjector::create_investing_pool( - x.0, - pool_setting, - guardian_multisig, - )?; - // Prepare Money related material - let mut pre_investments: Vec<(T::AccountId, AssetBalanceOf)> = - Default::default(); - let mut queued_investments: Vec<(T::AccountId, AssetBalanceOf)> = - Default::default(); - - let mut total_investment_amount: AssetBalanceOf = Default::default(); - - // ignored if return none, but technically it is impossible - if let Some(pool_bonds) = >::get(x.0) { - pre_investments = pool_bonds - .pre_investings - .into_iter() - .map(|b| (b.owner, b.amount)) - .collect(); - queued_investments = pool_bonds - .queued_pre_investings - .into_iter() - .map(|b| (b.0.owner, b.0.amount)) - .collect(); - total_investment_amount = pool_bonds.total_pre_investing_amount; - } + while let Some(x) = pending.pop_front() { + if let Some(pool_proposal) = >::get(x.0) { + // Creating investing pool + let start_time_u128: u128 = pool_proposal + .pool_start_time + .try_into() + .or(Err(ArithmeticError::Overflow))?; + let end_time_u128: u128 = pool_proposal + .pool_end_time + .try_into() + .or(Err(ArithmeticError::Overflow))?; + let epoch_range_u128: u128 = + T::StandardEpoch::get().try_into().or(Err(ArithmeticError::Overflow))?; + + let vec_inner = x.1.into_inner(); + let signatories: &[T::AccountId] = vec_inner.as_slice(); + let guardian_multisig = pallet_multisig::Pallet::::multi_account_id( + signatories, + signatories.len().try_into().or(Err(ArithmeticError::Overflow))?, + ); + + let total_epoch: u128 = + ((end_time_u128 - start_time_u128) / epoch_range_u128) + 1; + let pool_setting: PoolSetting< + T::AccountId, + BlockNumberFor, + AssetBalanceOf, + > = PoolSetting { + start_time: pool_proposal.pool_start_time, + epoch: total_epoch, + epoch_range: T::StandardEpoch::get(), + pool_cap: pool_proposal.max_pool_size, + // Curator + admin: pool_proposal.proposer.clone(), + }; + + T::InvestmentInjector::create_investing_pool( + x.0, + pool_setting, + guardian_multisig, + )?; + + // Prepare Money related material + let mut pre_investments: Vec<(T::AccountId, AssetBalanceOf)> = + Default::default(); + let mut queued_investments: Vec<(T::AccountId, AssetBalanceOf)> = + Default::default(); + + let mut total_investment_amount: AssetBalanceOf = Default::default(); + + // ignored if return none, but technically it is impossible + if let Some(pool_bonds) = >::get(x.0) { + pre_investments = pool_bonds + .pre_investings + .into_iter() + .map(|b| (b.owner, b.amount)) + .collect(); + queued_investments = pool_bonds + .queued_pre_investings + .into_iter() + .map(|b| (b.0.owner, b.0.amount)) + .collect(); + total_investment_amount = pool_bonds.total_pre_investing_amount; + } - // Inject investment - T::InvestmentInjector::inject_investment(x.0, pre_investments)?; - - // Do refund - // Return Queued queued_investments always - for investor in queued_investments.iter() { - let asset_refund_amount: AssetBalanceOf = - T::Fungibles::transfer( - T::AIUSDAssetId::get(), - &T::PreInvestingPool::get(), - &investor.0, - investor.1, - Preservation::Expendable, - )?; - Self::deposit_event(Event::::PoolWithdrawed { - user: investor.0.clone(), - pool_proposal_index: x.0, - amount: asset_refund_amount, - }); - } + // Inject investment + T::InvestmentInjector::inject_investment(x.0, pre_investments)?; + + // Do refund + // Return Queued queued_investments always + for investor in queued_investments.iter() { + let asset_refund_amount: AssetBalanceOf = T::Fungibles::transfer( + T::AIUSDAssetId::get(), + &T::PreInvestingPool::get(), + &investor.0, + investor.1, + Preservation::Expendable, + )?; + Self::deposit_event(Event::::PoolWithdrawed { + user: investor.0.clone(), + pool_proposal_index: x.0, + amount: asset_refund_amount, + }); + } - // Transfer official investment money to curator - let proposal_settlement: AssetBalanceOf = T::Fungibles::transfer( - T::AIUSDAssetId::get(), - &T::PreInvestingPool::get(), - &pool_proposal.proposer, - total_investment_amount, - Preservation::Expendable, - )?; - - Self::deposit_event(Event::::ProposalBaked { - pool_proposal_index: x.0, - curator: pool_proposal.proposer, - proposal_settlement, - }); - } - }, - // Nothing to bake - _ => { - break; - }, + // Transfer official investment money to curator + let proposal_settlement: AssetBalanceOf = T::Fungibles::transfer( + T::AIUSDAssetId::get(), + &T::PreInvestingPool::get(), + &pool_proposal.proposer, + total_investment_amount, + Preservation::Expendable, + )?; + + Self::deposit_event(Event::::ProposalBaked { + pool_proposal_index: x.0, + curator: pool_proposal.proposer, + proposal_settlement, + }); } } >::put(pending); @@ -785,71 +776,63 @@ pub mod pallet { #[transactional] pub fn dissolve_proposal(_origin: OriginFor) -> DispatchResult { let mut pending = >::take(); - loop { - match pending.pop_front() { - Some(x) => { - // Prepare Money related material - let mut pre_investments: Vec<(T::AccountId, AssetBalanceOf)> = - Default::default(); - let mut queued_investments: Vec<(T::AccountId, AssetBalanceOf)> = - Default::default(); - - // ignored if return none, but technically it is impossible - if let Some(pool_bonds) = >::get(x) { - pre_investments = pool_bonds - .pre_investings - .into_iter() - .map(|b| (b.owner, b.amount)) - .collect(); - queued_investments = pool_bonds - .queued_pre_investings - .into_iter() - .map(|b| (b.0.owner, b.0.amount)) - .collect(); - } - // Do Refund - // Return bonding - for investor in pre_investments.iter() { - let asset_refund_amount: AssetBalanceOf = T::Fungibles::transfer( - T::AIUSDAssetId::get(), - &T::PreInvestingPool::get(), - &investor.0, - investor.1, - Preservation::Expendable, - )?; - Self::deposit_event(Event::::PoolWithdrawed { - user: investor.clone().0, - pool_proposal_index: x, - amount: asset_refund_amount, - }); - } - // Return Queued queued_investments always - for investor in queued_investments.iter() { - let asset_refund_amount: AssetBalanceOf = T::Fungibles::transfer( - T::AIUSDAssetId::get(), - &T::PreInvestingPool::get(), - &investor.0, - investor.1, - Preservation::Expendable, - )?; - Self::deposit_event(Event::::PoolWithdrawed { - user: investor.clone().0, - pool_proposal_index: x, - amount: asset_refund_amount, - }); - } + while let Some(x) = pending.pop_front() { + // Prepare Money related material + let mut pre_investments: Vec<(T::AccountId, AssetBalanceOf)> = + Default::default(); + let mut queued_investments: Vec<(T::AccountId, AssetBalanceOf)> = + Default::default(); + + // ignored if return none, but technically it is impossible + if let Some(pool_bonds) = >::get(x) { + pre_investments = pool_bonds + .pre_investings + .into_iter() + .map(|b| (b.owner, b.amount)) + .collect(); + queued_investments = pool_bonds + .queued_pre_investings + .into_iter() + .map(|b| (b.0.owner, b.0.amount)) + .collect(); + } + // Do Refund + // Return bonding + for investor in pre_investments.iter() { + let asset_refund_amount: AssetBalanceOf = T::Fungibles::transfer( + T::AIUSDAssetId::get(), + &T::PreInvestingPool::get(), + &investor.0, + investor.1, + Preservation::Expendable, + )?; + Self::deposit_event(Event::::PoolWithdrawed { + user: investor.clone().0, + pool_proposal_index: x, + amount: asset_refund_amount, + }); + } - Self::deposit_event(Event::::ProposalDissolved { - pool_proposal_index: x, - }); - }, - // Nothing to dissolve - _ => { - break; - }, + // Return Queued queued_investments always + for investor in queued_investments.iter() { + let asset_refund_amount: AssetBalanceOf = T::Fungibles::transfer( + T::AIUSDAssetId::get(), + &T::PreInvestingPool::get(), + &investor.0, + investor.1, + Preservation::Expendable, + )?; + Self::deposit_event(Event::::PoolWithdrawed { + user: investor.clone().0, + pool_proposal_index: x, + amount: asset_refund_amount, + }); } + + Self::deposit_event(Event::::ProposalDissolved { pool_proposal_index: x }); } + >::put(pending); Ok(()) } @@ -928,21 +911,19 @@ pub mod pallet { // temp sorted by Aye from largestsmallest to smallest best_guardians.sort_by(|a, b| b.1.cmp(&a.1)); - let split_index: usize; - - match >::try_into( + let split_index: usize = match >::try_into( T::MaxGuardianSelectedPerProposal::get(), ) { - Ok(x) => split_index = x, - Err(_) => split_index = 0usize, - } + Ok(x) => x, + Err(_) => 0usize, + }; if best_guardians.len() > split_index { let _ = best_guardians.split_off(split_index); } // If existing one guardian - if best_guardians.len() > 0 { + if !best_guardians.is_empty() { pool_proposal.proposal_status_flags |= ProposalStatusFlags::GUARDIAN_SELECTED; } else { From aebd86f648d7fa294eebe01a750b54090077cc90 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 21:58:54 +0800 Subject: [PATCH 177/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index bb33cd8a80..451a8b1733 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -911,12 +911,10 @@ pub mod pallet { // temp sorted by Aye from largestsmallest to smallest best_guardians.sort_by(|a, b| b.1.cmp(&a.1)); - let split_index: usize = match >::try_into( + let split_index: usize = >::try_into( T::MaxGuardianSelectedPerProposal::get(), - ) { - Ok(x) => x, - Err(_) => 0usize, - }; + ) + .unwrap_or(0usize); if best_guardians.len() > split_index { let _ = best_guardians.split_off(split_index); From ec4f1016c6c171ffa266e456d6fd60234ab1773c Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 22:14:52 +0800 Subject: [PATCH 178/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/tests.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index e2e73efbec..9bd65592af 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -1,6 +1,5 @@ use crate::mock::*; use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; -use pallet_assets::Error as AssetError; use pallet_balances::Error as BalanceError; use sp_core::H256; use sp_runtime::{AccountId32, ArithmeticError}; From 37997dcfebd4cf8ba74d6eaa628f72fc3074971d Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 22:43:13 +0800 Subject: [PATCH 179/215] chore: fix --- parachain/runtime/paseo/src/lib.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/parachain/runtime/paseo/src/lib.rs b/parachain/runtime/paseo/src/lib.rs index 69c2e8f7ab..ee7503bc45 100644 --- a/parachain/runtime/paseo/src/lib.rs +++ b/parachain/runtime/paseo/src/lib.rs @@ -44,6 +44,9 @@ use runtime_common::EnsureEnclaveSigner; // for TEE pub use pallet_balances::Call as BalancesCall; +// for CollabAI +use pallet_collab_ai_common::EnsureSignedAndVerifiedCurator; + use sp_api::impl_runtime_apis; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{crypto::KeyTypeId, OpaqueMetadata, RuntimeDebug, H160, H256, U256}; @@ -1042,11 +1045,11 @@ parameter_types! { pub const MinimumGuardianDeposit: Balance = 20 * DOLLARS; // Declare the official AIUSDAssetId pub const AIUSDAssetId: u128 = 1000; - pub const OfficialGapPeriod: BlockNumber = prod_or_fast!(7 * DAYS, 10 * MINUTES, "ROCOCO_OFFICIALGAPPERIOD"); - pub const MinimumProposalLastTime: BlockNumber = prod_or_fast!(30 * DAYS, 10 * MINUTES, "ROCOCO_MINIMUMPROPOSALLASTTIME"); + pub OfficialGapPeriod: BlockNumber = prod_or_fast!(7 * DAYS, 10 * MINUTES, "ROCOCO_OFFICIALGAPPERIOD"); + pub MinimumProposalLastTime: BlockNumber = prod_or_fast!(30 * DAYS, 10 * MINUTES, "ROCOCO_MINIMUMPROPOSALLASTTIME"); pub const MinimumPoolDeposit: Balance = 1000 * DOLLARS; pub const MaximumPoolProposed: u128 = 10000; - pub const StandardEpoch: BlockNumber = prod_or_fast!(30 * DAYS, 10 * MINUTES, "ROCOCO_STANDARDEPOCH"); + pub StandardEpoch: BlockNumber = prod_or_fast!(30 * DAYS, 10 * MINUTES, "ROCOCO_STANDARDEPOCH"); pub const MaxGuardianPerProposal: u32 = 1000; pub const MaxGuardianSelectedPerProposal: u32 = 3; @@ -1079,7 +1082,7 @@ impl pallet_pool_proposal::Config for Runtime { type MinimumPoolDeposit = MinimumPoolDeposit; type MaximumPoolProposed = MaximumPoolProposed; type StandardEpoch = StandardEpoch; - type ProposalOrigin = Curator; + type ProposalOrigin = EnsureSignedAndVerifiedCurator; type PublicVotingOrigin = EnsureRootOrAllCouncil; type GuardianVoteResource = Guardian; type MaxGuardianPerProposal = MaxGuardianPerProposal; @@ -1098,9 +1101,9 @@ impl pallet_investing_pool::Config for Runtime { type PoolProposalPalletOrigin = EnsureRoot; type RewardUpdateOrigin = EnsureRootOrAllCouncil; type InvestingPoolAdminOrigin = EnsureRoot; - type Fungibles: Assets; - type StableTokenBeneficiaryId: StableTokenBeneficiaryId; - type CANBenefiicaryId: CANBenefiicaryId; + type Fungibles = Assets; + type StableTokenBeneficiaryId = StableTokenBeneficiaryId; + type CANBenefiicaryId = CANBenefiicaryId; } parameter_types! { From 39f54b94317b14e407c0814ff898be289505de9f Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 23:08:35 +0800 Subject: [PATCH 180/215] chore: fix --- parachain/runtime/paseo/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parachain/runtime/paseo/src/lib.rs b/parachain/runtime/paseo/src/lib.rs index ee7503bc45..f0b5b232c2 100644 --- a/parachain/runtime/paseo/src/lib.rs +++ b/parachain/runtime/paseo/src/lib.rs @@ -1048,7 +1048,7 @@ parameter_types! { pub OfficialGapPeriod: BlockNumber = prod_or_fast!(7 * DAYS, 10 * MINUTES, "ROCOCO_OFFICIALGAPPERIOD"); pub MinimumProposalLastTime: BlockNumber = prod_or_fast!(30 * DAYS, 10 * MINUTES, "ROCOCO_MINIMUMPROPOSALLASTTIME"); pub const MinimumPoolDeposit: Balance = 1000 * DOLLARS; - pub const MaximumPoolProposed: u128 = 10000; + pub const MaximumPoolProposed: u32 = 10000; pub StandardEpoch: BlockNumber = prod_or_fast!(30 * DAYS, 10 * MINUTES, "ROCOCO_STANDARDEPOCH"); pub const MaxGuardianPerProposal: u32 = 1000; pub const MaxGuardianSelectedPerProposal: u32 = 3; @@ -1093,7 +1093,7 @@ impl pallet_pool_proposal::Config for Runtime { parameter_types! { StableTokenBeneficiaryId: PalletId = PalletId(*b"cbai/sid"); - CANBenefiicaryId: PalletId = PalletId(*b"cbai/nid"); + CANBeneficiaryId: PalletId = PalletId(*b"cbai/nid"); } impl pallet_investing_pool::Config for Runtime { @@ -1103,7 +1103,7 @@ impl pallet_investing_pool::Config for Runtime { type InvestingPoolAdminOrigin = EnsureRoot; type Fungibles = Assets; type StableTokenBeneficiaryId = StableTokenBeneficiaryId; - type CANBenefiicaryId = CANBenefiicaryId; + type CANBeneficiaryId = CANBeneficiaryId; } parameter_types! { From 3748ab3bc593241a9d452a45481ca2217d3ff222 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 23:11:04 +0800 Subject: [PATCH 181/215] chore: fix --- parachain/runtime/paseo/src/precompiles.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/runtime/paseo/src/precompiles.rs b/parachain/runtime/paseo/src/precompiles.rs index 6a1815f5d1..fee345a6ce 100644 --- a/parachain/runtime/paseo/src/precompiles.rs +++ b/parachain/runtime/paseo/src/precompiles.rs @@ -173,7 +173,7 @@ pub type RococoNetworkPrecompiles = PrecompileSetBuilder< // Skip precompiles if out of range. PrecompilesInRangeInclusive< // We take range as last precompile index, UPDATE this once new prcompile is added - (AddressU64<1>, AddressU64<20556>), + (AddressU64<1>, AddressU64<20635>), PrecompilesSetAt, >, // Prefixed precompile sets (XC20) From c7c31c2b3678f34db86d6dc70cf1a5cf05600a5f Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 3 Nov 2024 23:28:49 +0800 Subject: [PATCH 182/215] chore: fix --- parachain/runtime/paseo/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/runtime/paseo/src/lib.rs b/parachain/runtime/paseo/src/lib.rs index f0b5b232c2..2ab5dfa6c1 100644 --- a/parachain/runtime/paseo/src/lib.rs +++ b/parachain/runtime/paseo/src/lib.rs @@ -1092,8 +1092,8 @@ impl pallet_pool_proposal::Config for Runtime { } parameter_types! { - StableTokenBeneficiaryId: PalletId = PalletId(*b"cbai/sid"); - CANBeneficiaryId: PalletId = PalletId(*b"cbai/nid"); + pub const StableTokenBeneficiaryId: PalletId = PalletId(*b"cbai/sid"); + pub const CANBeneficiaryId: PalletId = PalletId(*b"cbai/nid"); } impl pallet_investing_pool::Config for Runtime { From dd8db69f85152cc241fdf196ad2526ddec6e306c Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 4 Nov 2024 00:12:07 +0800 Subject: [PATCH 183/215] chore: fix --- parachain/pallets/collab-ai/common/src/lib.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index d634aebb51..7383b16c84 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -15,17 +15,16 @@ // along with Litentry. If not, see . #![cfg_attr(not(feature = "std"), no_std)] -use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; -use sp_core::{RuntimeDebug, H256}; -use sp_runtime::traits::AtLeast32BitUnsigned; -use sp_std::marker::PhantomData; - use frame_support::{ pallet_prelude::{DispatchResult, EnsureOrigin}, traits::EitherOfDiverse, }; use frame_system::{EnsureRoot, RawOrigin}; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_core::{RuntimeDebug, H256}; +use sp_runtime::traits::AtLeast32BitUnsigned; +use sp_std::{marker::PhantomData, vec::Vec}; pub type InfoHash = H256; pub type CuratorIndex = u128; From 8be88b40718ab35169f3e780d6e738c26be0918b Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 4 Nov 2024 00:58:48 +0800 Subject: [PATCH 184/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 2 +- parachain/pallets/collab-ai/pool-proposal/src/types.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 451a8b1733..9f2f23a458 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -52,7 +52,7 @@ use sp_runtime::{ traits::{AccountIdConversion, CheckedAdd, CheckedSub, Zero}, ArithmeticError, }; -use sp_std::collections::vec_deque::VecDeque; +use sp_std::{collections::vec_deque::VecDeque, vec::Vec}; pub use types::*; diff --git a/parachain/pallets/collab-ai/pool-proposal/src/types.rs b/parachain/pallets/collab-ai/pool-proposal/src/types.rs index fc185517a3..171c3c9558 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/types.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/types.rs @@ -21,7 +21,7 @@ use sp_runtime::{ traits::{CheckedAdd, CheckedSub}, ArithmeticError, BoundedVec, }; -use sp_std::cmp::Ordering; +use sp_std::{cmp::Ordering, vec::Vec}; bitflags! { /// Flags used to record the status of pool proposal From 9aeacd12b0954ea4a2dc174c71715228c57b97f0 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 4 Nov 2024 01:36:31 +0800 Subject: [PATCH 185/215] chore: fix --- parachain/precompiles/collab-ai/curator/src/lib.rs | 2 +- parachain/precompiles/collab-ai/guardian/src/lib.rs | 2 +- parachain/precompiles/collab-ai/pool-proposal/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index 7910547691..c199843b8c 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -9,7 +9,7 @@ use precompile_utils::prelude::*; use sp_runtime::traits::Dispatchable; use sp_core::{H256, U256}; -use sp_std::marker::PhantomData; +use sp_std::{marker::PhantomData, vec::Vec}; use pallet_collab_ai_common::CandidateStatus; diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index 541ec0326a..0860a4d655 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -24,7 +24,7 @@ use precompile_utils::prelude::*; use sp_runtime::traits::Dispatchable; use sp_core::{H256, U256}; -use sp_std::marker::PhantomData; +use sp_std::{marker::PhantomData, vec::Vec}; use pallet_collab_ai_common::{CandidateStatus, GuardianVote}; diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index 6ebd61c242..a0aa5a116c 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -15,7 +15,7 @@ use precompile_utils::prelude::*; use sp_runtime::traits::Dispatchable; use sp_core::{Get, H256, U256}; -use sp_std::marker::PhantomData; +use sp_std::{marker::PhantomData, vec::Vec}; use pallet_collab_ai_common::PoolProposalIndex; From 66f40ee536ab024084de64b59b963a84d3af655b Mon Sep 17 00:00:00 2001 From: Kailai Wang Date: Mon, 4 Nov 2024 00:26:41 +0000 Subject: [PATCH 186/215] bump paseo versions --- parachain/runtime/paseo/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/runtime/paseo/src/lib.rs b/parachain/runtime/paseo/src/lib.rs index 2ab5dfa6c1..faa67a9276 100644 --- a/parachain/runtime/paseo/src/lib.rs +++ b/parachain/runtime/paseo/src/lib.rs @@ -230,7 +230,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_name: create_runtime_str!("paseo-parachain"), authoring_version: 1, // same versioning-mechanism as polkadot: use last digit for minor updates - spec_version: 9202, + spec_version: 9203, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 2292cf313e1250bdfce37d3d0ce3822d6d13da77 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 20 Nov 2024 16:00:03 +0800 Subject: [PATCH 187/215] feat: add pool proposal query method --- .../collab-ai/investing-pool/src/lib.rs | 3 +- .../precompiles/collab-ai/guardian/src/lib.rs | 2 +- .../collab-ai/pool-proposal/PoolProposal.sol | 30 +++- .../collab-ai/pool-proposal/src/lib.rs | 162 ++++++++++++++++-- 4 files changed, 175 insertions(+), 22 deletions(-) diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index 2b574e8c8a..4e4a0fe2ea 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -428,7 +428,8 @@ pub mod pallet { let token_end_epoch = InvestingPoolAssetIdGenerator::get_token_end_epoch(asset_id); // Technically speaking, start_epoch <= end_epoch - if token_start_epoch > claimed_until_epoch { + // If start epoch = 0, means this is a collateral token, can not claim anything + if token_start_epoch > claimed_until_epoch || token_start_epoch == 0 { // Nothing to claim return Ok(()); } diff --git a/parachain/precompiles/collab-ai/guardian/src/lib.rs b/parachain/precompiles/collab-ai/guardian/src/lib.rs index 0860a4d655..644489b713 100644 --- a/parachain/precompiles/collab-ai/guardian/src/lib.rs +++ b/parachain/precompiles/collab-ai/guardian/src/lib.rs @@ -130,7 +130,7 @@ where Ok(()) } - #[precompile::public("PublicGuardianCount()")] + #[precompile::public("publicGuardianCount()")] #[precompile::view] fn public_guardian_count(handle: &mut impl PrecompileHandle) -> EvmResult { // Storage item: GuardianIndex u128: diff --git a/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol b/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol index 43b1ad7b16..4e3c277242 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol +++ b/parachain/precompiles/collab-ai/pool-proposal/PoolProposal.sol @@ -127,14 +127,14 @@ interface IPoolProposal { function batchPoolProposal(uint256 start_id, uint256 end_id) external view returns (PoolProposalInfo[] memory proposal_info); /// @notice Batch query pool proposals and their existing included pre stakings - /// @param start_id: Proposal index start_id, included + /// @param start_id: Proposal index start_id, included /// @param end_id: Proposal index end id, excluded /// @custom:selector 0x49dc251a /// poolPreInvestings(uint256,uint256) function poolPreInvestings(uint256 start_id, uint256 end_id) external view returns (StakingBond[] memory pre_investing_bond); /// @notice Batch query pool proposals and their queued pre stakings - /// @param start_id: Proposal index start_id, included + /// @param start_id: Proposal index start_id, included /// @param end_id: Proposal index end id, excluded /// @custom:selector 0x201be573 /// poolPreInvestingsQueued(uint256,uint256) @@ -145,4 +145,30 @@ interface IPoolProposal { /// @custom:selector 0x6630e6ee /// poolGuardian(uint256) function poolGuardian(uint256 pool_proposal_index) external view returns (bytes32[] memory guardian); + + /// @notice Query a user's all invested positions + /// @param user_address: user address, substrate + /// @custom:selector 0x814f8437 + /// userPoolPreInvestings(bytes32) + function userPoolPreInvestings(bytes32 user_address) external view returns (StakingBond[] memory pre_investing_bond); + + /// @notice Query a user's all queued positions + /// @param user_address: user address, substrate + /// @custom:selector 0x64833a66 + /// userPoolPreInvestingsQueued(bytes32) + function userPoolPreInvestingsQueued(bytes32 user_address) external view returns (QueuedStakingBond[] memory queued_bond); + + /// @notice Query corresponding pool proposal index's total pre-investing amount + /// @param start_id: Proposal index start_id, included + /// @param end_id: Proposal index end id, excluded + /// @custom:selector 0x3a4fbb0f + /// poolPreInvestingsTotal(uint256,uint256) + function poolPreInvestingsTotal(uint256 start_id, uint256 end_id) external view returns (uint256[] memory pre_investing_total); + + /// @notice Query corresponding pool proposal index's total pre-investing queued amount + /// @param start_id: Proposal index start_id, included + /// @param end_id: Proposal index end id, excluded + /// @custom:selector 0xa54205c4 + /// poolPreInvestingsQueuedTotal(uint256,uint256) + function poolPreInvestingsQueuedTotal(uint256 start_id, uint256 end_id) external view returns (uint256[] memory queued_total); } \ No newline at end of file diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index a0aa5a116c..07890e1e21 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -348,19 +348,11 @@ where let end_id: u128 = end_id.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; - - let length: u128 = end_id.checked_sub(start_id).ok_or(Into::::into( - RevertReason::value_is_too_large("id overflow"), - ))?; // Storage item: PoolPreInvestings -> // PoolProposalPreInvesting, BlockNumberFor, T::MaximumPoolProposed> - let length_usize: usize = length.try_into().map_err(|_| { - Into::::into(RevertReason::value_is_too_large("index type")) - })?; handle.record_db_read::( PalletBond::>::max_encoded_len() - .saturating_mul(Runtime::MaximumPoolProposed::get() as usize) - .saturating_mul(length_usize), + .saturating_mul(Runtime::MaximumPoolProposed::get() as usize), )?; let mut bond_result = Vec::::new(); for n in start_id..end_id { @@ -396,19 +388,11 @@ where let end_id: u128 = end_id.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; - - let length: u128 = end_id.checked_sub(start_id).ok_or(Into::::into( - RevertReason::value_is_too_large("id overflow"), - ))?; // Storage item: PoolPreInvestings -> // PoolProposalPreInvesting, BlockNumberFor, T::MaximumPoolProposed> - let length_usize: usize = length.try_into().map_err(|_| { - Into::::into(RevertReason::value_is_too_large("index type")) - })?; handle.record_db_read::( PalletBond::>::max_encoded_len() - .saturating_mul(Runtime::MaximumPoolProposed::get() as usize) - .saturating_mul(length_usize), + .saturating_mul(Runtime::MaximumPoolProposed::get() as usize), )?; let mut bond_result = Vec::::new(); @@ -471,6 +455,148 @@ where Ok(Default::default()) } } + + #[precompile::public("userPoolPreInvestings(bytes32)")] + #[precompile::view] + fn user_pool_pre_investings( + handle: &mut impl PrecompileHandle, + user_address: H256, + ) -> EvmResult> { + // Storage item: PendingPoolProposalStatus -> + // VecDeque> + // 16 * max number + // Storage item: PoolPreInvestings -> + // PoolProposalPreInvesting, BlockNumberFor, T::MaximumPoolProposed> + handle.record_db_read::( + 16usize.saturating_mul(Runtime::MaximumPoolProposed::get() as usize) + + PalletBond::>::max_encoded_len() + .saturating_mul(Runtime::MaximumPoolProposed::get() as usize), + )?; + + let user_address: [u8; 32] = user_address.into(); + let user_address = Runtime::AccountId::from(user_address); + + let mut bond_result = Vec::::new(); + + let pendings = pallet_pool_proposal::Pallet::::pending_pool_proposal_status(); + for pool_proposal_status in pendings.iter() { + // get underlying investings + if let Some(result) = pallet_pool_proposal::Pallet::::pool_pre_investings( + pool_proposal_status.pool_proposal_index, + ) { + if let Some(bond) = + result.pre_investings.into_iter().find(|&x| x.owner == user_address) + { + bond_result.extend(bond); + } + } + } + + Ok(bond_result) + } + + #[precompile::public("userPoolPreInvestingsQueued(bytes32)")] + #[precompile::view] + fn user_pool_pre_investings_queued( + handle: &mut impl PrecompileHandle, + user_address: H256, + ) -> EvmResult> { + // Storage item: PendingPoolProposalStatus -> + // VecDeque> + // 16 * max number + // Storage item: PoolPreInvestings -> + // PoolProposalPreInvesting, BlockNumberFor, T::MaximumPoolProposed> + handle.record_db_read::( + 16usize.saturating_mul(Runtime::MaximumPoolProposed::get() as usize) + + PalletBond::>::max_encoded_len() + .saturating_mul(Runtime::MaximumPoolProposed::get() as usize), + )?; + + let user_address: [u8; 32] = user_address.into(); + let user_address = Runtime::AccountId::from(user_address); + + let mut bond_result = Vec::::new(); + + let pendings = pallet_pool_proposal::Pallet::::pending_pool_proposal_status(); + for pool_proposal_status in pendings.iter() { + // get underlying investings + if let Some(result) = pallet_pool_proposal::Pallet::::pool_pre_investings( + pool_proposal_status.pool_proposal_index, + ) { + if let Some(bond) = + result.queued_pre_investings.into_iter().find(|&x| x.0.owner == user_address) + { + bond_result.extend(bond); + } + } + } + + Ok(bond_result) + } + + #[precompile::public("poolPreInvestingsTotal(uint256,uint256)")] + #[precompile::view] + fn pool_pre_investings_total( + handle: &mut impl PrecompileHandle, + start_id: U256, + end_id: U256, + ) -> EvmResult> { + let start_id: u128 = start_id.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + let end_id: u128 = end_id.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + // Storage item: PoolPreInvestings -> + // PoolProposalPreInvesting, BlockNumberFor, T::MaximumPoolProposed> + handle.record_db_read::( + PalletBond::>::max_encoded_len() + .saturating_mul(Runtime::MaximumPoolProposed::get() as usize), + )?; + + let mut total_vec_result = Vec::::new(); + for n in start_id..end_id { + if let Some(result) = pallet_pool_proposal::Pallet::::pool_pre_investings(n) { + let total: U256 = result.total_pre_investing_amount.into(); + + total_vec_result.push(total); + } + } + + Ok(total_vec_result) + } + + #[precompile::public("poolPreInvestingsQueuedTotal(uint256,uint256)")] + #[precompile::view] + fn pool_pre_investings_queued_total( + handle: &mut impl PrecompileHandle, + start_id: U256, + end_id: U256, + ) -> EvmResult> { + let start_id: u128 = start_id.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + let end_id: u128 = end_id.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + // Storage item: PoolPreInvestings -> + // PoolProposalPreInvesting, BlockNumberFor, T::MaximumPoolProposed> + handle.record_db_read::( + PalletBond::>::max_encoded_len() + .saturating_mul(Runtime::MaximumPoolProposed::get() as usize), + )?; + + let mut total_vec_result = Vec::::new(); + for n in start_id..end_id { + if let Some(result) = pallet_pool_proposal::Pallet::::pool_pre_investings(n) { + let total: U256 = result.total_queued_amount.into(); + + total_vec_result.push(total); + } + } + + Ok(total_vec_result) + } } #[derive(Default, Debug, solidity::Codec)] From 1771db1a69925e3373c912a7cabb40acef1b1110 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 20 Nov 2024 16:47:26 +0800 Subject: [PATCH 188/215] chore: fix --- parachain/precompiles/collab-ai/pool-proposal/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index 07890e1e21..3b768fb9d3 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -487,7 +487,7 @@ where if let Some(bond) = result.pre_investings.into_iter().find(|&x| x.owner == user_address) { - bond_result.extend(bond); + bond_result.append(bond); } } } @@ -526,7 +526,7 @@ where if let Some(bond) = result.queued_pre_investings.into_iter().find(|&x| x.0.owner == user_address) { - bond_result.extend(bond); + bond_result.append(bond); } } } From 8fba11f721bd5d0d2904b8ffe10f2ce2de7f45bc Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 20 Nov 2024 16:58:13 +0800 Subject: [PATCH 189/215] chore: fix --- parachain/precompiles/collab-ai/pool-proposal/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index 3b768fb9d3..64bd60c868 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -487,7 +487,7 @@ where if let Some(bond) = result.pre_investings.into_iter().find(|&x| x.owner == user_address) { - bond_result.append(bond); + bond_result.push(bond); } } } @@ -526,7 +526,7 @@ where if let Some(bond) = result.queued_pre_investings.into_iter().find(|&x| x.0.owner == user_address) { - bond_result.append(bond); + bond_result.push(bond); } } } From 6122f263d181b0a8b4befee63485093578f5207b Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 20 Nov 2024 17:11:33 +0800 Subject: [PATCH 190/215] chore: fix --- .../collab-ai/pool-proposal/src/lib.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index 64bd60c868..367281a8ad 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -487,7 +487,13 @@ where if let Some(bond) = result.pre_investings.into_iter().find(|&x| x.owner == user_address) { - bond_result.push(bond); + let owner: [u8; 32] = bond.owner.into(); + let owner = owner.into(); + bond_result.push(StakingBond { + pool_index: pool_proposal_status.pool_proposal_index.into(), + owner, + amount: bond.amount.into(), + }); } } } @@ -526,7 +532,14 @@ where if let Some(bond) = result.queued_pre_investings.into_iter().find(|&x| x.0.owner == user_address) { - bond_result.push(bond); + let owner: [u8; 32] = bond.0.owner.into(); + let owner = owner.into(); + bond_result.push(QueuedStakingBond { + pool_index: pool_proposal_status.pool_proposal_index.into(), + owner, + amount: bond.0.amount.into(), + queued_time: bond.1.into(), + }); } } } From 9e8c0df19f6100f161867c43eb35711343cf0421 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Wed, 20 Nov 2024 17:21:19 +0800 Subject: [PATCH 191/215] chore: fix --- parachain/precompiles/collab-ai/pool-proposal/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index 367281a8ad..5c5a08f649 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -485,7 +485,7 @@ where pool_proposal_status.pool_proposal_index, ) { if let Some(bond) = - result.pre_investings.into_iter().find(|&x| x.owner == user_address) + result.pre_investings.into_iter().find(|x| x.owner == user_address) { let owner: [u8; 32] = bond.owner.into(); let owner = owner.into(); @@ -530,7 +530,7 @@ where pool_proposal_status.pool_proposal_index, ) { if let Some(bond) = - result.queued_pre_investings.into_iter().find(|&x| x.0.owner == user_address) + result.queued_pre_investings.into_iter().find(|x| x.0.owner == user_address) { let owner: [u8; 32] = bond.0.owner.into(); let owner = owner.into(); From 00d4bd2639ffc6922167ac4c6dcb36529d52ec22 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 24 Nov 2024 16:12:13 +0800 Subject: [PATCH 192/215] chore: impl tests --- .../collab-ai/pool-proposal/src/mock.rs | 23 ++++++++++++++++ .../collab-ai/pool-proposal/src/tests.rs | 27 ++++++++++++------- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs index af0b6592f1..eef7d92ab6 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs @@ -251,3 +251,26 @@ pub fn assert_events(mut expected: Vec) { assert_eq!(next, evt, "Events don't match"); } } + +/// Rolls forward one block. Returns the new block number. +pub(crate) fn roll_one_block() -> u64 { + ParachainStaking::on_finalize(System::block_number()); + Balances::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Balances::on_initialize(System::block_number()); + ParachainStaking::on_initialize(System::block_number()); + System::block_number() +} + +/// Rolls to the desired block. Returns the number of blocks played. +pub(crate) fn roll_to(n: u64) -> u64 { + let mut num_blocks = 0; + let mut block = System::block_number(); + while block < n { + block = roll_one_block(); + num_blocks += 1; + } + num_blocks +} diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 9bd65592af..b4a64a8a3b 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -120,14 +120,23 @@ fn test_pre_stake_proposal_ok() { crate::Error::::ProposalNotExist ); - // // Proposal Expired - // assert_noop!( - // PoolProposal::pre_stake_proposal( - // RuntimeOrigin::signed(user_a), - // 2.into(), - // 500_000_000_000_000_000_000u128, - // ), - // crate::Error::::ProposalExpired - // ); + // Normal pre staking worked + assert_ok!(PoolProposal::pre_stake_proposal( + RuntimeOrigin::signed(user_a), + 1.into(), + 500_000_000_000_000_000_000u128, + )); + + // Go to proposal expire time + roll_to(150); + // Proposal Expired, Not work + assert_noop!( + PoolProposal::pre_stake_proposal( + RuntimeOrigin::signed(user_a), + 1.into(), + 500_000_000_000_000_000_000u128, + ), + crate::Error::::ProposalExpired + ); }) } From ccdd8936c429d9af589659bc7adeb5cacf8713f7 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 24 Nov 2024 16:27:10 +0800 Subject: [PATCH 193/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/mock.rs | 4 ++-- parachain/pallets/collab-ai/pool-proposal/src/tests.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs index eef7d92ab6..3caf2321d4 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs @@ -254,13 +254,13 @@ pub fn assert_events(mut expected: Vec) { /// Rolls forward one block. Returns the new block number. pub(crate) fn roll_one_block() -> u64 { - ParachainStaking::on_finalize(System::block_number()); + PoolProposal::on_finalize(System::block_number()); Balances::on_finalize(System::block_number()); System::on_finalize(System::block_number()); System::set_block_number(System::block_number() + 1); System::on_initialize(System::block_number()); Balances::on_initialize(System::block_number()); - ParachainStaking::on_initialize(System::block_number()); + PoolProposal::on_initialize(System::block_number()); System::block_number() } diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index b4a64a8a3b..0770473e73 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -123,7 +123,7 @@ fn test_pre_stake_proposal_ok() { // Normal pre staking worked assert_ok!(PoolProposal::pre_stake_proposal( RuntimeOrigin::signed(user_a), - 1.into(), + 1u128, 500_000_000_000_000_000_000u128, )); @@ -133,7 +133,7 @@ fn test_pre_stake_proposal_ok() { assert_noop!( PoolProposal::pre_stake_proposal( RuntimeOrigin::signed(user_a), - 1.into(), + 1u128, 500_000_000_000_000_000_000u128, ), crate::Error::::ProposalExpired From da29a50147531b99a893572ed6c87a3681e64370 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 24 Nov 2024 16:45:33 +0800 Subject: [PATCH 194/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/mock.rs | 4 +++- parachain/pallets/collab-ai/pool-proposal/src/tests.rs | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs index 3caf2321d4..adcb2e89e2 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs @@ -17,7 +17,9 @@ use crate as pallet_pool_proposal; use frame_support::{ assert_ok, construct_runtime, parameter_types, - traits::{AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, Everything}, + traits::{ + AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, Everything, OnFinalize, OnInitialize, + }, }; use sp_core::{Get, H256}; use sp_runtime::{ diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 0770473e73..13b4b3d4e8 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -113,7 +113,7 @@ fn test_pre_stake_proposal_ok() { // Pool not exist assert_noop!( PoolProposal::pre_stake_proposal( - RuntimeOrigin::signed(user_a), + RuntimeOrigin::signed(user_a.clone()), 2u128, 500_000_000_000_000_000_000u128, ), @@ -122,7 +122,7 @@ fn test_pre_stake_proposal_ok() { // Normal pre staking worked assert_ok!(PoolProposal::pre_stake_proposal( - RuntimeOrigin::signed(user_a), + RuntimeOrigin::signed(user_a.clone()), 1u128, 500_000_000_000_000_000_000u128, )); From 7f4c4a99341b119fa4b30e758840e75f35ee9d94 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 24 Nov 2024 19:03:54 +0800 Subject: [PATCH 195/215] chore: add tests --- .../collab-ai/pool-proposal/src/tests.rs | 92 ++++++++++++++++++- 1 file changed, 90 insertions(+), 2 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 13b4b3d4e8..4ce48037e2 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -88,9 +88,8 @@ fn test_pre_stake_proposal_ok() { let pool_last_time = 10000; let estimated_pool_reward = 2_000_000_000_000_000_000_000u128; let pool_info_hash: H256 = H256([2; 32]); - let _pool_info_hash_2: H256 = H256([3; 32]); - // Worked + // Setup assert_ok!(PoolProposal::propose_investing_pool( RuntimeOrigin::signed(user_a.clone()), max_pool_size, @@ -127,6 +126,12 @@ fn test_pre_stake_proposal_ok() { 500_000_000_000_000_000_000u128, )); + assert_events(vec![RuntimeEvent::PoolProposal(crate::Event::PoolPreInvested { + user: user_a.clone(), + pool_proposal_index: 1u128, + amount: 500_000_000_000_000_000_000u128, + })]); + // Go to proposal expire time roll_to(150); // Proposal Expired, Not work @@ -140,3 +145,86 @@ fn test_pre_stake_proposal_ok() { ); }) } + +fn test_withdraw_pre_investing_ok() { + new_test_ext().execute_with(|| { + let user_a: AccountId32 = AccountId32::from([1u8; 32]); + let user_b: AccountId32 = AccountId32::from([2u8; 32]); + Balances::make_free_balance_be(&user_a, 100_000_000_000_000_000_000); + Balances::make_free_balance_be(&user_b, 100_000_000_000_000_000_000); + + let max_pool_size = 10_000_000_000_000_000_000u128; + let proposal_last_time = 100; + let pool_last_time = 10000; + let estimated_pool_reward = 2_000_000_000_000_000_000_000u128; + let pool_info_hash: H256 = H256([2; 32]); + + // Setup + assert_ok!(PoolProposal::propose_investing_pool( + RuntimeOrigin::signed(user_a.clone()), + max_pool_size, + proposal_last_time, + pool_last_time, + estimated_pool_reward, + pool_info_hash + )); + + // Normal pre staking worked + assert_ok!(PoolProposal::pre_stake_proposal( + RuntimeOrigin::signed(user_a.clone()), + 1u128, + 5_000_000_000_000_000_000u128, + )); + + // Can not withdraw if pool is fullfiled + assert_noop!( + PoolProposal::withdraw_pre_investing( + RuntimeOrigin::signed(user_a.clone()), + 1u128, + 1_000_000_000_000_000_000u128, + ), + crate::Error::::ProposalPreInvestingLocked + ); + + // Fullfil the pool + assert_ok!(PoolProposal::pre_stake_proposal( + RuntimeOrigin::signed(user_a.clone()), + 1u128, + 495_000_000_000_000_000_000u128, + )); + + // pre investing and queued + assert_events(vec![RuntimeEvent::PoolProposal(crate::Event::PoolPreInvested { + user: user_a.clone(), + pool_proposal_index: 1u128, + amount: 5_000_000_000_000_000_000u128, + })]); + assert_events(vec![RuntimeEvent::PoolProposal(crate::Event::PoolPreStakeQueued { + user: user_a.clone(), + pool_proposal_index: 1u128, + amount: 490_000_000_000_000_000_000u128, + })]); + + // Withdraw succeed + assert_ok!(PoolProposal::withdraw_pre_investing( + RuntimeOrigin::signed(user_a.clone()), + 1u128, + 490_000_000_000_000_000_000u128, + )); + assert_events(vec![RuntimeEvent::PoolProposal(crate::Event::PoolWithdrawed { + user: user_a.clone(), + pool_proposal_index: 1u128, + amount: 490_000_000_000_000_000_000u128, + })]); + }) +} + +fn test_public_vote_proposal_ok() {} + +fn test_guardian_participate_proposal_ok() {} + +fn test_bake_proposal_ok() {} + +fn test_dissolve_proposal_ok() {} + +// TODO: solve pending test, types test From a4bdb4c5b7e06fdcd7b525f36e148b6b0b07497f Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 24 Nov 2024 19:31:24 +0800 Subject: [PATCH 196/215] chore: add tests --- .../collab-ai/pool-proposal/src/lib.rs | 31 +++++++-- .../collab-ai/pool-proposal/src/tests.rs | 64 +++++++++++++++++-- 2 files changed, 83 insertions(+), 12 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 9f2f23a458..7a635af97e 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -265,11 +265,18 @@ pub mod pallet { amount: AssetBalanceOf, }, /// A public vote result of proposal get passed - ProposalPublicVoted { pool_proposal_index: PoolProposalIndex, vote_result: bool }, + ProposalPublicVoted { + pool_proposal_index: PoolProposalIndex, + vote_result: bool, + }, /// A proposal is ready for baking - ProposalReadyForBake { pool_proposal_index: PoolProposalIndex }, + ProposalReadyForBake { + pool_proposal_index: PoolProposalIndex, + }, /// A proposal is ready for full dissolve, since the proposal expired but not satisifed all requirement - ProposalReadyForDissolve { pool_proposal_index: PoolProposalIndex }, + ProposalReadyForDissolve { + pool_proposal_index: PoolProposalIndex, + }, /// A proposal passed all checking and become a investing pool ProposalBaked { pool_proposal_index: PoolProposalIndex, @@ -277,7 +284,13 @@ pub mod pallet { proposal_settlement: AssetBalanceOf, }, /// A proposal failed some checking or type error, but fund is returned - ProposalDissolved { pool_proposal_index: PoolProposalIndex }, + ProposalDissolved { + pool_proposal_index: PoolProposalIndex, + }, + PorposalGuardian { + pool_proposal_index: PoolProposalIndex, + guardian: T::AccountId, + }, } #[pallet::error] @@ -624,6 +637,7 @@ pub mod pallet { // Including KYC. Otherwise he will be ignored no matter how much vote he collects #[pallet::call_index(4)] #[pallet::weight({195_000_000})] + #[transactional] pub fn guardian_participate_proposal( origin: OriginFor, pool_proposal_index: PoolProposalIndex, @@ -637,7 +651,7 @@ pub mod pallet { match maybe_ordered_set.as_mut() { Some(ordered_set) => { ensure!( - ordered_set.insert(who), + ordered_set.insert(who.clone()), Error::::GuardianDuplicatedOrOversized ); Ok(()) @@ -646,7 +660,7 @@ pub mod pallet { let mut new_ordered_set = OrderedSet::new(); ensure!( - new_ordered_set.insert(who), + new_ordered_set.insert(who.clone()), Error::::GuardianDuplicatedOrOversized ); *maybe_ordered_set = Some(new_ordered_set); @@ -654,7 +668,10 @@ pub mod pallet { }, } }, - ) + )?; + + Self::deposit_event(Event::PorposalGuardian { pool_proposal_index, guardian: who }); + Ok(()) } // Make all avaialable qualified proposal into investing pool diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 4ce48037e2..af0009a034 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -219,12 +219,66 @@ fn test_withdraw_pre_investing_ok() { }) } -fn test_public_vote_proposal_ok() {} +fn test_public_vote_proposal_ok() { + new_test_ext().execute_with(|| { + // Pool not exist + assert_noop!( + PoolProposal::public_vote_proposal(RuntimeOrigin::root(), 1u128, true,), + crate::Error::::ProposalNotExist + ); + + let user_a: AccountId32 = AccountId32::from([1u8; 32]); + let user_b: AccountId32 = AccountId32::from([2u8; 32]); + Balances::make_free_balance_be(&user_a, 100_000_000_000_000_000_000); + Balances::make_free_balance_be(&user_b, 100_000_000_000_000_000_000); + + let max_pool_size = 10_000_000_000_000_000_000u128; + let proposal_last_time = 100; + let pool_last_time = 10000; + let estimated_pool_reward = 2_000_000_000_000_000_000_000u128; + let pool_info_hash: H256 = H256([2; 32]); + + // Setup + assert_ok!(PoolProposal::propose_investing_pool( + RuntimeOrigin::signed(user_a.clone()), + max_pool_size, + proposal_last_time, + pool_last_time, + estimated_pool_reward, + pool_info_hash + )); -fn test_guardian_participate_proposal_ok() {} + // Wrong origin + assert_noop!( + PoolProposal::public_vote_proposal(RuntimeOrigin::signed(user_a.clone()), 1u128, true,), + sp_runtime::DispatchError::BadOrigin + ); + + // Works + assert_ok!(PoolProposal::public_vote_proposal( + RuntimeOrigin::signed(user_a.clone()), + 1u128, + true, + )); + assert_events(vec![RuntimeEvent::PoolProposal(crate::Event::ProposalPublicVoted { + pool_proposal_index: 1u128, + vote_result: true, + })]); + }) +} -fn test_bake_proposal_ok() {} +fn test_guardian_participate_proposal_ok() { + new_test_ext().execute_with(|| { + assert_ok!(PoolProposal::guardian_participate_proposal( + RuntimeOrigin::signed(user_a.clone()), + 1u128, + )); -fn test_dissolve_proposal_ok() {} + assert_events(vec![RuntimeEvent::PoolProposal(crate::Event::PorposalGuardian { + pool_proposal_index: 1u128, + guardian: user_a, + })]); + }) +} -// TODO: solve pending test, types test +// TODO: test_bake_proposal_ok, test_dissolve_proposal_ok, solve pending test, types test From 237c8dc0e1e0629eb3fcd123bd4545c8bf828d56 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 24 Nov 2024 21:03:57 +0800 Subject: [PATCH 197/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index af0009a034..1f2fb81226 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -269,6 +269,7 @@ fn test_public_vote_proposal_ok() { fn test_guardian_participate_proposal_ok() { new_test_ext().execute_with(|| { + let user_a: AccountId32 = AccountId32::from([1u8; 32]); assert_ok!(PoolProposal::guardian_participate_proposal( RuntimeOrigin::signed(user_a.clone()), 1u128, From 266d6d4d340777988a9a852ab920be655fb79b85 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 24 Nov 2024 23:17:35 +0800 Subject: [PATCH 198/215] chore: fix --- .../pallets/collab-ai/investing-pool/src/lib.rs | 17 ++++++++++++++--- .../collab-ai/pool-proposal/src/tests.rs | 3 +++ parachain/runtime/paseo/src/lib.rs | 3 ++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index 4e4a0fe2ea..6dfe4e48f9 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -186,7 +186,7 @@ pub mod pallet { type PoolProposalPalletOrigin: EnsureOrigin; /// Origin used to update epoch reward for investing pool - type RewardUpdateOrigin: EnsureOrigin; + type RewardUpdateOrigin: EnsureOrigin; /// Origin used to administer the investing pool type InvestingPoolAdminOrigin: EnsureOrigin; @@ -339,6 +339,7 @@ pub mod pallet { EpochNotExist, NoAssetId, TypeIncompatibleOrArithmeticError, + WrongPoolAdmin, } #[pallet::hooks] @@ -369,6 +370,7 @@ pub mod pallet { /// Update a reward for an investing pool of specific epoch /// Each epoch can be only updated once + /// Pool admin will transfer its AIUSD into pool accordingly #[pallet::call_index(1)] #[pallet::weight({1000})] #[transactional] @@ -378,11 +380,12 @@ pub mod pallet { epoch: u128, reward: BalanceOf, ) -> DispatchResult { - T::RewardUpdateOrigin::ensure_origin(origin)?; + let who = T::RewardUpdateOrigin::ensure_origin(origin)?; let setting = >::get(pool_id).ok_or(Error::::PoolNotExisted)?; ensure!(0 < epoch && epoch <= setting.epoch, Error::::EpochNotExist); + ensure!(setting.admin == who.clone(), Error::::WrongPoolAdmin); >::try_mutate( pool_id, @@ -403,7 +406,15 @@ pub mod pallet { // Mint AIUSD into reward pool let aiusd_asset_id = >::get().ok_or(Error::::NoAssetId)?; let beneficiary_account: T::AccountId = Self::stable_token_beneficiary_account(); - let _ = T::Fungibles::mint_into(aiusd_asset_id, &beneficiary_account, reward)?; + + // Curator must transfer corresponding cash into reward pool + T::Fungibles::transfer( + aiusd_asset_id, + &who, + &beneficiary_account, + reward, + Preservation::Expendable, + )?; Ok(()) } diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 1f2fb81226..e314d5d5af 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -146,6 +146,7 @@ fn test_pre_stake_proposal_ok() { }) } +#[test] fn test_withdraw_pre_investing_ok() { new_test_ext().execute_with(|| { let user_a: AccountId32 = AccountId32::from([1u8; 32]); @@ -219,6 +220,7 @@ fn test_withdraw_pre_investing_ok() { }) } +#[test] fn test_public_vote_proposal_ok() { new_test_ext().execute_with(|| { // Pool not exist @@ -267,6 +269,7 @@ fn test_public_vote_proposal_ok() { }) } +#[test] fn test_guardian_participate_proposal_ok() { new_test_ext().execute_with(|| { let user_a: AccountId32 = AccountId32::from([1u8; 32]); diff --git a/parachain/runtime/paseo/src/lib.rs b/parachain/runtime/paseo/src/lib.rs index e939fa5774..52894bfeb6 100644 --- a/parachain/runtime/paseo/src/lib.rs +++ b/parachain/runtime/paseo/src/lib.rs @@ -1098,7 +1098,8 @@ parameter_types! { impl pallet_investing_pool::Config for Runtime { type RuntimeEvent = RuntimeEvent; type PoolProposalPalletOrigin = EnsureRoot; - type RewardUpdateOrigin = EnsureRootOrAllCouncil; + // Equal to Proposal's admin is judged inside pallet + type RewardUpdateOrigin = EnsureSignedAndVerifiedCurator; type InvestingPoolAdminOrigin = EnsureRoot; type Fungibles = Assets; type StableTokenBeneficiaryId = StableTokenBeneficiaryId; From b6bd860558fbba8b7ea1176974488713695c7900 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Mon, 25 Nov 2024 15:19:08 +0800 Subject: [PATCH 199/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/tests.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index e314d5d5af..601ed7e836 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -184,7 +184,7 @@ fn test_withdraw_pre_investing_ok() { 1u128, 1_000_000_000_000_000_000u128, ), - crate::Error::::ProposalPreInvestingLocked + crate::Error::::InsufficientPreInvesting ); // Fullfil the pool @@ -252,16 +252,12 @@ fn test_public_vote_proposal_ok() { // Wrong origin assert_noop!( - PoolProposal::public_vote_proposal(RuntimeOrigin::signed(user_a.clone()), 1u128, true,), + PoolProposal::public_vote_proposal(RuntimeOrigin::signed(user_a), 1u128, true,), sp_runtime::DispatchError::BadOrigin ); // Works - assert_ok!(PoolProposal::public_vote_proposal( - RuntimeOrigin::signed(user_a.clone()), - 1u128, - true, - )); + assert_ok!(PoolProposal::public_vote_proposal(RuntimeOrigin::root(), 1u128, true,)); assert_events(vec![RuntimeEvent::PoolProposal(crate::Event::ProposalPublicVoted { pool_proposal_index: 1u128, vote_result: true, From caf2678165632e53dbf1effc6bff5dc00b5a208b Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Tue, 26 Nov 2024 16:49:10 +0800 Subject: [PATCH 200/215] chore: temp commit; precompile --- .../collab-ai/investing-pool/src/lib.rs | 5 ++ .../collab-ai/investing-pool/src/mock.rs | 0 .../collab-ai/investing-pool/src/tests.rs | 0 .../collab-ai/pool-proposal/src/lib.rs | 4 ++ .../collab-ai/pool-proposal/src/mock.rs | 2 + .../collab-ai/investing-pool/Cargo.toml | 51 +++++++++++++++++ .../investing-pool/InvestingPool.sol | 55 +++++++++++++++++++ .../collab-ai/investing-pool/src/lib.rs | 52 ++++++++++++++++++ 8 files changed, 169 insertions(+) create mode 100644 parachain/pallets/collab-ai/investing-pool/src/mock.rs create mode 100644 parachain/pallets/collab-ai/investing-pool/src/tests.rs create mode 100644 parachain/precompiles/collab-ai/investing-pool/Cargo.toml create mode 100644 parachain/precompiles/collab-ai/investing-pool/InvestingPool.sol create mode 100644 parachain/precompiles/collab-ai/investing-pool/src/lib.rs diff --git a/parachain/pallets/collab-ai/investing-pool/src/lib.rs b/parachain/pallets/collab-ai/investing-pool/src/lib.rs index 6dfe4e48f9..dbdcc3fb42 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/lib.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/lib.rs @@ -39,6 +39,11 @@ use sp_std::{fmt::Debug, prelude::*}; use pallet_collab_ai_common::*; +// #[cfg(test)] +// mod mock; +// #[cfg(test)] +// mod tests; + #[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] pub struct InvestingWeightInfo { // For a single position or diff --git a/parachain/pallets/collab-ai/investing-pool/src/mock.rs b/parachain/pallets/collab-ai/investing-pool/src/mock.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/parachain/pallets/collab-ai/investing-pool/src/tests.rs b/parachain/pallets/collab-ai/investing-pool/src/tests.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 7a635af97e..2b952e47f5 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -114,6 +114,10 @@ pub mod pallet { #[pallet::constant] type MaximumPoolProposed: Get; + /// The maximum amount of investor per pool for both pre-investing and queued + #[pallet::constant] + type MaximumInvestingPerProposal: Get; + /// Standard epoch length #[pallet::constant] type StandardEpoch: Get>; diff --git a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs index adcb2e89e2..888bff8e03 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs @@ -54,6 +54,7 @@ parameter_types! { pub const MaxGuardianPerProposal: u32 = 2; pub const MaxGuardianSelectedPerProposal: u32 = 1; pub const MaximumPoolProposed: u32 = 1; + pub const MaximumInvestingPerProposal: u32 = 100; pub const DepositBase: Balance = 1; pub const DepositFactor: Balance = 1; @@ -200,6 +201,7 @@ impl pallet_pool_proposal::Config for Test { type MinimumProposalLastTime = MinimumProposalLastTime; type MinimumPoolDeposit = MinimumPoolDeposit; type MaximumPoolProposed = MaximumPoolProposed; + type MaximumInvestingPerProposal = MaximumInvestingPerProposal; type StandardEpoch = StandardEpoch; type ProposalOrigin = EnsureSignedAndCurator; type PublicVotingOrigin = frame_system::EnsureRoot; diff --git a/parachain/precompiles/collab-ai/investing-pool/Cargo.toml b/parachain/precompiles/collab-ai/investing-pool/Cargo.toml new file mode 100644 index 0000000000..df315bc4b9 --- /dev/null +++ b/parachain/precompiles/collab-ai/investing-pool/Cargo.toml @@ -0,0 +1,51 @@ +[package] +authors = ["Trust Computing GmbH "] +edition = '2021' +name = "pallet-evm-precompile-investing-pool" +version = '0.1.0' + +[dependencies] +precompile-utils = { workspace = true } + +# Substrate +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-collab-ai-common = { workspace = true } +pallet-investing-pool = { workspace = true } +parity-scale-codec = { workspace = true, features = ["max-encoded-len"] } +scale-info = { workspace = true, features = ["derive"] } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +# Frontier +fp-evm = { workspace = true } +pallet-evm = { workspace = true, features = ["forbid-evm-reentrancy"] } + +[dev-dependencies] +derive_more = { workspace = true } +hex-literal = { workspace = true } +libsecp256k1 = { workspace = true } +serde = { workspace = true } +sha3 = { workspace = true } +precompile-utils = { workspace = true, features = ["std", "testing"] } +pallet-timestamp = { workspace = true, features = ["std"] } +parity-scale-codec = { workspace = true, features = ["max-encoded-len", "std"] } +scale-info = { workspace = true, features = ["derive"] } +sp-runtime = { workspace = true, features = ["std"] } + +[features] +default = ["std"] +std = [ + "fp-evm/std", + "frame-support/std", + "frame-system/std", + "pallet-collab-ai-common/std", + "pallet-investing-pool/std", + "pallet-evm/std", + "pallet-timestamp/std", + "precompile-utils/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/parachain/precompiles/collab-ai/investing-pool/InvestingPool.sol b/parachain/precompiles/collab-ai/investing-pool/InvestingPool.sol new file mode 100644 index 0000000000..26e1068b7d --- /dev/null +++ b/parachain/precompiles/collab-ai/investing-pool/InvestingPool.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity >=0.8.3; + +interface IInvestingPool { + + /// @notice Update epoch reward of pool + /// @param pool_proposal_index: Index of pool proposal + /// @param epoch: Epoch index + /// @param reward: Amount of total reward for epoch + /// @custom:selector 0xb712851b + /// updateReward(uint256,uint256,uint256) + function updateReward(uint256 pool_proposal_index, uint256 epoch, uint256 reward) external; + + /// @notice Claim both epoch reward and CAN token reward, will claim until the epoch where reward updated + /// @param asset_id: Token id of corresponding token + /// @param amount: Amount of token + /// @custom:selector 0xc3490263 + /// claim(uint256,uint256) + function claim(uint256 asset_id, uint256 amount) external; + + + /// @dev A structure for pool setting + struct PoolSetting { + uint256 startTime; + uint256 epoch; + uint256 epoch_range; + uint256 pool_cap; + bytes32 admin; + } + + /// @notice Claim both epoch reward and CAN token reward, will claim until the epoch where reward updated + /// @param pool_proposal_index: List of pool proposal index + /// @custom:selector 0xd3e557b6 + /// investingPoolSetting(uint256[]) + function investingPoolSetting(uint256[] calldata pool_proposal_index) external view returns (PoolSetting[] memory pool_setting); + + /// @dev A structure for recording epoch reward + struct EpochReward { + uint256 totalReward; + uint256 claimedReward; + } + + /// @notice Query All epoch rewards updated by curator + /// @param pool_proposal_index: Pool proposal index + /// @custom:selector 0x25819dc7 + /// stableInvestingPoolEpochReward(uint256) + function stableInvestingPoolEpochReward(uint256 pool_proposal_index) external view returns (EpochReward[] memory epcoh_reward); + + /// @notice Query the estimated reward can be collected given the list of pair of token type and amounts + /// @param asset_id: a list of asset ids + /// @param amount: a list of amount of corresponding token + /// @custom:selector 0xfb570be1 + /// estimateReward(uint256[],uint256[]) + function estimateReward(uint256[] calldata asset_id, uint256[] calldata amount) external view returns (uint256 aiusd, uint256 can); +} \ No newline at end of file diff --git a/parachain/precompiles/collab-ai/investing-pool/src/lib.rs b/parachain/precompiles/collab-ai/investing-pool/src/lib.rs new file mode 100644 index 0000000000..7e8192d1e2 --- /dev/null +++ b/parachain/precompiles/collab-ai/investing-pool/src/lib.rs @@ -0,0 +1,52 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use fp_evm::{PrecompileFailure, PrecompileHandle}; +use frame_support::{ + dispatch::{GetDispatchInfo, PostDispatchInfo}, + traits::Currency, +}; +use frame_system::pallet_prelude::BlockNumberFor; +use pallet_evm::AddressMapping; + +use parity_scale_codec::MaxEncodedLen; +use precompile_utils::prelude::*; +use sp_runtime::traits::Dispatchable; + +use sp_core::{Get, H256, U256}; +use sp_std::{marker::PhantomData, vec::Vec}; + +use pallet_collab_ai_common::PoolProposalIndex; + +pub struct InvestingPoolPrecompile(PhantomData); + + + +#[precompile_utils::precompile] +impl InvestingPoolPrecompile +where + Runtime: pallet_investing_pool::Config + pallet_evm::Config, + Runtime::AccountId: From<[u8; 32]> + Into<[u8; 32]>, + ::RuntimeCall: + Dispatchable + GetDispatchInfo, + ::RuntimeCall: From>, + <::RuntimeCall as Dispatchable>::RuntimeOrigin: + From>, + AssetBalanceOf: TryFrom + Into, + BlockNumberFor: TryFrom + Into, + BalanceOf: TryFrom + Into, +{ + +} + + +#[derive(Default, Debug, solidity::Codec)] +struct PoolProposalInfo { + exist: bool, + proposer: H256, + info_hash: H256, + max_pool_size: U256, + pool_start_time: U256, + pool_end_time: U256, + estimated_pool_reward: U256, + proposal_status_flags: u8, +} From 4c31c9d2e8b0d5e4bb39e5916ea61dcd9710b592 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Tue, 26 Nov 2024 17:44:03 +0800 Subject: [PATCH 201/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs index 2b952e47f5..99ebdd09f6 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/lib.rs @@ -204,7 +204,7 @@ pub mod pallet { T::AccountId, AssetBalanceOf, BlockNumberFor, - T::MaximumPoolProposed, + T::MaximumInvestingPerProposal, >, OptionQuery, >; From f087688aaea1a386e9d55c30326f988a60ccd1fd Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 1 Dec 2024 19:29:14 +0800 Subject: [PATCH 202/215] chore: add tests --- parachain/Cargo.lock | 25 +++ parachain/Cargo.toml | 2 + .../collab-ai/investing-pool/src/mock.rs | 19 ++ .../collab-ai/investing-pool/src/tests.rs | 19 ++ .../collab-ai/pool-proposal/src/tests.rs | 24 ++- .../collab-ai/aiusd-convertor/src/lib.rs | 16 ++ .../precompiles/collab-ai/curator/src/lib.rs | 16 ++ .../investing-pool/InvestingPool.sol | 13 +- .../collab-ai/investing-pool/src/lib.rs | 177 ++++++++++++++++-- .../collab-ai/pool-proposal/src/lib.rs | 16 ++ parachain/runtime/paseo/Cargo.toml | 2 + parachain/runtime/paseo/src/lib.rs | 2 + parachain/runtime/paseo/src/precompiles.rs | 7 + 13 files changed, 311 insertions(+), 27 deletions(-) diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index f08e59039c..8de3258d13 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -7540,6 +7540,30 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-evm-precompile-investing-pool" +version = "0.1.0" +dependencies = [ + "derive_more", + "fp-evm", + "frame-support", + "frame-system", + "hex-literal", + "libsecp256k1", + "pallet-collab-ai-common", + "pallet-evm", + "pallet-investing-pool", + "pallet-timestamp", + "parity-scale-codec", + "precompile-utils", + "scale-info", + "serde", + "sha3", + "sp-core", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-evm-precompile-modexp" version = "2.0.0-dev" @@ -8772,6 +8796,7 @@ dependencies = [ "pallet-evm-precompile-dispatch", "pallet-evm-precompile-ed25519", "pallet-evm-precompile-guardian", + "pallet-evm-precompile-investing-pool", "pallet-evm-precompile-modexp", "pallet-evm-precompile-parachain-staking", "pallet-evm-precompile-pool-proposal", diff --git a/parachain/Cargo.toml b/parachain/Cargo.toml index 2aec779792..305a02245e 100644 --- a/parachain/Cargo.toml +++ b/parachain/Cargo.toml @@ -32,6 +32,7 @@ members = [ 'precompiles/collab-ai/curator', 'precompiles/collab-ai/guardian', 'precompiles/collab-ai/pool-proposal', + 'precompiles/collab-ai/investing-pool', 'precompiles/parachain-staking', 'precompiles/score-staking', 'runtime/litentry', @@ -289,6 +290,7 @@ pallet-evm-precompile-aiusd-convertor = { path = "precompiles/collab-ai/aiusd-co pallet-evm-precompile-curator = { path = "precompiles/collab-ai/curator", default-features = false } pallet-evm-precompile-guardian = { path = "precompiles/collab-ai/guardian", default-features = false } pallet-evm-precompile-pool-proposal = { path = "precompiles/collab-ai/pool-proposal", default-features = false } +pallet-evm-precompile-investing-pool = { path = "precompiles/collab-ai/investing-pool", default-features = false } pallet-evm-assertions = { path = "pallets/evm-assertions", default-features = false } diff --git a/parachain/pallets/collab-ai/investing-pool/src/mock.rs b/parachain/pallets/collab-ai/investing-pool/src/mock.rs index e69de29bb2..002a4ea7e1 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/mock.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/mock.rs @@ -0,0 +1,19 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +// TODO +// TODO +// TODO \ No newline at end of file diff --git a/parachain/pallets/collab-ai/investing-pool/src/tests.rs b/parachain/pallets/collab-ai/investing-pool/src/tests.rs index e69de29bb2..002a4ea7e1 100644 --- a/parachain/pallets/collab-ai/investing-pool/src/tests.rs +++ b/parachain/pallets/collab-ai/investing-pool/src/tests.rs @@ -0,0 +1,19 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +// TODO +// TODO +// TODO \ No newline at end of file diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 601ed7e836..14cc39d820 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -1,3 +1,19 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + use crate::mock::*; use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; use pallet_balances::Error as BalanceError; @@ -195,15 +211,15 @@ fn test_withdraw_pre_investing_ok() { )); // pre investing and queued - assert_events(vec![RuntimeEvent::PoolProposal(crate::Event::PoolPreInvested { + assert_events(vec![RuntimeEvent::PoolProposal(crate::Event::PoolPreStakeQueued { user: user_a.clone(), pool_proposal_index: 1u128, - amount: 5_000_000_000_000_000_000u128, + amount: 490_000_000_000_000_000_000u128, })]); - assert_events(vec![RuntimeEvent::PoolProposal(crate::Event::PoolPreStakeQueued { + assert_events(vec![RuntimeEvent::PoolProposal(crate::Event::PoolPreInvested { user: user_a.clone(), pool_proposal_index: 1u128, - amount: 490_000_000_000_000_000_000u128, + amount: 5_000_000_000_000_000_000u128, })]); // Withdraw succeed diff --git a/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs b/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs index 31ff97e4fb..77b73d6ac5 100644 --- a/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs +++ b/parachain/precompiles/collab-ai/aiusd-convertor/src/lib.rs @@ -1,3 +1,19 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + #![cfg_attr(not(feature = "std"), no_std)] use fp_evm::{PrecompileFailure, PrecompileHandle}; diff --git a/parachain/precompiles/collab-ai/curator/src/lib.rs b/parachain/precompiles/collab-ai/curator/src/lib.rs index c199843b8c..281b6ce034 100644 --- a/parachain/precompiles/collab-ai/curator/src/lib.rs +++ b/parachain/precompiles/collab-ai/curator/src/lib.rs @@ -1,3 +1,19 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + #![cfg_attr(not(feature = "std"), no_std)] use fp_evm::{PrecompileFailure, PrecompileHandle}; diff --git a/parachain/precompiles/collab-ai/investing-pool/InvestingPool.sol b/parachain/precompiles/collab-ai/investing-pool/InvestingPool.sol index 26e1068b7d..a6655d6063 100644 --- a/parachain/precompiles/collab-ai/investing-pool/InvestingPool.sol +++ b/parachain/precompiles/collab-ai/investing-pool/InvestingPool.sol @@ -21,7 +21,7 @@ interface IInvestingPool { /// @dev A structure for pool setting struct PoolSetting { - uint256 startTime; + uint256 start_time; uint256 epoch; uint256 epoch_range; uint256 pool_cap; @@ -36,8 +36,8 @@ interface IInvestingPool { /// @dev A structure for recording epoch reward struct EpochReward { - uint256 totalReward; - uint256 claimedReward; + uint256 total_reward; + uint256 claimed_reward; } /// @notice Query All epoch rewards updated by curator @@ -45,11 +45,4 @@ interface IInvestingPool { /// @custom:selector 0x25819dc7 /// stableInvestingPoolEpochReward(uint256) function stableInvestingPoolEpochReward(uint256 pool_proposal_index) external view returns (EpochReward[] memory epcoh_reward); - - /// @notice Query the estimated reward can be collected given the list of pair of token type and amounts - /// @param asset_id: a list of asset ids - /// @param amount: a list of amount of corresponding token - /// @custom:selector 0xfb570be1 - /// estimateReward(uint256[],uint256[]) - function estimateReward(uint256[] calldata asset_id, uint256[] calldata amount) external view returns (uint256 aiusd, uint256 can); } \ No newline at end of file diff --git a/parachain/precompiles/collab-ai/investing-pool/src/lib.rs b/parachain/precompiles/collab-ai/investing-pool/src/lib.rs index 7e8192d1e2..e467992b0d 100644 --- a/parachain/precompiles/collab-ai/investing-pool/src/lib.rs +++ b/parachain/precompiles/collab-ai/investing-pool/src/lib.rs @@ -1,3 +1,19 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + #![cfg_attr(not(feature = "std"), no_std)] use fp_evm::{PrecompileFailure, PrecompileHandle}; @@ -7,6 +23,7 @@ use frame_support::{ }; use frame_system::pallet_prelude::BlockNumberFor; use pallet_evm::AddressMapping; +use pallet_investing_pool::BalanceOf; use parity_scale_codec::MaxEncodedLen; use precompile_utils::prelude::*; @@ -15,12 +32,10 @@ use sp_runtime::traits::Dispatchable; use sp_core::{Get, H256, U256}; use sp_std::{marker::PhantomData, vec::Vec}; -use pallet_collab_ai_common::PoolProposalIndex; +use pallet_collab_ai_common::{InvestingPoolAssetIdGenerator, PoolProposalIndex}; pub struct InvestingPoolPrecompile(PhantomData); - - #[precompile_utils::precompile] impl InvestingPoolPrecompile where @@ -28,25 +43,161 @@ where Runtime::AccountId: From<[u8; 32]> + Into<[u8; 32]>, ::RuntimeCall: Dispatchable + GetDispatchInfo, - ::RuntimeCall: From>, + ::RuntimeCall: From>, <::RuntimeCall as Dispatchable>::RuntimeOrigin: From>, AssetBalanceOf: TryFrom + Into, BlockNumberFor: TryFrom + Into, BalanceOf: TryFrom + Into, { + #[precompile::public("updateReward(uint256,uint256,uint256)")] + fn updateReward( + handle: &mut impl PrecompileHandle, + pool_proposal_index: U256, + epoch: U256, + reward: U256, + ) -> EvmResult { + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + + let pool_proposal_index: u128 = pool_proposal_index.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + + let epoch: u128 = epoch.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("epoch type")) + })?; + + let reward: AssetBalanceOf = reward.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("balance type")) + })?; + + let call = pallet_investing_pool::Call::::update_reward { + pool_proposal_index, + epoch, + reward, + }; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + + Ok(()) + } + + #[precompile::public("claim(uint256,uint256)")] + fn claim(handle: &mut impl PrecompileHandle, asset_id: U256, amount: U256) -> EvmResult { + let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + + let asset_id: u128 = asset_id.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("asset type")) + })?; + + let amount: AssetBalanceOf = amount.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("balance type")) + })?; + let call = pallet_investing_pool::Call::::claim { asset_id, amount }; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + + Ok(()) + } + + #[precompile::public("investingPoolSetting(uint256[])")] + #[precompile::view] + fn investing_pool_setting( + handle: &mut impl PrecompileHandle, + pool_proposal_index: Vec, + ) -> EvmResult> { + // Storage item: PoolSetting + let length_usize: usize = pool_proposal_index.len().try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + handle.record_db_read::( + PoolSetting::>::max_encoded_len( + ) + .saturating_mul(length_usize), + )?; + + let mut setting_result = Vec::::new(); + + for index in pool_proposal_index.iter() { + // get underlying investings + if let Some(result) = + pallet_investing_pool::Pallet::::investing_pool_setting(index) + { + let admin: [u8; 32] = result.admin.into(); + let admin = admin.into(); + setting_result.push(PoolSetting { + start_time: result.start_time.into(), + epoch: result.epoch.into(), + epoch_range: result.epoch_range.into(), + pool_cap: result.pool_cap.into(), + admin, + }); + } else { + setting_result.push(Default::default()); + } + } + + Ok(setting_result) + } + + #[precompile::public("stableInvestingPoolEpochReward(uint256)")] + #[precompile::view] + fn stable_investing_pool_epoch_reward( + handle: &mut impl PrecompileHandle, + pool_proposal_index: U256, + ) -> EvmResult> { + // Storage item: PoolSetting + handle.record_db_read::(PoolSetting::< + Runtime::AccountId, + BlockNumberFor, + BalanceOf, + >::max_encoded_len())?; + let mut reward_result = Vec::::new(); + let mut epoch = 0u128; + + if let Some(result) = + pallet_investing_pool::Pallet::::investing_pool_setting(pool_proposal_index) + { + epoch = result.epoch.into(); + let length_usize: usize = epoch.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + // Storage item: (BalanceOf, BalanceOf) + handle.record_db_read::(32 * length_usize)?; + } else { + return Ok(reward_result); + } + + for i in 1..(epoch + 1) { + if let Some(result) = + pallet_investing_pool::Pallet::::stable_investing_pool_epoch_reward( + index, i, + ) { + let admin: [u8; 32] = result.admin.into(); + let admin = admin.into(); + setting_result.push(EpochReward { + total_reward: result.0.into(), + claimed_reward: result.1.into(), + }); + } else { + // Until the first pending epoch + break; + } + } + Ok(setting_result) + } } +#[derive(Default, Debug, solidity::Codec)] +struct PoolSetting { + start_time: U256, + epoch: U256, + epoch_range: U256, + pool_cap: U256, + admin: H256, +} #[derive(Default, Debug, solidity::Codec)] -struct PoolProposalInfo { - exist: bool, - proposer: H256, - info_hash: H256, - max_pool_size: U256, - pool_start_time: U256, - pool_end_time: U256, - estimated_pool_reward: U256, - proposal_status_flags: u8, +struct EpochReward { + total_reward: U256, + claimed_reward: U256, } diff --git a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs index 5c5a08f649..bd0c31e037 100644 --- a/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs +++ b/parachain/precompiles/collab-ai/pool-proposal/src/lib.rs @@ -1,3 +1,19 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + #![cfg_attr(not(feature = "std"), no_std)] use fp_evm::{PrecompileFailure, PrecompileHandle}; diff --git a/parachain/runtime/paseo/Cargo.toml b/parachain/runtime/paseo/Cargo.toml index c47e3fb2fc..1962a28d85 100644 --- a/parachain/runtime/paseo/Cargo.toml +++ b/parachain/runtime/paseo/Cargo.toml @@ -124,6 +124,7 @@ pallet-evm-precompile-aiusd-convertor = { workspace = true } pallet-evm-precompile-curator = { workspace = true } pallet-evm-precompile-guardian = { workspace = true } pallet-evm-precompile-pool-proposal = { workspace = true } +pallet-evm-precompile-investing-pool = { workspace = true } moonbeam-evm-tracer = { workspace = true } moonbeam-rpc-primitives-debug = { workspace = true } @@ -244,6 +245,7 @@ std = [ "pallet-evm-precompile-curator/std", "pallet-evm-precompile-guardian/std", "pallet-evm-precompile-pool-proposal/std", + "pallet-evm-precompile-investing-pool/std", "pallet-identity/std", "pallet-membership/std", "pallet-message-queue/std", diff --git a/parachain/runtime/paseo/src/lib.rs b/parachain/runtime/paseo/src/lib.rs index 52894bfeb6..873c16c393 100644 --- a/parachain/runtime/paseo/src/lib.rs +++ b/parachain/runtime/paseo/src/lib.rs @@ -1048,6 +1048,7 @@ parameter_types! { pub MinimumProposalLastTime: BlockNumber = prod_or_fast!(30 * DAYS, 10 * MINUTES, "ROCOCO_MINIMUMPROPOSALLASTTIME"); pub const MinimumPoolDeposit: Balance = 1000 * DOLLARS; pub const MaximumPoolProposed: u32 = 10000; + pub const MaximumInvestingPerProposal: u32 = 100000; pub StandardEpoch: BlockNumber = prod_or_fast!(30 * DAYS, 10 * MINUTES, "ROCOCO_STANDARDEPOCH"); pub const MaxGuardianPerProposal: u32 = 1000; pub const MaxGuardianSelectedPerProposal: u32 = 3; @@ -1080,6 +1081,7 @@ impl pallet_pool_proposal::Config for Runtime { type MinimumProposalLastTime = MinimumProposalLastTime; type MinimumPoolDeposit = MinimumPoolDeposit; type MaximumPoolProposed = MaximumPoolProposed; + type MaximumInvestingPerProposal = MaximumInvestingPerProposal; type StandardEpoch = StandardEpoch; type ProposalOrigin = EnsureSignedAndVerifiedCurator; type PublicVotingOrigin = EnsureRootOrAllCouncil; diff --git a/parachain/runtime/paseo/src/precompiles.rs b/parachain/runtime/paseo/src/precompiles.rs index fee345a6ce..9af0bc5fbf 100644 --- a/parachain/runtime/paseo/src/precompiles.rs +++ b/parachain/runtime/paseo/src/precompiles.rs @@ -41,6 +41,7 @@ use sp_std::fmt::Debug; use pallet_evm_precompile_aiusd_convertor::AIUSDConvertorPrecompile; use pallet_evm_precompile_curator::CuratorPrecompile; use pallet_evm_precompile_guardian::GuardianPrecompile; +use pallet_evm_precompile_investing_pool::InvestingPoolPrecompile; use pallet_evm_precompile_pool_proposal::PoolProposalPrecompile; /// The asset precompile address prefix. Addresses that match against this prefix will be routed @@ -159,6 +160,12 @@ pub type PrecompilesSetAt = ( PoolProposalPrecompile, (CallableByContract, CallableByPrecompile), >, + // InvestingPool: pallet_investing_pool = 153 + 20480 + PrecompileAt< + AddressU64<20633>, + InvestingPoolPrecompile, + (CallableByContract, CallableByPrecompile), + >, // AIUSDConvertor: pallet_aiusd_convertor = 154 + 20480 PrecompileAt< AddressU64<20634>, From c8803aa4e1ba85f0f98e7b438a10c767fdc452d4 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 1 Dec 2024 19:35:37 +0800 Subject: [PATCH 203/215] chore: fmt --- parachain/Cargo.toml | 2 +- parachain/runtime/paseo/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/Cargo.toml b/parachain/Cargo.toml index 305a02245e..57f2e7b3db 100644 --- a/parachain/Cargo.toml +++ b/parachain/Cargo.toml @@ -290,7 +290,7 @@ pallet-evm-precompile-aiusd-convertor = { path = "precompiles/collab-ai/aiusd-co pallet-evm-precompile-curator = { path = "precompiles/collab-ai/curator", default-features = false } pallet-evm-precompile-guardian = { path = "precompiles/collab-ai/guardian", default-features = false } pallet-evm-precompile-pool-proposal = { path = "precompiles/collab-ai/pool-proposal", default-features = false } -pallet-evm-precompile-investing-pool = { path = "precompiles/collab-ai/investing-pool", default-features = false } +pallet-evm-precompile-investing-pool = { path = "precompiles/collab-ai/investing-pool", default-features = false } pallet-evm-assertions = { path = "pallets/evm-assertions", default-features = false } diff --git a/parachain/runtime/paseo/Cargo.toml b/parachain/runtime/paseo/Cargo.toml index 1962a28d85..eebb95261f 100644 --- a/parachain/runtime/paseo/Cargo.toml +++ b/parachain/runtime/paseo/Cargo.toml @@ -123,8 +123,8 @@ pallet-evm-precompile-score-staking = { workspace = true } pallet-evm-precompile-aiusd-convertor = { workspace = true } pallet-evm-precompile-curator = { workspace = true } pallet-evm-precompile-guardian = { workspace = true } -pallet-evm-precompile-pool-proposal = { workspace = true } pallet-evm-precompile-investing-pool = { workspace = true } +pallet-evm-precompile-pool-proposal = { workspace = true } moonbeam-evm-tracer = { workspace = true } moonbeam-rpc-primitives-debug = { workspace = true } From ceed0be92057d9efdc1c73a1124d1fde19c39c85 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 1 Dec 2024 20:00:57 +0800 Subject: [PATCH 204/215] chore: fix --- .../collab-ai/investing-pool/src/lib.rs | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/parachain/precompiles/collab-ai/investing-pool/src/lib.rs b/parachain/precompiles/collab-ai/investing-pool/src/lib.rs index e467992b0d..9b8dc948c8 100644 --- a/parachain/precompiles/collab-ai/investing-pool/src/lib.rs +++ b/parachain/precompiles/collab-ai/investing-pool/src/lib.rs @@ -17,13 +17,10 @@ #![cfg_attr(not(feature = "std"), no_std)] use fp_evm::{PrecompileFailure, PrecompileHandle}; -use frame_support::{ - dispatch::{GetDispatchInfo, PostDispatchInfo}, - traits::Currency, -}; +use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; use frame_system::pallet_prelude::BlockNumberFor; use pallet_evm::AddressMapping; -use pallet_investing_pool::BalanceOf; +use pallet_investing_pool::{AssetIdOf, BalanceOf}; use parity_scale_codec::MaxEncodedLen; use precompile_utils::prelude::*; @@ -32,7 +29,9 @@ use sp_runtime::traits::Dispatchable; use sp_core::{Get, H256, U256}; use sp_std::{marker::PhantomData, vec::Vec}; -use pallet_collab_ai_common::{InvestingPoolAssetIdGenerator, PoolProposalIndex}; +use pallet_collab_ai_common::{ + InvestingPoolAssetIdGenerator, PoolProposalIndex, PoolSetting as InvestingPoolSetting, +}; pub struct InvestingPoolPrecompile(PhantomData); @@ -46,7 +45,7 @@ where ::RuntimeCall: From>, <::RuntimeCall as Dispatchable>::RuntimeOrigin: From>, - AssetBalanceOf: TryFrom + Into, + AssetIdOf: TryFrom + Into, BlockNumberFor: TryFrom + Into, BalanceOf: TryFrom + Into, { @@ -59,20 +58,21 @@ where ) -> EvmResult { let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); - let pool_proposal_index: u128 = pool_proposal_index.try_into().map_err(|_| { - Into::::into(RevertReason::value_is_too_large("index type")) - })?; + let pool_proposal_index: PoolProposalIndex = + pool_proposal_index.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; let epoch: u128 = epoch.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("epoch type")) })?; - let reward: AssetBalanceOf = reward.try_into().map_err(|_| { + let reward: BalanceOf = reward.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("balance type")) })?; let call = pallet_investing_pool::Call::::update_reward { - pool_proposal_index, + pool_id: pool_proposal_index, epoch, reward, }; @@ -89,7 +89,7 @@ where Into::::into(RevertReason::value_is_too_large("asset type")) })?; - let amount: AssetBalanceOf = amount.try_into().map_err(|_| { + let amount: BalanceOf = amount.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("balance type")) })?; @@ -110,7 +110,7 @@ where Into::::into(RevertReason::value_is_too_large("index type")) })?; handle.record_db_read::( - PoolSetting::>::max_encoded_len( + InvestingPoolSetting::>::max_encoded_len( ) .saturating_mul(length_usize), )?; @@ -118,6 +118,9 @@ where let mut setting_result = Vec::::new(); for index in pool_proposal_index.iter() { + let index: PoolProposalIndex = index.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; // get underlying investings if let Some(result) = pallet_investing_pool::Pallet::::investing_pool_setting(index) @@ -146,7 +149,7 @@ where pool_proposal_index: U256, ) -> EvmResult> { // Storage item: PoolSetting - handle.record_db_read::(PoolSetting::< + handle.record_db_read::(InvestingPoolSetting::< Runtime::AccountId, BlockNumberFor, BalanceOf, @@ -154,6 +157,11 @@ where let mut reward_result = Vec::::new(); let mut epoch = 0u128; + let pool_proposal_index: PoolProposalIndex = + pool_proposal_index.try_into().map_err(|_| { + Into::::into(RevertReason::value_is_too_large("index type")) + })?; + if let Some(result) = pallet_investing_pool::Pallet::::investing_pool_setting(pool_proposal_index) { @@ -170,11 +178,12 @@ where for i in 1..(epoch + 1) { if let Some(result) = pallet_investing_pool::Pallet::::stable_investing_pool_epoch_reward( - index, i, + pool_proposal_index, + i, ) { let admin: [u8; 32] = result.admin.into(); let admin = admin.into(); - setting_result.push(EpochReward { + reward_result.push(EpochReward { total_reward: result.0.into(), claimed_reward: result.1.into(), }); @@ -183,7 +192,7 @@ where break; } } - Ok(setting_result) + Ok(reward_result) } } From b4e1edbd1addc7fa573cb74e1e070818d3e2ba29 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 1 Dec 2024 20:13:57 +0800 Subject: [PATCH 205/215] chore: fix --- .../collab-ai/investing-pool/src/lib.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/parachain/precompiles/collab-ai/investing-pool/src/lib.rs b/parachain/precompiles/collab-ai/investing-pool/src/lib.rs index 9b8dc948c8..20997a426d 100644 --- a/parachain/precompiles/collab-ai/investing-pool/src/lib.rs +++ b/parachain/precompiles/collab-ai/investing-pool/src/lib.rs @@ -26,12 +26,10 @@ use parity_scale_codec::MaxEncodedLen; use precompile_utils::prelude::*; use sp_runtime::traits::Dispatchable; -use sp_core::{Get, H256, U256}; +use sp_core::{H256, U256}; use sp_std::{marker::PhantomData, vec::Vec}; -use pallet_collab_ai_common::{ - InvestingPoolAssetIdGenerator, PoolProposalIndex, PoolSetting as InvestingPoolSetting, -}; +use pallet_collab_ai_common::{PoolProposalIndex, PoolSetting as InvestingPoolSetting}; pub struct InvestingPoolPrecompile(PhantomData); @@ -110,7 +108,7 @@ where Into::::into(RevertReason::value_is_too_large("index type")) })?; handle.record_db_read::( - InvestingPoolSetting::>::max_encoded_len( + InvestingPoolSetting::, BalanceOf>::max_encoded_len( ) .saturating_mul(length_usize), )?; @@ -118,12 +116,12 @@ where let mut setting_result = Vec::::new(); for index in pool_proposal_index.iter() { - let index: PoolProposalIndex = index.try_into().map_err(|_| { + let index_u128: PoolProposalIndex = *index.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; // get underlying investings if let Some(result) = - pallet_investing_pool::Pallet::::investing_pool_setting(index) + pallet_investing_pool::Pallet::::investing_pool_setting(index_u128) { let admin: [u8; 32] = result.admin.into(); let admin = admin.into(); @@ -151,7 +149,7 @@ where // Storage item: PoolSetting handle.record_db_read::(InvestingPoolSetting::< Runtime::AccountId, - BlockNumberFor, + BlockNumberFor, BalanceOf, >::max_encoded_len())?; let mut reward_result = Vec::::new(); @@ -181,8 +179,6 @@ where pool_proposal_index, i, ) { - let admin: [u8; 32] = result.admin.into(); - let admin = admin.into(); reward_result.push(EpochReward { total_reward: result.0.into(), claimed_reward: result.1.into(), From 2f04c10bdb0a225c62d08355d71dbb53abddcbe1 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 1 Dec 2024 20:23:02 +0800 Subject: [PATCH 206/215] chore: fix --- parachain/pallets/collab-ai/common/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/common/src/lib.rs b/parachain/pallets/collab-ai/common/src/lib.rs index 7383b16c84..9a42b75236 100644 --- a/parachain/pallets/collab-ai/common/src/lib.rs +++ b/parachain/pallets/collab-ai/common/src/lib.rs @@ -88,7 +88,7 @@ pub trait ProposerQuery { fn is_proposer(account: AccountId, proposal_index: PoolProposalIndex) -> bool; } -#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, TypeInfo)] +#[derive(PartialEq, Eq, Clone, Encode, Debug, Decode, MaxEncodedLen, TypeInfo)] pub struct PoolSetting { // The start time of investing pool pub start_time: BlockNumber, From b1796a9ef215c05aed5cf6a301f6c4d4f6e14166 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 1 Dec 2024 20:35:42 +0800 Subject: [PATCH 207/215] chore: fix --- parachain/precompiles/collab-ai/investing-pool/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/precompiles/collab-ai/investing-pool/src/lib.rs b/parachain/precompiles/collab-ai/investing-pool/src/lib.rs index 20997a426d..ab09015d2b 100644 --- a/parachain/precompiles/collab-ai/investing-pool/src/lib.rs +++ b/parachain/precompiles/collab-ai/investing-pool/src/lib.rs @@ -116,7 +116,7 @@ where let mut setting_result = Vec::::new(); for index in pool_proposal_index.iter() { - let index_u128: PoolProposalIndex = *index.try_into().map_err(|_| { + let index_u128: PoolProposalIndex = index.clone().try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; // get underlying investings @@ -153,7 +153,7 @@ where BalanceOf, >::max_encoded_len())?; let mut reward_result = Vec::::new(); - let mut epoch = 0u128; + let mut epoch: u128; let pool_proposal_index: PoolProposalIndex = pool_proposal_index.try_into().map_err(|_| { From c7cff64ba86790767fa7d9af4bb6fea61ba3b7ef Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 1 Dec 2024 20:53:12 +0800 Subject: [PATCH 208/215] chore: fix --- .../collab-ai/pool-proposal/src/tests.rs | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 14cc39d820..1badf13f5f 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -211,16 +211,18 @@ fn test_withdraw_pre_investing_ok() { )); // pre investing and queued - assert_events(vec![RuntimeEvent::PoolProposal(crate::Event::PoolPreStakeQueued { - user: user_a.clone(), - pool_proposal_index: 1u128, - amount: 490_000_000_000_000_000_000u128, - })]); - assert_events(vec![RuntimeEvent::PoolProposal(crate::Event::PoolPreInvested { - user: user_a.clone(), - pool_proposal_index: 1u128, - amount: 5_000_000_000_000_000_000u128, - })]); + assert_events(vec![ + RuntimeEvent::PoolProposal(crate::Event::PoolPreInvested { + user: user_a.clone(), + pool_proposal_index: 1u128, + amount: 5_000_000_000_000_000_000u128, + }), + RuntimeEvent::PoolProposal(crate::Event::PoolPreStakeQueued { + user: user_a.clone(), + pool_proposal_index: 1u128, + amount: 490_000_000_000_000_000_000u128, + }), + ]); // Withdraw succeed assert_ok!(PoolProposal::withdraw_pre_investing( From e32055e9d534a7750e40cb3a7329febbd5b6cded Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 1 Dec 2024 20:55:30 +0800 Subject: [PATCH 209/215] chore: fix --- parachain/precompiles/collab-ai/investing-pool/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/precompiles/collab-ai/investing-pool/src/lib.rs b/parachain/precompiles/collab-ai/investing-pool/src/lib.rs index ab09015d2b..764e491d55 100644 --- a/parachain/precompiles/collab-ai/investing-pool/src/lib.rs +++ b/parachain/precompiles/collab-ai/investing-pool/src/lib.rs @@ -48,7 +48,7 @@ where BalanceOf: TryFrom + Into, { #[precompile::public("updateReward(uint256,uint256,uint256)")] - fn updateReward( + fn update_reward( handle: &mut impl PrecompileHandle, pool_proposal_index: U256, epoch: U256, @@ -153,7 +153,7 @@ where BalanceOf, >::max_encoded_len())?; let mut reward_result = Vec::::new(); - let mut epoch: u128; + let epoch: u128; let pool_proposal_index: PoolProposalIndex = pool_proposal_index.try_into().map_err(|_| { From 6a2265a7288822cdf843e4cf8a74b6e726f466ab Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 1 Dec 2024 21:09:45 +0800 Subject: [PATCH 210/215] chore: fix --- .../collab-ai/pool-proposal/src/mock.rs | 2 +- .../collab-ai/pool-proposal/src/tests.rs | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs index 888bff8e03..709862f087 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/mock.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/mock.rs @@ -140,7 +140,7 @@ impl pallet_balances::Config for Test { pub struct PreInvestingPool; impl Get for PreInvestingPool { fn get() -> AccountId32 { - AccountId32::new([1u8; 32]) + AccountId32::new([8u8; 32]) } } diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 1badf13f5f..a213661c81 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -230,11 +230,19 @@ fn test_withdraw_pre_investing_ok() { 1u128, 490_000_000_000_000_000_000u128, )); - assert_events(vec![RuntimeEvent::PoolProposal(crate::Event::PoolWithdrawed { - user: user_a.clone(), - pool_proposal_index: 1u128, - amount: 490_000_000_000_000_000_000u128, - })]); + assert_events(vec![ + RuntimeEvent::Assets(Event::Transferred { + asset_id: 1, + from: PreInvestingPool::get(), + to: user_a.clone(), + amount: 490_000_000_000_000_000_000, + }), + RuntimeEvent::PoolProposal(crate::Event::PoolWithdrawed { + user: user_a, + pool_proposal_index: 1u128, + amount: 490_000_000_000_000_000_000u128, + }), + ]); }) } From 1910a5a6958ff4201a73d84e46cec91ef7869ef9 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 1 Dec 2024 21:18:46 +0800 Subject: [PATCH 211/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index a213661c81..a6bf7e61fa 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -17,7 +17,7 @@ use crate::mock::*; use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; use pallet_balances::Error as BalanceError; -use sp_core::H256; +use sp_core::{Get, H256}; use sp_runtime::{AccountId32, ArithmeticError}; #[test] From ee483cc38b2375d2612aa7e486516b4fd9191166 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 1 Dec 2024 21:28:08 +0800 Subject: [PATCH 212/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index a6bf7e61fa..1353058f49 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -231,7 +231,7 @@ fn test_withdraw_pre_investing_ok() { 490_000_000_000_000_000_000u128, )); assert_events(vec![ - RuntimeEvent::Assets(Event::Transferred { + RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id: 1, from: PreInvestingPool::get(), to: user_a.clone(), From 41409c091ad9a593122dbda3dae10f69a68643ce Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 1 Dec 2024 21:44:29 +0800 Subject: [PATCH 213/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/tests.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 1353058f49..2a21511248 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -231,17 +231,17 @@ fn test_withdraw_pre_investing_ok() { 490_000_000_000_000_000_000u128, )); assert_events(vec![ + RuntimeEvent::PoolProposal(crate::Event::PoolWithdrawed { + user: user_a, + pool_proposal_index: 1u128, + amount: 490_000_000_000_000_000_000u128, + }), RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id: 1, from: PreInvestingPool::get(), to: user_a.clone(), amount: 490_000_000_000_000_000_000, }), - RuntimeEvent::PoolProposal(crate::Event::PoolWithdrawed { - user: user_a, - pool_proposal_index: 1u128, - amount: 490_000_000_000_000_000_000u128, - }), ]); }) } From c2b354297d2f44cfa6161cce59f50fe14a5a16e7 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 1 Dec 2024 21:53:46 +0800 Subject: [PATCH 214/215] chore: fix --- parachain/pallets/collab-ai/pool-proposal/src/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs index 2a21511248..e6b4594315 100644 --- a/parachain/pallets/collab-ai/pool-proposal/src/tests.rs +++ b/parachain/pallets/collab-ai/pool-proposal/src/tests.rs @@ -232,14 +232,14 @@ fn test_withdraw_pre_investing_ok() { )); assert_events(vec![ RuntimeEvent::PoolProposal(crate::Event::PoolWithdrawed { - user: user_a, + user: user_a.clone(), pool_proposal_index: 1u128, amount: 490_000_000_000_000_000_000u128, }), RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id: 1, from: PreInvestingPool::get(), - to: user_a.clone(), + to: user_a, amount: 490_000_000_000_000_000_000, }), ]); From 6317d2d63219860136eaeb9a877d5048fbad4f37 Mon Sep 17 00:00:00 2001 From: Minqi Wang Date: Sun, 1 Dec 2024 22:18:56 +0800 Subject: [PATCH 215/215] chore: fix --- parachain/precompiles/collab-ai/investing-pool/src/lib.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/parachain/precompiles/collab-ai/investing-pool/src/lib.rs b/parachain/precompiles/collab-ai/investing-pool/src/lib.rs index 764e491d55..064522493d 100644 --- a/parachain/precompiles/collab-ai/investing-pool/src/lib.rs +++ b/parachain/precompiles/collab-ai/investing-pool/src/lib.rs @@ -104,9 +104,7 @@ where pool_proposal_index: Vec, ) -> EvmResult> { // Storage item: PoolSetting - let length_usize: usize = pool_proposal_index.len().try_into().map_err(|_| { - Into::::into(RevertReason::value_is_too_large("index type")) - })?; + let length_usize: usize = pool_proposal_index.len(); handle.record_db_read::( InvestingPoolSetting::, BalanceOf>::max_encoded_len( ) @@ -116,7 +114,7 @@ where let mut setting_result = Vec::::new(); for index in pool_proposal_index.iter() { - let index_u128: PoolProposalIndex = index.clone().try_into().map_err(|_| { + let index_u128: PoolProposalIndex = (*index).try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?; // get underlying investings @@ -163,7 +161,7 @@ where if let Some(result) = pallet_investing_pool::Pallet::::investing_pool_setting(pool_proposal_index) { - epoch = result.epoch.into(); + epoch = result.epoch; let length_usize: usize = epoch.try_into().map_err(|_| { Into::::into(RevertReason::value_is_too_large("index type")) })?;