Skip to content

Commit

Permalink
add extra args and destExec support
Browse files Browse the repository at this point in the history
  • Loading branch information
huangzhen1997 committed Jan 3, 2025
1 parent ae3e43c commit 11cd2f3
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 52 deletions.
69 changes: 39 additions & 30 deletions core/capabilities/ccip/ccipsolana/executecodec.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ccipsolana
import (
"bytes"
"context"
"encoding/binary"
"fmt"

agbinary "github.com/gagliardetto/binary"
Expand All @@ -23,9 +24,6 @@ func NewExecutePluginCodecV1() *ExecutePluginCodecV1 {
}

func (e *ExecutePluginCodecV1) Encode(ctx context.Context, report cciptypes.ExecutePluginReport) ([]byte, error) {
// TODO:
// 1. destGasAmount
// 2. ExtraArgs
var buf bytes.Buffer
encoder := agbinary.NewBorshEncoder(&buf)

Expand All @@ -34,20 +32,14 @@ func (e *ExecutePluginCodecV1) Encode(ctx context.Context, report cciptypes.Exec
}

chainReport := report.ChainReports[0]

// skip proofFlagBits check, as ProofFlagBits is missing in current ExecutionReportSingleChain
// if chainReport.ProofFlagBits.IsEmpty() {
// return nil, fmt.Errorf("proof flag bits are empty")
// }

solanaProofs := make([][32]byte, 0, len(chainReport.Proofs))
for _, proof := range chainReport.Proofs {
solanaProofs = append(solanaProofs, proof)
}

var msg ccip_router.Any2SolanaRampMessage
if len(chainReport.Messages) > 0 {
// currently report only include single message
if len(chainReport.Messages) != 0 {
// currently only allow commiting one message at a time
message := chainReport.Messages[0]
receiver, err := solana.PublicKeyFromBase58(string(message.Receiver))
if err != nil {
Expand All @@ -60,11 +52,6 @@ func (e *ExecutePluginCodecV1) Encode(ctx context.Context, report cciptypes.Exec
return nil, fmt.Errorf("empty amount for token: %s", tokenAmount.DestTokenAddress)
}

// destGasAmount, err := abiDecodeUint32(tokenAmount.DestExecData)
// if err != nil {
// return nil, fmt.Errorf("decode dest gas amount: %w", err)
// }

DestTokenAddress, err := solana.PublicKeyFromBase58(string(tokenAmount.DestTokenAddress))
if err != nil {
return nil, fmt.Errorf("invalid receiver address: %s, %w", string(message.Receiver), err)
Expand All @@ -74,10 +61,18 @@ func (e *ExecutePluginCodecV1) Encode(ctx context.Context, report cciptypes.Exec
SourcePoolAddress: tokenAmount.SourcePoolAddress,
DestTokenAddress: DestTokenAddress,
ExtraData: tokenAmount.ExtraData,
Amount: BigIntToBytes32(tokenAmount.Amount),
// DestGasAmount: destGasAmount,
Amount: bigIntToBytes32(tokenAmount.Amount),
DestGasAmount: bytesToUint32(tokenAmount.DestExecData),
})
}

var extraArgs ccip_router.SolanaExtraArgs
decoder := agbinary.NewBorshDecoder(message.ExtraArgs)
err = extraArgs.UnmarshalWithDecoder(decoder)
if err != nil {
return nil, fmt.Errorf("invalid extra arguments: %w", err)
}

msg = ccip_router.Any2SolanaRampMessage{
Header: ccip_router.RampMessageHeader{
MessageId: message.Header.MessageID,
Expand All @@ -90,7 +85,7 @@ func (e *ExecutePluginCodecV1) Encode(ctx context.Context, report cciptypes.Exec
Data: message.Data,
Receiver: receiver,
TokenAmounts: tokenAmounts,
// ExtraArgs:
ExtraArgs: extraArgs,
}
}

Expand Down Expand Up @@ -133,21 +128,25 @@ func (e *ExecutePluginCodecV1) Decode(ctx context.Context, encodedReport []byte)

tokenAmounts := make([]cciptypes.RampTokenAmount, 0, len(executeReport.Message.TokenAmounts))
for _, tokenAmount := range executeReport.Message.TokenAmounts {
// destData, err := abiEncodeUint32(tokenAmount.DestGasAmount)
// if err != nil {
// return cciptypes.ExecutePluginReport{}, fmt.Errorf("abi encode dest gas amount: %w", err)
// }
destData := make([]byte, 4)
binary.BigEndian.PutUint32(destData, tokenAmount.DestGasAmount)

tokenAmounts = append(tokenAmounts, cciptypes.RampTokenAmount{
SourcePoolAddress: tokenAmount.SourcePoolAddress,
// TODO: should this be abi-encoded?
DestTokenAddress: cciptypes.UnknownAddress(tokenAmount.DestTokenAddress.String()),
ExtraData: tokenAmount.ExtraData,
Amount: priceHelper(tokenAmount.Amount[:]),
// DestExecData: destData,
DestTokenAddress: cciptypes.UnknownAddress(tokenAmount.DestTokenAddress.String()),
ExtraData: tokenAmount.ExtraData,
Amount: priceHelper(tokenAmount.Amount[:]),
DestExecData: destData,
})
}

var buf bytes.Buffer
encoder := agbinary.NewBorshEncoder(&buf)
err = executeReport.Message.ExtraArgs.MarshalWithEncoder(encoder)
if err != nil {
return cciptypes.ExecutePluginReport{}, fmt.Errorf("unpack encoded report: %w", err)
}

messages := make([]cciptypes.Message, 0, 1)
message := cciptypes.Message{
Header: cciptypes.RampMessageHeader{
Expand All @@ -162,7 +161,7 @@ func (e *ExecutePluginCodecV1) Decode(ctx context.Context, encodedReport []byte)
Sender: executeReport.Message.Sender,
Data: executeReport.Message.Data,
Receiver: cciptypes.UnknownAddress(executeReport.Message.Receiver.String()),
ExtraArgs: cciptypes.Bytes{}, // <-- todo: info not available, but not required atm
ExtraArgs: buf.Bytes(),
FeeToken: cciptypes.UnknownAddress{}, // <-- todo: info not available, but not required atm
FeeTokenAmount: cciptypes.BigInt{}, // <-- todo: info not available, but not required atm
TokenAmounts: tokenAmounts,
Expand All @@ -186,7 +185,17 @@ func (e *ExecutePluginCodecV1) Decode(ctx context.Context, encodedReport []byte)
return report, nil
}

func BigIntToBytes32(n cciptypes.BigInt) [32]uint8 {
func bytesToUint32(b []byte) uint32 {
if len(b) < 4 {
var padded [4]byte
copy(padded[4-len(b):], b) // Pad from the right for big-endian
return binary.BigEndian.Uint32(padded[:])
}

return binary.BigEndian.Uint32(b)
}

func bigIntToBytes32(n cciptypes.BigInt) [32]uint8 {
var b [32]uint8
raw := n.Bytes()
copy(b[32-len(raw):], raw) // Right-align and zero-pad
Expand Down
52 changes: 30 additions & 22 deletions core/capabilities/ccip/ccipsolana/executecodec_test.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
package ccipsolana

import (
"bytes"
"encoding/binary"
"math/big"
"math/rand"
"testing"

agbinary "github.com/gagliardetto/binary"
solanago "github.com/gagliardetto/solana-go"
"github.com/smartcontractkit/chainlink-ccip/chains/solana/contracts/tests/config"
"github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/ccip_router"

cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils"

"github.com/gagliardetto/solana-go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand All @@ -28,33 +34,37 @@ var randomExecuteReport = func(t *testing.T) cciptypes.ExecutePluginReport {
if err != nil {
panic(err)
}
data, err := cciptypes.NewBytesFromString("0x1234")
extraData, err := cciptypes.NewBytesFromString("0x1234")
require.NoError(t, err)

destGasAmount := uint32(10)
destExecData := make([]byte, 4)
binary.BigEndian.PutUint32(destExecData, destGasAmount)

tokenAmounts := make([]cciptypes.RampTokenAmount, numTokensPerMsg)
for z := 0; z < numTokensPerMsg; z++ {
tokenAmounts[z] = cciptypes.RampTokenAmount{
SourcePoolAddress: cciptypes.UnknownAddress(key.PublicKey().String()),
DestTokenAddress: cciptypes.UnknownAddress(key.PublicKey().String()),
ExtraData: data,
ExtraData: extraData,
Amount: cciptypes.NewBigInt(big.NewInt(rand.Int63())),
DestExecData: destExecData,
}
}

// TODO enable extraArgs
// extraArgs := ccip_router.SolanaExtraArgs{
// ComputeUnits: 1000,
// Accounts: []ccip_router.SolanaAccountMeta{
// {Pubkey: config.CcipReceiverProgram},
// {Pubkey: config.ReceiverTargetAccountPDA, IsWritable: true},
// {Pubkey: solana.SystemProgramID, IsWritable: false},
// },
// }

// senderAddr = solanacommon.MakeRandom32ByteArray()
// receiverAddr := solanacommon.MakeRandom32ByteArray()
// feeTokenAddr := solanacommon.MakeRandom32ByteArray()
// onRampAddr := solanacommon.MakeRandom32ByteArray()
extraArgs := ccip_router.SolanaExtraArgs{
ComputeUnits: 1000,
Accounts: []ccip_router.SolanaAccountMeta{
{Pubkey: config.CcipReceiverProgram},
{Pubkey: config.ReceiverTargetAccountPDA, IsWritable: true},
{Pubkey: solana.SystemProgramID, IsWritable: false},
},
}

var buf bytes.Buffer
encoder := agbinary.NewBorshEncoder(&buf)
err = extraArgs.MarshalWithEncoder(encoder)
require.NoError(t, err)

reportMessages[j] = cciptypes.Message{
Header: cciptypes.RampMessageHeader{
Expand All @@ -66,10 +76,10 @@ var randomExecuteReport = func(t *testing.T) cciptypes.ExecutePluginReport {
MsgHash: utils.RandomBytes32(),
OnRamp: cciptypes.UnknownAddress(key.PublicKey().String()),
},
Sender: cciptypes.UnknownAddress(key.PublicKey().String()),
Data: data,
Receiver: cciptypes.UnknownAddress(key.PublicKey().String()),
//ExtraArgs: extraArgs,
Sender: cciptypes.UnknownAddress(key.PublicKey().String()),
Data: extraData,
Receiver: cciptypes.UnknownAddress(key.PublicKey().String()),
ExtraArgs: buf.Bytes(),
FeeToken: cciptypes.UnknownAddress(key.PublicKey().String()),
FeeTokenAmount: cciptypes.NewBigInt(big.NewInt(rand.Int63())),
TokenAmounts: tokenAmounts,
Expand All @@ -86,7 +96,6 @@ var randomExecuteReport = func(t *testing.T) cciptypes.ExecutePluginReport {
Messages: reportMessages,
OffchainTokenData: tokenData,
Proofs: []cciptypes.Bytes32{utils.RandomBytes32(), utils.RandomBytes32()},
//ProofFlagBits: cciptypes.NewBigInt(utils.RandUint256()),
}
}

Expand Down Expand Up @@ -142,7 +151,6 @@ func TestExecutePluginCodecV1(t *testing.T) {
report.ChainReports[i].Messages[j].Header.MsgHash = cciptypes.Bytes32{}
report.ChainReports[i].Messages[j].Header.OnRamp = cciptypes.UnknownAddress{}
report.ChainReports[i].Messages[j].FeeToken = cciptypes.UnknownAddress{}
report.ChainReports[i].Messages[j].ExtraArgs = cciptypes.Bytes{}
report.ChainReports[i].Messages[j].FeeTokenAmount = cciptypes.BigInt{}
}
}
Expand Down

0 comments on commit 11cd2f3

Please sign in to comment.