Skip to content

Commit 49a09ca

Browse files
authored
feat: third party service contract for pallet-smart-contract (#522)
1 parent ef3c64e commit 49a09ca

File tree

10 files changed

+1363
-63
lines changed

10 files changed

+1363
-63
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# 3. Third party service contract
2+
3+
Date: 2022-10-17
4+
5+
## Status
6+
7+
Accepted
8+
9+
## Context
10+
11+
See [here](https://github.com/threefoldtech/tfchain/issues/445) for more details.
12+
13+
## Decision
14+
15+
The third party service contract flow is described [here](../../substrate-node/pallets/pallet-smart-contract/third-party_service_contract.md#flow).
16+
17+
## Consequences
18+
19+
### the good
20+
21+
- It is now possible to create generic contract between two `TFChain` users (without restriction of account type) for some service and bill for it.
22+
23+
### the worrying
24+
25+
- Keep eyes on potential abuses and be prepared to handle all the malicious cases that can show up.

substrate-node/pallets/pallet-smart-contract/src/cost.rs

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@ use crate::pallet;
22
use crate::pallet::BalanceOf;
33
use crate::pallet::Error;
44
use crate::types;
5-
use crate::types::{Contract, ContractBillingInformation};
5+
use crate::types::{Contract, ContractBillingInformation, ServiceContract, ServiceContractBill};
66
use crate::Config;
7-
use frame_support::dispatch::DispatchErrorWithPostInfo;
7+
use frame_support::{dispatch::DispatchErrorWithPostInfo, traits::Get};
88
use pallet_tfgrid::types as pallet_tfgrid_types;
9-
use sp_runtime::Percent;
10-
use sp_runtime::SaturatedConversion;
9+
use sp_runtime::{Percent, SaturatedConversion};
1110
use substrate_fixed::types::U64F64;
1211
use tfchain_support::{resources::Resources, types::NodeCertification};
1312

@@ -101,7 +100,8 @@ impl<T: Config> Contract<T> {
101100
// Calculate total cost for a name contract
102101
types::ContractData::NameContract(_) => {
103102
// bill user for name usage for number of seconds elapsed
104-
let total_cost_u64f64 = (U64F64::from_num(pricing_policy.unique_name.value) / 3600)
103+
let total_cost_u64f64 = (U64F64::from_num(pricing_policy.unique_name.value)
104+
/ U64F64::from_num(T::BillingReferencePeriod::get()))
105105
* U64F64::from_num(seconds_elapsed);
106106
total_cost_u64f64.to_num::<u64>()
107107
}
@@ -111,6 +111,36 @@ impl<T: Config> Contract<T> {
111111
}
112112
}
113113

114+
impl ServiceContract {
115+
pub fn calculate_bill_cost_tft<T: Config>(
116+
&self,
117+
service_bill: ServiceContractBill,
118+
) -> Result<BalanceOf<T>, DispatchErrorWithPostInfo> {
119+
// Calculate the cost in mUSD for service contract bill
120+
let total_cost = self.calculate_bill_cost::<T>(service_bill);
121+
122+
if total_cost == 0 {
123+
return Ok(BalanceOf::<T>::saturated_from(0 as u128));
124+
}
125+
126+
// Calculate the cost in TFT for service contract
127+
let total_cost_tft_64 = calculate_cost_in_tft_from_musd::<T>(total_cost)?;
128+
129+
// convert to balance object
130+
let amount_due: BalanceOf<T> = BalanceOf::<T>::saturated_from(total_cost_tft_64);
131+
132+
return Ok(amount_due);
133+
}
134+
135+
pub fn calculate_bill_cost<T: Config>(&self, service_bill: ServiceContractBill) -> u64 {
136+
// bill user for service usage for elpased usage (window) in seconds
137+
let contract_cost = U64F64::from_num(self.base_fee) * U64F64::from_num(service_bill.window)
138+
/ U64F64::from_num(T::BillingReferencePeriod::get())
139+
+ U64F64::from_num(service_bill.variable_amount);
140+
contract_cost.round().to_num::<u64>()
141+
}
142+
}
143+
114144
// Calculates the total cost of a node contract.
115145
pub fn calculate_resources_cost<T: Config>(
116146
resources: Resources,
@@ -130,14 +160,16 @@ pub fn calculate_resources_cost<T: Config>(
130160
let su_used = hru / 1200 + sru / 200;
131161
// the pricing policy su cost value is expressed in 1 hours or 3600 seconds.
132162
// we bill every 3600 seconds but here we need to calculate the cost per second and multiply it by the seconds elapsed.
133-
let su_cost = (U64F64::from_num(pricing_policy.su.value) / 3600)
163+
let su_cost = (U64F64::from_num(pricing_policy.su.value)
164+
/ U64F64::from_num(T::BillingReferencePeriod::get()))
134165
* U64F64::from_num(seconds_elapsed)
135166
* su_used;
136167
log::debug!("su cost: {:?}", su_cost);
137168

138169
let cu = calculate_cu(cru, mru);
139170

140-
let cu_cost = (U64F64::from_num(pricing_policy.cu.value) / 3600)
171+
let cu_cost = (U64F64::from_num(pricing_policy.cu.value)
172+
/ U64F64::from_num(T::BillingReferencePeriod::get()))
141173
* U64F64::from_num(seconds_elapsed)
142174
* cu;
143175
log::debug!("cu cost: {:?}", cu_cost);
@@ -146,7 +178,8 @@ pub fn calculate_resources_cost<T: Config>(
146178

147179
if ipu > 0 {
148180
let total_ip_cost = U64F64::from_num(ipu)
149-
* (U64F64::from_num(pricing_policy.ipu.value) / 3600)
181+
* (U64F64::from_num(pricing_policy.ipu.value)
182+
/ U64F64::from_num(T::BillingReferencePeriod::get()))
150183
* U64F64::from_num(seconds_elapsed);
151184
log::debug!("ip cost: {:?}", total_ip_cost);
152185
total_cost += total_ip_cost;

0 commit comments

Comments
 (0)