1
1
import { Cardano , Serialization } from '@cardano-sdk/core' ;
2
- import { OpaqueNumber } from '@cardano-sdk/util' ;
3
2
4
3
/**
5
4
* The constant overhead of 160 bytes accounts for the transaction input and the entry in the UTxO map data
@@ -52,34 +51,69 @@ const getTotalExUnits = (redeemers: Cardano.Redeemer[]): Cardano.ExUnits => {
52
51
} ;
53
52
54
53
/**
55
- * Gets the minimum fee incurred by the scripts on the transaction.
54
+ * Starting in the Conway era, the ref script min fee calculation is given by the total size (in bytes) of
55
+ * reference scripts priced according to a different, growing tiered pricing model.
56
+ * See https://github.com/CardanoSolutions/ogmios/releases/tag/v6.5.0
56
57
*
57
- * @param tx The transaction to compute the min script fee from.
58
- * @param exUnitsPrice The prices of the execution units.
58
+ * @param tx The transaction to compute the min ref script fee from.
59
+ * @param resolvedInputs The resolved inputs of the transaction.
60
+ * @param coinsPerRefScriptByte The price per byte of the reference script.
59
61
*/
60
- const minScriptFee = ( tx : Cardano . Tx , exUnitsPrice : Cardano . Prices ) : bigint => {
61
- if ( ! tx . witness . redeemers ) return BigInt ( 0 ) ;
62
+ const minRefScriptFee = ( tx : Cardano . Tx , resolvedInputs : Cardano . Utxo [ ] , coinsPerRefScriptByte : number ) : bigint => {
63
+ if ( coinsPerRefScriptByte === 0 ) return BigInt ( 0 ) ;
62
64
63
- const totalExUnits = getTotalExUnits ( tx . witness . redeemers ) ;
65
+ let base : number = coinsPerRefScriptByte ;
66
+ const range = 25_600 ;
67
+ const multiplier = 1.2 ;
68
+
69
+ let totalRefScriptsSize = 0 ;
70
+
71
+ const totalInputs = [ ...tx . body . inputs , ...( tx . body . referenceInputs ?? [ ] ) ] ;
72
+ for ( const output of totalInputs ) {
73
+ const resolvedInput = resolvedInputs . find (
74
+ ( input ) => input [ 0 ] . txId === output . txId && input [ 0 ] . index === output . index
75
+ ) ;
64
76
65
- return BigInt ( Math . ceil ( totalExUnits . steps * exUnitsPrice . steps + totalExUnits . memory * exUnitsPrice . memory ) ) ;
77
+ if ( resolvedInput && resolvedInput [ 1 ] . scriptReference ) {
78
+ totalRefScriptsSize += Serialization . Script . fromCore ( resolvedInput [ 1 ] . scriptReference ) . toCbor ( ) . length / 2 ;
79
+ }
80
+ }
81
+
82
+ let scriptRefFee = 0 ;
83
+ while ( totalRefScriptsSize > 0 ) {
84
+ scriptRefFee += Math . ceil ( Math . min ( range , totalRefScriptsSize ) * base ) ;
85
+ totalRefScriptsSize = Math . max ( totalRefScriptsSize - range , 0 ) ;
86
+ base *= multiplier ;
87
+ }
88
+
89
+ return BigInt ( scriptRefFee ) ;
66
90
} ;
67
91
68
92
/**
69
- * The value of the min fee constant is a payable fee, regardless of the size of the transaction. This parameter was
70
- * primarily introduced to prevent Distributed-Denial-of-Service (DDoS) attacks. This constant makes such attacks
71
- * prohibitively expensive, and eliminates the possibility of an attacker generating millions of small transactions
72
- * to flood and crash the system.
93
+ * Gets the minimum fee incurred by the scripts on the transaction.
94
+ *
95
+ * @param tx The transaction to compute the min script fee from.
96
+ * @param exUnitsPrice The prices of the execution units.
97
+ * @param resolvedInputs The resolved inputs of the transaction.
98
+ * @param coinsPerRefScriptByte The price per byte of the reference script.
73
99
*/
74
- export type MinFeeConstant = OpaqueNumber < 'MinFeeConstant' > ;
75
- export const MinFeeConstant = ( value : number ) : MinFeeConstant => value as unknown as MinFeeConstant ;
100
+ const minScriptFee = (
101
+ tx : Cardano . Tx ,
102
+ exUnitsPrice : Cardano . Prices ,
103
+ resolvedInputs : Cardano . Utxo [ ] ,
104
+ coinsPerRefScriptByte : number
105
+ ) : bigint => {
106
+ const scriptRefFee = minRefScriptFee ( tx , resolvedInputs , coinsPerRefScriptByte ) ;
76
107
77
- /**
78
- * Min fee coefficient reflects the dependence of the transaction cost on the size of the transaction. The larger
79
- * the transaction, the more resources are needed to store and process it.
80
- */
81
- export type MinFeeCoefficient = OpaqueNumber < 'MinFeeCoefficient' > ;
82
- export const MinFeeCoefficient = ( value : number ) : MinFeeCoefficient => value as unknown as MinFeeCoefficient ;
108
+ if ( ! tx . witness . redeemers ) return BigInt ( scriptRefFee ) ;
109
+
110
+ const totalExUnits = getTotalExUnits ( tx . witness . redeemers ) ;
111
+
112
+ return (
113
+ BigInt ( Math . ceil ( totalExUnits . steps * exUnitsPrice . steps + totalExUnits . memory * exUnitsPrice . memory ) ) +
114
+ scriptRefFee
115
+ ) ;
116
+ } ;
83
117
84
118
/**
85
119
* Gets the minimum fee incurred by the transaction size.
@@ -88,7 +122,7 @@ export const MinFeeCoefficient = (value: number): MinFeeCoefficient => value as
88
122
* @param minFeeConstant The prices of the execution units.
89
123
* @param minFeeCoefficient The prices of the execution units.
90
124
*/
91
- const minNoScriptFee = ( tx : Cardano . Tx , minFeeConstant : MinFeeConstant , minFeeCoefficient : MinFeeCoefficient ) => {
125
+ const minNoScriptFee = ( tx : Cardano . Tx , minFeeConstant : number , minFeeCoefficient : number ) => {
92
126
const txSize = serializeTx ( tx ) . length ;
93
127
return BigInt ( Math . ceil ( txSize * minFeeCoefficient + minFeeConstant ) ) ;
94
128
} ;
@@ -130,13 +164,14 @@ export const minAdaRequired = (output: Cardano.TxOut, coinsPerUtxoByte: bigint):
130
164
* Gets the minimum transaction fee for the given transaction given its size and its execution units budget.
131
165
*
132
166
* @param tx The transaction to compute the min fee from.
133
- * @param exUnitsPrice The current (given by protocol parameters) execution unit prices.
134
- * @param minFeeConstant The current (given by protocol parameters) constant fee that all transaction must pay.
135
- * @param minFeeCoefficient The current (given by protocol parameters) transaction size fee coefficient.
167
+ * @param resolvedInputs The resolved inputs of the transaction.
168
+ * @param pparams The protocol parameters.
136
169
*/
137
- export const minFee = (
138
- tx : Cardano . Tx ,
139
- exUnitsPrice : Cardano . Prices ,
140
- minFeeConstant : MinFeeConstant ,
141
- minFeeCoefficient : MinFeeCoefficient
142
- ) => minNoScriptFee ( tx , minFeeConstant , minFeeCoefficient ) + minScriptFee ( tx , exUnitsPrice ) ;
170
+ export const minFee = ( tx : Cardano . Tx , resolvedInputs : Cardano . Utxo [ ] , pparams : Cardano . ProtocolParameters ) =>
171
+ minNoScriptFee ( tx , pparams . minFeeConstant , pparams . minFeeCoefficient ) +
172
+ minScriptFee (
173
+ tx ,
174
+ pparams . prices ,
175
+ resolvedInputs ,
176
+ pparams . minFeeRefScriptCostPerByte ? Number ( pparams . minFeeRefScriptCostPerByte ) : 0
177
+ ) ;
0 commit comments