go-ethereum/XDCx/order_processor_test.go
2025-04-10 18:52:49 +08:00

582 lines
18 KiB
Go

package XDCx
import (
"math/big"
"reflect"
"testing"
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/node"
)
func Test_getCancelFeeV1(t *testing.T) {
type CancelFeeArg struct {
baseTokenDecimal *big.Int
feeRate *big.Int
order *tradingstate.OrderItem
}
tests := []struct {
name string
args CancelFeeArg
want *big.Int
}{
// zero fee test: SELL
{
"zero fee getCancelFeeV1: SELL",
CancelFeeArg{
baseTokenDecimal: common.Big1,
feeRate: common.Big0,
order: &tradingstate.OrderItem{
Quantity: new(big.Int).SetUint64(10000),
Side: tradingstate.Ask,
},
},
common.Big0,
},
// zero fee test: BUY
{
"zero fee getCancelFeeV1: BUY",
CancelFeeArg{
baseTokenDecimal: common.Big1,
feeRate: common.Big0,
order: &tradingstate.OrderItem{
Quantity: new(big.Int).SetUint64(10000),
Price: new(big.Int).SetUint64(1),
Side: tradingstate.Bid,
},
},
common.Big0,
},
// test getCancelFee: SELL
{
"test getCancelFeeV1:: SELL",
CancelFeeArg{
baseTokenDecimal: common.Big1,
feeRate: new(big.Int).SetUint64(10), // 10/10000= 0.1%
order: &tradingstate.OrderItem{
Quantity: new(big.Int).SetUint64(10000),
Side: tradingstate.Ask,
},
},
common.Big1,
},
// test getCancelFee:: BUY
{
"test getCancelFeeV1:: BUY",
CancelFeeArg{
baseTokenDecimal: common.Big1,
feeRate: new(big.Int).SetUint64(10), // 10/10000= 0.1%
order: &tradingstate.OrderItem{
Quantity: new(big.Int).SetUint64(10000),
Price: new(big.Int).SetUint64(1),
Side: tradingstate.Bid,
},
},
common.Big1,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := getCancelFeeV1(tt.args.baseTokenDecimal, tt.args.feeRate, tt.args.order); !reflect.DeepEqual(got, tt.want) {
t.Errorf("getCancelFeeV1() = %v, quantity %v", got, tt.want)
}
})
}
}
func Test_getCancelFee(t *testing.T) {
stack, err := node.New(&node.DefaultConfig)
if err != nil {
t.Fatalf("could not create new node: %v", err)
}
XDCx := New(stack, &DefaultConfig)
defer stack.Close()
db := rawdb.NewMemoryDatabase()
stateCache := tradingstate.NewDatabase(db)
tradingStateDb, _ := tradingstate.New(types.EmptyRootHash, stateCache)
testTokenA := common.HexToAddress("0x1000000000000000000000000000000000000002")
testTokenB := common.HexToAddress("0x1100000000000000000000000000000000000003")
// set decimal
// tokenA has decimal 10^18
XDCx.SetTokenDecimal(testTokenA, common.BasePrice)
// tokenB has decimal 10^8
tokenBDecimal := new(big.Int).Exp(big.NewInt(10), big.NewInt(8), nil)
XDCx.SetTokenDecimal(testTokenB, tokenBDecimal)
// set tokenAPrice = 1 XDC
tradingStateDb.SetMediumPriceBeforeEpoch(tradingstate.GetTradingOrderBookHash(testTokenA, common.XDCNativeAddressBinary), common.BasePrice)
// set tokenBPrice = 1 XDC
tradingStateDb.SetMediumPriceBeforeEpoch(tradingstate.GetTradingOrderBookHash(common.XDCNativeAddressBinary, testTokenB), tokenBDecimal)
type CancelFeeArg struct {
feeRate *big.Int
order *tradingstate.OrderItem
}
tests := []struct {
name string
args CancelFeeArg
want *big.Int
}{
// BASE: testTokenA,
// QUOTE: XDC
// zero fee test: SELL
{
"TokenA/XDC zero fee test: SELL",
CancelFeeArg{
feeRate: common.Big0,
order: &tradingstate.OrderItem{
BaseToken: testTokenA,
QuoteToken: common.XDCNativeAddressBinary,
Quantity: new(big.Int).SetUint64(10000),
Side: tradingstate.Ask,
},
},
common.Big0,
},
// zero fee test: BUY
{
"TokenA/XDC zero fee test: BUY",
CancelFeeArg{
feeRate: common.Big0,
order: &tradingstate.OrderItem{
BaseToken: testTokenA,
QuoteToken: common.XDCNativeAddressBinary,
Quantity: new(big.Int).SetUint64(10000),
Side: tradingstate.Bid,
},
},
common.Big0,
},
// test getCancelFee: SELL
{
"TokenA/XDC test getCancelFee:: SELL",
CancelFeeArg{
feeRate: new(big.Int).SetUint64(10), // 10/10000= 0.1%
order: &tradingstate.OrderItem{
BaseToken: common.XDCNativeAddressBinary,
QuoteToken: testTokenA,
Quantity: new(big.Int).SetUint64(10000),
Side: tradingstate.Ask,
},
},
common.RelayerCancelFee,
},
// test getCancelFee:: BUY
{
"TokenA/XDC test getCancelFee:: BUY",
CancelFeeArg{
feeRate: new(big.Int).SetUint64(10), // 10/10000= 0.1%
order: &tradingstate.OrderItem{
Quantity: new(big.Int).SetUint64(10000),
BaseToken: common.XDCNativeAddressBinary,
QuoteToken: testTokenA,
Side: tradingstate.Bid,
},
},
common.RelayerCancelFee,
},
// BASE: XDC
// QUOTE: testTokenA
// zero fee test: SELL
{
"XDC/TokenA zero fee test: SELL",
CancelFeeArg{
feeRate: common.Big0,
order: &tradingstate.OrderItem{
BaseToken: common.XDCNativeAddressBinary,
QuoteToken: testTokenA,
Quantity: new(big.Int).SetUint64(10000),
Side: tradingstate.Ask,
},
},
common.Big0,
},
// zero fee test: BUY
{
"XDC/TokenA zero fee test: BUY",
CancelFeeArg{
feeRate: common.Big0,
order: &tradingstate.OrderItem{
BaseToken: common.XDCNativeAddressBinary,
QuoteToken: testTokenA,
Quantity: new(big.Int).SetUint64(10000),
Side: tradingstate.Bid,
},
},
common.Big0,
},
// test getCancelFee: SELL
{
"XDC/TokenA test getCancelFee:: SELL",
CancelFeeArg{
feeRate: new(big.Int).SetUint64(10), // 10/10000= 0.1%
order: &tradingstate.OrderItem{
BaseToken: common.XDCNativeAddressBinary,
QuoteToken: testTokenA,
Quantity: new(big.Int).SetUint64(10000),
Side: tradingstate.Ask,
},
},
common.RelayerCancelFee,
},
// test getCancelFee:: BUY
{
"XDC/TokenA test getCancelFee:: BUY",
CancelFeeArg{
feeRate: new(big.Int).SetUint64(10), // 10/10000= 0.1%
order: &tradingstate.OrderItem{
Quantity: new(big.Int).SetUint64(10000),
BaseToken: common.XDCNativeAddressBinary,
QuoteToken: testTokenA,
Side: tradingstate.Bid,
},
},
common.RelayerCancelFee,
},
// BASE: testTokenB
// QUOTE: testTokenA
// zero fee test: SELL
{
"TokenB/TokenA zero fee test: SELL",
CancelFeeArg{
feeRate: common.Big0,
order: &tradingstate.OrderItem{
BaseToken: testTokenB,
QuoteToken: testTokenA,
Quantity: new(big.Int).SetUint64(10000),
Side: tradingstate.Ask,
},
},
common.Big0,
},
// zero fee test: BUY
{
"TokenB/TokenA zero fee test: BUY",
CancelFeeArg{
feeRate: common.Big0,
order: &tradingstate.OrderItem{
BaseToken: testTokenB,
QuoteToken: testTokenA,
Quantity: new(big.Int).SetUint64(10000),
Side: tradingstate.Bid,
},
},
common.Big0,
},
// test getCancelFee: SELL
{
"TokenB/TokenA test getCancelFee:: SELL",
CancelFeeArg{
feeRate: new(big.Int).SetUint64(10), // 10/10000= 0.1%
order: &tradingstate.OrderItem{
BaseToken: testTokenB,
QuoteToken: testTokenA,
Quantity: new(big.Int).SetUint64(10000),
Side: tradingstate.Ask,
},
},
new(big.Int).Exp(big.NewInt(10), big.NewInt(4), nil),
},
// test getCancelFee:: BUY
{
"TokenB/TokenA test getCancelFee:: BUY",
CancelFeeArg{
feeRate: new(big.Int).SetUint64(10), // 10/10000= 0.1%
order: &tradingstate.OrderItem{
Quantity: new(big.Int).SetUint64(10000),
BaseToken: testTokenB,
QuoteToken: testTokenA,
Side: tradingstate.Bid,
},
},
common.RelayerCancelFee,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got, _ := XDCx.getCancelFee(nil, nil, tradingStateDb, tt.args.order, tt.args.feeRate); !reflect.DeepEqual(got, tt.want) {
t.Errorf("getCancelFee() = %v, quantity %v", got, tt.want)
}
})
}
// testcase: can't get price of token in XDC
testTokenC := common.HexToAddress("0x1200000000000000000000000000000000000004")
XDCx.SetTokenDecimal(testTokenC, big.NewInt(1))
tokenCOrder := CancelFeeArg{
feeRate: new(big.Int).SetUint64(10), // 10/10000= 0.1%
order: &tradingstate.OrderItem{
Quantity: new(big.Int).SetUint64(10000),
BaseToken: testTokenC,
QuoteToken: testTokenA,
Side: tradingstate.Ask,
},
}
if fee, _ := XDCx.getCancelFee(nil, nil, tradingStateDb, tokenCOrder.order, tokenCOrder.feeRate); fee != nil && fee.Sign() != 0 {
t.Errorf("getCancelFee() = %v, want %v", fee, common.Big0)
}
// testcase: invalid token decimal
testTokenD := common.HexToAddress("0x1300000000000000000000000000000000000005")
XDCx.SetTokenDecimal(testTokenD, big.NewInt(0))
tokenDOrder := CancelFeeArg{
feeRate: new(big.Int).SetUint64(10), // 10/10000= 0.1%
order: &tradingstate.OrderItem{
Quantity: new(big.Int).SetUint64(10000),
BaseToken: testTokenD,
QuoteToken: testTokenA,
Side: tradingstate.Ask,
},
}
if fee, _ := XDCx.getCancelFee(nil, nil, tradingStateDb, tokenDOrder.order, tokenDOrder.feeRate); fee != nil && fee.Sign() != 0 {
t.Errorf("getCancelFee() = %v, want %v", fee, common.Big0)
}
}
func TestGetTradeQuantity(t *testing.T) {
type GetTradeQuantityArg struct {
takerSide string
takerFeeRate *big.Int
takerBalance *big.Int
makerPrice *big.Int
makerFeeRate *big.Int
makerBalance *big.Int
baseTokenDecimal *big.Int
quantityToTrade *big.Int
}
tests := []struct {
name string
args GetTradeQuantityArg
quantity *big.Int
rejectMaker bool
}{
{
"BUY: feeRate = 0, price 1, quantity 1000, taker balance 1000, maker balance 1000",
GetTradeQuantityArg{
takerSide: tradingstate.Bid,
takerFeeRate: common.Big0,
takerBalance: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
makerPrice: common.BasePrice,
makerFeeRate: common.Big0,
makerBalance: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
baseTokenDecimal: common.BasePrice,
quantityToTrade: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
},
new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
false,
},
{
"BUY: feeRate = 0, price 1, quantity 1000, taker balance 1000, maker balance 900 -> reject maker",
GetTradeQuantityArg{
takerSide: tradingstate.Bid,
takerFeeRate: common.Big0,
takerBalance: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
makerPrice: common.BasePrice,
makerFeeRate: common.Big0,
makerBalance: new(big.Int).Mul(big.NewInt(900), common.BasePrice),
baseTokenDecimal: common.BasePrice,
quantityToTrade: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
},
new(big.Int).Mul(big.NewInt(900), common.BasePrice),
true,
},
{
"BUY: feeRate = 0, price 1, quantity 1000, taker balance 900, maker balance 1000 -> reject taker",
GetTradeQuantityArg{
takerSide: tradingstate.Bid,
takerFeeRate: common.Big0,
takerBalance: new(big.Int).Mul(big.NewInt(900), common.BasePrice),
makerPrice: common.BasePrice,
makerFeeRate: common.Big0,
makerBalance: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
baseTokenDecimal: common.BasePrice,
quantityToTrade: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
},
new(big.Int).Mul(big.NewInt(900), common.BasePrice),
false,
},
{
"BUY: feeRate = 0, price 1, quantity 1000, taker balance 0, maker balance 1000 -> reject taker",
GetTradeQuantityArg{
takerSide: tradingstate.Bid,
takerFeeRate: common.Big0,
takerBalance: common.Big0,
makerPrice: common.BasePrice,
makerFeeRate: common.Big0,
makerBalance: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
baseTokenDecimal: common.BasePrice,
quantityToTrade: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
},
common.Big0,
false,
},
{
"BUY: feeRate = 0, price 1, quantity 1000, taker balance 0, maker balance 0 -> reject both taker",
GetTradeQuantityArg{
takerSide: tradingstate.Bid,
takerFeeRate: common.Big0,
takerBalance: common.Big0,
makerPrice: common.BasePrice,
makerFeeRate: common.Big0,
makerBalance: common.Big0,
baseTokenDecimal: common.BasePrice,
quantityToTrade: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
},
common.Big0,
false,
},
{
"BUY: feeRate = 0, price 1, quantity 1000, taker balance 500, maker balance 100 -> reject both taker, maker",
GetTradeQuantityArg{
takerSide: tradingstate.Bid,
takerFeeRate: common.Big0,
takerBalance: new(big.Int).Mul(big.NewInt(500), common.BasePrice),
makerPrice: common.BasePrice,
makerFeeRate: common.Big0,
makerBalance: new(big.Int).Mul(big.NewInt(100), common.BasePrice),
baseTokenDecimal: common.BasePrice,
quantityToTrade: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
},
new(big.Int).Mul(big.NewInt(100), common.BasePrice),
true,
},
{
"SELL: feeRate = 0, price 1, quantity 1000, taker balance 1000, maker balance 1000",
GetTradeQuantityArg{
takerSide: tradingstate.Ask,
takerFeeRate: common.Big0,
takerBalance: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
makerPrice: common.BasePrice,
makerFeeRate: common.Big0,
makerBalance: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
baseTokenDecimal: common.BasePrice,
quantityToTrade: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
},
new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
false,
},
{
"SELL: feeRate = 0, price 1, quantity 1000, taker balance 1000, maker balance 900 -> reject maker",
GetTradeQuantityArg{
takerSide: tradingstate.Ask,
takerFeeRate: common.Big0,
takerBalance: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
makerPrice: common.BasePrice,
makerFeeRate: common.Big0,
makerBalance: new(big.Int).Mul(big.NewInt(900), common.BasePrice),
baseTokenDecimal: common.BasePrice,
quantityToTrade: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
},
new(big.Int).Mul(big.NewInt(900), common.BasePrice),
true,
},
{
"SELL: feeRate = 0, price 1, quantity 1000, taker balance 900, maker balance 1000 -> reject taker",
GetTradeQuantityArg{
takerSide: tradingstate.Ask,
takerFeeRate: common.Big0,
takerBalance: new(big.Int).Mul(big.NewInt(900), common.BasePrice),
makerPrice: common.BasePrice,
makerFeeRate: common.Big0,
makerBalance: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
baseTokenDecimal: common.BasePrice,
quantityToTrade: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
},
new(big.Int).Mul(big.NewInt(900), common.BasePrice),
false,
},
{
"SELL: feeRate = 0, price 1, quantity 1000, taker balance 0, maker balance 1000 -> reject taker",
GetTradeQuantityArg{
takerSide: tradingstate.Ask,
takerFeeRate: common.Big0,
takerBalance: common.Big0,
makerPrice: common.BasePrice,
makerFeeRate: common.Big0,
makerBalance: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
baseTokenDecimal: common.BasePrice,
quantityToTrade: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
},
common.Big0,
false,
},
{
"SELL: feeRate = 0, price 1, quantity 1000, taker balance 0, maker balance 0 -> reject maker",
GetTradeQuantityArg{
takerSide: tradingstate.Ask,
takerFeeRate: common.Big0,
takerBalance: common.Big0,
makerPrice: common.BasePrice,
makerFeeRate: common.Big0,
makerBalance: common.Big0,
baseTokenDecimal: common.BasePrice,
quantityToTrade: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
},
common.Big0,
true,
},
{
"SELL: feeRate = 0, price 1, quantity 1000, taker balance 500, maker balance 100 -> reject both taker, maker",
GetTradeQuantityArg{
takerSide: tradingstate.Ask,
takerFeeRate: common.Big0,
takerBalance: new(big.Int).Mul(big.NewInt(500), common.BasePrice),
makerPrice: common.BasePrice,
makerFeeRate: common.Big0,
makerBalance: new(big.Int).Mul(big.NewInt(100), common.BasePrice),
baseTokenDecimal: common.BasePrice,
quantityToTrade: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
},
new(big.Int).Mul(big.NewInt(100), common.BasePrice),
true,
},
{
"SELL: feeRate = 0, price 1, quantity 1000, taker balance 0, maker balance 100 -> reject both taker, maker",
GetTradeQuantityArg{
takerSide: tradingstate.Ask,
takerFeeRate: common.Big0,
takerBalance: common.Big0,
makerPrice: common.BasePrice,
makerFeeRate: common.Big0,
makerBalance: new(big.Int).Mul(big.NewInt(100), common.BasePrice),
baseTokenDecimal: common.BasePrice,
quantityToTrade: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
},
common.Big0,
false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got1 := GetTradeQuantity(tt.args.takerSide, tt.args.takerFeeRate, tt.args.takerBalance, tt.args.makerPrice, tt.args.makerFeeRate, tt.args.makerBalance, tt.args.baseTokenDecimal, tt.args.quantityToTrade)
if !reflect.DeepEqual(got, tt.quantity) {
t.Errorf("GetTradeQuantity() got = %v, quantity %v", got, tt.quantity)
}
if got1 != tt.rejectMaker {
t.Errorf("GetTradeQuantity() got1 = %v, quantity %v", got1, tt.rejectMaker)
}
})
}
}