Skip to content

Commit a017b7f

Browse files
committed
Add and test MCMS/Timelock JSON decoder
1 parent 1ed892e commit a017b7f

File tree

5 files changed

+216
-7
lines changed

5 files changed

+216
-7
lines changed

pkg/bindings/mcms/timelock/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ type Data struct {
341341
// Represents a single call
342342
type Call struct {
343343
// Address of the target contract to call.
344-
Target address.Address `tlb:"addr"`
344+
Target *address.Address `tlb:"addr"`
345345
// Value in TONs to send with the call.
346346
Value *big.Int `tlb:"## 256"`
347347
// Data to send with the call - message body.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package mcms
2+
3+
import (
4+
"github.com/xssnick/tonutils-go/address"
5+
"github.com/xssnick/tonutils-go/tvm/cell"
6+
7+
cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
8+
9+
"github.com/smartcontractkit/chainlink-ton/pkg/bindings/mcms/mcms"
10+
11+
"github.com/smartcontractkit/chainlink-ton/pkg/ton/debug/lib"
12+
"github.com/smartcontractkit/chainlink-ton/pkg/ton/tvm"
13+
)
14+
15+
var TLBs = lib.MustNewTLBMap([]interface{}{
16+
mcms.SetRoot{},
17+
mcms.Execute{},
18+
mcms.SetConfig{},
19+
mcms.SubmitErrorReport{},
20+
mcms.TransferOracleRole{},
21+
mcms.NewRoot{},
22+
mcms.ConfigSet{},
23+
mcms.OpExecuted{},
24+
mcms.ErrorReportSubmitted{},
25+
mcms.OracleRoleTransferred{},
26+
})
27+
28+
type decoder struct{}
29+
30+
func NewDecoder() lib.ContractDecoder {
31+
return &decoder{}
32+
}
33+
34+
func (d *decoder) ContractType() cldf.ContractType {
35+
return cldf.ContractType("com.chainlink.ton.mcms.MCMS")
36+
}
37+
38+
func (d *decoder) EventInfo(dstAddr *address.Address, msg *cell.Cell) (lib.MessageInfo, error) {
39+
return nil, &lib.UnknownMessageError{}
40+
}
41+
42+
func (d *decoder) ExternalMessageInfo(msg *cell.Cell) (lib.MessageInfo, error) {
43+
return nil, &lib.UnknownMessageError{}
44+
}
45+
46+
func (d *decoder) InternalMessageInfo(msg *cell.Cell) (lib.MessageInfo, error) {
47+
return lib.NewMessageInfoFromCell(d.ContractType(), msg, TLBs)
48+
}
49+
50+
// TODO: implement exit code descriptions for MCMS
51+
// Notice: tvm.ExitCode is not the right type to use (these are low-level TVM exit codes),
52+
// we should define our own ExitCode type for our contracts
53+
func (d *decoder) ExitCodeInfo(exitCode tvm.ExitCode) (string, error) {
54+
switch exitCode {
55+
default:
56+
return "", &lib.UnknownMessageError{}
57+
}
58+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package timelock
2+
3+
import (
4+
"github.com/xssnick/tonutils-go/address"
5+
"github.com/xssnick/tonutils-go/tvm/cell"
6+
7+
cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
8+
9+
"github.com/smartcontractkit/chainlink-ton/pkg/bindings/mcms/timelock"
10+
11+
"github.com/smartcontractkit/chainlink-ton/pkg/ton/debug/lib"
12+
"github.com/smartcontractkit/chainlink-ton/pkg/ton/tvm"
13+
)
14+
15+
var TLBs = lib.MustNewTLBMap([]interface{}{
16+
timelock.Init{},
17+
timelock.ScheduleBatch{},
18+
timelock.Cancel{},
19+
timelock.ExecuteBatch{},
20+
timelock.UpdateDelay{},
21+
timelock.UpdateOpFinalizationTimeout{},
22+
timelock.BlockFunctionSelector{},
23+
timelock.UnblockFunctionSelector{},
24+
timelock.BypasserExecuteBatch{},
25+
timelock.UpdateExecutorRoleCheck{},
26+
timelock.SubmitErrorReport{},
27+
timelock.CallScheduled{},
28+
timelock.CallExecuted{},
29+
timelock.BypasserCallExecuted{},
30+
timelock.Cancelled{},
31+
timelock.MinDelayChange{},
32+
timelock.FunctionSelectorBlocked{},
33+
timelock.FunctionSelectorUnblocked{},
34+
timelock.ExecutorRoleCheckUpdated{},
35+
})
36+
37+
type decoder struct{}
38+
39+
func NewDecoder() lib.ContractDecoder {
40+
return &decoder{}
41+
}
42+
43+
func (d *decoder) ContractType() cldf.ContractType {
44+
return cldf.ContractType("com.chainlink.ton.mcms.Timelock")
45+
}
46+
47+
func (d *decoder) EventInfo(dstAddr *address.Address, msg *cell.Cell) (lib.MessageInfo, error) {
48+
return nil, &lib.UnknownMessageError{}
49+
}
50+
51+
func (d *decoder) ExternalMessageInfo(msg *cell.Cell) (lib.MessageInfo, error) {
52+
return nil, &lib.UnknownMessageError{}
53+
}
54+
55+
func (d *decoder) InternalMessageInfo(msg *cell.Cell) (lib.MessageInfo, error) {
56+
return lib.NewMessageInfoFromCell(d.ContractType(), msg, TLBs)
57+
}
58+
59+
// TODO: implement exit code descriptions for MCMS
60+
// Notice: tvm.ExitCode is not the right type to use (these are low-level TVM exit codes),
61+
// we should define our own ExitCode type for our contracts
62+
func (d *decoder) ExitCodeInfo(exitCode tvm.ExitCode) (string, error) {
63+
switch exitCode {
64+
default:
65+
return "", &lib.UnknownMessageError{}
66+
}
67+
}

pkg/ton/debug/lib/lib_test.go

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import (
66
"testing"
77

88
"github.com/smartcontractkit/chainlink-ton/pkg/bindings/jetton/wallet"
9+
"github.com/smartcontractkit/chainlink-ton/pkg/bindings/mcms/mcms"
10+
"github.com/smartcontractkit/chainlink-ton/pkg/bindings/mcms/timelock"
11+
"github.com/smartcontractkit/chainlink-ton/pkg/ccip/bindings/common"
912

1013
"github.com/xssnick/tonutils-go/address"
1114
"github.com/xssnick/tonutils-go/tlb"
@@ -27,7 +30,14 @@ type Baz struct {
2730
Val *address.Address `tlb:"addr"`
2831
}
2932

30-
var TLBs = MustNewTLBMap([]interface{}{Foo{}, Bar{}, Baz{}, wallet.AskToTransfer{}})
33+
var TLBs = MustNewTLBMap([]interface{}{
34+
Foo{},
35+
Bar{},
36+
Baz{},
37+
wallet.AskToTransfer{},
38+
mcms.Execute{},
39+
timelock.ScheduleBatch{},
40+
})
3141

3242
func mustToCell(v interface{}) *cell.Cell {
3343
c, err := tlb.ToCell(v)
@@ -159,8 +169,81 @@ func TestDecodeJSONMapFromCell(t *testing.T) {
159169
},
160170
expectErr: false,
161171
},
172+
{
173+
name: "Decode MCMS Execute > Timelock ScheduleBatch > Op[]s with Bar and Baz in payload",
174+
cell: mustToCell(mcms.Execute{
175+
QueryID: 31,
176+
Op: mcms.Op{
177+
ChainID: big.NewInt(-14),
178+
MultiSig: address.MustParseAddr("EQADa3W6G0nSiTV4a6euRA42fU9QxSEnb-WeDpcrtWzA2jM8"),
179+
Nonce: 42,
180+
To: address.MustParseAddr("EQADa3W6G0nSiTV4a6euRA42fU9QxSEnb-WeDpcrtWzA2jM8"),
181+
Value: tlb.MustFromTON("1.5"),
182+
Data: mustToCell(timelock.ScheduleBatch{
183+
QueryID: 31,
184+
Calls: common.SnakeData[timelock.Call]{
185+
timelock.Call{
186+
Target: address.MustParseAddr("EQADa3W6G0nSiTV4a6euRA42fU9QxSEnb-WeDpcrtWzA2jM8"),
187+
Value: tlb.MustFromTON("0.5").Nano(),
188+
Data: mustToCell(Bar{
189+
Val: big.NewInt(55555555),
190+
}),
191+
},
192+
timelock.Call{
193+
Target: address.MustParseAddr("EQADa3W6G0nSiTV4a6euRA42fU9QxSEnb-WeDpcrtWzA2jM8"),
194+
Value: tlb.MustFromTON("1.0").Nano(),
195+
Data: mustToCell(Baz{
196+
Val: address.MustParseAddr("EQADa3W6G0nSiTV4a6euRA42fU9QxSEnb-WeDpcrtWzA2jM8"),
197+
}),
198+
},
199+
},
200+
Predecessor: big.NewInt(-1),
201+
Salt: big.NewInt(1337),
202+
Delay: 10000,
203+
}),
204+
},
205+
}),
206+
wantType: "Execute",
207+
wantMap: map[string]interface{}{
208+
"QueryID": float64(31),
209+
"Op": map[string]interface{}{
210+
"ChainID": float64(-14),
211+
"MultiSig": "EQADa3W6G0nSiTV4a6euRA42fU9QxSEnb-WeDpcrtWzA2jM8",
212+
"Nonce": float64(42),
213+
"To": "EQADa3W6G0nSiTV4a6euRA42fU9QxSEnb-WeDpcrtWzA2jM8",
214+
"Value": "1500000000",
215+
"Data": map[string]interface{}{
216+
"QueryID": float64(31),
217+
"Calls": []interface{}{
218+
map[string]interface{}{
219+
"Target": "EQADa3W6G0nSiTV4a6euRA42fU9QxSEnb-WeDpcrtWzA2jM8",
220+
"Value": "500000000",
221+
"Data": map[string]interface{}{
222+
"Val": float64(55555555),
223+
},
224+
},
225+
map[string]interface{}{
226+
"Target": "EQADa3W6G0nSiTV4a6euRA42fU9QxSEnb-WeDpcrtWzA2jM8",
227+
"Value": "1000000000",
228+
"Data": map[string]interface{}{
229+
"Val": "EQADa3W6G0nSiTV4a6euRA42fU9QxSEnb-WeDpcrtWzA2jM8",
230+
},
231+
},
232+
},
233+
"Predecessor": float64(-1),
234+
"Salt": float64(1337),
235+
"Delay": float64(10000),
236+
},
237+
},
238+
"Proof": nil,
239+
},
240+
},
162241
}
163242

243+
// TODO: *cell.Cell in nested struct is not getting decoded
244+
// gotMap = map[Op:map[ChainID:-14 Data:te6cckECBQEAARQAAagJRxj0AAAAAAAAAB///////////////////////////////////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU5AAAAAAAAJxABAoOAAG1ut0NpOlEmrw109ciBxs+p6hikJO38s8HS5XatmBtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7msoBACAwAQAAAAAgNPteMBg4AAbW63Q2k6USavDXT1yIHGz6nqGKQk7fyzwdLldq2YG0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHc1lAEAQASwAAAAOAAG1ut0NpOlEmrw109ciBxs+p6hikJO38s8HS5XatmBtQHjc2Pw== MultiSig:EQADa3W6G0nSiTV4a6euRA42fU9QxSEnb-WeDpcrtWzA2jM8 Nonce:42 To:EQADa3W6G0nSiTV4a6euRA42fU9QxSEnb-WeDpcrtWzA2jM8 Value:1500000000] Proof:<nil> QueryID:31],
245+
// want = map[Op:map[ChainID:-14 Data:map[Calls:[map[Data:map[Val:5.5555555e+07] Target:EQADa3W6G0nSiTV4a6euRA42fU9QxSEnb-WeDpcrtWzA2jM8 Value:500000000] map[Data:map[Val:EQADa3W6G0nSiTV4a6euRA42fU9QxSEnb-WeDpcrtWzA2jM8] Target:EQADa3W6G0nSiTV4a6euRA42fU9QxSEnb-WeDpcrtWzA2jM8 Value:1000000000]] Delay:10000 Predecessor:-1 QueryID:31 Salt:1337] MultiSig:EQADa3W6G0nSiTV4a6euRA42fU9QxSEnb-WeDpcrtWzA2jM8 Nonce:42 To:EQADa3W6G0nSiTV4a6euRA42fU9QxSEnb-WeDpcrtWzA2jM8 Value:1500000000] QueryID:31]
246+
164247
for _, tt := range tests {
165248
t.Run(tt.name, func(t *testing.T) {
166249
gotType, gotMap, err := DecodeJSONMapFromCell(tt.cell, TLBs)

pkg/ton/debug/pretty_print.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,15 @@ func NewDebuggerSequenceTrace(addresses map[string]cldf.TypeAndVersion, outputFm
5858
}
5959
}
6060

61+
// TODO: refactor how decoders are composed together - just a map of TLBs
6162
func defaultDecoders() map[cldf.ContractType]lib.ContractDecoder {
6263
t := make(map[cldf.ContractType]lib.ContractDecoder)
63-
registerDecoder(t, wallet.NewDecoder(t))
64-
registerDecoder(t, minter.NewDecoder(t))
65-
registerDecoder(t, router.NewDecoder(t))
66-
registerDecoder(t, onramp.NewDecoder(t))
64+
registerDecoder(t, wallet.NewDecoder())
65+
registerDecoder(t, minter.NewDecoder())
66+
registerDecoder(t, router.NewDecoder())
67+
registerDecoder(t, onramp.NewDecoder())
6768
registerDecoder(t, feequoter.NewDecoder())
68-
registerDecoder(t, ccipsendexecutor.NewDecoder(t))
69+
registerDecoder(t, ccipsendexecutor.NewDecoder())
6970
return t
7071
}
7172

0 commit comments

Comments
 (0)