@@ -4,17 +4,18 @@ import (
44 "math/big"
55
66 "github.com/strahe/synapse-go/chain"
7+ "github.com/strahe/synapse-go/pdp"
78 "github.com/strahe/synapse-go/warmstorage"
89)
910
1011// CalculateEffectiveRate computes the storage rate for the given total data size.
1112// Integer division is used to match on-chain Solidity truncation.
1213// If epochsPerMonth is zero or negative, chain.EpochsPerMonth is used as a safe default.
13- // Nil sizeBytes, pricePerTiBPerMonth, or minMonthlyRate are treated as zero.
14+ // Nil sizeBytes, pricePerTiBPerMonth, or datasetFeePerMonth are treated as zero.
1415func CalculateEffectiveRate (
1516 sizeBytes * big.Int ,
1617 pricePerTiBPerMonth * big.Int ,
17- minMonthlyRate * big.Int ,
18+ datasetFeePerMonth * big.Int ,
1819 epochsPerMonth int64 ,
1920) EffectiveRate {
2021 if epochsPerMonth <= 0 {
@@ -28,43 +29,69 @@ func CalculateEffectiveRate(
2829 if pricePerTiBPerMonth == nil {
2930 pricePerTiBPerMonth = new (big.Int )
3031 }
31- if minMonthlyRate == nil {
32- minMonthlyRate = new (big.Int )
32+ if datasetFeePerMonth == nil {
33+ datasetFeePerMonth = new (big.Int )
34+ }
35+
36+ if sizeBytes .Sign () == 0 {
37+ return EffectiveRate {
38+ RatePerEpoch : new (big.Int ),
39+ RatePerMonth : new (big.Int ),
40+ }
3341 }
3442
3543 ratePerMonth := new (big.Int ).Mul (pricePerTiBPerMonth , sizeBytes )
3644 ratePerMonth .Div (ratePerMonth , bigTiB )
37- if ratePerMonth .Cmp (minMonthlyRate ) < 0 {
38- ratePerMonth .Set (minMonthlyRate )
39- }
45+ ratePerMonth .Add (ratePerMonth , datasetFeePerMonth )
4046
4147 ratePerEpoch := new (big.Int ).Mul (pricePerTiBPerMonth , sizeBytes )
4248 divisor := new (big.Int ).Mul (bigTiB , epm )
4349 ratePerEpoch .Div (ratePerEpoch , divisor )
44-
45- minEpochRate := new (big.Int ).Div (minMonthlyRate , epm )
46- if minEpochRate .Cmp (bigOne ) < 0 {
47- minEpochRate .Set (bigOne )
48- }
49- if ratePerEpoch .Cmp (minEpochRate ) < 0 {
50- ratePerEpoch .Set (minEpochRate )
51- }
50+ ratePerEpoch .Add (ratePerEpoch , new (big.Int ).Div (datasetFeePerMonth , epm ))
5251
5352 return EffectiveRate {
5453 RatePerEpoch : ratePerEpoch ,
5554 RatePerMonth : ratePerMonth ,
5655 }
5756}
5857
58+ // CalculateUploadFees computes one-time upload fees from the price list.
59+ func CalculateUploadFees (priceList * warmstorage.PriceList , isNewDataSet bool , pieceCount * big.Int ) UploadFees {
60+ if priceList == nil {
61+ priceList = & warmstorage.PriceList {}
62+ }
63+ pieces := copyBigOrDefault (pieceCount , bigOne )
64+ if pieces .Sign () <= 0 {
65+ pieces .SetInt64 (1 )
66+ }
67+
68+ maxBatch := big .NewInt (pdp .MaxAddPiecesBatchSize )
69+ addPiecesOperationCount := new (big.Int ).Add (pieces , new (big.Int ).Sub (maxBatch , bigOne ))
70+ addPiecesOperationCount .Div (addPiecesOperationCount , maxBatch )
71+
72+ createDataSetFee := new (big.Int )
73+ if isNewDataSet {
74+ createDataSetFee .Set (zeroBig (priceList .Fees .CreateDataSetFee ))
75+ }
76+ addPiecesFee := new (big.Int ).Mul (zeroBig (priceList .Fees .AddPiecesBaseFee ), addPiecesOperationCount )
77+ addPiecesFee .Add (addPiecesFee , new (big.Int ).Mul (zeroBig (priceList .Fees .AddPiecesPerPieceFee ), pieces ))
78+ total := new (big.Int ).Add (createDataSetFee , addPiecesFee )
79+
80+ return UploadFees {
81+ CreateDataSetFee : createDataSetFee ,
82+ AddPiecesFee : addPiecesFee ,
83+ Total : total ,
84+ }
85+ }
86+
5987// CalculateAdditionalLockupRequired returns the incremental lockup needed to
6088// store uploadSizeBytes into a dataset that currently holds currentDataSetSizeBytes.
61- // Nil dataSizeBytes, currentDataSetSizeBytes, pricing, and usdfcSybilFee use zero-value defaults.
89+ // Nil dataSizeBytes, currentDataSetSizeBytes, and priceList use zero-value defaults.
6290func CalculateAdditionalLockupRequired (
6391 dataSizeBytes * big.Int ,
6492 currentDataSetSizeBytes * big.Int ,
65- pricing * warmstorage.ServicePrice ,
66- lockupPeriod int64 ,
67- usdfcSybilFee * big.Int ,
93+ priceList * warmstorage.PriceList ,
94+ lockupPeriod * big.Int ,
6895 isNewDataSet bool ,
6996 enableCDN bool ,
7097) AdditionalLockup {
@@ -74,28 +101,24 @@ func CalculateAdditionalLockupRequired(
74101 if currentDataSetSizeBytes == nil {
75102 currentDataSetSizeBytes = new (big.Int )
76103 }
77- if pricing == nil {
78- pricing = & warmstorage.ServicePrice {}
79- }
80- var epm int64
81- if pricing .EpochsPerMonth != nil && pricing .EpochsPerMonth .Sign () > 0 {
82- epm = pricing .EpochsPerMonth .Int64 ()
104+ if priceList == nil {
105+ priceList = & warmstorage.PriceList {}
83106 }
84107
85108 var rateDelta * big.Int
86109 if currentDataSetSizeBytes .Sign () > 0 && ! isNewDataSet {
87110 newTotalSize := new (big.Int ).Add (currentDataSetSizeBytes , dataSizeBytes )
88111 newRate := CalculateEffectiveRate (
89112 newTotalSize ,
90- pricing . PricePerTiBPerMonthNoCDN ,
91- pricing . MinimumPricePerMonth ,
92- epm ,
113+ priceList . Rates . StoragePerTiBPerMonth ,
114+ priceList . Rates . DatasetFeePerMonth ,
115+ chain . EpochsPerMonth ,
93116 )
94117 currentRate := CalculateEffectiveRate (
95118 currentDataSetSizeBytes ,
96- pricing . PricePerTiBPerMonthNoCDN ,
97- pricing . MinimumPricePerMonth ,
98- epm ,
119+ priceList . Rates . StoragePerTiBPerMonth ,
120+ priceList . Rates . DatasetFeePerMonth ,
121+ chain . EpochsPerMonth ,
99122 )
100123 rateDelta = new (big.Int ).Sub (newRate .RatePerEpoch , currentRate .RatePerEpoch )
101124 if rateDelta .Sign () < 0 {
@@ -104,37 +127,48 @@ func CalculateAdditionalLockupRequired(
104127 } else {
105128 newRate := CalculateEffectiveRate (
106129 dataSizeBytes ,
107- pricing . PricePerTiBPerMonthNoCDN ,
108- pricing . MinimumPricePerMonth ,
109- epm ,
130+ priceList . Rates . StoragePerTiBPerMonth ,
131+ priceList . Rates . DatasetFeePerMonth ,
132+ chain . EpochsPerMonth ,
110133 )
111134 rateDelta = new (big.Int ).Set (newRate .RatePerEpoch )
112135 }
113136
114- if lockupPeriod <= 0 {
115- lockupPeriod = DefaultLockupPeriod
137+ effectiveLockupPeriod := copyBigOrDefault (lockupPeriod , priceList .Lockups .DefaultLockupPeriod )
138+ if effectiveLockupPeriod .Sign () <= 0 {
139+ effectiveLockupPeriod .SetInt64 (DefaultLockupPeriod )
116140 }
117- rateLockup := new (big.Int ).Mul (rateDelta , big . NewInt ( lockupPeriod ) )
141+ streamingLockup := new (big.Int ).Mul (rateDelta , effectiveLockupPeriod )
118142
119- cdnLockup := new (big.Int )
120- if isNewDataSet && enableCDN {
121- cdnLockup .Set (cdnFixedLockup )
143+ lifecycleLockup := new (big.Int )
144+ if isNewDataSet {
145+ lifecycleLockup .Set (zeroBig ( priceList . Lockups . LifecycleReserveTarget ) )
122146 }
123147
124- sybilFee := new (big.Int )
125- if isNewDataSet && usdfcSybilFee != nil {
126- sybilFee .Set (usdfcSybilFee )
148+ cdnLockup := new (big.Int )
149+ cacheMissLockup := new (big.Int )
150+ if isNewDataSet && enableCDN {
151+ cdnLockup .Set (zeroBig (priceList .Lockups .CDNLockupAmount ))
152+ cacheMissLockup .Set (zeroBig (priceList .Lockups .CacheMissLockupAmount ))
127153 }
128154
129- totalLockup := new (big.Int ).Add (rateLockup , cdnLockup )
130- totalLockup .Add (totalLockup , sybilFee )
155+ totalLockup := new (big.Int ).Add (streamingLockup , lifecycleLockup )
156+ totalLockup .Add (totalLockup , cdnLockup )
157+ totalLockup .Add (totalLockup , cacheMissLockup )
158+ cdnFixedAlias := new (big.Int ).Add (cdnLockup , cacheMissLockup )
131159
132160 return AdditionalLockup {
133- RateDelta : rateDelta ,
134- RateLockup : rateLockup ,
135- CDNFixedLockup : cdnLockup ,
136- SybilFee : sybilFee ,
137- TotalLockup : totalLockup ,
161+ RateDeltaPerEpoch : rateDelta ,
162+ StreamingLockup : streamingLockup ,
163+ LifecycleLockup : lifecycleLockup ,
164+ CDNLockup : cdnLockup ,
165+ CacheMissLockup : cacheMissLockup ,
166+ Total : totalLockup ,
167+ RateDelta : copyBigOrDefault (rateDelta , nil ),
168+ RateLockup : copyBigOrDefault (streamingLockup , nil ),
169+ CDNFixedLockup : cdnFixedAlias ,
170+ SybilFee : copyBigOrDefault (lifecycleLockup , nil ),
171+ TotalLockup : copyBigOrDefault (totalLockup , nil ),
138172 }
139173}
140174
@@ -148,10 +182,12 @@ func CalculateAdditionalLockupRequired(
148182// Nil *big.Int fields are treated as zero. Negative epoch counts are clamped to zero.
149183func CalculateDepositNeeded (calc DepositCalculation ) * big.Int {
150184 additionalLockup := zeroBig (calc .AdditionalLockup )
185+ fees := zeroBig (calc .Fees )
151186 rateDelta := zeroBig (calc .RateDelta )
152187 currentLockupRate := zeroBig (calc .CurrentLockupRate )
153188 debt := zeroBig (calc .Debt )
154189 availableFunds := zeroBig (calc .AvailableFunds )
190+ runwayInEpochs := zeroBig (calc .RunwayInEpochs )
155191 runwayEpochs := calc .ExtraRunwayEpochs
156192 if runwayEpochs < 0 {
157193 runwayEpochs = 0
@@ -165,25 +201,26 @@ func CalculateDepositNeeded(calc DepositCalculation) *big.Int {
165201 runway := new (big.Int ).Mul (combinedRate , big .NewInt (runwayEpochs ))
166202
167203 raw := new (big.Int ).Add (additionalLockup , runway )
204+ raw .Add (raw , fees )
168205 raw .Sub (raw , availableFunds )
169206 raw .Add (raw , debt )
170207
171- if currentLockupRate .Sign () == 0 && calc .IsNewDataSet {
172- if raw .Sign () < 0 {
173- return new (big.Int )
208+ skipBuffer := currentLockupRate .Sign () == 0 && calc .IsNewDataSet
209+ buffer := new (big.Int )
210+ if ! skipBuffer {
211+ if raw .Sign () > 0 {
212+ buffer .Mul (combinedRate , bufferEpochsBig )
213+ } else if runwayInEpochs .Cmp (bufferEpochsBig ) <= 0 {
214+ buffer .Mul (combinedRate , bufferEpochsBig )
215+ buffer .Sub (buffer , availableFunds )
216+ if buffer .Sign () < 0 {
217+ buffer .SetInt64 (0 )
218+ }
174219 }
175- return raw
176220 }
177221
178- bufferCost := new (big.Int ).Mul (combinedRate , bufferEpochsBig )
179222 if raw .Sign () > 0 {
180- return raw .Add (raw , bufferCost )
181- }
182-
183- remainingAfterRequirements := new (big.Int ).Neg (raw )
184- buffer := new (big.Int ).Sub (bufferCost , remainingAfterRequirements )
185- if buffer .Sign () < 0 {
186- return new (big.Int )
223+ return raw .Add (raw , buffer )
187224 }
188225 return buffer
189226}
@@ -197,7 +234,7 @@ func zeroBig(v *big.Int) *big.Int {
197234
198235// isFWSSMaxApproved returns true when all FWSS approval conditions are met.
199236// Nil *big.Int fields are treated as zero (not approved).
200- func isFWSSMaxApproved (approved bool , rateAllowance , lockAllowance , maxLockPeriod * big.Int ) bool {
237+ func isFWSSMaxApproved (approved bool , rateAllowance , lockAllowance , maxLockPeriod , requiredLockupPeriod * big.Int ) bool {
201238 if ! approved {
202239 return false
203240 }
@@ -208,8 +245,52 @@ func isFWSSMaxApproved(approved bool, rateAllowance, lockAllowance, maxLockPerio
208245 if lockAllowance == nil || lockAllowance .Cmp (halfMaxUint256 ) < 0 {
209246 return false
210247 }
211- if maxLockPeriod == nil || maxLockPeriod .Cmp (big .NewInt (DefaultLockupPeriod )) < 0 {
248+ required := copyBigOrDefault (requiredLockupPeriod , big .NewInt (DefaultLockupPeriod ))
249+ if required .Sign () <= 0 {
250+ required .SetInt64 (DefaultLockupPeriod )
251+ }
252+ if maxLockPeriod == nil || maxLockPeriod .Cmp (required ) < 0 {
212253 return false
213254 }
214255 return true
215256}
257+
258+ func copyBigOrDefault (v , def * big.Int ) * big.Int {
259+ if v != nil {
260+ return new (big.Int ).Set (v )
261+ }
262+ if def != nil {
263+ return new (big.Int ).Set (def )
264+ }
265+ return new (big.Int )
266+ }
267+
268+ func requiredLockupPeriod (priceList * warmstorage.PriceList ) * big.Int {
269+ if priceList != nil && priceList .Lockups .DefaultLockupPeriod != nil && priceList .Lockups .DefaultLockupPeriod .Sign () > 0 {
270+ return new (big.Int ).Set (priceList .Lockups .DefaultLockupPeriod )
271+ }
272+ return big .NewInt (DefaultLockupPeriod )
273+ }
274+
275+ func aggregateLockup (rateDelta , streaming , lifecycle , cdn , cacheMiss , total * big.Int ) AdditionalLockup {
276+ rateDeltaOut := copyBigOrDefault (rateDelta , nil )
277+ streamingOut := copyBigOrDefault (streaming , nil )
278+ lifecycleOut := copyBigOrDefault (lifecycle , nil )
279+ cdnOut := copyBigOrDefault (cdn , nil )
280+ cacheMissOut := copyBigOrDefault (cacheMiss , nil )
281+ totalOut := copyBigOrDefault (total , nil )
282+ cdnFixedAlias := new (big.Int ).Add (cdnOut , cacheMissOut )
283+ return AdditionalLockup {
284+ RateDeltaPerEpoch : rateDeltaOut ,
285+ StreamingLockup : streamingOut ,
286+ LifecycleLockup : lifecycleOut ,
287+ CDNLockup : cdnOut ,
288+ CacheMissLockup : cacheMissOut ,
289+ Total : totalOut ,
290+ RateDelta : copyBigOrDefault (rateDeltaOut , nil ),
291+ RateLockup : copyBigOrDefault (streamingOut , nil ),
292+ CDNFixedLockup : cdnFixedAlias ,
293+ SybilFee : copyBigOrDefault (lifecycleOut , nil ),
294+ TotalLockup : copyBigOrDefault (totalOut , nil ),
295+ }
296+ }
0 commit comments