threefoldtech / tfchain

Threefold Chain.
Apache License 2.0
15 stars 11 forks source link

Staking Discount Miscalculation Due to Per-Contract Discount Application #1013

Open sameh-farouk opened 1 month ago

sameh-farouk commented 1 month ago

Description

The staking discount is intended to reward users with a discount based on their total balance and the duration they can run a contract. However, the current implementation applies the discount per contract cost, leading to incorrect discount calculations when users have multiple active contracts.

The expected behavior is for the discount to be calculated based on the user's total balance across all contracts, ensuring the discount reflects the actual consumption. Currently, the system assumes each contract has exclusive access to the user’s full balance, resulting in the user receiving a discount as if each contract is the only one consuming the balance.

This results in unintended benefits for users who have many contracts, as they can receive discounts on each contract independently of the others.

Example Scenario

Let’s take a user with 1,000 TFT and one contract that consumes 10 TFT per day.

Screenshot_20241003_023852

For a single contract consuming 10 TFT per day, the monthly cost would be 300 TFT. To cover 3 months, the user would need 900 TFT, meaning with 1,000 TFT, the user qualifies for a 20% discount on a single contract.

However, the issue arises when the user has multiple contracts. Let’s take a user with the same 1,000 TFT but 100 contracts, each consuming 10 TFT per day.

Current Behavior

The system calculates the discount for each contract independently based on the user's full balance of 1,000 TFT. Each contract assumes the user has sufficient balance to qualify for a 20% discount, even though the balance is being shared across multiple contracts. As a result, the user receives a 20% discount for all 100 contracts, as if each one is consuming the balance separately.

Expected Behavior

The user's total consumption across all 100 contracts is 1,000 TFT per day (10 TFT per contract × 100 contracts). Therefore, the user's balance of 1,000 TFT would only cover one day of operation for all 100 contracts combined. Since the user's balance is not enough to cover the contracts for 3 months, no discount should be applied.

Impact

By applying the staking discount per contract, the user is receiving a larger overall discount than intended. The user’s total balance is effectively "reused" across each contract, resulting in over-discounting, which breaks the intended logic of the staking discount system.

Note:

This issue has been identified primarily through code auditing. However, the observation has not yet been confirmed by reproducing the behavior in practice.

renauter commented 1 month ago

This discount plan was introduced to bring incentive to deploy on the grid and also for the user to buy sufficient TFT to maintain the deployment for a significant period. I guess at the time the idea was to find a simple way to implement this (without adding a dedicated storage). We don't have a direct way to know exactly, for a given twin, what are all contracts he owns and maybe this is why the per-contract discount was chosen. So it was intended to be like that.

But of course this is not ideal as you described well in the 100 contracts scenario. Maybe adding a new storage which will save a cumulative contract cost for a given twin could do the job, even if it will require to update this storage map each time a contract changed, and thus add one more complexity layer to what is already complex. Unless we find another way with less impact.

To be discussed...