@@ -97,6 +97,87 @@ impl FeeModel {
9797/// Models for simulating Stellar transaction fee behaviour.
9898pub struct FeeModel ;
9999
100+ /// A fee curve snapshot matching the Horizon `fee_stats` shape (#119).
101+ #[ derive( Debug , Clone , serde:: Serialize , serde:: Deserialize ) ]
102+ pub struct FeeCurve {
103+ pub last_ledger : String ,
104+ pub last_ledger_base_fee : String ,
105+ pub ledger_capacity_usage : String ,
106+ pub fee_charged : FeePercentiles ,
107+ pub max_fee : FeePercentiles ,
108+ }
109+
110+ #[ derive( Debug , Clone , serde:: Serialize , serde:: Deserialize ) ]
111+ pub struct FeePercentiles {
112+ pub max : String ,
113+ pub min : String ,
114+ pub mode : String ,
115+ pub p10 : String ,
116+ pub p20 : String ,
117+ pub p30 : String ,
118+ pub p40 : String ,
119+ pub p50 : String ,
120+ pub p60 : String ,
121+ pub p70 : String ,
122+ pub p80 : String ,
123+ pub p90 : String ,
124+ pub p95 : String ,
125+ pub p99 : String ,
126+ }
127+
128+ impl FeeModel {
129+ /// Generate a `FeeCurve` scaled by `pressure` (0.0–1.0) (#122).
130+ ///
131+ /// At pressure 0 fees stay at `base_fee`; at pressure 1 they reach `max_fee`.
132+ pub fn generate ( base_fee : u64 , max_fee : u64 , pressure : f64 , ledger_seq : u64 ) -> FeeCurve {
133+ let pressure = pressure. clamp ( 0.0 , 1.0 ) ;
134+ let fee = |pct : f64 | -> String {
135+ let scaled = base_fee as f64 + ( max_fee - base_fee) as f64 * pressure * pct;
136+ ( scaled as u64 ) . to_string ( )
137+ } ;
138+
139+ FeeCurve {
140+ last_ledger : ledger_seq. to_string ( ) ,
141+ last_ledger_base_fee : base_fee. to_string ( ) ,
142+ ledger_capacity_usage : format ! ( "{:.2}" , pressure) ,
143+ fee_charged : FeePercentiles {
144+ min : base_fee. to_string ( ) ,
145+ max : fee ( 1.0 ) ,
146+ mode : fee ( 0.6 ) ,
147+ p10 : fee ( 0.1 ) ,
148+ p20 : fee ( 0.2 ) ,
149+ p30 : fee ( 0.3 ) ,
150+ p40 : fee ( 0.4 ) ,
151+ p50 : fee ( 0.5 ) ,
152+ p60 : fee ( 0.6 ) ,
153+ p70 : fee ( 0.7 ) ,
154+ p80 : fee ( 0.8 ) ,
155+ p90 : fee ( 0.9 ) ,
156+ p95 : fee ( 0.95 ) ,
157+ p99 : fee ( 0.99 ) ,
158+ } ,
159+ max_fee : FeePercentiles {
160+ min : base_fee. to_string ( ) ,
161+ max : fee ( 1.0 ) ,
162+ mode : fee ( 0.7 ) ,
163+ p10 : fee ( 0.15 ) ,
164+ p20 : fee ( 0.25 ) ,
165+ p30 : fee ( 0.35 ) ,
166+ p40 : fee ( 0.45 ) ,
167+ p50 : fee ( 0.55 ) ,
168+ p60 : fee ( 0.65 ) ,
169+ p70 : fee ( 0.75 ) ,
170+ p80 : fee ( 0.85 ) ,
171+ p90 : fee ( 0.92 ) ,
172+ p95 : fee ( 0.97 ) ,
173+ p99 : fee ( 1.0 ) ,
174+ } ,
175+ }
176+ }
177+
178+ /// Serialise a `FeeCurve` to a JSON string (#119).
179+ pub fn to_json( curve : & FeeCurve ) -> Result < String , serde_json:: Error > {
180+ serde_json:: to_string ( curve)
100181impl FeeModel {
101182 /// Generate fee points for a single config.
102183 pub fn generate ( config : & FeeModelConfig ) -> Vec < FeePoint > {
0 commit comments