-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: multichain ocr3 contract transmitter
- Loading branch information
Showing
2 changed files
with
166 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package evm | ||
|
||
import ( | ||
"context" | ||
"encoding/binary" | ||
"encoding/hex" | ||
"fmt" | ||
|
||
"github.com/ethereum/go-ethereum/accounts/abi" | ||
gethcommon "github.com/ethereum/go-ethereum/common" | ||
"github.com/pkg/errors" | ||
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" | ||
"github.com/smartcontractkit/chainlink/v2/core/logger" | ||
"github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" | ||
"github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" | ||
"github.com/smartcontractkit/libocr/offchainreporting2plus/types" | ||
) | ||
|
||
var _ ocr3types.ContractTransmitter[any] = &contractTransmitterOCR3[any]{} | ||
|
||
type contractTransmitterOCR3[RI any] struct { | ||
contractAddress gethcommon.Address | ||
contractABI abi.ABI | ||
transmitter Transmitter | ||
transmittedEventSig gethcommon.Hash | ||
lp logpoller.LogPoller | ||
lggr logger.Logger | ||
reportToEvmTxMeta ReportToEthMetadata | ||
} | ||
|
||
func NewOCR3ContractTransmitter[RI any]( | ||
address gethcommon.Address, | ||
contractABI abi.ABI, | ||
transmitter Transmitter, | ||
lp logpoller.LogPoller, | ||
lggr logger.Logger, | ||
reportToEvmTxMeta ReportToEthMetadata, | ||
) (*contractTransmitterOCR3[RI], error) { | ||
transmitted, ok := contractABI.Events["Transmitted"] | ||
if !ok { | ||
return nil, fmt.Errorf("abi missing Transmitted event") | ||
} | ||
|
||
err := lp.RegisterFilter(logpoller.Filter{ | ||
Name: transmitterFilterName(address), | ||
EventSigs: []gethcommon.Hash{transmitted.ID}, | ||
Addresses: []gethcommon.Address{address}, | ||
}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if reportToEvmTxMeta == nil { | ||
reportToEvmTxMeta = reportToEvmTxMetaNoop | ||
} | ||
return &contractTransmitterOCR3[RI]{ | ||
contractAddress: address, | ||
contractABI: contractABI, | ||
transmitter: transmitter, | ||
transmittedEventSig: transmitted.ID, | ||
lp: lp, | ||
lggr: lggr, | ||
reportToEvmTxMeta: reportToEvmTxMeta, | ||
}, nil | ||
} | ||
|
||
// FromAccount implements ocr3types.ContractTransmitter. | ||
func (c *contractTransmitterOCR3[RI]) FromAccount() (types.Account, error) { | ||
return types.Account(c.transmitter.FromAddress().Hex()), nil | ||
} | ||
|
||
// Transmit implements ocr3types.ContractTransmitter. | ||
func (c *contractTransmitterOCR3[RI]) Transmit(ctx context.Context, configDigest types.ConfigDigest, seqNum uint64, rwi ocr3types.ReportWithInfo[RI], sigs []types.AttributedOnchainSignature) error { | ||
var rs [][32]byte | ||
var ss [][32]byte | ||
var vs [32]byte | ||
if len(sigs) > 32 { | ||
return errors.New("too many signatures, maximum is 32") | ||
} | ||
for i, as := range sigs { | ||
r, s, v, err := evmutil.SplitSignature(as.Signature) | ||
if err != nil { | ||
panic("eventTransmit(ev): error in SplitSignature") | ||
} | ||
rs = append(rs, r) | ||
ss = append(ss, s) | ||
vs[i] = v | ||
} | ||
|
||
// report ctx for OCR3 consists of the following | ||
// reportContext[0]: ConfigDigest | ||
// reportContext[1]: 24 byte padding, 8 byte sequence number | ||
// reportContext[2]: unused | ||
var rawReportCtx [3][32]byte | ||
copy(rawReportCtx[0][:], configDigest[:]) | ||
binary.BigEndian.PutUint64(rawReportCtx[1][24:], seqNum) | ||
|
||
txMeta, err := c.reportToEvmTxMeta(rwi.Report) | ||
if err != nil { | ||
c.lggr.Warnw("failed to generate tx metadata for report", "err", err) | ||
} | ||
|
||
c.lggr.Debugw("Transmitting report", "report", hex.EncodeToString(rwi.Report), "rawReportCtx", rawReportCtx, "contractAddress", c.contractAddress, "txMeta", txMeta) | ||
|
||
payload, err := c.contractABI.Pack("transmit", rawReportCtx, []byte(rwi.Report), rs, ss, vs) | ||
if err != nil { | ||
return errors.Wrapf(err, "abi.Pack failed with args: (%v, %s, %v, %v, %v)", rawReportCtx, hex.EncodeToString(rwi.Report), rs, ss, vs) | ||
} | ||
|
||
return errors.Wrap(c.transmitter.CreateEthTransaction(ctx, c.contractAddress, payload, txMeta), "failed to send Eth transaction") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package evm | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" | ||
"github.com/smartcontractkit/chainlink/v2/core/logger" | ||
"github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" | ||
"github.com/smartcontractkit/libocr/offchainreporting2plus/types" | ||
) | ||
|
||
type MultichainMeta interface { | ||
GetDestinationChainID() string | ||
} | ||
|
||
type multichainTransmitterOCR3[RI MultichainMeta] struct { | ||
transmitters map[string]ocr3types.ContractTransmitter[RI] | ||
lp logpoller.LogPoller | ||
lggr logger.Logger | ||
} | ||
|
||
func NewMultichainTransmitterOCR3[RI MultichainMeta]( | ||
transmitters map[string]ocr3types.ContractTransmitter[RI], | ||
lp logpoller.LogPoller, | ||
lggr logger.Logger, | ||
) (*multichainTransmitterOCR3[RI], error) { | ||
return &multichainTransmitterOCR3[RI]{ | ||
transmitters: transmitters, | ||
lp: lp, | ||
lggr: lggr, | ||
}, nil | ||
} | ||
|
||
// FromAccount implements ocr3types.ContractTransmitter. | ||
func (m *multichainTransmitterOCR3[RI]) FromAccount() (types.Account, error) { | ||
var accounts []string | ||
for _, t := range m.transmitters { | ||
account, err := t.FromAccount() | ||
if err != nil { | ||
return "", err | ||
} | ||
accounts = append(accounts, string(account)) | ||
} | ||
return types.Account(strings.Join(accounts, ",")), nil | ||
} | ||
|
||
// Transmit implements ocr3types.ContractTransmitter. | ||
func (m *multichainTransmitterOCR3[RI]) Transmit(ctx context.Context, configDigest types.ConfigDigest, seqNr uint64, rwi ocr3types.ReportWithInfo[RI], sigs []types.AttributedOnchainSignature) error { | ||
transmitter, ok := m.transmitters[rwi.Info.GetDestinationChainID()] | ||
if !ok { | ||
return fmt.Errorf("no transmitter for chain %s", rwi.Info.GetDestinationChainID()) | ||
} | ||
return transmitter.Transmit(ctx, configDigest, seqNr, rwi, sigs) | ||
} |