Skip to content

Commit ebb60b4

Browse files
committed
WIP
1 parent df514c9 commit ebb60b4

File tree

1 file changed

+79
-1
lines changed

1 file changed

+79
-1
lines changed

capabilities/writetarget/write_target.go

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"encoding/hex"
88
"errors"
99
"fmt"
10+
"math/big"
1011
"time"
1112

1213
"go.opentelemetry.io/otel/attribute"
@@ -57,6 +58,8 @@ type TargetStrategy interface {
5758
TransmitReport(ctx context.Context, report []byte, reportContext []byte, signatures [][]byte, request capabilities.CapabilityRequest) (string, error)
5859
// Wrapper around the ChainWriter to get the transaction status
5960
GetTransactionStatus(ctx context.Context, transactionID string) (commontypes.TransactionStatus, error)
61+
// Wrapper around the ChainWriter to get the fee esimate
62+
GetEstimateFee(ctx context.Context, contract string, method string, args any, toAddress string, meta *commontypes.TxMeta, val *big.Int) (commontypes.EstimateFee, error)
6063
}
6164

6265
var (
@@ -175,6 +178,53 @@ func success() capabilities.CapabilityResponse {
175178
return capabilities.CapabilityResponse{}
176179
}
177180

181+
// getGasSpendLimit returns the gas spend limit for the given chain ID from the request metadata
182+
func (c *writeTarget) getGasSpendLimit(request capabilities.CapabilityRequest) (string, error) {
183+
spendType := "GAS." + c.chainInfo.ChainID
184+
185+
for _, limit := range request.Metadata.SpendLimits {
186+
if spendType == string(limit.SpendType) {
187+
return limit.Limit, nil
188+
}
189+
}
190+
return "", fmt.Errorf("no gas spend limit found for chain %s", c.chainInfo.ChainID)
191+
}
192+
193+
// checkGasEstimate verifies if the estimated gas fee is within the spend limit and returns the fee
194+
func (c *writeTarget) checkGasEstimate(ctx context.Context, request capabilities.CapabilityRequest) (*big.Int, uint32, error) {
195+
spendLimit, err := c.getGasSpendLimit(request)
196+
if err != nil {
197+
return nil, 0, fmt.Errorf("failed to get gas spend limit, not performing gas estimation: %w", err)
198+
}
199+
200+
// Get gas estimate from ContractWriter
201+
fee, err := c.targetStrategy.GetEstimateFee(ctx, "", "", nil, "", nil, nil)
202+
if err != nil {
203+
return nil, 0, fmt.Errorf("failed to get gas estimate: %w", err)
204+
}
205+
206+
// Convert spend limit from ETH to wei
207+
limitFloat, ok := new(big.Float).SetString(spendLimit)
208+
if !ok {
209+
return nil, 0, fmt.Errorf("invalid gas spend limit format: %s", spendLimit)
210+
}
211+
212+
// Multiply by 10^decimals to convert from ETH to wei
213+
multiplier := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(fee.Decimals)), nil))
214+
limitFloat.Mul(limitFloat, multiplier)
215+
216+
// Convert to big.Int for comparison
217+
limit := new(big.Int)
218+
limitFloat.Int(limit)
219+
220+
// Compare estimate with limit
221+
if fee.Fee.Cmp(limit) > 0 {
222+
return nil, 0, fmt.Errorf("estimated gas fee %s exceeds spend limit %s", fee.Fee.String(), limit.String())
223+
}
224+
225+
return fee.Fee, fee.Decimals, nil
226+
}
227+
178228
func (c *writeTarget) Execute(ctx context.Context, request capabilities.CapabilityRequest) (capabilities.CapabilityResponse, error) {
179229
// Take the local timestamp
180230
tsStart := time.Now().UnixMilli()
@@ -189,6 +239,23 @@ func (c *writeTarget) Execute(ctx context.Context, request capabilities.Capabili
189239

190240
c.lggr.Debugw("Execute", "request", request, "capInfo", capInfo)
191241

242+
// Check gas estimate before proceeding
243+
fee, _, err := c.checkGasEstimate(ctx, request)
244+
if err != nil {
245+
// Build error message
246+
info := &requestInfo{
247+
tsStart: tsStart,
248+
node: c.nodeAddress,
249+
request: request,
250+
}
251+
errMsg := c.asEmittedError(ctx, &wt.WriteError{
252+
Code: uint32(TransmissionStateFatal),
253+
Summary: "InsufficientFunds",
254+
Cause: err.Error(),
255+
}, "info", info)
256+
return capabilities.CapabilityResponse{}, errMsg
257+
}
258+
192259
// Helper to keep track of the request info
193260
info := requestInfo{
194261
tsStart: tsStart,
@@ -342,7 +409,18 @@ func (c *writeTarget) Execute(ctx context.Context, request capabilities.Capabili
342409
if err != nil {
343410
return capabilities.CapabilityResponse{}, err
344411
}
345-
return success(), nil
412+
413+
return capabilities.CapabilityResponse{
414+
Metadata: capabilities.ResponseMetadata{
415+
Metering: []capabilities.MeteringNodeDetail{
416+
{
417+
Peer2PeerID: c.nodeAddress,
418+
SpendUnit: "GAS",
419+
SpendValue: fee.String(),
420+
},
421+
},
422+
},
423+
}, nil
346424
}
347425

348426
func (c *writeTarget) RegisterToWorkflow(ctx context.Context, request capabilities.RegisterToWorkflowRequest) error {

0 commit comments

Comments
 (0)