Skip to content

Commit 020e0fa

Browse files
Merge pull request #81 from smartcontractkit/NONEVM-2205-ccip-provider-transmitter
feat(relayer): ccip provider and contract transmitter
1 parent 085d565 commit 020e0fa

File tree

3 files changed

+198
-2
lines changed

3 files changed

+198
-2
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package ocr
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
8+
"github.com/smartcontractkit/chainlink-common/pkg/logger"
9+
"github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3"
10+
"github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types"
11+
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
12+
13+
"github.com/smartcontractkit/chainlink-ton/pkg/txm"
14+
15+
"github.com/xssnick/tonutils-go/address"
16+
"github.com/xssnick/tonutils-go/tlb"
17+
"github.com/xssnick/tonutils-go/ton/wallet"
18+
"github.com/xssnick/tonutils-go/tvm/cell"
19+
)
20+
21+
// ToEd25519CalldataFunc is a function that takes in the OCR3 report and Ed25519 signature data and processes them.
22+
// It returns the contract name, method name, and arguments for the on-chain contract call.
23+
// The ReportWithInfo bytes field is also decoded according to the implementation of this function,
24+
// the commit and execute plugins have different representations for this data.
25+
// Ed25519 signatures are 96 bytes long (64 bytes signature + 32 bytes public key).
26+
type ToEd25519CalldataFunc func(
27+
rawReportCtx [2][32]byte,
28+
report ocr3types.ReportWithInfo[[]byte],
29+
signatures [][96]byte,
30+
codec ccipocr3.ExtraDataCodec,
31+
) (contract string, method string, args any, err error)
32+
33+
type RawReportContext3Func func(configDigest [32]byte, seqNr uint64) [2][32]byte
34+
35+
var _ ocr3types.ContractTransmitter[[]byte] = &ccipTransmitter{}
36+
37+
type ccipTransmitter struct {
38+
txm txm.TxManager
39+
offrampAddress string
40+
toEd25519CalldataFn ToEd25519CalldataFunc
41+
rawReportContextFn RawReportContext3Func
42+
extraDataCodec ccipocr3.ExtraDataCodec
43+
lggr logger.Logger
44+
}
45+
46+
func NewCCIPTransmitter(
47+
txm txm.TxManager,
48+
lggr logger.Logger,
49+
) (ocr3types.ContractTransmitter[[]byte], error) {
50+
if txm == nil || lggr == nil {
51+
return nil, errors.New("invalid transmitter args")
52+
}
53+
54+
return &ccipTransmitter{
55+
txm: txm,
56+
lggr: lggr,
57+
}, nil
58+
}
59+
60+
func (c *ccipTransmitter) FromAccount(context.Context) (ocrtypes.Account, error) {
61+
w := c.txm.GetClient().Wallet
62+
return ocrtypes.Account(w.Address().StringRaw()), nil
63+
}
64+
65+
func (c *ccipTransmitter) Transmit(
66+
ctx context.Context,
67+
configDigest ocrtypes.ConfigDigest,
68+
seqNr uint64,
69+
reportWithInfo ocr3types.ReportWithInfo[[]byte],
70+
sigs []ocrtypes.AttributedOnchainSignature,
71+
) error {
72+
if len(sigs) > 32 {
73+
return errors.New("too many signatures, maximum is 32")
74+
}
75+
76+
rawReportCtx := c.rawReportContextFn(configDigest, seqNr)
77+
78+
signatures := make([][96]byte, 0, len(sigs))
79+
for _, sig := range sigs {
80+
if len(sig.Signature) != 96 {
81+
return fmt.Errorf("invalid ed25519 signature length, expected 96, got %d", len(sig.Signature))
82+
}
83+
var fixedSig [96]byte
84+
copy(fixedSig[:], sig.Signature)
85+
signatures = append(signatures, fixedSig)
86+
}
87+
88+
_, method, args, err := c.toEd25519CalldataFn(rawReportCtx, reportWithInfo, signatures, c.extraDataCodec)
89+
if err != nil {
90+
return fmt.Errorf("failed to generate call data: %w", err)
91+
}
92+
93+
body, ok := args.(*cell.Cell)
94+
if !ok {
95+
return fmt.Errorf("expected args to be *cell.Cell, got %T", args)
96+
}
97+
98+
w := c.txm.GetClient().Wallet
99+
request := txm.Request{
100+
Mode: wallet.PayGasSeparately,
101+
FromWallet: w,
102+
ContractAddress: *address.MustParseAddr(c.offrampAddress),
103+
Body: body,
104+
Amount: tlb.MustFromTON("0.05"),
105+
}
106+
107+
c.lggr.Infow("Submitting transaction", "address", c.offrampAddress, "method", method)
108+
109+
if err := c.txm.Enqueue(request); err != nil {
110+
return fmt.Errorf("failed to submit transaction via txm: %w", err)
111+
}
112+
113+
return nil
114+
}

pkg/ccip/provider/provider.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package provider
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"sync"
7+
8+
"github.com/smartcontractkit/chainlink-common/pkg/logger"
9+
"github.com/smartcontractkit/chainlink-common/pkg/services"
10+
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
11+
"github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3"
12+
"github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types"
13+
14+
"github.com/smartcontractkit/chainlink-ton/pkg/ccip/ocr"
15+
"github.com/smartcontractkit/chainlink-ton/pkg/txm"
16+
)
17+
18+
var _ commontypes.CCIPProvider = &Provider{}
19+
20+
const CCIPProviderName = "TONCCIPProvider"
21+
22+
type Provider struct {
23+
lggr logger.Logger
24+
ca ccipocr3.ChainAccessor
25+
ct ocr3types.ContractTransmitter[[]byte]
26+
27+
wg sync.WaitGroup
28+
services.StateMachine
29+
}
30+
31+
func NewCCIPProvider(lggr logger.Logger, txm txm.TxManager) (*Provider, error) {
32+
ct, err := ocr.NewCCIPTransmitter(txm, lggr)
33+
if err != nil {
34+
return nil, fmt.Errorf("failed to create a CCIP ContractTransmitter %w", err)
35+
}
36+
37+
cp := &Provider{
38+
lggr: logger.Named(lggr, CCIPProviderName),
39+
ct: ct,
40+
}
41+
42+
return cp, nil
43+
}
44+
45+
func (cp *Provider) Name() string {
46+
return cp.lggr.Name()
47+
}
48+
49+
func (cp *Provider) Ready() error {
50+
return cp.StateMachine.Ready()
51+
}
52+
53+
func (cp *Provider) Start(ctx context.Context) error {
54+
return cp.StartOnce(CCIPProviderName, func() error {
55+
cp.lggr.Debugw("Starting CCIPProvider")
56+
return nil
57+
})
58+
}
59+
60+
func (cp *Provider) Close() error {
61+
return cp.StopOnce(CCIPProviderName, func() error {
62+
cp.wg.Wait()
63+
return nil
64+
})
65+
}
66+
67+
func (cp *Provider) HealthReport() map[string]error {
68+
return map[string]error{cp.Name(): cp.Healthy()}
69+
}
70+
71+
func (cp *Provider) ChainAccessor() ccipocr3.ChainAccessor {
72+
return cp.ca
73+
}
74+
75+
func (cp *Provider) ContractTransmitter() ocr3types.ContractTransmitter[[]byte] {
76+
return cp.ct
77+
}
78+
79+
func (cp *Provider) Codec() ccipocr3.Codec {
80+
// TODO(NONEVM-1460): implement
81+
return ccipocr3.Codec{}
82+
}

pkg/relay/relay.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
1313
"github.com/smartcontractkit/chainlink-common/pkg/types/core"
1414

15+
provider "github.com/smartcontractkit/chainlink-ton/pkg/ccip/provider"
1516
"github.com/smartcontractkit/chainlink-ton/pkg/ton/tracetracking"
1617
"github.com/smartcontractkit/chainlink-ton/pkg/ton/tvm"
1718
"github.com/smartcontractkit/chainlink-ton/pkg/txm"
@@ -48,8 +49,7 @@ func (r *Relayer) TON() (commontypes.TONService, error) {
4849
}
4950

5051
func (r *Relayer) NewCCIPProvider(ctx context.Context, rargs commontypes.RelayArgs) (commontypes.CCIPProvider, error) {
51-
// TODO(NONEVM-1460): implement
52-
return nil, errors.New("unimplemented")
52+
return provider.NewCCIPProvider(r.lggr, r.chain.TxManager())
5353
}
5454

5555
func NewRelayer(lggr logger.Logger, chain Chain, tonService Service, _ core.CapabilitiesRegistry) *Relayer {

0 commit comments

Comments
 (0)