Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .changeset/bold-olives-smell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink-deployments-framework": minor
---

Use Metadata.ContractVersion instead of ContractTypeAndVersion
5 changes: 0 additions & 5 deletions engine/cld/commands/mcms/testdata/proposal.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,39 +24,34 @@
"data": "ebpQlw==",
"value": 0,
"contractType": "",
"contractTypeAndVersion": "",
"tags": null
},
{
"to": "0x53850c7ee54fce09174f21f6c4b5602e4ca46353",
"data": "ebpQlw==",
"value": 0,
"contractType": "",
"contractTypeAndVersion": "",
"tags": null
},
{
"to": "0x7ae20d26f2969ae44054a02e1acf19c3eecff148",
"data": "ebpQlw==",
"value": 0,
"contractType": "",
"contractTypeAndVersion": "",
"tags": null
},
{
"to": "0xed54914840214c01c06de50737ae9d9fe184cc26",
"data": "ebpQlw==",
"value": 0,
"contractType": "",
"contractTypeAndVersion": "",
"tags": null
},
{
"to": "0xfa2a8aa2982999f3df3b66405886c4007d6d8418",
"data": "ebpQlw==",
"value": 0,
"contractType": "",
"contractTypeAndVersion": "",
"tags": null
}
]
Expand Down
2 changes: 1 addition & 1 deletion engine/test/internal/mcmsutils/encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func TestDecodeProposal(t *testing.T) {
assert.Equal(t, "v1", proposal.Version)
assert.Equal(t, mcmstypes.ProposalKind("Proposal"), proposal.Kind)
require.Contains(t, proposal.ChainMetadata, mcmstypes.ChainSelector(3379446385462418246))
require.Len(t, proposal.Operations, 1)
require.Len(t, proposal.Operations, 2)
})

t.Run("failed decoding", func(t *testing.T) {
Expand Down
14 changes: 13 additions & 1 deletion engine/test/internal/mcmsutils/testdata/proposal.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@
}
},
"operations": [
{
"chainSelector": 3379446385462418246,
"transaction": {
"to": "0x123",
"additionalFields": {
"value": 0
},
"data": "",
"tags": null,
"contractType": ""
}
},
{
"chainSelector": 3379446385462418246,
"transaction": {
Expand All @@ -23,7 +35,7 @@
"data": "",
"tags": null,
"contractType": "",
"contractTypeAndVersion": ""
"contractVersion": "1.2.3"
}
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@
"transactions": [
{
"to": "0x0000000000000000000000000000000000000000",
"additionalFields": {"value": 0},
"additionalFields": {
"value": 0
},
"data": "ZGF0YQ==",
"contractType": "",
"contractTypeAndVersion": "",
"tags": null
}
]
}
]
}
}
17 changes: 11 additions & 6 deletions experimental/analyzer/decoded_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,35 @@ func (d *DecodedCall) String(context *FieldContext) string {
// resolveContractInfo looks up the contract type and version from the proposal
// context's registered addresses.
func resolveContractInfo(ctx ProposalContext, chainSelector uint64, mcmsTx types.Transaction) (contractType, contractVersion string) {
// Use ContractVersion from transaction metadata (set by proposal creator) as fallback
if mcmsTx.ContractVersion != nil {
contractVersion = mcmsTx.ContractVersion.String()
}

dpc, ok := ctx.(*DefaultProposalContext)
if !ok {
return mcmsTx.ContractType, ""
return mcmsTx.ContractType, contractVersion
}

addresses, ok := dpc.AddressesByChain[chainSelector]
if !ok {
return mcmsTx.ContractType, ""
return mcmsTx.ContractType, contractVersion
}

tv, ok := addresses[mcmsTx.To]
if !ok {
return mcmsTx.ContractType, ""
return mcmsTx.ContractType, contractVersion
}

ct := string(tv.Type)
if ct == "" {
ct = mcmsTx.ContractType
}

var cv string
// Override with the DataStore version if available
if tv.Version.Original() != "" {
cv = tv.Version.String()
contractVersion = tv.Version.String()
}

return ct, cv
return ct, contractVersion
}
55 changes: 30 additions & 25 deletions experimental/analyzer/ton_analyzer.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package analyzer

import (
"encoding/json"
"fmt"

"github.com/smartcontractkit/mcms/sdk"
"github.com/smartcontractkit/mcms/sdk/ton"
"github.com/smartcontractkit/mcms/types"

"github.com/smartcontractkit/chainlink-deployments-framework/deployment"

"github.com/smartcontractkit/chainlink-ton/pkg/bindings"
)

Expand All @@ -29,37 +28,43 @@ func AnalyzeTONTransactions(ctx ProposalContext, chainSelector uint64, txs []typ

// AnalyzeTONTransaction decodes a single TON transaction using the MCMS TON decoder.
//
// Unlike Aptos/Sui analyzers, this function does not unmarshal AdditionalFields because
// the TON decoder only requires tx.Data (BOC cell) and tx.ContractType (metadata).
// AdditionalFields in TON is only used by the encoder/timelock_converter for the Value field.
//
// On decode failure, this function returns a DecodedCall with the error in the Method field
// instead of returning an error. This allows the proposal to continue processing even if
// a single transaction fails to decode.
func AnalyzeTONTransaction(ctx ProposalContext, decoder sdk.Decoder, chainSelector uint64, mcmsTx types.Transaction) (*DecodedCall, error) {
contractTypeAndVersion, err := deployment.TypeAndVersionFromString(mcmsTx.ContractTypeAndVersion)
if err != nil {
contractType, contractVersion := resolveContractInfo(ctx, chainSelector, mcmsTx)
errStr := fmt.Errorf("failed to decode TON transaction: failed to parse contract type and version: %w", err)
contractType, contractVersion := resolveContractInfo(ctx, chainSelector, mcmsTx)

return &DecodedCall{
Address: mcmsTx.To,
Method: errStr.Error(),
ContractType: contractType,
ContractVersion: contractVersion,
}, nil
}
decodedOp, err := decoder.Decode(mcmsTx, contractTypeAndVersion.Type.String())
if err != nil {
var typeErr string
fullyQualifiedName := func() string {
var additionalFields ton.AdditionalFields
if err := json.Unmarshal(mcmsTx.AdditionalFields, &additionalFields); err != nil {
typeErr = fmt.Sprintf("; additionally failed to unmarshal TON additional fields: %s", err)
return ""
Comment thread
patricios-space marked this conversation as resolved.
}

fullyQualifiedName := string(additionalFields.ContractTypeFull)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Let's extract into a type/func which we document and allows anybody to produce a FQN

// If ContractVersion is provided, append it to the fully qualified name to ensure the decoder uses the correct version.
// If it is skipped, the decoder will use the latest version available for the contract type.
// Note: we don't use contractVersion from resolveContractInfo because that only represents the short type used by the datastore.
Comment thread
patricios-space marked this conversation as resolved.
Comment thread
patricios-space marked this conversation as resolved.
if mcmsTx.ContractVersion != nil {
Comment thread
patricios-space marked this conversation as resolved.
fullyQualifiedName += "@" + mcmsTx.ContractVersion.String()
}
Comment on lines +45 to +51

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want this in TON because we only want to select a version explicitly via TX params


return fullyQualifiedName
}()

decodedOp, errDec := decoder.Decode(mcmsTx, fullyQualifiedName)
if errDec != nil {
// Don't return an error to not block the whole proposal decoding because of a single transaction decode failure.
// Instead, put the error message in the Method field so it's visible in the report.
errStr := fmt.Errorf("failed to decode TON transaction: %w", err)
errStr := "failed to decode TON transaction: " + errDec.Error() + typeErr

//nolint:nilerr // We are intentionally not returning an error here to allow the proposal to be processed even if decoding fails.
return &DecodedCall{
Address: mcmsTx.To,
Method: errStr.Error(),
ContractType: contractTypeAndVersion.Type.String(),
ContractVersion: contractTypeAndVersion.Version.String(),
Method: errStr,
ContractType: contractType,
ContractVersion: contractVersion,
}, nil
}

Expand All @@ -73,7 +78,7 @@ func AnalyzeTONTransaction(ctx ProposalContext, decoder sdk.Decoder, chainSelect
Method: decodedOp.MethodName(),
Inputs: namedArgs,
Outputs: []NamedField{},
ContractType: contractTypeAndVersion.Type.String(),
ContractVersion: contractTypeAndVersion.Version.String(),
ContractType: contractType,
ContractVersion: contractVersion,
}, nil
}
Loading
Loading