diff --git a/core/capabilities/ccip/ccipaptos/msghasher.go b/core/capabilities/ccip/ccipaptos/msghasher.go index ba8c093062d..f0e5fa7ebc1 100644 --- a/core/capabilities/ccip/ccipaptos/msghasher.go +++ b/core/capabilities/ccip/ccipaptos/msghasher.go @@ -298,7 +298,6 @@ func parseExtraDataMap(input map[string]any) (*big.Int, error) { lowercase := strings.ToLower(fieldName) switch lowercase { case "gaslimit": - // Expect [][32]byte if val, ok := fieldValue.(*big.Int); ok { outputGas = val return outputGas, nil diff --git a/core/capabilities/ccip/ccipsui/msghasher.go b/core/capabilities/ccip/ccipsui/msghasher.go index 7df33889079..a5411c205f1 100644 --- a/core/capabilities/ccip/ccipsui/msghasher.go +++ b/core/capabilities/ccip/ccipsui/msghasher.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "math" "math/big" "strings" @@ -71,13 +72,8 @@ func (h *MessageHasherV1) Hash(ctx context.Context, msg ccipocr3common.Message) return [32]byte{}, fmt.Errorf("failed to decode dest exec data: %w", err) } - destGasAmountValue, ok := destExecDataDecodedMap["destGasAmount"] - if !ok { - return [32]byte{}, errors.New("destGasAmount not found in destExecDataDecodedMap") - } - - destGasAmount, ok := destGasAmountValue.(uint32) - if !ok { + destGasAmount, err := extractDestGasAmountFromMap(destExecDataDecodedMap) + if err != nil { return [32]byte{}, fmt.Errorf("invalid type for destGasAmount, expected uint32, got %T", destGasAmount) } @@ -306,10 +302,20 @@ func parseExtraDataMap(input map[string]any) (*big.Int, [32]byte, error) { if !ok { return nil, [32]byte{}, errors.New("token receiver not found in extra data map") } - tokenReceiverBytes, ok := tokenReceiver.([32]byte) - if !ok { - return nil, [32]byte{}, errors.New("token receiver not a [32]byte") + + tokenReceiverBytes := [32]byte{} + switch v := tokenReceiver.(type) { + case [32]byte: + tokenReceiverBytes = v + case []byte: // LOOP gRPC converts [32]byte -> []byte + if len(v) != 32 { + return nil, [32]byte{}, fmt.Errorf("invalid length for TokenReceiver: expected 32, got %d", len(v)) + } + copy(tokenReceiverBytes[:], v) + default: + return nil, [32]byte{}, fmt.Errorf("invalid type for TokenReceiver, expected [32]byte, got %T", tokenReceiver) } + return outputGasInt, tokenReceiverBytes, nil } @@ -319,11 +325,17 @@ func extractDestGasAmountFromMap(input map[string]any) (uint32, error) { lowercase := strings.ToLower(fieldName) switch lowercase { case "destgasamount": - // Expect uint32 - if val, ok := fieldValue.(uint32); ok { - return val, nil + switch v := fieldValue.(type) { + case uint32: + return v, nil + case int64: // LOOP converts expected uint32 to int64 + if v > math.MaxUint32 { + return 0, fmt.Errorf("destGasAmount exceeds uint32 max, got %d", v) + } + return uint32(v), nil //nolint:gosec // G115: validated to be within uint32 max above + default: + return 0, errors.New("invalid type for destgasamount, expected uint32 or int64") } - return 0, errors.New("invalid type for destgasamount, expected uint32") default: } } diff --git a/core/capabilities/ccip/ccipsui/msghasher_test.go b/core/capabilities/ccip/ccipsui/msghasher_test.go new file mode 100644 index 00000000000..cc7fcfd54ca --- /dev/null +++ b/core/capabilities/ccip/ccipsui/msghasher_test.go @@ -0,0 +1,77 @@ +package ccipsui + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestParseExtraDataMap(t *testing.T) { + tokenReceiverExample := [32]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20} + + tests := []struct { + name string + input map[string]any + want *struct { + gasLimit *big.Int + tokenReceiver [32]byte + } + expectErr bool + }{ + { + name: "valid input with [32]byte for tokenReceiver", + input: map[string]any{ + "gasLimit": new(big.Int).SetInt64(500000), + "tokenReceiver": [32]byte{0x01}, + }, + want: &struct { + gasLimit *big.Int + tokenReceiver [32]byte + }{ + gasLimit: new(big.Int).SetInt64(500000), + tokenReceiver: [32]byte{0x01}, + }, + expectErr: false, + }, + { + name: "valid input with []byte for tokenReceiver", + input: map[string]any{ + "gasLimit": new(big.Int).SetInt64(500000), + "tokenReceiver": tokenReceiverExample[:], // convert to slice for input + }, + want: &struct { + gasLimit *big.Int + tokenReceiver [32]byte + }{ + gasLimit: new(big.Int).SetInt64(500000), + tokenReceiver: tokenReceiverExample, + }, + expectErr: false, + }, + { + name: "invalid input with []byte for tokenReceiver", + input: map[string]any{ + "gasLimit": new(big.Int).SetInt64(500000), + "tokenReceiver": tokenReceiverExample[:16], // 16 bytes, we expect an error due to length + }, + want: nil, + expectErr: true, + }, + } + + // Run tests + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gasLimit, tokenReceiver, err := parseExtraDataMap(tt.input) + if tt.expectErr { + require.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, tt.want.gasLimit, gasLimit) + assert.Equal(t, tt.want.tokenReceiver, tokenReceiver) + } + }) + } +} diff --git a/deployment/ccip/shared/stateview/state.go b/deployment/ccip/shared/stateview/state.go index 826d336712b..535cdb0dffe 100644 --- a/deployment/ccip/shared/stateview/state.go +++ b/deployment/ccip/shared/stateview/state.go @@ -539,10 +539,10 @@ func (c CCIPOnChainState) SupportedChains() map[uint64]struct{} { for chain := range c.SuiChains { chains[chain] = struct{}{} } - for chain := range c.TonChains { chains[chain] = struct{}{} } + return chains }