mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
assets: reject malformed RFQ asset rates
Validate the rate pointer and decimal coefficient before converting asset units. Return errors for nil, malformed, non-positive, and oversized-scale rates instead of allowing nil dereferences or division-by-zero panics. Add regression tests for each case.
This commit is contained in:
parent
dc39d63d8d
commit
cfbade1239
2 changed files with 62 additions and 2 deletions
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
@ -12,7 +13,6 @@ import (
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcutil"
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
"github.com/lightninglabs/taproot-assets/rfqmath"
|
"github.com/lightninglabs/taproot-assets/rfqmath"
|
||||||
"github.com/lightninglabs/taproot-assets/rpcutils"
|
|
||||||
"github.com/lightninglabs/taproot-assets/taprpc"
|
"github.com/lightninglabs/taproot-assets/taprpc"
|
||||||
"github.com/lightninglabs/taproot-assets/taprpc/priceoraclerpc"
|
"github.com/lightninglabs/taproot-assets/taprpc/priceoraclerpc"
|
||||||
"github.com/lightninglabs/taproot-assets/taprpc/rfqrpc"
|
"github.com/lightninglabs/taproot-assets/taprpc/rfqrpc"
|
||||||
|
|
@ -275,7 +275,7 @@ func (c *TapdClient) GetAssetPrice(ctx context.Context, assetID string,
|
||||||
func getSatsFromAssetAmt(assetAmt uint64, assetRate *rfqrpc.FixedPoint) (
|
func getSatsFromAssetAmt(assetAmt uint64, assetRate *rfqrpc.FixedPoint) (
|
||||||
btcutil.Amount, error) {
|
btcutil.Amount, error) {
|
||||||
|
|
||||||
rateFP, err := rpcutils.UnmarshalRfqFixedPoint(assetRate)
|
rateFP, err := unmarshalAssetRate(assetRate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("cannot unmarshal asset rate: %w", err)
|
return 0, fmt.Errorf("cannot unmarshal asset rate: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -287,6 +287,33 @@ func getSatsFromAssetAmt(assetAmt uint64, assetRate *rfqrpc.FixedPoint) (
|
||||||
return msatAmt.ToSatoshis(), nil
|
return msatAmt.ToSatoshis(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// unmarshalAssetRate validates and converts an RPC asset rate to the fixed
|
||||||
|
// point representation used for RFQ arithmetic.
|
||||||
|
func unmarshalAssetRate(assetRate *rfqrpc.FixedPoint) (
|
||||||
|
*rfqmath.BigIntFixedPoint, error) {
|
||||||
|
|
||||||
|
if assetRate == nil {
|
||||||
|
return nil, fmt.Errorf("asset rate cannot be nil")
|
||||||
|
}
|
||||||
|
if assetRate.Scale > math.MaxUint8 {
|
||||||
|
return nil, fmt.Errorf("scale value overflow: %v", assetRate.Scale)
|
||||||
|
}
|
||||||
|
|
||||||
|
coefficient, ok := new(big.Int).SetString(assetRate.Coefficient, 10)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("invalid asset rate coefficient: %q",
|
||||||
|
assetRate.Coefficient)
|
||||||
|
}
|
||||||
|
if coefficient.Sign() <= 0 {
|
||||||
|
return nil, fmt.Errorf("asset rate coefficient must be positive")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &rfqmath.BigIntFixedPoint{
|
||||||
|
Coefficient: rfqmath.NewBigInt(coefficient),
|
||||||
|
Scale: uint8(assetRate.Scale),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// getPaymentMaxAmount returns the milisat amount we are willing to pay for the
|
// getPaymentMaxAmount returns the milisat amount we are willing to pay for the
|
||||||
// payment.
|
// payment.
|
||||||
func getPaymentMaxAmount(satAmount btcutil.Amount, feeLimitMultiplier float64) (
|
func getPaymentMaxAmount(satAmount btcutil.Amount, feeLimitMultiplier float64) (
|
||||||
|
|
|
||||||
|
|
@ -308,6 +308,39 @@ func TestGetSatsFromAssetAmt(t *testing.T) {
|
||||||
expected: btcutil.Amount(0),
|
expected: btcutil.Amount(0),
|
||||||
expectError: false,
|
expectError: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
assetAmt: 1000,
|
||||||
|
assetRate: nil,
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
assetAmt: 1000,
|
||||||
|
assetRate: &rfqrpc.FixedPoint{
|
||||||
|
Coefficient: "not-a-number", Scale: 0,
|
||||||
|
},
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
assetAmt: 1000,
|
||||||
|
assetRate: &rfqrpc.FixedPoint{
|
||||||
|
Coefficient: "0", Scale: 0,
|
||||||
|
},
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
assetAmt: 1000,
|
||||||
|
assetRate: &rfqrpc.FixedPoint{
|
||||||
|
Coefficient: "-1", Scale: 0,
|
||||||
|
},
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
assetAmt: 1000,
|
||||||
|
assetRate: &rfqrpc.FixedPoint{
|
||||||
|
Coefficient: "1", Scale: 256,
|
||||||
|
},
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue