diff --git a/.changeset/utils-todecimal-jsonnumber.md b/.changeset/utils-todecimal-jsonnumber.md new file mode 100644 index 00000000000..2d3936ac882 --- /dev/null +++ b/.changeset/utils-todecimal-jsonnumber.md @@ -0,0 +1,7 @@ +--- +"chainlink": patch +--- + +Teach `utils.ToDecimal` to convert `json.Number` so pipeline tasks that consume HTTP JSON payloads (ethabiencode, fluxmonitor, OCR data sources) no longer fail with "type json.Number cannot be converted to decimal.Decimal". + +#bugfix diff --git a/core/utils/decimal.go b/core/utils/decimal.go index 1ff6f645738..80278361577 100644 --- a/core/utils/decimal.go +++ b/core/utils/decimal.go @@ -1,6 +1,7 @@ package utils import ( + "encoding/json" "math" "math/big" @@ -14,6 +15,14 @@ import ( // https://github.com/smartcontractkit/chainlink/pull/14841 func ToDecimal(input any) (decimal.Decimal, error) { switch v := input.(type) { + case json.Number: + // json.Number is what encoding/json returns when Decoder.UseNumber() + // has been set, which is how the pipeline parses HTTP / JSON payloads + // containing numeric values. Without this case any downstream task + // that receives a json.Number (e.g. ethabiencode with a uint256[] + // argument, fluxmonitor, OCR data sources) fails the conversion with + // "type json.Number cannot be converted to decimal.Decimal". + return decimal.NewFromString(string(v)) case string: return decimal.NewFromString(v) case int: diff --git a/core/utils/decimal_test.go b/core/utils/decimal_test.go index 068376ebbba..fae86d9b1e6 100644 --- a/core/utils/decimal_test.go +++ b/core/utils/decimal_test.go @@ -1,6 +1,7 @@ package utils import ( + "encoding/json" "math" "math/big" "testing" @@ -46,6 +47,12 @@ func TestDecimal(t *testing.T) { {math.NaN(), true}, {float32(math.NaN()), true}, {true, true}, + // json.Number is produced by Decoder.UseNumber, which the pipeline + // uses when decoding JSON HTTP responses. Both integer and floating + // point forms have to be accepted; see #8504. + {json.Number("123"), false}, + {json.Number("-1.1"), false}, + {json.Number("not-a-number"), true}, } for _, tc := range tt { _, err := ToDecimal(tc.v)