1
1
import { Cardano , Serialization } from '@cardano-sdk/core' ;
2
- import { OpaqueNumber } from '@cardano-sdk/util ' ;
2
+ import { ProtocolParametersForInputSelection } from '@cardano-sdk/input-selection ' ;
3
3
4
4
/**
5
5
* The constant overhead of 160 bytes accounts for the transaction input and the entry in the UTxO map data
@@ -52,34 +52,69 @@ const getTotalExUnits = (redeemers: Cardano.Redeemer[]): Cardano.ExUnits => {
52
52
} ;
53
53
54
54
/**
55
- * Gets the minimum fee incurred by the scripts on the transaction.
55
+ * Starting in the Conway era, the ref script min fee calculation is given by the total size (in bytes) of
56
+ * reference scripts priced according to a different, growing tiered pricing model.
57
+ * See https://github.com/CardanoSolutions/ogmios/releases/tag/v6.5.0
56
58
*
57
- * @param tx The transaction to compute the min script fee from.
58
- * @param exUnitsPrice The prices of the execution units.
59
+ * @param tx The transaction to compute the min ref script fee from.
60
+ * @param resolvedInputs The resolved inputs of the transaction.
61
+ * @param coinsPerRefScriptByte The price per byte of the reference script.
59
62
*/
60
- const minScriptFee = ( tx : Cardano . Tx , exUnitsPrice : Cardano . Prices ) : bigint => {
61
- if ( ! tx . witness . redeemers ) return BigInt ( 0 ) ;
63
+ const minRefScriptFee = ( tx : Cardano . Tx , resolvedInputs : Cardano . Utxo [ ] , coinsPerRefScriptByte : number ) : bigint => {
64
+ if ( coinsPerRefScriptByte === 0 ) return BigInt ( 0 ) ;
62
65
63
- const totalExUnits = getTotalExUnits ( tx . witness . redeemers ) ;
66
+ let base : number = coinsPerRefScriptByte ;
67
+ const range = 25_600 ;
68
+ const multiplier = 1.2 ;
69
+
70
+ let totalRefScriptsSize = 0 ;
71
+
72
+ const totalInputs = [ ...tx . body . inputs , ...( tx . body . referenceInputs ?? [ ] ) ] ;
73
+ for ( const output of totalInputs ) {
74
+ const resolvedInput = resolvedInputs . find (
75
+ ( input ) => input [ 0 ] . txId === output . txId && input [ 0 ] . index === output . index
76
+ ) ;
64
77
65
- return BigInt ( Math . ceil ( totalExUnits . steps * exUnitsPrice . steps + totalExUnits . memory * exUnitsPrice . memory ) ) ;
78
+ if ( resolvedInput && resolvedInput [ 1 ] . scriptReference ) {
79
+ totalRefScriptsSize += Serialization . Script . fromCore ( resolvedInput [ 1 ] . scriptReference ) . toCbor ( ) . length / 2 ;
80
+ }
81
+ }
82
+
83
+ let scriptRefFee = 0 ;
84
+ while ( totalRefScriptsSize > 0 ) {
85
+ scriptRefFee += Math . ceil ( Math . min ( range , totalRefScriptsSize ) * base ) ;
86
+ totalRefScriptsSize = Math . max ( totalRefScriptsSize - range , 0 ) ;
87
+ base *= multiplier ;
88
+ }
89
+
90
+ return BigInt ( scriptRefFee ) ;
66
91
} ;
67
92
68
93
/**
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.
94
+ * Gets the minimum fee incurred by the scripts on the transaction.
95
+ *
96
+ * @param tx The transaction to compute the min script fee from.
97
+ * @param exUnitsPrice The prices of the execution units.
98
+ * @param resolvedInputs The resolved inputs of the transaction.
99
+ * @param coinsPerRefScriptByte The price per byte of the reference script.
73
100
*/
74
- export type MinFeeConstant = OpaqueNumber < 'MinFeeConstant' > ;
75
- export const MinFeeConstant = ( value : number ) : MinFeeConstant => value as unknown as MinFeeConstant ;
101
+ const minScriptFee = (
102
+ tx : Cardano . Tx ,
103
+ exUnitsPrice : Cardano . Prices ,
104
+ resolvedInputs : Cardano . Utxo [ ] ,
105
+ coinsPerRefScriptByte : number
106
+ ) : bigint => {
107
+ const scriptRefFee = minRefScriptFee ( tx , resolvedInputs , coinsPerRefScriptByte ) ;
76
108
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 ;
109
+ if ( ! tx . witness . redeemers ) return BigInt ( scriptRefFee ) ;
110
+
111
+ const totalExUnits = getTotalExUnits ( tx . witness . redeemers ) ;
112
+
113
+ return (
114
+ BigInt ( Math . ceil ( totalExUnits . steps * exUnitsPrice . steps + totalExUnits . memory * exUnitsPrice . memory ) ) +
115
+ scriptRefFee
116
+ ) ;
117
+ } ;
83
118
84
119
/**
85
120
* Gets the minimum fee incurred by the transaction size.
@@ -88,7 +123,7 @@ export const MinFeeCoefficient = (value: number): MinFeeCoefficient => value as
88
123
* @param minFeeConstant The prices of the execution units.
89
124
* @param minFeeCoefficient The prices of the execution units.
90
125
*/
91
- const minNoScriptFee = ( tx : Cardano . Tx , minFeeConstant : MinFeeConstant , minFeeCoefficient : MinFeeCoefficient ) => {
126
+ const minNoScriptFee = ( tx : Cardano . Tx , minFeeConstant : number , minFeeCoefficient : number ) => {
92
127
const txSize = serializeTx ( tx ) . length ;
93
128
return BigInt ( Math . ceil ( txSize * minFeeCoefficient + minFeeConstant ) ) ;
94
129
} ;
@@ -130,13 +165,14 @@ export const minAdaRequired = (output: Cardano.TxOut, coinsPerUtxoByte: bigint):
130
165
* Gets the minimum transaction fee for the given transaction given its size and its execution units budget.
131
166
*
132
167
* @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.
168
+ * @param resolvedInputs The resolved inputs of the transaction.
169
+ * @param pparams The protocol parameters.
136
170
*/
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 ) ;
171
+ export const minFee = ( tx : Cardano . Tx , resolvedInputs : Cardano . Utxo [ ] , pparams : ProtocolParametersForInputSelection ) =>
172
+ minNoScriptFee ( tx , pparams . minFeeConstant , pparams . minFeeCoefficient ) +
173
+ minScriptFee (
174
+ tx ,
175
+ pparams . prices ,
176
+ resolvedInputs ,
177
+ pparams . minFeeRefScriptCostPerByte ? Number ( pparams . minFeeRefScriptCostPerByte ) : 0
178
+ ) ;
0 commit comments