Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions chain_capabilities/aptos/actions/write_report.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,13 +231,13 @@ func (wr *writeReport) execute(
ownLedgerVersion, ownFeeInOctas, ownVMStatus, ownBlockTimestamp, feeErr := wr.getTxnInfoFromChain(ctx, txReply.TxHash)
if feeErr != nil {
wr.lggr.Errorw("Failed to get transaction fee, using zero for metering", "txHash", txReply.TxHash, "error", feeErr)
ownMeteringMetadata = metering.GetResponseMetadataWriteReport(big.NewFloat(0), wr.chainSelector)
ownMeteringMetadata = metering.GetResponseMetadataWriteReport(big.NewFloat(0), 0, wr.chainSelector)
monitoring.LogAndEmitError(ctx, wr.lggr, wr.beholderProcessor,
wr.messageBuilder.BuildWriteReportTxFeeCalculationError(telemetryContext, request, txReply.TxHash, feeErr.Error()))
} else {
pinnedLedgerVersion = &ownLedgerVersion
feeInAPT := aptosOctasToAPT(ownFeeInOctas)
ownMeteringMetadata = metering.GetResponseMetadataWriteReport(feeInAPT, wr.chainSelector)
ownMeteringMetadata = metering.GetResponseMetadataWriteReport(feeInAPT, ownFeeInOctas, wr.chainSelector)
wr.lggr.Debugw("WriteReport fee", "feeInAPT", feeInAPT.String(), "feeInOctas", ownFeeInOctas, "ledgerVersion", ownLedgerVersion)
}

Expand Down Expand Up @@ -285,7 +285,7 @@ func (wr *writeReport) execute(
}
feeInOctas := successResult.GasUsed * successResult.GasUnitPrice
feeInAPT := aptosOctasToAPT(feeInOctas)
meteringMetadata := metering.GetResponseMetadataWriteReport(feeInAPT, wr.chainSelector)
meteringMetadata := metering.GetResponseMetadataWriteReport(feeInAPT, feeInOctas, wr.chainSelector)
wr.lggr.Debugw("WriteReport fee", "feeInAPT", feeInAPT.String(), "feeInOctas", feeInOctas)

monitoring.LogAndEmitSuccess(ctx, "WriteReport sent a duplicate transaction, report already on-chain",
Expand All @@ -294,7 +294,7 @@ func (wr *writeReport) execute(

if txReply.TxStatus == aptostypes.TxFatal {
wr.lggr.Errorw("Transaction failed to get processed, but report was already submitted, this is unexpected and should be investigated", "txHash", txReply.TxHash)
meteringMetadata = metering.GetResponseMetadataWriteReport(big.NewFloat(0), wr.chainSelector)
meteringMetadata = metering.GetResponseMetadataWriteReport(big.NewFloat(0), 0, wr.chainSelector)
}

return &aptoscap.WriteReportReply{
Expand Down Expand Up @@ -363,7 +363,7 @@ func (wr *writeReport) execute(
var replyMeta capabilities.ResponseMetadata
if recvStatus != nil && *recvStatus == aptoscap.ReceiverContractExecutionStatus_RECEIVER_CONTRACT_EXECUTION_STATUS_REVERTED {
feeInAPT := aptosOctasToAPT(feeOctas)
replyMeta = metering.GetResponseMetadataWriteReport(feeInAPT, wr.chainSelector)
replyMeta = metering.GetResponseMetadataWriteReport(feeInAPT, feeOctas, wr.chainSelector)
}
return &aptoscap.WriteReportReply{
TxStatus: aptoscap.TxStatus_TX_STATUS_FATAL,
Expand Down
7 changes: 4 additions & 3 deletions chain_capabilities/aptos/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/smartcontractkit/capabilities/libs v0.0.0-20260714133332-db2a5f11cd64
github.com/smartcontractkit/chain-selectors v1.0.104
github.com/smartcontractkit/chainlink-aptos v0.0.0-20260506112908-f0d993b5bd6d
github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260707203317-661b54b51a33
github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260804191526-b7a850ae7648
)

require (
Expand All @@ -20,6 +20,7 @@ require (
github.com/jonboulle/clockwork v0.5.0 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/smartcontractkit/chainlink-protos/metering/go v0.0.0-20260710151514-27b5a126dabe // indirect
github.com/stretchr/objx v0.5.2 // indirect
go.opentelemetry.io/contrib/bridges/prometheus v0.68.0 // indirect
go.uber.org/goleak v1.3.0 // indirect
Expand Down Expand Up @@ -90,8 +91,8 @@ require (
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect
github.com/scylladb/go-reflectx v1.0.1 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/smartcontractkit/chainlink-common v0.11.2-0.20260713185857-30ad2e76c0f4
github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260626151909-052e55e62e62 // indirect
github.com/smartcontractkit/chainlink-common v0.11.2-0.20260819122115-078a7ae707aa
github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260724142814-45996a1bcb72 // indirect
github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b // indirect
github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260709145319-7782fb89eb16 // indirect
github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e // indirect
Expand Down
14 changes: 8 additions & 6 deletions chain_capabilities/aptos/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions chain_capabilities/aptos/metering/metering.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ package metering
import (
"fmt"
"math/big"
"strconv"

"github.com/smartcontractkit/chainlink-common/pkg/capabilities"
)

var WriteReportSpendUnitFormat = "GAS.%d" // %d will be replaced with the chain selector

func GetResponseMetadataWriteReport(fee *big.Float, chainSelector uint64) capabilities.ResponseMetadata {
func GetResponseMetadataWriteReport(feeInAPT *big.Float, feeInOctas uint64, chainSelector uint64) capabilities.ResponseMetadata {
return capabilities.ResponseMetadata{
Metering: []capabilities.MeteringNodeDetail{
{
SpendValue: fee.Text('f', -1), // stored in APT
SpendUnit: fmt.Sprintf(WriteReportSpendUnitFormat, chainSelector),
SpendValue: feeInAPT.Text('f', -1),
SpendValueInGasUnits: strconv.FormatUint(feeInOctas, 10),
SpendUnit: fmt.Sprintf(WriteReportSpendUnitFormat, chainSelector),
},
},
}
Expand Down
9 changes: 8 additions & 1 deletion chain_capabilities/aptos/metering/metering_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package metering

import (
"math/big"
"strconv"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -12,34 +13,39 @@ func TestGetResponseMetadataWriteReport(t *testing.T) {
tests := []struct {
name string
fee *big.Float
feeInOctas uint64
chainSelector uint64
expectedSpendUnit string
expectedValue string
}{
{
name: "Standard Aptos fee (500 octas = 0.000005 APT)",
fee: new(big.Float).Quo(new(big.Float).SetUint64(500), big.NewFloat(1e8)),
feeInOctas: 500,
chainSelector: 1,
expectedSpendUnit: "GAS.1",
expectedValue: "0.000005",
},
{
name: "Large fee (1 APT)",
fee: new(big.Float).SetFloat64(1.0),
feeInOctas: 100_000_000,
chainSelector: 42,
expectedSpendUnit: "GAS.42",
expectedValue: "1",
},
{
name: "Zero fee",
fee: new(big.Float).SetFloat64(0),
feeInOctas: 0,
chainSelector: 100,
expectedSpendUnit: "GAS.100",
expectedValue: "0",
},
{
name: "Typical fee (gasUsed=500 * gasUnitPrice=100 = 50000 octas = 0.0005 APT)",
fee: new(big.Float).Quo(new(big.Float).SetUint64(50_000), big.NewFloat(1e8)),
feeInOctas: 50_000,
chainSelector: 1,
expectedSpendUnit: "GAS.1",
expectedValue: "0.0005",
Expand All @@ -48,10 +54,11 @@ func TestGetResponseMetadataWriteReport(t *testing.T) {

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
result := GetResponseMetadataWriteReport(test.fee, test.chainSelector)
result := GetResponseMetadataWriteReport(test.fee, test.feeInOctas, test.chainSelector)
require.Len(t, result.Metering, 1)
assert.Equal(t, test.expectedSpendUnit, result.Metering[0].SpendUnit)
assert.Equal(t, test.expectedValue, result.Metering[0].SpendValue)
assert.Equal(t, strconv.FormatUint(test.feeInOctas, 10), result.Metering[0].SpendValueInGasUnits)
assert.Empty(t, result.Metering[0].Peer2PeerID, "Peer2PeerID should be empty")
})
}
Expand Down
12 changes: 6 additions & 6 deletions chain_capabilities/evm/actions/write_report.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,18 +103,18 @@ func (e *EVM) executeWriteReport(ctx context.Context, request *evm.WriteReportRe
return wr.executeWriteReport(ctx, request, metadata, telemetryContext)
}

func (e *WriteReport) getFee(ctx context.Context, txIdempotencyKey string) (*big.Float, error) {
func (e *WriteReport) getFee(ctx context.Context, txIdempotencyKey string) (*big.Float, *big.Int, error) {
if txIdempotencyKey == "" {
return nil, fmt.Errorf("txIdempotencyKey is empty, cannot retrieve transaction fee")
return nil, nil, fmt.Errorf("txIdempotencyKey is empty, cannot retrieve transaction fee")
}

feeInWei, errTxFee := e.GetTransactionFee(ctx, txIdempotencyKey)
if errTxFee != nil {
return nil, fmt.Errorf("failed to get transaction fee: %w", errTxFee)
return nil, nil, fmt.Errorf("failed to get transaction fee: %w", errTxFee)
}
feeInEth := new(big.Float).Quo(new(big.Float).SetInt(feeInWei.TransactionFee), big.NewFloat(1e18))
e.lggr.Debugw("WriteReport fee", "feeInEth", feeInEth.String(), "feeInWei", feeInWei.TransactionFee.String())
return feeInEth, nil
return feeInEth, feeInWei.TransactionFee, nil
}

func (e *WriteReport) executeWriteReport(ctx context.Context, request *evm.WriteReportRequest, metadata capabilities.RequestMetadata, telemetryContext monitoring.TelemetryContext) (*evm.WriteReportReply, capabilities.ResponseMetadata, error) {
Expand Down Expand Up @@ -243,11 +243,11 @@ func (e *WriteReport) executeWriteReport(ctx context.Context, request *evm.Write
e.lggr.Infow("Got final transmission status", newTransmissionInfo.LogAttrs()...)

var meteringMetadata capabilities.ResponseMetadata
transactionFee, err := e.getFee(ctx, transactionResult.TxIdempotencyKey)
transactionFee, feeInWei, err := e.getFee(ctx, transactionResult.TxIdempotencyKey)
if err != nil {
monitoring.LogAndEmitError(ctx, e.lggr, e.beholderProcessor, e.messageBuilder.BuildWriteReportTxFeeCalculationError(telemetryContext, request, transactionResult.TxIdempotencyKey, err.Error()))
} else {
meteringMetadata = metering.GetResponseMetadataWriteReport(transactionFee, e.chainSelector)
meteringMetadata = metering.GetResponseMetadataWriteReport(transactionFee, feeInWei, e.chainSelector)
}

switch newTransmissionInfo.State {
Expand Down
14 changes: 7 additions & 7 deletions chain_capabilities/evm/actions/write_report_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1021,7 +1021,7 @@ func TestWriteReport_ExecuteWriteReport(t *testing.T) {
}, txResult.Response)

// Retried tx => should be metered.
evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003")
evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003", "300")
})

t.Run("TX first transmission - Successful TX execution (ensures non-nil + positive gas config passed to forwarder)", func(t *testing.T) {
Expand Down Expand Up @@ -1093,7 +1093,7 @@ func TestWriteReport_ExecuteWriteReport(t *testing.T) {
TransactionFee: pb.NewBigIntFromInt(big.NewInt(retryTxFee)),
}, txResult.Response)

evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003")
evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003", "300")
})

t.Run("TX first transmission - Error submitting TX (ensures gas config passed is non-nil + positive)", func(t *testing.T) {
Expand Down Expand Up @@ -1193,7 +1193,7 @@ func TestWriteReport_ExecuteWriteReport(t *testing.T) {
TransactionFee: pb.NewBigIntFromInt(big.NewInt(2000)),
}, txResult.Response)

evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003")
evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003", "300")
})

t.Run("TX first transmission - Duplicate tx: txmgr reports reverted but transmission succeeded => use onchain tx hash", func(t *testing.T) {
Expand Down Expand Up @@ -1271,7 +1271,7 @@ func TestWriteReport_ExecuteWriteReport(t *testing.T) {
TransactionFee: pb.NewBigIntFromInt(big.NewInt(txFee)),
}, txResult.Response)

evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003")
evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003", "300")
})

t.Run("TX first transmission - Fatal tx but transmission succeeded => use onchain tx hash", func(t *testing.T) {
Expand Down Expand Up @@ -1344,7 +1344,7 @@ func TestWriteReport_ExecuteWriteReport(t *testing.T) {
TransactionFee: pb.NewBigIntFromInt(big.NewInt(txFee)),
}, txResult.Response)

evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003")
evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003", "300")
})

t.Run("TX first transmission - Fatal tx and GetSuccessfulTransmissionHash fails => returns error", func(t *testing.T) {
Expand Down Expand Up @@ -1518,7 +1518,7 @@ func TestWriteReport_ExecuteWriteReport(t *testing.T) {
require.Equal(t, receiptTxHash[:], txResult.Response.TxHash)
require.NotNil(t, txResult.Response.ReceiverContractExecutionStatus)
require.Equal(t, evm.ReceiverContractExecutionStatus_RECEIVER_CONTRACT_EXECUTION_STATUS_REVERTED.Enum(), txResult.Response.ReceiverContractExecutionStatus.Enum())
evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003")
evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003", "300")

if queuePosition == 0 {
mockForwarderClient.AssertNotCalled(t, "GetReportProcessedEvents", mock.Anything, mock.Anything, mock.Anything, mock.Anything)
Expand Down Expand Up @@ -2253,7 +2253,7 @@ func TestWriteReport_RevertReceiptFetchFailsReturnsUserError(t *testing.T) {
assertMetadata: func(t *testing.T, metadata capabilities.ResponseMetadata) {
t.Helper()

evmtest.ValidateMeteringWriteReport(t, metadata, 1, "0.0000000000000003")
evmtest.ValidateMeteringWriteReport(t, metadata, 1, "0.0000000000000003", "300")
},
},
}
Expand Down
7 changes: 4 additions & 3 deletions chain_capabilities/evm/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ require (
github.com/smartcontractkit/capabilities/chain_capabilities/common v0.0.0-20260729165045-b00a39493e13
github.com/smartcontractkit/capabilities/libs v0.0.0-20260714133332-db2a5f11cd64
github.com/smartcontractkit/chain-selectors v1.0.106
github.com/smartcontractkit/chainlink-common v0.11.2-0.20260714130758-475cb096a3e1
github.com/smartcontractkit/chainlink-common v0.11.2-0.20260819122115-078a7ae707aa
github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260410162948-2dca02f24e98
github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20251022073203-7d8ae8cf67c1
github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20260410144512-ca02ad6ed16a
github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260707203317-661b54b51a33
github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260804191526-b7a850ae7648
github.com/stretchr/testify v1.11.1
go.opentelemetry.io/otel v1.43.0
go.uber.org/zap v1.27.1
Expand Down Expand Up @@ -90,10 +90,11 @@ require (
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/smartcontractkit/chainlink-common/keystore v1.1.1-0.20260529092756-a94bc8ce96d6 // indirect
github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260626151909-052e55e62e62 // indirect
github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260724142814-45996a1bcb72 // indirect
github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20260326122810-b657beadfb57 // indirect
github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20260401162955-be2bc6b5264b // indirect
github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b // indirect
github.com/smartcontractkit/chainlink-protos/metering/go v0.0.0-20260710151514-27b5a126dabe // indirect
github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260709145319-7782fb89eb16 // indirect
github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20260528173149-f5b8336b19d9 // indirect
github.com/stretchr/objx v0.5.2 // indirect
Expand Down
Loading
Loading