Skip to content

Commit

Permalink
fix abi decoding usdc payload (#156)
Browse files Browse the repository at this point in the history
  • Loading branch information
RensR authored Sep 22, 2023
1 parent 9649076 commit 7cacf4b
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rpc"
"github.com/pkg/errors"
Expand Down Expand Up @@ -230,7 +231,7 @@ func (c *LogPollerReader) GetLastUSDCMessagePriorToLogIndexInTx(ctx context.Cont
for i := range logs {
current := logs[len(logs)-i-1]
if current.LogIndex < logIndex {
c.lggr.Infow("Found USDC message", "logIndex", current.LogIndex, "txHash", current.TxHash.Hex(), "log", current)
c.lggr.Infow("Found USDC message", "logIndex", current.LogIndex, "txHash", current.TxHash.Hex(), "data", hexutil.Encode(current.Data))
return current.Data, nil
}
}
Expand Down
37 changes: 34 additions & 3 deletions core/services/ocr2/plugins/ccip/tokendata/usdc/usdc.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"sync"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"

"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
Expand Down Expand Up @@ -53,6 +54,19 @@ const (
attestationStatusPending attestationStatus = "pending_confirmations"
)

type usdcPayload []byte

func (d usdcPayload) AbiString() string {
return `[{"type": "bytes"}]`
}

func (d usdcPayload) Validate() error {
if len(d) == 0 {
return errors.New("must be non-empty")
}
return nil
}

var _ tokendata.Reader = &TokenDataReader{}

func NewUSDCTokenDataReader(lggr logger.Logger, sourceChainEvents ccipdata.Reader, usdcTokenAddress, usdcMessageTransmitterAddress, onRampAddress common.Address, usdcAttestationApi *url.URL) *TokenDataReader {
Expand Down Expand Up @@ -89,7 +103,7 @@ func (s *TokenDataReader) getUpdatedAttestation(ctx context.Context, msg interna
return attestationResponse{}, errors.Wrap(err, "failed getting the USDC message body")
}

s.lggr.Infow("Calling attestation API", "messageBody", messageBodyHash, "messageID", msg.MessageId)
s.lggr.Infow("Calling attestation API", "messageBodyHash", hexutil.Encode(messageBodyHash[:]), "messageID", hexutil.Encode(msg.MessageId[:]))

response, err := s.callAttestationApi(ctx, messageBodyHash)
if err != nil {
Expand All @@ -112,15 +126,27 @@ func (s *TokenDataReader) getUSDCMessageBodyHash(ctx context.Context, msg intern
return [32]byte{}, err
}

s.lggr.Infow("Got USDC message body", "messageBody", usdcMessageBody, "messageID", msg.MessageId)
s.lggr.Infow("Got USDC message body", "messageBody", hexutil.Encode(usdcMessageBody), "messageID", hexutil.Encode(msg.MessageId[:]))

msgBodyHash := utils.Keccak256Fixed(usdcMessageBody)
parsedMsgBody, err := decodeUSDCMessageSent(usdcMessageBody)
if err != nil {
return [32]byte{}, errors.Wrap(err, "failed parsing solidity struct")
}
msgBodyHash := utils.Keccak256Fixed(parsedMsgBody)

// Save the attempt in the cache in case the external call fails
s.usdcMessageHashCache[msg.SequenceNumber] = msgBodyHash
return msgBodyHash, nil
}

func decodeUSDCMessageSent(logData []byte) ([]byte, error) {
decodeAbiStruct, err := abihelpers.DecodeAbiStruct[usdcPayload](logData)
if err != nil {
return nil, err
}
return decodeAbiStruct, nil
}

func (s *TokenDataReader) callAttestationApi(ctx context.Context, usdcMessageHash [32]byte) (attestationResponse, error) {
fullAttestationUrl := fmt.Sprintf("%s/%s/%s/0x%x", s.attestationApi, version, attestationPath, usdcMessageHash)
req, err := http.NewRequestWithContext(ctx, "GET", fullAttestationUrl, nil)
Expand All @@ -143,6 +169,11 @@ func (s *TokenDataReader) callAttestationApi(ctx context.Context, usdcMessageHas
if err != nil {
return attestationResponse{}, err
}

if response.Status == "" {
return attestationResponse{}, fmt.Errorf("invalid attestation response: %s", string(body))
}

return response, nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -75,11 +76,14 @@ func TestUSDCReader_ReadTokenData(t *testing.T) {
},
}, nil)

expectedBody, err := hexutil.Decode("0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f80000000000000001000000020000000000048d71000000000000000000000000eb08f243e5d3fcff26a9e38ae5520a669f4019d000000000000000000000000023a04d5935ed8bc8e3eb78db3541f0abfb001c6e0000000000000000000000006cb3ed9b441eb674b58495c8b3324b59faff5243000000000000000000000000000000005425890298aed601595a70ab815c96711a31bc65000000000000000000000000ab4f961939bfe6a93567cc57c59eed7084ce2131000000000000000000000000000000000000000000000000000000000000271000000000000000000000000035e08285cfed1ef159236728f843286c55fc08610000000000000000")
require.NoError(t, err)

eventsClient.On("GetLastUSDCMessagePriorToLogIndexInTx",
mock.Anything,
logIndex,
common.Hash(txHash),
).Return(attestationBytes, nil)
).Return(expectedBody, nil)
attestationURI, err := url.ParseRequestURI(ts.URL)
require.NoError(t, err)

Expand Down
12 changes: 10 additions & 2 deletions core/services/ocr2/plugins/ccip/tokendata/usdc/usdc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,17 @@ func TestGetUSDCReaderSourceLPFilters(t *testing.T) {
}

func TestGetUSDCMessageBody(t *testing.T) {
expectedBody, err := hexutil.Decode("0x0000000000000001000000020000000000048D71000000000000000000000000EB08F243E5D3FCFF26A9E38AE5520A669F4019D000000000000000000000000023A04D5935ED8BC8E3EB78DB3541F0ABFB001C6E0000000000000000000000006CB3ED9B441EB674B58495C8B3324B59FAFF5243000000000000000000000000000000005425890298AED601595A70AB815C96711A31BC65000000000000000000000000AB4F961939BFE6A93567CC57C59EED7084CE2131000000000000000000000000000000000000000000000000000000000000271000000000000000000000000035E08285CFED1EF159236728F843286C55FC0861")
expectedBody, err := hexutil.Decode("0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f80000000000000001000000020000000000048d71000000000000000000000000eb08f243e5d3fcff26a9e38ae5520a669f4019d000000000000000000000000023a04d5935ed8bc8e3eb78db3541f0abfb001c6e0000000000000000000000006cb3ed9b441eb674b58495c8b3324b59faff5243000000000000000000000000000000005425890298aed601595a70ab815c96711a31bc65000000000000000000000000ab4f961939bfe6a93567cc57c59eed7084ce2131000000000000000000000000000000000000000000000000000000000000271000000000000000000000000035e08285cfed1ef159236728f843286c55fc08610000000000000000")
require.NoError(t, err)
expectedBodyHash := utils.Keccak256Fixed(expectedBody)

parsedBody, err := decodeUSDCMessageSent(expectedBody)
require.NoError(t, err)

expectedPostParse := "0x0000000000000001000000020000000000048d71000000000000000000000000eb08f243e5d3fcff26a9e38ae5520a669f4019d000000000000000000000000023a04d5935ed8bc8e3eb78db3541f0abfb001c6e0000000000000000000000006cb3ed9b441eb674b58495c8b3324b59faff5243000000000000000000000000000000005425890298aed601595a70ab815c96711a31bc65000000000000000000000000ab4f961939bfe6a93567cc57c59eed7084ce2131000000000000000000000000000000000000000000000000000000000000271000000000000000000000000035e08285cfed1ef159236728f843286c55fc0861"

require.Equal(t, expectedPostParse, hexutil.Encode(parsedBody))

expectedBodyHash := utils.Keccak256Fixed(parsedBody)

sourceChainEventsMock := ccipdata.MockReader{}
sourceChainEventsMock.On("GetLastUSDCMessagePriorToLogIndexInTx", mock.Anything, mock.Anything, mock.Anything).Return(expectedBody, nil)
Expand Down

0 comments on commit 7cacf4b

Please sign in to comment.