Skip to content

Commit

Permalink
Merge pull request #242 from Fair-Squares/233-tenancy-pallet
Browse files Browse the repository at this point in the history
Rent distribution
  • Loading branch information
ndkazu authored Feb 13, 2023
2 parents 913468b + 6c56048 commit 6209de6
Show file tree
Hide file tree
Showing 11 changed files with 185 additions and 24 deletions.
104 changes: 101 additions & 3 deletions pallets/asset_management/src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,20 @@ impl<T: Config> Pallet<T> {
Ok(())
}

pub fn owners_infos(asset_account: T::AccountId) -> Option<Share::Ownership<T>> {
//Find the asset in Share Distributor using asset account
let assets = Share::Virtual::<T>::iter_keys();
let mut infos = None;
for (i, j) in assets {
let ownership = Share::Pallet::<T>::virtual_acc(i, j).unwrap();
if asset_account.clone() == ownership.virtual_account {
//Get the owners
infos = Some(ownership);
}
}
infos
}

pub fn tenant_link_asset(
tenant: T::AccountId,
collection: T::NftCollectionId,
Expand Down Expand Up @@ -258,6 +272,7 @@ impl<T: Config> Pallet<T> {
///with the amount that has been actually paid.
///If the balance of the Tenant is negative, an event is emitted to notify him of his debt,
///If not, nothing happens.
///It will also distribute payed rent to the owners, according to their share.
pub fn finish_block(now: T::BlockNumber) -> Weight {
if (now % <T as Config>::CheckPeriod::get()).is_zero() {
//get list of tenants
Expand All @@ -268,9 +283,11 @@ impl<T: Config> Pallet<T> {
let time = <T as Config>::Lease::get();
let remaining_p = tenant.remaining_payments;
let contract_begin = tenant.contract_start;
let rent =
Roles::Pallet::<T>::balance_to_u128_option(tenant.rent).unwrap() * time as u128;
let rent = Roles::Pallet::<T>::balance_to_u128_option(tenant.rent).unwrap()
* time as u128;
let rent_float = rent as f64;
let rent0 =
Roles::Pallet::<T>::balance_to_u128_option(tenant.rent).unwrap() as u128;

//Calculate rent per block
let total_blocks = <T as Config>::ContractLength::get();
Expand All @@ -285,11 +302,92 @@ impl<T: Config> Pallet<T> {

//check how many rents were payed
let payed = (time as u128 - remaining_p as u128) * rent.clone();
let asset_account = tenant.asset_account.unwrap();
let asset_account_free_balance =
<T as Config>::Currency::free_balance(&asset_account);

let infos = Self::owners_infos(asset_account.clone()).unwrap();

//Distribute rent to owners if number of rents
//awaiting for distribution is greater than 0
if infos.rent_nbr > 0 {
//Get owners list

let owners = infos.owners;
let rent1 = Self::u128_to_balance_option2(rent0.clone()).unwrap();

//Get Asset_tokens infos
let token_id = infos.token_id;
let total_issuance =
Assetss::Pallet::<T>::total_supply(token_id.clone().into());
let total_issuance_float =
Self::balance_to_u128_option(total_issuance).unwrap() as f64;

//Remove maintenance fees from rent and convert it to f64
let maintenance = T::Maintenance::get() * rent1.clone();
let distribute = rent1.saturating_sub(maintenance.clone());

//Get the total amount to distribute
let distribute_float = (Self::balance_to_u128_option1(distribute.clone())
.unwrap() * infos.rent_nbr as u128) as f64;

debug_assert!(distribute.clone() > Zero::zero());
debug_assert!(distribute.clone() < rent1.clone());
debug_assert!(maintenance.clone() < asset_account_free_balance);

//Reserve maintenance fees
let reservation =
<T as Config>::Currency::reserve(&asset_account, maintenance.into());

debug_assert!(reservation.is_ok());

//Now distribute rent between owners according to their share
for i in owners.clone() {
//Get owner's share: we divide
//the owner's tokens by the total token issuance, and multiply the result by
//the total amount to be distributed.
let share = Assetss::Pallet::<T>::balance(token_id.clone().into(), &i);
let share_float = Self::balance_to_u128_option(share).unwrap() as f64
/ total_issuance_float;
let amount_float = share_float * distribute_float.clone();
let amount =
Self::u128_to_balance_option2(amount_float as u128).unwrap();
<T as Config>::Currency::transfer(
&asset_account,
&i,
amount,
ExistenceRequirement::AllowDeath,
)
.ok();
}

//Emmit rent distribution event
Self::deposit_event(Event::RentDistributed {
owners,
amount: distribute,
when: now,
});

//Now return the awaiting payment number to 0
let ownership_infos = Share::Virtual::<T>::iter_keys();
for (i, j) in ownership_infos {
let infos = Share::Pallet::<T>::virtual_acc(&i, &j).unwrap();
if infos.virtual_account == asset_account {
Share::Virtual::<T>::mutate(i.clone(), j.clone(), |val| {
let mut val0 = val.clone().unwrap();
val0.rent_nbr = 0;
*val = Some(val0);
});
}
}
}

//Calculate the debt if negative balance
if payed < amount_due && (now % <T as Config>::RentCheck::get()).is_zero() {
let tenant_debt0 = amount_due - payed;
let debt = Self::u128_to_balance_option2(tenant_debt0).unwrap();

//Emmit event to inform the tenant of the amount of his debt
//Event to inform the tenant of the amount of his debt
Self::deposit_event(Event::TenantDebt {
tenant: tenant.account_id,
debt,
Expand Down
9 changes: 8 additions & 1 deletion pallets/asset_management/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
//! proposals:
//! - Admit a Tenant for a given asset.
//! - Evict a Tenant from a given asset.
//! The Representative has to submit a judgement about the tenant profile. This judgement
//! The Representative has to submit a judgement about the tenant profile. This judgement
//! will be considered by the owners before voting.
//! Representatives receive a judgement fee from the aspiring tenant.
//! A positive result of the referendum will send a guaranty_deposit payment request to the tenant.
Expand Down Expand Up @@ -137,6 +137,10 @@ pub mod pallet {
/// Lease period in number of months
#[pallet::constant]
type Lease: Get<u32>;

/// Maintenance fees percentage taken on monthly rent
#[pallet::constant]
type Maintenance: Get<Percent>;
}

//Store the referendum_index and the struct containing the
Expand Down Expand Up @@ -214,6 +218,9 @@ pub mod pallet {
///The amount of the tenant debt
TenantDebt { tenant: T::AccountId, debt: BalanceOf<T>, when: BlockNumberOf<T> },

///Rent distributed to owners
RentDistributed { owners: Vec<T::AccountId>, amount: BalanceOf<T>, when: BlockNumberOf<T> },

/// Guaranty payment request sent
GuarantyPaymentRequested {
tenant: T::AccountId,
Expand Down
2 changes: 2 additions & 0 deletions pallets/asset_management/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ parameter_types! {
pub const RentCheckPeriod: BlockNumber = 1;
pub const ContractLength: BlockNumber = 365;
pub const Lease: u32 = 12;
pub const Maintenance:Percent = Percent::from_percent(3);
}

impl pallet_asset_management::Config for Test {
Expand All @@ -428,6 +429,7 @@ impl pallet_asset_management::Config for Test {
type ContractLength = ContractLength;
type RoR = RoR;
type Lease = Lease;
type Maintenance = Maintenance;
type WeightInfo = ();
}

Expand Down
2 changes: 1 addition & 1 deletion pallets/payment/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ pub mod pallet {
<Self as PaymentHandler<T>>::reserve_payment_amount(&from, &to, payment)?;

// release the payment and delete the payment from storage
<Self as PaymentHandler<T>>::settle_payment(&from, &to, Percent::from_percent(100))?;
//<Self as PaymentHandler<T>>::settle_payment(&from, &to, Percent::from_percent(100))?;

Self::deposit_event(Event::PaymentRequestCompleted { from, to });

Expand Down
20 changes: 10 additions & 10 deletions pallets/payment/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,7 @@ fn test_accept_and_pay() {
let creator_initial_balance = 100_000_000_000;
let payment_amount = 20;
let expected_incentive_amount = 0;
let recipient_initial_balance = 1;
//let recipient_initial_balance = 1;

assert_ok!(PaymentModule::request_payment(
Origin::signed(PAYMENT_RECIPENT),
Expand Down Expand Up @@ -758,10 +758,10 @@ fn test_accept_and_pay() {
Balances::free_balance(&PAYMENT_CREATOR),
creator_initial_balance - payment_amount
);
assert_eq!(Balances::free_balance(&PAYMENT_RECIPENT), payment_amount.saturating_add(recipient_initial_balance));
assert_eq!(Balances::reserved_balance(&PAYMENT_RECIPENT), payment_amount);

// should be deleted from storage
assert_eq!(PaymentStore::<Test>::get(PAYMENT_CREATOR, PAYMENT_RECIPENT), None);
//assert_eq!(PaymentStore::<Test>::get(PAYMENT_CREATOR, PAYMENT_RECIPENT), None);

assert_eq!(
last_event(),
Expand Down Expand Up @@ -795,7 +795,7 @@ fn test_accept_and_pay_should_fail_for_non_payment_requested() {
fn test_accept_and_pay_should_charge_fee_correctly() {
new_test_ext().execute_with(|| {
let creator_initial_balance = 100_000_000_000;
let recipient_initial_balance = 1;
//let recipient_initial_balance = 1;
let payment_amount = 20;
let expected_incentive_amount = 0;
let expected_fee_amount = payment_amount / MARKETPLACE_FEE_PERCENTAGE as u64;
Expand Down Expand Up @@ -828,19 +828,19 @@ fn test_accept_and_pay_should_charge_fee_correctly() {
creator_initial_balance - payment_amount - expected_fee_amount
);
assert_eq!(
Balances::free_balance(&PAYMENT_RECIPENT_FEE_CHARGED),
payment_amount.saturating_add(recipient_initial_balance)
Balances::reserved_balance(&PAYMENT_RECIPENT_FEE_CHARGED),
payment_amount
);
assert_eq!(
/*assert_eq!(
Balances::free_balance(&FEE_RECIPIENT_ACCOUNT),
expected_fee_amount.saturating_add(recipient_initial_balance)
);
);*/

// should be deleted from storage
assert_eq!(
/*assert_eq!(
PaymentStore::<Test>::get(PAYMENT_CREATOR, PAYMENT_RECIPENT_FEE_CHARGED),
None
);
);*/

assert_eq!(
last_event(),
Expand Down
5 changes: 4 additions & 1 deletion pallets/share_distributor/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ pub struct Ownership<T: Config> {
pub created: BlockNumberOf<T>,
///TokenId
pub token_id: <T as pallet::Config>::AssetId,
///Number of rents awaiting distribution
pub rent_nbr: u32,
}

impl<T: Config> Ownership<T> {
Expand All @@ -75,7 +77,8 @@ impl<T: Config> Ownership<T> {
let owners = Vec::new();
let created = <frame_system::Pallet<T>>::block_number();
let token_id: <T as pallet::Config>::AssetId = TokenId::<T>::get().into();
let ownership = Ownership::<T> { virtual_account, owners, created, token_id };
let rent_nbr = 0;
let ownership = Ownership::<T> { virtual_account, owners, created, token_id, rent_nbr };

Virtual::<T>::insert(collection, item, ownership);

Expand Down
14 changes: 14 additions & 0 deletions pallets/tenancy/src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ impl<T: Config> Pallet<T> {
*val = Some(val0);
});

//Paying the rent will increment the `awaiting_number_of_rents` field
// in the Share_distributor --> Virtual storage --> Ownership struct
let ownership_infos = Share::Virtual::<T>::iter_keys();
for (i, j) in ownership_infos {
let infos = Share::Pallet::<T>::virtual_acc(&i, &j).unwrap();
if infos.virtual_account == asset_account {
Share::Virtual::<T>::mutate(i.clone(), j.clone(), |val| {
let mut val0 = val.clone().unwrap();
val0.rent_nbr = 1 + val0.rent_nbr;
*val = Some(val0);
});
}
}

Ok(())
}

Expand Down
8 changes: 3 additions & 5 deletions pallets/tenancy/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//!# Tenancy Pallet
//!
//!The Tenancy pallet is used by aspiring and active tenants to execute payments
//!The Tenancy pallet is used by aspiring and active tenants to execute payments
//!and make requests depending on their status.
//!
//!## Overview
Expand All @@ -11,13 +11,13 @@
//!
//!### Dispatchable Functions
//!
//!* `request_asset` - A prospecting tenant can requestfor a particular asset
//!* `request_asset` - A prospecting tenant can requestfor a particular asset
//! after providing personal information requested by the Representative.
//!
//!* `pay_guaranty_deposit` - A newly selected tenant pays for a guaranty deposit
//! requested by the asset's owners, and confirms the start of his contract/lease.
//!
//!* `pay_rent` - The Tenant can pay the monthly rent anytime.
//!* `pay_rent` - The Tenant can pay the monthly rent anytime.
//! He cannot pay more than 12 months, which is the length of the lease/contract.

#![cfg_attr(not(feature = "std"), no_std)]
Expand Down Expand Up @@ -73,7 +73,6 @@ pub mod pallet {
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
type WeightInfo: WeightInfo;
type Currency: Currency<Self::AccountId> + ReservableCurrency<Self::AccountId>;

}

#[pallet::storage]
Expand All @@ -85,7 +84,6 @@ pub mod pallet {
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {

///Guaranty deposit successfully payed
GuarantyDepositPayment {
tenant: T::AccountId,
Expand Down
3 changes: 2 additions & 1 deletion pallets/tenancy/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ impl system::Config for Test {
type MaxConsumers = frame_support::traits::ConstU32<16>;
}


impl pallet_tenancy::Config for Test {
type Event = Event;
type Currency = Balances;
Expand Down Expand Up @@ -443,6 +442,7 @@ parameter_types! {
pub const RentCheckPeriod: BlockNumber = 25;
pub const ContractLength: BlockNumber = 365;
pub const Lease: u32 = 12;
pub const Maintenance:Percent = Percent::from_percent(3);
}

impl pallet_asset_management::Config for Test {
Expand All @@ -460,6 +460,7 @@ impl pallet_asset_management::Config for Test {
type ContractLength = ContractLength;
type RoR = RoR;
type Lease = Lease;
type Maintenance = Maintenance;
type WeightInfo = ();
}

Expand Down
Loading

0 comments on commit 6209de6

Please sign in to comment.