@@ -18,6 +18,7 @@ import (
1818 retry "github.com/yetanotherco/aligned_layer/core"
1919 "github.com/yetanotherco/aligned_layer/core/config"
2020 "github.com/yetanotherco/aligned_layer/core/utils"
21+ "github.com/yetanotherco/aligned_layer/metrics"
2122)
2223
2324type AvsWriter struct {
@@ -27,9 +28,10 @@ type AvsWriter struct {
2728 Signer signer.Signer
2829 Client eth.InstrumentedClient
2930 ClientFallback eth.InstrumentedClient
31+ metrics * metrics.Metrics
3032}
3133
32- func NewAvsWriterFromConfig (baseConfig * config.BaseConfig , ecdsaConfig * config.EcdsaConfig ) (* AvsWriter , error ) {
34+ func NewAvsWriterFromConfig (baseConfig * config.BaseConfig , ecdsaConfig * config.EcdsaConfig , metrics * metrics. Metrics ) (* AvsWriter , error ) {
3335
3436 buildAllConfig := clients.BuildAllConfig {
3537 EthHttpUrl : baseConfig .EthRpcUrl ,
@@ -69,6 +71,7 @@ func NewAvsWriterFromConfig(baseConfig *config.BaseConfig, ecdsaConfig *config.E
6971 Signer : privateKeySigner ,
7072 Client : baseConfig .EthRpcClient ,
7173 ClientFallback : baseConfig .EthRpcClientFallback ,
74+ metrics : metrics ,
7275 }, nil
7376}
7477
@@ -83,11 +86,6 @@ func (w *AvsWriter) SendAggregatedResponse(batchIdentifierHash [32]byte, batchMe
8386 return nil , err
8487 }
8588
86- err = w .checkRespondToTaskFeeLimit (tx , txOpts , batchIdentifierHash , senderAddress )
87- if err != nil {
88- return nil , err
89- }
90-
9189 // Set the nonce, as we might have to replace the transaction with a higher gas price
9290 txNonce := big .NewInt (int64 (tx .Nonce ()))
9391 txOpts .Nonce = txNonce
@@ -114,7 +112,9 @@ func (w *AvsWriter) SendAggregatedResponse(batchIdentifierHash [32]byte, batchMe
114112 onGasPriceBumped (txOpts .GasPrice )
115113 }
116114
117- err = w .checkRespondToTaskFeeLimit (tx , txOpts , batchIdentifierHash , senderAddress )
115+ // We compare both Aggregator funds and Batcher balance in Aligned against respondToTaskFeeLimit
116+ // Both are required to have some balance, more details inside the function
117+ err = w .checkAggAndBatcherHaveEnoughBalance (tx , txOpts , batchIdentifierHash , senderAddress )
118118 if err != nil {
119119 return nil , retry.PermanentError {Inner : err }
120120 }
@@ -128,6 +128,7 @@ func (w *AvsWriter) SendAggregatedResponse(batchIdentifierHash [32]byte, batchMe
128128
129129 receipt , err := utils .WaitForTransactionReceiptRetryable (w .Client , w .ClientFallback , tx .Hash (), timeToWaitBeforeBump )
130130 if receipt != nil {
131+ w .checkIfAggregatorHadToPaidForBatcher (tx , batchIdentifierHash )
131132 return receipt , nil
132133 }
133134
@@ -145,29 +146,45 @@ func (w *AvsWriter) SendAggregatedResponse(batchIdentifierHash [32]byte, batchMe
145146 return retry .RetryWithData (respondToTaskV2Func , retry .MinDelay , retry .RetryFactor , 0 , retry .MaxInterval , 0 )
146147}
147148
148- func (w * AvsWriter ) checkRespondToTaskFeeLimit (tx * types.Transaction , txOpts bind.TransactOpts , batchIdentifierHash [32 ]byte , senderAddress [20 ]byte ) error {
149- aggregatorAddress := txOpts .From
150- simulatedCost := new (big.Int ).Mul (new (big.Int ).SetUint64 (tx .Gas ()), tx .GasPrice ())
151- w .logger .Info ("Simulated cost" , "cost" , simulatedCost )
152-
153- // Get RespondToTaskFeeLimit
149+ // Calculates the transaction cost from the receipt and compares it with the batcher respondToTaskFeeLimit
150+ // if the tx cost was higher, then it means the aggregator has paid the difference for the batcher (txCost - respondToTaskFeeLimit) and so metrics are updated accordingly.
151+ // otherwise nothing is done.
152+ func (w * AvsWriter ) checkIfAggregatorHadToPaidForBatcher (tx * types.Transaction , batchIdentifierHash [32 ]byte ) {
154153 batchState , err := w .BatchesStateRetryable (& bind.CallOpts {}, batchIdentifierHash )
155154 if err != nil {
156- // Fallback also failed
157- // Proceed to check values against simulated costs
158- w .logger .Error ("Failed to get batch state" , "error" , err )
159- w .logger .Info ("Proceeding with simulated cost checks" )
160- return w .compareBalances (simulatedCost , aggregatorAddress , senderAddress )
155+ return
161156 }
162- // At this point, batchState was successfully retrieved
163- // Proceed to check values against RespondToTaskFeeLimit
164157 respondToTaskFeeLimit := batchState .RespondToTaskFeeLimit
165- w .logger .Info ("Batch RespondToTaskFeeLimit" , "RespondToTaskFeeLimit" , respondToTaskFeeLimit )
166158
167- if respondToTaskFeeLimit .Cmp (simulatedCost ) < 0 {
168- return fmt .Errorf ("cost of transaction is higher than Batch.RespondToTaskFeeLimit" )
159+ // NOTE we are not using tx.Cost() because tx.Cost() includes tx.Value()
160+ txCost := new (big.Int ).Mul (big .NewInt (int64 (tx .Gas ())), tx .GasPrice ())
161+
162+ if respondToTaskFeeLimit .Cmp (txCost ) < 0 {
163+ aggregatorDifferencePaid := new (big.Int ).Sub (txCost , respondToTaskFeeLimit )
164+ aggregatorDifferencePaidInEth := utils .WeiToEth (aggregatorDifferencePaid )
165+ w .metrics .AddAggregatorGasPaidForBatcher (aggregatorDifferencePaidInEth )
166+ w .metrics .IncAggregatorPaidForBatcher ()
167+ w .logger .Warnf ("cost of transaction was higher than Batch.RespondToTaskFeeLimit, aggregator has paid the for the difference, aprox: %vethers" , aggregatorDifferencePaidInEth )
169168 }
169+ }
170+
171+ func (w * AvsWriter ) checkAggAndBatcherHaveEnoughBalance (tx * types.Transaction , txOpts bind.TransactOpts , batchIdentifierHash [32 ]byte , senderAddress [20 ]byte ) error {
172+ w .logger .Info ("Checking if aggregator and batcher have enough balance for the transaction" )
173+ aggregatorAddress := txOpts .From
174+ txCost := new (big.Int ).Mul (new (big.Int ).SetUint64 (tx .Gas ()), txOpts .GasPrice )
175+ w .logger .Info ("Transaction cost" , "cost" , txCost )
170176
177+ batchState , err := w .BatchesStateRetryable (& bind.CallOpts {}, batchIdentifierHash )
178+ if err != nil {
179+ w .logger .Error ("Failed to get batch state" , "error" , err )
180+ w .logger .Info ("Proceeding to check balances against transaction cost" )
181+ return w .compareBalances (txCost , aggregatorAddress , senderAddress )
182+ }
183+ respondToTaskFeeLimit := batchState .RespondToTaskFeeLimit
184+ w .logger .Info ("Checking balance against Batch RespondToTaskFeeLimit" , "RespondToTaskFeeLimit" , respondToTaskFeeLimit )
185+ // Note: we compare both Aggregator funds and Batcher balance in Aligned against respondToTaskFeeLimit
186+ // Batcher will pay up to respondToTaskFeeLimit, for this he needs that amount of funds in Aligned
187+ // Aggregator will pay any extra cost, for this he needs at least respondToTaskFeeLimit in his balance
171188 return w .compareBalances (respondToTaskFeeLimit , aggregatorAddress , senderAddress )
172189}
173190
0 commit comments