Skip to content

Commit

Permalink
feat: NFT Origins in INV4
Browse files Browse the repository at this point in the history
  • Loading branch information
arrudagates committed Sep 4, 2023
1 parent 785f18d commit c4d400f
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 31 deletions.
1 change: 1 addition & 0 deletions INV4/pallet-inv4/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ log = { version = "0.4.14", default-features = false }

# InvArch dependencies
primitives = { package = "invarch-primitives", path = "../../primitives", default-features = false }
pallet-nft-origins = { path = "../../pallet-nft-origins", default-features = false }

sp-io = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v0.9.43" }
sp-core = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v0.9.43" }
Expand Down
2 changes: 1 addition & 1 deletion INV4/pallet-inv4/src/fee_handling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub trait MultisigFeeHandler<T: Config> {

fn handle_creation_fee(
imbalance: FeeAssetNegativeImbalance<
<T::Currency as Currency<T::AccountId>>::NegativeImbalance,
<<T as Config>::Currency as Currency<T::AccountId>>::NegativeImbalance,
Credit<T::AccountId, T::Tokens>,
>,
);
Expand Down
28 changes: 23 additions & 5 deletions INV4/pallet-inv4/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ pub mod pallet {

use crate::{
fee_handling::MultisigFeeHandler,
multisig::{MultisigMember, MultisigMemberOf},
voting::{Tally, VoteRecord},
};

Expand Down Expand Up @@ -87,7 +88,9 @@ pub mod pallet {
pub type CallOf<T> = <T as Config>::RuntimeCall;

#[pallet::config]
pub trait Config: frame_system::Config + pallet_balances::Config {
pub trait Config:
frame_system::Config + pallet_balances::Config + pallet_nft_origins::Config
{
/// The IPS Pallet Events
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
/// The IPS ID type
Expand Down Expand Up @@ -251,7 +254,7 @@ pub mod pallet {
MultisigVoteAdded {
core_id: T::CoreId,
executor_account: T::AccountId,
voter: T::AccountId,
voter: MultisigMemberOf<T>,
votes_added: VoteRecord<T>,
current_votes: Tally<T>,
call_hash: T::Hash,
Expand All @@ -269,7 +272,7 @@ pub mod pallet {
MultisigExecuted {
core_id: T::CoreId,
executor_account: T::AccountId,
voter: T::AccountId,
voter: MultisigMemberOf<T>,
call_hash: T::Hash,
call: CallOf<T>,
result: DispatchResult,
Expand Down Expand Up @@ -321,6 +324,7 @@ pub mod pallet {
INV4Origin<T, <T as pallet::Config>::CoreId, <T as frame_system::Config>::AccountId>,
<T as frame_system::Config>::RuntimeOrigin,
>: From<<T as frame_system::Config>::RuntimeOrigin>,
Result<pallet_nft_origins::origin::NftOrigin, <T as frame_system::Config>::RuntimeOrigin>: From<<T as frame_system::Config>::RuntimeOrigin>,
<<T as pallet::Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance: Sum,
{
/// Create IP (Intellectual Property) Set (IPS)
Expand Down Expand Up @@ -354,7 +358,7 @@ pub mod pallet {
pub fn token_mint(
origin: OriginFor<T>,
amount: BalanceOf<T>,
target: T::AccountId,
target: MultisigMemberOf<T>,
) -> DispatchResult {
Pallet::<T>::inner_token_mint(origin, amount, target)
}
Expand All @@ -365,7 +369,7 @@ pub mod pallet {
pub fn token_burn(
origin: OriginFor<T>,
amount: BalanceOf<T>,
target: T::AccountId,
target: MultisigMemberOf<T>,
) -> DispatchResult {
Pallet::<T>::inner_token_burn(origin, amount, target)
}
Expand Down Expand Up @@ -395,6 +399,20 @@ pub mod pallet {
call_hash: T::Hash,
aye: bool,
) -> DispatchResultWithPostInfo {
let caller = MultisigMember::AccountId(ensure_signed(caller)?);
Pallet::<T>::inner_vote_multisig(caller, core_id, call_hash, aye)
}

#[pallet::call_index(10)]
#[pallet::weight(1)]
pub fn nft_vote_multisig(
origin: OriginFor<T>,
core_id: T::CoreId,
call_hash: T::Hash,
aye: bool,
) -> DispatchResultWithPostInfo {
let caller = MultisigMember::Nft(pallet_nft_origins::origin::ensure_nft::<T, OriginFor<T>>(origin)?);

Pallet::<T>::inner_vote_multisig(caller, core_id, call_hash, aye)
}

Expand Down
61 changes: 44 additions & 17 deletions INV4/pallet-inv4/src/multisig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::{
util::derive_core_account,
voting::{Tally, Vote},
};
use codec::Decode;
use core::{
convert::{TryFrom, TryInto},
iter::Sum,
Expand Down Expand Up @@ -34,7 +35,7 @@ pub type BoundedCallBytes<T> = BoundedVec<u8, <T as Config>::MaxCallSize>;
#[derive(Clone, Encode, Decode, RuntimeDebug, MaxEncodedLen, TypeInfo, PartialEq, Eq)]
pub struct MultisigOperation<AccountId, TallyOf, Call, Metadata> {
pub tally: TallyOf,
pub original_caller: AccountId,
pub original_caller: MultisigMember<AccountId>,
pub actual_call: Call,
pub metadata: Option<Metadata>,
pub fee_asset: FeeAsset,
Expand All @@ -47,6 +48,25 @@ pub type MultisigOperationOf<T> = MultisigOperation<
BoundedVec<u8, <T as pallet::Config>::MaxMetadata>,
>;

#[derive(
Clone, Encode, Decode, RuntimeDebug, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord,
)]
pub enum MultisigMember<AccountId> {
AccountId(AccountId),
Nft(pallet_nft_origins::location::NftLocation),
}

impl<AccountId: Decode> MultisigMember<AccountId> {
pub fn account(self) -> AccountId {
match self {
Self::AccountId(account_id) => account_id,
Self::Nft(nft_location) => nft_location.derive_account::<AccountId>(),
}
}
}

pub type MultisigMemberOf<T> = MultisigMember<<T as frame_system::Config>::AccountId>;

impl<T: Config> Pallet<T>
where
Result<
Expand All @@ -59,16 +79,18 @@ where
pub(crate) fn inner_token_mint(
origin: OriginFor<T>,
amount: BalanceOf<T>,
target: T::AccountId,
target: MultisigMemberOf<T>,
) -> DispatchResult {
let core_origin = ensure_multisig::<T, OriginFor<T>>(origin)?;
let core_id = core_origin.id;

T::AssetsProvider::mint_into(core_id, &target, amount)?;
let target_account = target.account();

T::AssetsProvider::mint_into(core_id, &target_account, amount)?;

Self::deposit_event(Event::Minted {
core_id,
target,
target: target_account,
amount,
});

Expand All @@ -79,22 +101,24 @@ where
pub(crate) fn inner_token_burn(
origin: OriginFor<T>,
amount: BalanceOf<T>,
target: T::AccountId,
target: MultisigMemberOf<T>,
) -> DispatchResult {
let core_origin = ensure_multisig::<T, OriginFor<T>>(origin)?;
let core_id = core_origin.id;

let target_account = target.account();

T::AssetsProvider::burn_from(
core_id,
&target,
&target_account,
amount,
Precision::Exact,
Fortitude::Polite,
)?;

Self::deposit_event(Event::Burned {
core_id,
target,
target: target_account,
amount,
});

Expand Down Expand Up @@ -140,7 +164,7 @@ where
<T as Config>::CoreId,
<T as frame_system::Config>::AccountId,
>(core_id),
voter: owner,
voter: MultisigMember::AccountId(owner),
call_hash,
call: *call,
result: dispatch_result.map(|_| ()).map_err(|e| e.error),
Expand All @@ -160,12 +184,12 @@ where
owner_balance,
Zero::zero(),
BoundedBTreeMap::try_from(BTreeMap::from([(
owner.clone(),
MultisigMember::AccountId(owner.clone()),
Vote::Aye(owner_balance),
)]))
.map_err(|_| Error::<T>::MaxCallersExceeded)?,
),
original_caller: owner.clone(),
original_caller: MultisigMember::AccountId(owner.clone()),
actual_call: bounded_call,
metadata,
fee_asset,
Expand All @@ -190,15 +214,16 @@ where

/// Vote on a multisig transaction that has not been executed yet
pub(crate) fn inner_vote_multisig(
caller: OriginFor<T>,
caller: MultisigMemberOf<T>,
core_id: T::CoreId,
call_hash: T::Hash,
aye: bool,
) -> DispatchResultWithPostInfo {
Multisig::<T>::try_mutate_exists(core_id, call_hash, |data| {
let owner = ensure_signed(caller.clone())?;
//let owner = ensure_signed(caller.clone())?;
let caller_account = caller.clone().account();

let voter_balance: BalanceOf<T> = T::AssetsProvider::balance(core_id, &owner);
let voter_balance: BalanceOf<T> = T::AssetsProvider::balance(core_id, &caller_account);

ensure!(!voter_balance.is_zero(), Error::<T>::NoPermission);

Expand All @@ -216,7 +241,7 @@ where

old_data
.tally
.process_vote(owner.clone(), Some(new_vote_record))?;
.process_vote(caller.clone(), Some(new_vote_record))?;

let support = old_data.tally.support(core_id);
let approval = old_data.tally.approval(core_id);
Expand All @@ -242,7 +267,7 @@ where
<T as Config>::CoreId,
<T as frame_system::Config>::AccountId,
>(core_id),
voter: owner,
voter: caller,
call_hash,
call: decoded_call,
result: dispatch_result.map(|_| ()).map_err(|e| e.error),
Expand All @@ -257,7 +282,7 @@ where
<T as Config>::CoreId,
<T as frame_system::Config>::AccountId,
>(core_id),
voter: owner,
voter: caller,
votes_added: new_vote_record,
current_votes: old_data.tally,
call_hash,
Expand All @@ -279,7 +304,9 @@ where

let mut old_data = data.take().ok_or(Error::<T>::MultisigCallNotFound)?;

let old_vote = old_data.tally.process_vote(owner.clone(), None)?;
let old_vote = old_data
.tally
.process_vote(MultisigMember::AccountId(owner.clone()), None)?;

*data = Some(old_data.clone());

Expand Down
11 changes: 7 additions & 4 deletions INV4/pallet-inv4/src/voting.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::{origin::INV4Origin, BalanceOf, Config, CoreStorage, Error, Multisig, Pallet};
use crate::{
multisig::MultisigMemberOf, origin::INV4Origin, BalanceOf, Config, CoreStorage, Error,
Multisig, Pallet,
};
use codec::{Decode, Encode, HasCompact, MaxEncodedLen};
use core::marker::PhantomData;
use frame_support::{
Expand Down Expand Up @@ -33,15 +36,15 @@ pub type Core<T> = <T as Config>::CoreId;
pub struct Tally<T: Config> {
pub ayes: Votes<T>,
pub nays: Votes<T>,
pub records: BoundedBTreeMap<T::AccountId, Vote<Votes<T>>, T::MaxCallers>,
pub records: BoundedBTreeMap<MultisigMemberOf<T>, Vote<Votes<T>>, T::MaxCallers>,
dummy: PhantomData<T>,
}

impl<T: Config> Tally<T> {
pub fn from_parts(
ayes: Votes<T>,
nays: Votes<T>,
records: BoundedBTreeMap<T::AccountId, Vote<Votes<T>>, T::MaxCallers>,
records: BoundedBTreeMap<MultisigMemberOf<T>, Vote<Votes<T>>, T::MaxCallers>,
) -> Self {
Tally {
ayes,
Expand All @@ -53,7 +56,7 @@ impl<T: Config> Tally<T> {

pub fn process_vote(
&mut self,
account: T::AccountId,
account: MultisigMemberOf<T>,
maybe_vote: Option<Vote<Votes<T>>>,
) -> Result<Vote<Votes<T>>, DispatchError> {
let votes = if let Some(vote) = maybe_vote {
Expand Down
10 changes: 10 additions & 0 deletions pallet-nft-origins/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,5 +204,15 @@ pub mod pallet {

Ok(())
}

#[pallet::call_index(93)]
#[pallet::weight(1)]
pub fn test_dispatch_locally_as_nft(
_: OriginFor<T>,
nft_location: NftLocation,
call: Box<<T as Config>::RuntimeCall>,
) -> DispatchResultWithPostInfo {
(*call).dispatch(NftOrigin::Nft(nft_location).into())
}
}
}
16 changes: 12 additions & 4 deletions pallet-nft-origins/src/location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use sp_io::hashing::blake2_256;
use sp_runtime::traits::TrailingZeroInput;
use xcm::latest::Junction;

#[derive(PartialEq, Eq, Encode, Decode, TypeInfo, MaxEncodedLen, Clone, RuntimeDebug)]
#[derive(
PartialEq, Eq, Encode, Decode, TypeInfo, MaxEncodedLen, Clone, RuntimeDebug, PartialOrd, Ord,
)]
pub struct Parachain(pub u32);

impl Parachain {
Expand All @@ -26,7 +28,9 @@ impl Parachain {
}
}

#[derive(PartialEq, Eq, Encode, Decode, TypeInfo, MaxEncodedLen, Clone, RuntimeDebug)]
#[derive(
PartialEq, Eq, Encode, Decode, TypeInfo, MaxEncodedLen, Clone, RuntimeDebug, PartialOrd, Ord,
)]
#[repr(u8)]
pub enum Collection {
/// Pallet based NFT collection
Expand All @@ -37,7 +41,9 @@ pub enum Collection {
Contract32([u8; 32]) = 2,
}

#[derive(PartialEq, Eq, Encode, Decode, TypeInfo, MaxEncodedLen, Clone, RuntimeDebug)]
#[derive(
PartialEq, Eq, Encode, Decode, TypeInfo, MaxEncodedLen, Clone, RuntimeDebug, PartialOrd, Ord,
)]
#[repr(u8)]
pub enum Nft {
/// U128 NFT id
Expand All @@ -50,7 +56,9 @@ pub enum Nft {
Key32([u8; 32]) = 3,
}

#[derive(PartialEq, Eq, Encode, Decode, TypeInfo, MaxEncodedLen, Clone, RuntimeDebug)]
#[derive(
PartialEq, Eq, Encode, Decode, TypeInfo, MaxEncodedLen, Clone, RuntimeDebug, PartialOrd, Ord,
)]
pub struct NftLocation {
/// Chain where the collection and NFT originate
pub chain: Parachain,
Expand Down

0 comments on commit c4d400f

Please sign in to comment.