Skip to content

Commit 448b4f7

Browse files
committed
chore: explicit decimal typings for order book
1 parent 52dede3 commit 448b4f7

File tree

2 files changed

+128
-12
lines changed

2 files changed

+128
-12
lines changed

core/contractsapi/attestation_encoding_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,58 @@ func TestEncodeActionArgs_RoundTrip(t *testing.T) {
216216
}
217217
}
218218

219+
func TestEncodeActionArgs_WithDecimal(t *testing.T) {
220+
// Test encoding Decimal types (used for threshold values)
221+
decimal, err := types.ParseDecimalExplicit("87000.50", 36, 18)
222+
require.NoError(t, err)
223+
224+
args := []any{
225+
"0x1111111111111111111111111111111111111111",
226+
"stbtcusd000000000000000000000000",
227+
int64(1735689600),
228+
decimal, // Threshold as Decimal
229+
nil, // FrozenAt
230+
}
231+
232+
encoded, err := EncodeActionArgs(args)
233+
require.NoError(t, err)
234+
require.NotNil(t, encoded)
235+
236+
// Verify we can read the encoded format
237+
buf := bytes.NewReader(encoded)
238+
var argCount uint32
239+
err = binary.Read(buf, binary.LittleEndian, &argCount)
240+
require.NoError(t, err)
241+
assert.Equal(t, uint32(5), argCount)
242+
243+
// Decode each argument
244+
for i := 0; i < 5; i++ {
245+
var argLen uint32
246+
err = binary.Read(buf, binary.LittleEndian, &argLen)
247+
require.NoError(t, err)
248+
249+
argBytes := make([]byte, argLen)
250+
_, err = buf.Read(argBytes)
251+
require.NoError(t, err)
252+
253+
var encodedVal types.EncodedValue
254+
err = encodedVal.UnmarshalBinary(argBytes)
255+
require.NoError(t, err)
256+
257+
decodedVal, err := encodedVal.Decode()
258+
require.NoError(t, err)
259+
260+
// Verify the Decimal argument (index 3)
261+
if i == 3 {
262+
decodedDecimal, ok := decodedVal.(*types.Decimal)
263+
require.True(t, ok, "arg 3 should be *types.Decimal")
264+
require.NotNil(t, decodedDecimal)
265+
// The value should match (87000.50 with 18 decimal places)
266+
assert.Equal(t, "87000.500000000000000000", decodedDecimal.String())
267+
}
268+
}
269+
}
270+
219271
func TestEncodeActionArgs_EdgeCases(t *testing.T) {
220272
t.Run("nil args", func(t *testing.T) {
221273
encoded, err := EncodeActionArgs(nil)

core/contractsapi/order_book_binary.go

Lines changed: 76 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,19 @@ func (o *OrderBook) CreatePriceAboveThresholdMarket(
102102
input CreatePriceAboveThresholdMarketInput,
103103
opts ...kwilClientType.TxOpt,
104104
) (kwiltypes.Hash, error) {
105+
// Parse threshold as Decimal (NUMERIC(36,18))
106+
thresholdDecimal, err := kwiltypes.ParseDecimalExplicit(input.Threshold, 36, 18)
107+
if err != nil {
108+
return kwiltypes.Hash{}, fmt.Errorf("invalid threshold: %w", err)
109+
}
110+
105111
// Build action arguments in the order expected by the node
106112
// price_above_threshold($data_provider, $stream_id, $timestamp, $threshold, $frozen_at)
107113
args := []any{
108114
input.DataProvider,
109115
input.StreamID,
110116
input.Timestamp,
111-
input.Threshold,
117+
thresholdDecimal,
112118
input.FrozenAt, // Can be nil
113119
}
114120

@@ -152,13 +158,19 @@ func (o *OrderBook) CreatePriceBelowThresholdMarket(
152158
input CreatePriceBelowThresholdMarketInput,
153159
opts ...kwilClientType.TxOpt,
154160
) (kwiltypes.Hash, error) {
161+
// Parse threshold as Decimal (NUMERIC(36,18))
162+
thresholdDecimal, err := kwiltypes.ParseDecimalExplicit(input.Threshold, 36, 18)
163+
if err != nil {
164+
return kwiltypes.Hash{}, fmt.Errorf("invalid threshold: %w", err)
165+
}
166+
155167
// Build action arguments
156168
// price_below_threshold($data_provider, $stream_id, $timestamp, $threshold, $frozen_at)
157169
args := []any{
158170
input.DataProvider,
159171
input.StreamID,
160172
input.Timestamp,
161-
input.Threshold,
173+
thresholdDecimal,
162174
input.FrozenAt,
163175
}
164176

@@ -200,14 +212,24 @@ func (o *OrderBook) CreateValueInRangeMarket(
200212
input CreateValueInRangeMarketInput,
201213
opts ...kwilClientType.TxOpt,
202214
) (kwiltypes.Hash, error) {
215+
// Parse min/max values as Decimal (NUMERIC(36,18))
216+
minValueDecimal, err := kwiltypes.ParseDecimalExplicit(input.MinValue, 36, 18)
217+
if err != nil {
218+
return kwiltypes.Hash{}, fmt.Errorf("invalid min_value: %w", err)
219+
}
220+
maxValueDecimal, err := kwiltypes.ParseDecimalExplicit(input.MaxValue, 36, 18)
221+
if err != nil {
222+
return kwiltypes.Hash{}, fmt.Errorf("invalid max_value: %w", err)
223+
}
224+
203225
// Build action arguments
204226
// value_in_range($data_provider, $stream_id, $timestamp, $min_value, $max_value, $frozen_at)
205227
args := []any{
206228
input.DataProvider,
207229
input.StreamID,
208230
input.Timestamp,
209-
input.MinValue,
210-
input.MaxValue,
231+
minValueDecimal,
232+
maxValueDecimal,
211233
input.FrozenAt,
212234
}
213235

@@ -249,14 +271,24 @@ func (o *OrderBook) CreateValueEqualsMarket(
249271
input CreateValueEqualsMarketInput,
250272
opts ...kwilClientType.TxOpt,
251273
) (kwiltypes.Hash, error) {
274+
// Parse target/tolerance values as Decimal (NUMERIC(36,18))
275+
targetValueDecimal, err := kwiltypes.ParseDecimalExplicit(input.TargetValue, 36, 18)
276+
if err != nil {
277+
return kwiltypes.Hash{}, fmt.Errorf("invalid target_value: %w", err)
278+
}
279+
toleranceDecimal, err := kwiltypes.ParseDecimalExplicit(input.Tolerance, 36, 18)
280+
if err != nil {
281+
return kwiltypes.Hash{}, fmt.Errorf("invalid tolerance: %w", err)
282+
}
283+
252284
// Build action arguments
253285
// value_equals($data_provider, $stream_id, $timestamp, $target_value, $tolerance, $frozen_at)
254286
args := []any{
255287
input.DataProvider,
256288
input.StreamID,
257289
input.Timestamp,
258-
input.TargetValue,
259-
input.Tolerance,
290+
targetValueDecimal,
291+
toleranceDecimal,
260292
input.FrozenAt,
261293
}
262294

@@ -294,11 +326,17 @@ func BuildPriceAboveThresholdQueryComponents(input types.PriceAboveThresholdInpu
294326
return nil, fmt.Errorf("invalid input: %w", err)
295327
}
296328

329+
// Parse threshold as Decimal (NUMERIC(36,18))
330+
thresholdDecimal, err := kwiltypes.ParseDecimalExplicit(input.Threshold, 36, 18)
331+
if err != nil {
332+
return nil, fmt.Errorf("invalid threshold: %w", err)
333+
}
334+
297335
args := []any{
298336
input.DataProvider,
299337
input.StreamID,
300338
input.Timestamp,
301-
input.Threshold,
339+
thresholdDecimal,
302340
input.FrozenAt,
303341
}
304342

@@ -321,11 +359,17 @@ func BuildPriceBelowThresholdQueryComponents(input types.PriceBelowThresholdInpu
321359
return nil, fmt.Errorf("invalid input: %w", err)
322360
}
323361

362+
// Parse threshold as Decimal (NUMERIC(36,18))
363+
thresholdDecimal, err := kwiltypes.ParseDecimalExplicit(input.Threshold, 36, 18)
364+
if err != nil {
365+
return nil, fmt.Errorf("invalid threshold: %w", err)
366+
}
367+
324368
args := []any{
325369
input.DataProvider,
326370
input.StreamID,
327371
input.Timestamp,
328-
input.Threshold,
372+
thresholdDecimal,
329373
input.FrozenAt,
330374
}
331375

@@ -348,12 +392,22 @@ func BuildValueInRangeQueryComponents(input types.ValueInRangeInput) ([]byte, er
348392
return nil, fmt.Errorf("invalid input: %w", err)
349393
}
350394

395+
// Parse min/max values as Decimal (NUMERIC(36,18))
396+
minValueDecimal, err := kwiltypes.ParseDecimalExplicit(input.MinValue, 36, 18)
397+
if err != nil {
398+
return nil, fmt.Errorf("invalid min_value: %w", err)
399+
}
400+
maxValueDecimal, err := kwiltypes.ParseDecimalExplicit(input.MaxValue, 36, 18)
401+
if err != nil {
402+
return nil, fmt.Errorf("invalid max_value: %w", err)
403+
}
404+
351405
args := []any{
352406
input.DataProvider,
353407
input.StreamID,
354408
input.Timestamp,
355-
input.MinValue,
356-
input.MaxValue,
409+
minValueDecimal,
410+
maxValueDecimal,
357411
input.FrozenAt,
358412
}
359413

@@ -376,12 +430,22 @@ func BuildValueEqualsQueryComponents(input types.ValueEqualsInput) ([]byte, erro
376430
return nil, fmt.Errorf("invalid input: %w", err)
377431
}
378432

433+
// Parse target/tolerance values as Decimal (NUMERIC(36,18))
434+
targetValueDecimal, err := kwiltypes.ParseDecimalExplicit(input.TargetValue, 36, 18)
435+
if err != nil {
436+
return nil, fmt.Errorf("invalid target_value: %w", err)
437+
}
438+
toleranceDecimal, err := kwiltypes.ParseDecimalExplicit(input.Tolerance, 36, 18)
439+
if err != nil {
440+
return nil, fmt.Errorf("invalid tolerance: %w", err)
441+
}
442+
379443
args := []any{
380444
input.DataProvider,
381445
input.StreamID,
382446
input.Timestamp,
383-
input.TargetValue,
384-
input.Tolerance,
447+
targetValueDecimal,
448+
toleranceDecimal,
385449
input.FrozenAt,
386450
}
387451

0 commit comments

Comments
 (0)