Skip to content

Commit 6a08d8c

Browse files
Introduce new transaction fee calculation (#279)
Add new transaction fee calculation
1 parent 341bc4a commit 6a08d8c

File tree

14 files changed

+247
-35
lines changed

14 files changed

+247
-35
lines changed

contracts/FlowFees.cdc

+86
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ pub contract FlowFees {
99
// Event that is emitted when tokens are withdrawn from the fee vault
1010
pub event TokensWithdrawn(amount: UFix64)
1111

12+
// Event that is emitted when fees are deducted
13+
pub event FeesDeducted(amount: UFix64, inclusionEffort: UFix64, executionEffort: UFix64)
14+
15+
// Event that is emitted when fee parameters change
16+
pub event FeeParametersChanged(surgeFactor: UFix64, inclusionEffortCost: UFix64, executionEffortCost: UFix64)
17+
1218
// Private vault with public deposit function
1319
access(self) var vault: @FlowToken.Vault
1420

@@ -33,6 +39,86 @@ pub contract FlowFees {
3339
emit TokensWithdrawn(amount: amount)
3440
return <-vault
3541
}
42+
43+
/// Allows the administrator to change all the fee parameters at once
44+
pub fun setFeeParameters(surgeFactor: UFix64, inclusionEffortCost: UFix64, executionEffortCost: UFix64) {
45+
let newParameters = FeeParameters(surgeFactor: surgeFactor, inclusionEffortCost: inclusionEffortCost, executionEffortCost: executionEffortCost)
46+
FlowFees.setFeeParameters(newParameters)
47+
}
48+
49+
/// Allows the administrator to change the fee surge factor
50+
pub fun setFeeSurgeFactor(_ surgeFactor: UFix64) {
51+
let oldParameters = FlowFees.getFeeParameters()
52+
let newParameters = FeeParameters(surgeFactor: surgeFactor, inclusionEffortCost: oldParameters.inclusionEffortCost, executionEffortCost: oldParameters.executionEffortCost)
53+
FlowFees.setFeeParameters(newParameters)
54+
}
55+
}
56+
57+
/// A struct holding the fee parameters needed to calculate the fees
58+
pub struct FeeParameters {
59+
/// The surge factor is used to make transaction fees respond to high loads on the network
60+
pub var surgeFactor: UFix64
61+
/// The FLOW cost of one unit of inclusion effort. The FVM is responsible for metering inclusion effort.
62+
pub var inclusionEffortCost: UFix64
63+
/// The FLOW cost of one unit of execution effort. The FVM is responsible for metering execution effort.
64+
pub var executionEffortCost: UFix64
65+
66+
init(surgeFactor: UFix64, inclusionEffortCost: UFix64, executionEffortCost: UFix64){
67+
self.surgeFactor = surgeFactor
68+
self.inclusionEffortCost = inclusionEffortCost
69+
self.executionEffortCost = executionEffortCost
70+
}
71+
}
72+
73+
/// Called when a transaction is submitted to deduct the fee
74+
/// from the AuthAccount that submitted it
75+
pub fun deductTransactionFee(_ acct: AuthAccount, inclusionEffort: UFix64, executionEffort: UFix64) {
76+
var feeAmount = self.computeFees(inclusionEffort: inclusionEffort, executionEffort: executionEffort)
77+
78+
if feeAmount == UFix64(0) {
79+
// If there are no fees to deduct, do not continue,
80+
// so that there are no unnecessarily emitted events
81+
return
82+
}
83+
84+
let tokenVault = acct.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault)
85+
?? panic("Unable to borrow reference to the default token vault")
86+
87+
88+
if feeAmount > tokenVault.balance {
89+
// In the future this code path will never be reached,
90+
// as payers that are under account minimum balance will not have their transactions included in a collection
91+
//
92+
// Currently this is not used to fail the transaction (as that is the responsibility of the minimum account balance logic),
93+
// But is used to reduce the balance of the vault to 0.0, if the vault has less available balance than the transaction fees.
94+
feeAmount = tokenVault.balance
95+
}
96+
97+
let feeVault <- tokenVault.withdraw(amount: feeAmount)
98+
self.vault.deposit(from: <-feeVault)
99+
100+
// The fee calculation can be reconstructed using the data from this event and the FeeParameters at the block when the event happened
101+
emit FeesDeducted(amount: feeAmount, inclusionEffort: inclusionEffort, executionEffort: executionEffort)
102+
}
103+
104+
pub fun getFeeParameters(): FeeParameters {
105+
return self.account.copy<FeeParameters>(from: /storage/FlowTxFeeParameters) ?? panic("Error getting tx fee parameters. They need to be initialized first!")
106+
}
107+
108+
access(self) fun setFeeParameters(_ feeParameters: FeeParameters) {
109+
// empty storage before writing new FeeParameters to it
110+
self.account.load<FeeParameters>(from: /storage/FlowTxFeeParameters)
111+
self.account.save(feeParameters,to: /storage/FlowTxFeeParameters)
112+
emit FeeParametersChanged(surgeFactor: feeParameters.surgeFactor, inclusionEffortCost: feeParameters.inclusionEffortCost, executionEffortCost: feeParameters.executionEffortCost)
113+
}
114+
115+
116+
// compute the transaction fees with the current fee parameters and the given inclusionEffort and executionEffort
117+
pub fun computeFees(inclusionEffort: UFix64, executionEffort: UFix64): UFix64 {
118+
let params = self.getFeeParameters()
119+
120+
let totalFees = params.surgeFactor * ( inclusionEffort * params.inclusionEffortCost + executionEffort * params.executionEffortCost )
121+
return totalFees
36122
}
37123

38124
init(adminAccount: AuthAccount) {

contracts/FlowServiceAccount.cdc

+2
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ pub contract FlowServiceAccount {
5959
?? panic("Unable to borrow reference to the default token vault")
6060
}
6161

62+
/// Will be deprecated and can be deleted after the switchover to FlowFees.deductTransactionFee
63+
///
6264
/// Called when a transaction is submitted to deduct the fee
6365
/// from the AuthAccount that submitted it
6466
pub fun deductTransactionFee(_ acct: AuthAccount) {

lib/go/contracts/internal/assets/assets.go

+6-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)