Skip to content

Commit f916c88

Browse files
committed
feat: Canton MCMS proposal analyzer
1 parent 52ef992 commit f916c88

13 files changed

Lines changed: 1471 additions & 11 deletions
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"chainlink-deployments-framework": minor
3+
---
4+
5+
feat(analyzer): implement Canton MCMS proposal analyzer
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package analyzer
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
7+
mcmscantonsdk "github.com/smartcontractkit/mcms/sdk/canton"
8+
"github.com/smartcontractkit/mcms/types"
9+
)
10+
11+
func AnalyzeCantonTransactions(ctx ProposalContext, chainSelector uint64, txs []types.Transaction) ([]*DecodedCall, error) {
12+
decoder := mcmscantonsdk.NewDecoder()
13+
decodedTxs := make([]*DecodedCall, len(txs))
14+
for i, op := range txs {
15+
analyzedTransaction, err := AnalyzeCantonTransaction(ctx, decoder, chainSelector, op)
16+
if err != nil {
17+
return nil, fmt.Errorf("failed to analyze Canton transaction %d: %w", i, err)
18+
}
19+
decodedTxs[i] = analyzedTransaction
20+
}
21+
22+
return decodedTxs, nil
23+
}
24+
25+
// AnalyzeCantonTransaction decodes a single Canton MCMS transaction. Each transaction already
26+
// describes the target call (Daml choice or factory deploy) via its AdditionalFields, so it is decoded directly
27+
func AnalyzeCantonTransaction(ctx ProposalContext, decoder *mcmscantonsdk.Decoder, chainSelector uint64, mcmsTx types.Transaction) (*DecodedCall, error) {
28+
contractType, contractVersion := resolveContractInfo(ctx, chainSelector, mcmsTx)
29+
30+
var additionalFields mcmscantonsdk.AdditionalFields
31+
if err := json.Unmarshal(mcmsTx.AdditionalFields, &additionalFields); err != nil {
32+
return nil, fmt.Errorf("failed to unmarshal Canton additional fields: %w", err)
33+
}
34+
35+
// Pass the resolved contract type as the fallback contract-type key
36+
// The decoder prefers the entity name parsed from AdditionalFields.TargetTemplateID when present.
37+
decodedOp, err := decoder.Decode(mcmsTx, contractType)
38+
if err != nil {
39+
errStr := fmt.Errorf("failed to decode Canton transaction %q: %w", additionalFields.FunctionName, err)
40+
41+
return &DecodedCall{
42+
Address: mcmsTx.To,
43+
Method: errStr.Error(),
44+
ContractType: contractType,
45+
ContractVersion: contractVersion,
46+
}, nil
47+
}
48+
49+
namedArgs, err := toNamedFields(decodedOp)
50+
if err != nil {
51+
return nil, fmt.Errorf("failed to convert decoded operation to named arguments: %w", err)
52+
}
53+
54+
return &DecodedCall{
55+
Address: mcmsTx.To,
56+
Method: decodedOp.MethodName(),
57+
Inputs: namedArgs,
58+
Outputs: []NamedField{},
59+
ContractType: contractType,
60+
ContractVersion: contractVersion,
61+
}, nil
62+
}

0 commit comments

Comments
 (0)