Skip to content

Commit

Permalink
Merge pull request #160 from Fair-Squares/126-implement-asset-distrib…
Browse files Browse the repository at this point in the history
…utor-pallet-fungible-+-config-shares-that-get-minted

126 implement asset distributor pallet fungible + config shares that get minted
  • Loading branch information
ndkazu authored Sep 22, 2022
2 parents 83febc5 + 2271783 commit 703c22a
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 33 deletions.
1 change: 1 addition & 0 deletions pallets/share_distributor/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[package]
name = "pallet-share_distributor"
version = "4.0.0-dev"
description = "Distribute to the asset new owners/contributors, the ownership nft, and the ownership token"
authors = ["Fair Squares"]
homepage = "https://fair-squares.nl"
edition = "2021"
Expand Down
19 changes: 16 additions & 3 deletions pallets/share_distributor/src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use super::*;
use enum_iterator::all;

impl<T: Config> Pallet<T> {

///The function below create a virtual account from the NFT collection and item id's
pub fn virtual_account(collection_id: T::NftCollectionId, item_id: T::NftItemId) -> DispatchResult {
//Create virtual account
let text0 = format!("{:?}_{:?}_account",collection_id,item_id.clone());
Expand All @@ -33,6 +35,7 @@ pub fn virtual_account(collection_id: T::NftCollectionId, item_id: T::NftItemId)
Ok(())
}

///This function executes all actions relatives to nft transfer from the seller to the virtual account
pub fn nft_transaction(collection_id: T::NftCollectionId, item_id: T::NftItemId,virtual_id:T::AccountId) -> DispatchResult {

//Get collection
Expand All @@ -52,6 +55,7 @@ Ok(())

}

///Collect contributors to the bid, and their shares
pub fn owner_and_shares(collection_id: T::NftCollectionId, item_id: T::NftItemId) -> Vec<(T::AccountId, Percent)>{

//Get owners and their reserved contribution to the bid
Expand All @@ -66,23 +70,31 @@ pub fn owner_and_shares(collection_id: T::NftCollectionId, item_id: T::NftItemId
let share = Percent::from_rational(contribution,price0);
debug_assert!(!share.is_zero());
vec.push((i.0.clone(),share));
//Update Virtual_account storage
Virtual::<T>::mutate(collection_id.clone(),item_id.clone(),|val|{
let mut val0 = val.clone().unwrap();
val0.owners.push(i.0.clone());
*val = Some(val0);

});

}
vec
}



///Create 100 Ownership tokens owned by a virtual account
pub fn create_tokens(origin: OriginFor<T>,collection_id: T::NftCollectionId, item_id: T::NftItemId,account: T::AccountId) -> DispatchResult{

//Get token class Id:
ensure!(Virtual::<T>::get(collection_id,item_id).is_some(),Error::<T>::InvalidValue);
let token_id = Virtual::<T>::get(collection_id,item_id).unwrap().token_id;
let to = T::Lookup::unlookup(account.clone());
TokenId::<T>::mutate(|val|{
let val0 = val.clone();
*val = val0+1;
});
ensure!(Virtual::<T>::get(collection_id,item_id).is_some(),Error::<T>::InvalidValue);
let token_id = Virtual::<T>::get(collection_id,item_id).unwrap().token_id;


//Create token class
let res = Assets::Pallet::<T>::force_create(origin.clone(),token_id.clone().into(),to.clone(),false,One::one());
Expand All @@ -99,6 +111,7 @@ pub fn create_tokens(origin: OriginFor<T>,collection_id: T::NftCollectionId, ite

}

///Distribute the ownership tokens to the group of new owners
pub fn distribute_tokens(account:T::AccountId,collection_id: T::NftCollectionId, item_id: T::NftItemId) -> DispatchResult{
let shares = Self::owner_and_shares(collection_id.clone(),item_id.clone());
ensure!(Virtual::<T>::get(collection_id,item_id).is_some(),Error::<T>::InvalidValue);
Expand Down
45 changes: 40 additions & 5 deletions pallets/share_distributor/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
#![cfg_attr(not(feature = "std"), no_std)]
//! # Share_Distributor Pallet
//!
//! The Share_Distributor Pallet is called by the Bidding Pallet
//! after a Finalised bid was identified on-chain.
//! It will distribute to the asset new owners, the ownership nft, and the ownership token
//! connected to the asset at the center of the transaction.
//!
//! ## Overview
//!
//! The On boarding Pallet fulfill the following tasks:
//! - Create a virtual account which will hold the nft
//! - Connect the Virtual account to the new owners/contributors
//! through the use of a storage/struct
//! - Execute the Nft transaction between Seller and Virtual account
//! - Mint 100 Ownership Tokens, which represent the asset share of
//! each owner
//! - Distribute the ownership tokens to the new owners.
//!
//! Dispatchable Functions
//!
//! * `create_virtual` - Will sequencially execute each of the steps
//! described in the Overview.

#![cfg_attr(not(feature = "std"), no_std)]

pub use pallet::*;
pub use pallet_assets as Assets;
Expand Down Expand Up @@ -88,6 +111,11 @@ pub mod pallet {
nft_transfer_to: T::AccountId,
nft_transfer_from: T::AccountId,
when: BlockNumberOf<T>
},
OwnershipTokensDistributed{
from: T::AccountId,
to: Vec<T::AccountId>,
token_id:<T as pallet::Config>::AssetId,
}

}
Expand Down Expand Up @@ -127,7 +155,7 @@ pub mod pallet {
Self::distribute_tokens(account.clone(),collection_id.clone(),item_id.clone()).ok();


// Emit an event.
// Emit some events.
let created = <frame_system::Pallet<T>>::block_number();
Self::deposit_event(Event::VirtualCreated{
account: account.clone(),
Expand All @@ -136,13 +164,20 @@ pub mod pallet {
when: created.clone(),
});

//Emit another event
Self::deposit_event(Event::NftTransactionExecuted{
nft_transfer_to: account,
nft_transfer_from: seller,
nft_transfer_to: account.clone(),
nft_transfer_from: seller.clone(),
when: created
});

let new_owners = Self::virtual_acc(collection_id.clone(),item_id.clone()).unwrap().owners;
let token_id = Self::virtual_acc(collection_id.clone(),item_id.clone()).unwrap().token_id;
Self::deposit_event(Event::OwnershipTokensDistributed{
from: account.clone(),
to: new_owners,
token_id: token_id,
});

Ok(())
}

Expand Down
120 changes: 95 additions & 25 deletions pallets/share_distributor/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ pub use crate::mock::*;
pub use frame_support::{assert_noop, assert_ok};
use frame_system::pallet_prelude::OriginFor;

pub type Bvec<Test> = BoundedVec<u8, <Test as pallet_uniques::Config>::StringLimit>;

pub fn prep_roles() {
RoleModule::set_role(Origin::signed(CHARLIE).clone(), CHARLIE, Acc::SERVICER).ok();
RoleModule::account_approval(Origin::signed(ALICE), CHARLIE).ok();
Expand All @@ -19,21 +21,11 @@ pub fn prep_roles() {
RoleModule::account_approval(Origin::signed(ALICE), ACCOUNT_WITH_NO_BALANCE0).ok();
}

#[test]
fn virtual0(){
ExtBuilder::default().build().execute_with(|| {
let metadata0: BoundedVec<u8, <Test as pallet_uniques::Config>::StringLimit> =
b"metadata0".to_vec().try_into().unwrap();
let metadata1: BoundedVec<u8, <Test as pallet_uniques::Config>::StringLimit> =
b"metadata1".to_vec().try_into().unwrap();
let metadata2: BoundedVec<u8, <Test as pallet_uniques::Config>::StringLimit> =
b"metadata2".to_vec().try_into().unwrap();
pub fn prep_test(price1:u64,price2:u64, metadata0:Bvec<Test>,metadata1:Bvec<Test>,metadata2:Bvec<Test>){

prep_roles();

//put some funds in FairSquare SlashFees account
let fees_account = Onboarding::Pallet::<Test>::account_id();
<Test as pallet::Config>::Currency::make_free_balance_be(&fees_account,150_000u32.into());


//Dave and EVE contribute to the fund
assert_ok!(HousingFund::Pallet::<Test>::contribute_to_fund(Origin::signed(DAVE),50_000));
assert_ok!(HousingFund::Pallet::<Test>::contribute_to_fund(Origin::signed(EVE),50_000));
Expand All @@ -51,17 +43,40 @@ fn virtual0(){
metadata0
));
// Bob creates a proposal without submiting for review
let price = 40_000;

assert_ok!(OnboardingModule::create_and_submit_proposal(
Origin::signed(BOB),
NftColl::OFFICESTEST,
Some(price.clone()),
Some(price1.clone()),
metadata1,
false
));


assert_ok!(OnboardingModule::create_and_submit_proposal(
Origin::signed(BOB),
NftColl::APPARTMENTSTEST,
Some(price2.clone()),
metadata2,
false
));

}


#[test]
fn share_distributor0(){
ExtBuilder::default().build().execute_with(|| {

let metadata0 = b"metadata0".to_vec().try_into().unwrap();
let metadata1 = b"metadata1".to_vec().try_into().unwrap();
let metadata2 = b"metadata2".to_vec().try_into().unwrap();
//put some funds in FairSquare SlashFees account
let fees_account = Onboarding::Pallet::<Test>::account_id();
<Test as pallet::Config>::Currency::make_free_balance_be(&fees_account,150_000u32.into());

let price1 = 40_000;
let price2 = 30_000;
prep_test(price1.clone(),price2.clone(),metadata0,metadata1,metadata2);
let coll_id0 = NftColl::OFFICESTEST.value();
let item_id0 = pallet_nft::ItemsCount::<Test>::get()[coll_id0 as usize] - 1;
let origin: OriginFor<Test> = frame_system::RawOrigin::Root.into();
Expand Down Expand Up @@ -89,7 +104,7 @@ fn virtual0(){
let fund_op = HousingFund::FundOperation{
nft_collection_id: coll_id0.clone(),
nft_item_id: item_id0.clone(),
amount: price.clone(),
amount: price1.clone(),
block_number:1,
contributions:vec![(EVE,25_000),(DAVE,15_000)],
};
Expand All @@ -100,6 +115,7 @@ fn virtual0(){
//Create token
assert_ok!(ShareDistributor::create_tokens(origin.clone(),coll_id0.clone(),item_id0.clone(),new_owner0.clone()));
assert_eq!(1,ShareDistributor::token_id());
assert_eq!(0,ShareDistributor::virtual_acc(coll_id0.clone(),item_id0.clone()).unwrap().token_id);
assert_eq!(100,Assets::Pallet::<Test>::total_supply(id.clone()));

//Check that new_owner0 is in possession of 100 tokens
Expand All @@ -114,15 +130,8 @@ fn virtual0(){
println!("Tokens own by DAVE:{:?}\nTokens own by Eve:{:?}",balance0,balance1);

// Bob creates a second proposal without submiting for review
let price = 30_000;

assert_ok!(OnboardingModule::create_and_submit_proposal(
Origin::signed(BOB),
NftColl::APPARTMENTSTEST,
Some(price.clone()),
metadata2,
false
));



let coll_id1 = NftColl::APPARTMENTSTEST.value();
Expand Down Expand Up @@ -160,4 +169,65 @@ fn virtual0(){


});
}

#[test]
fn share_distributor1(){
ExtBuilder::default().build().execute_with(|| {
let metadata0 = b"metadata0".to_vec().try_into().unwrap();
let metadata1 = b"metadata1".to_vec().try_into().unwrap();
let metadata2 = b"metadata2".to_vec().try_into().unwrap();
//put some funds in FairSquare SlashFees account
let fees_account = Onboarding::Pallet::<Test>::account_id();
<Test as pallet::Config>::Currency::make_free_balance_be(&fees_account,150_000u32.into());

let price1 = 40_000;
let price2 = 30_000;
prep_test(price1.clone(),price2.clone(),metadata0,metadata1,metadata2);
let coll_id0 = NftColl::OFFICESTEST.value();
let item_id0 = pallet_nft::ItemsCount::<Test>::get()[coll_id0 as usize] - 1;
let origin: OriginFor<Test> = frame_system::RawOrigin::Root.into();
let origin2 = Origin::signed(BOB);

//Create a FundOperation struct for this asset
let fund_op = HousingFund::FundOperation{
nft_collection_id: coll_id0.clone(),
nft_item_id: item_id0.clone(),
amount: price1.clone(),
block_number:1,
contributions:vec![(EVE,25_000),(DAVE,15_000)],
};

//Add new owners and asset to housing fund
HousingFund::Reservations::<Test>::insert((coll_id0.clone(),item_id0.clone()),fund_op);

//Change first asset status to FINALISED
Onboarding::Pallet::<Test>::change_status(origin2.clone(),NftColl::OFFICESTEST,item_id0.clone(),Onboarding::AssetStatus::FINALISED).ok();

//Store initial owner
let old_owner0 = pallet_nft::Pallet::<Test>::owner(coll_id0.clone(),item_id0.clone()).unwrap();

assert_ok!(ShareDistributor::create_virtual(origin.clone(),coll_id0.clone(),item_id0.clone()));
let when = <frame_system::Pallet<Test>>::block_number();
let new_owner0 = ShareDistributor::virtual_acc(coll_id0.clone(),item_id0.clone()).unwrap().virtual_account;
let owners = ShareDistributor::virtual_acc(coll_id0.clone(),item_id0.clone()).unwrap().owners;
assert_eq!(owners.len()>1,true);
expect_events(vec![
crate::Event::VirtualCreated {
account: new_owner0.clone(),
collection: coll_id0.clone(),
item: item_id0.clone(),
when: when,
}
.into(),
crate::Event::NftTransactionExecuted {
nft_transfer_to: new_owner0.clone(),
nft_transfer_from: old_owner0.clone(),
when: when,
}
.into()
]);


})
}

0 comments on commit 703c22a

Please sign in to comment.