2020-01-14 15:04:47 +00:00
|
|
|
package keeper_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2020-04-30 14:23:41 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
2023-04-05 23:21:59 +00:00
|
|
|
sdkmath "cosmossdk.io/math"
|
2020-01-14 15:04:47 +00:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2022-01-08 00:39:27 +00:00
|
|
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
|
|
|
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
2020-01-14 15:04:47 +00:00
|
|
|
|
2024-05-01 03:17:24 +00:00
|
|
|
"github.com/0glabs/0g-chain/app"
|
|
|
|
"github.com/0glabs/0g-chain/x/auction/types"
|
2020-01-14 15:04:47 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type AuctionType int
|
|
|
|
|
|
|
|
const (
|
2020-02-28 22:16:22 +00:00
|
|
|
Invalid AuctionType = 0
|
|
|
|
Surplus AuctionType = 1
|
|
|
|
Debt AuctionType = 2
|
|
|
|
Collateral AuctionType = 3
|
2020-01-14 15:04:47 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestAuctionBidding(t *testing.T) {
|
2022-01-08 00:39:27 +00:00
|
|
|
config := sdk.GetConfig()
|
|
|
|
app.SetBech32AddressPrefixes(config)
|
|
|
|
|
2022-05-09 18:37:36 +00:00
|
|
|
someTime := time.Date(0o001, time.January, 1, 0, 0, 0, 0, time.UTC)
|
2020-01-14 15:04:47 +00:00
|
|
|
|
|
|
|
_, addrs := app.GeneratePrivKeyAddressPairs(5)
|
|
|
|
buyer := addrs[0]
|
|
|
|
secondBuyer := addrs[1]
|
|
|
|
modName := "liquidator"
|
|
|
|
collateralAddrs := addrs[2:]
|
|
|
|
collateralWeights := is(30, 20, 10)
|
|
|
|
|
2022-02-08 16:42:00 +00:00
|
|
|
initialBalance := cs(c("token1", 1000), c("token2", 1000))
|
|
|
|
|
2020-01-14 15:04:47 +00:00
|
|
|
type auctionArgs struct {
|
|
|
|
auctionType AuctionType
|
|
|
|
seller string
|
|
|
|
lot sdk.Coin
|
|
|
|
bid sdk.Coin
|
|
|
|
debt sdk.Coin
|
|
|
|
addresses []sdk.AccAddress
|
2023-04-05 23:21:59 +00:00
|
|
|
weights []sdkmath.Int
|
2020-01-14 15:04:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type bidArgs struct {
|
2020-02-28 22:16:22 +00:00
|
|
|
bidder sdk.AccAddress
|
|
|
|
amount sdk.Coin
|
2020-01-14 15:04:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
auctionArgs auctionArgs
|
2020-02-28 22:16:22 +00:00
|
|
|
setupBids []bidArgs
|
2020-01-14 15:04:47 +00:00
|
|
|
bidArgs bidArgs
|
2020-04-23 16:35:58 +00:00
|
|
|
expectedError error
|
2020-01-14 15:04:47 +00:00
|
|
|
expectedEndTime time.Time
|
|
|
|
expectedBidder sdk.AccAddress
|
|
|
|
expectedBid sdk.Coin
|
2020-04-23 16:35:58 +00:00
|
|
|
expectPass bool
|
|
|
|
expectPanic bool
|
2020-01-14 15:04:47 +00:00
|
|
|
}{
|
|
|
|
{
|
|
|
|
"basic: auction doesn't exist",
|
2023-04-05 23:21:59 +00:00
|
|
|
auctionArgs{Surplus, "", c("token1", 1), c("token2", 1), sdk.Coin{}, []sdk.AccAddress{}, []sdkmath.Int{}},
|
2020-02-28 22:16:22 +00:00
|
|
|
nil,
|
|
|
|
bidArgs{buyer, c("token2", 10)},
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrAuctionNotFound,
|
2022-02-08 17:03:47 +00:00
|
|
|
someTime.Add(types.DefaultForwardBidDuration),
|
2020-01-14 15:04:47 +00:00
|
|
|
buyer,
|
|
|
|
c("token2", 10),
|
|
|
|
false,
|
2020-04-23 16:35:58 +00:00
|
|
|
true,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
2020-02-28 22:16:22 +00:00
|
|
|
{
|
|
|
|
"basic: closed auction",
|
2023-04-05 23:21:59 +00:00
|
|
|
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdkmath.Int{}},
|
2020-02-28 22:16:22 +00:00
|
|
|
nil,
|
|
|
|
bidArgs{buyer, c("token2", 10)},
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrAuctionHasExpired,
|
2020-02-28 22:16:22 +00:00
|
|
|
types.DistantFuture,
|
|
|
|
nil,
|
|
|
|
c("token2", 0),
|
|
|
|
false,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-02-28 22:16:22 +00:00
|
|
|
},
|
2020-01-14 15:04:47 +00:00
|
|
|
{
|
2022-01-08 00:39:27 +00:00
|
|
|
// This is the first bid on an auction with NO bids
|
2020-01-14 15:04:47 +00:00
|
|
|
"surplus: normal",
|
2023-04-05 23:21:59 +00:00
|
|
|
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdkmath.Int{}},
|
2020-02-28 22:16:22 +00:00
|
|
|
nil,
|
|
|
|
bidArgs{buyer, c("token2", 10)},
|
2020-04-23 16:35:58 +00:00
|
|
|
nil,
|
2022-02-08 17:03:47 +00:00
|
|
|
someTime.Add(types.DefaultForwardBidDuration),
|
2020-01-14 15:04:47 +00:00
|
|
|
buyer,
|
|
|
|
c("token2", 10),
|
|
|
|
true,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"surplus: second bidder",
|
2023-04-05 23:21:59 +00:00
|
|
|
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdkmath.Int{}},
|
2020-02-28 22:16:22 +00:00
|
|
|
[]bidArgs{{buyer, c("token2", 10)}},
|
|
|
|
bidArgs{secondBuyer, c("token2", 11)},
|
2020-04-23 16:35:58 +00:00
|
|
|
nil,
|
2022-02-08 17:03:47 +00:00
|
|
|
someTime.Add(types.DefaultForwardBidDuration),
|
2020-01-14 15:04:47 +00:00
|
|
|
secondBuyer,
|
|
|
|
c("token2", 11),
|
|
|
|
true,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"surplus: invalid bid denom",
|
2023-04-05 23:21:59 +00:00
|
|
|
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdkmath.Int{}},
|
2020-02-28 22:16:22 +00:00
|
|
|
nil,
|
|
|
|
bidArgs{buyer, c("badtoken", 10)},
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrInvalidBidDenom,
|
2020-02-28 22:16:22 +00:00
|
|
|
types.DistantFuture,
|
|
|
|
nil, // surplus auctions are created with initial bidder as a nil address
|
|
|
|
c("token2", 0),
|
|
|
|
false,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-02-28 22:16:22 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"surplus: invalid bid (less than)",
|
2023-04-05 23:21:59 +00:00
|
|
|
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 0), sdk.Coin{}, []sdk.AccAddress{}, []sdkmath.Int{}},
|
2020-02-28 22:16:22 +00:00
|
|
|
[]bidArgs{{buyer, c("token2", 100)}},
|
|
|
|
bidArgs{buyer, c("token2", 99)},
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrBidTooSmall,
|
2022-02-08 17:03:47 +00:00
|
|
|
someTime.Add(types.DefaultForwardBidDuration),
|
2020-01-14 15:04:47 +00:00
|
|
|
buyer,
|
2020-02-28 22:16:22 +00:00
|
|
|
c("token2", 100),
|
2020-01-14 15:04:47 +00:00
|
|
|
false,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"surplus: invalid bid (equal)",
|
2023-04-05 23:21:59 +00:00
|
|
|
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 0), sdk.Coin{}, []sdk.AccAddress{}, []sdkmath.Int{}},
|
2020-02-28 22:16:22 +00:00
|
|
|
nil,
|
|
|
|
bidArgs{buyer, c("token2", 0)}, // min bid is technically 0 at default 5%, but it's capped at 1
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrBidTooSmall,
|
2020-02-28 22:16:22 +00:00
|
|
|
types.DistantFuture,
|
|
|
|
nil, // surplus auctions are created with initial bidder as a nil address
|
|
|
|
c("token2", 0),
|
|
|
|
false,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-02-28 22:16:22 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"surplus: invalid bid (less than min increment)",
|
2023-04-05 23:21:59 +00:00
|
|
|
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 0), sdk.Coin{}, []sdk.AccAddress{}, []sdkmath.Int{}},
|
2020-02-28 22:16:22 +00:00
|
|
|
[]bidArgs{{buyer, c("token2", 100)}},
|
|
|
|
bidArgs{buyer, c("token2", 104)}, // min bid is 105 at default 5%
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrBidTooSmall,
|
2022-02-08 17:03:47 +00:00
|
|
|
someTime.Add(types.DefaultForwardBidDuration),
|
2020-01-14 15:04:47 +00:00
|
|
|
buyer,
|
2020-02-28 22:16:22 +00:00
|
|
|
c("token2", 100),
|
2020-01-14 15:04:47 +00:00
|
|
|
false,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"debt: normal",
|
2023-04-05 23:21:59 +00:00
|
|
|
auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdkmath.Int{}}, // initial bid, lot
|
2020-02-28 22:16:22 +00:00
|
|
|
nil,
|
|
|
|
bidArgs{buyer, c("token1", 10)},
|
2020-04-23 16:35:58 +00:00
|
|
|
nil,
|
2022-02-08 17:03:47 +00:00
|
|
|
someTime.Add(types.DefaultForwardBidDuration),
|
2020-01-14 15:04:47 +00:00
|
|
|
buyer,
|
|
|
|
c("token2", 100),
|
|
|
|
true,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"debt: second bidder",
|
2023-04-05 23:21:59 +00:00
|
|
|
auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdkmath.Int{}}, // initial bid, lot
|
2020-02-28 22:16:22 +00:00
|
|
|
[]bidArgs{{buyer, c("token1", 10)}},
|
|
|
|
bidArgs{secondBuyer, c("token1", 9)},
|
2020-04-23 16:35:58 +00:00
|
|
|
nil,
|
2022-02-08 17:03:47 +00:00
|
|
|
someTime.Add(types.DefaultForwardBidDuration),
|
2020-01-14 15:04:47 +00:00
|
|
|
secondBuyer,
|
|
|
|
c("token2", 100),
|
|
|
|
true,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"debt: invalid lot denom",
|
2023-04-05 23:21:59 +00:00
|
|
|
auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdkmath.Int{}}, // initial bid, lot
|
2020-02-28 22:16:22 +00:00
|
|
|
nil,
|
|
|
|
bidArgs{buyer, c("badtoken", 10)},
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrInvalidLotDenom,
|
2020-02-28 22:16:22 +00:00
|
|
|
types.DistantFuture,
|
2022-01-08 00:39:27 +00:00
|
|
|
authtypes.NewModuleAddress(modName),
|
2020-02-28 22:16:22 +00:00
|
|
|
c("token2", 100),
|
2020-01-14 15:04:47 +00:00
|
|
|
false,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"debt: invalid lot size (larger)",
|
2023-04-05 23:21:59 +00:00
|
|
|
auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdkmath.Int{}},
|
2020-02-28 22:16:22 +00:00
|
|
|
nil,
|
|
|
|
bidArgs{buyer, c("token1", 21)},
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrLotTooLarge,
|
2020-02-28 22:16:22 +00:00
|
|
|
types.DistantFuture,
|
2022-01-08 00:39:27 +00:00
|
|
|
authtypes.NewModuleAddress(modName),
|
2020-02-28 22:16:22 +00:00
|
|
|
c("token2", 100),
|
|
|
|
false,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-02-28 22:16:22 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"debt: invalid lot size (equal)",
|
2023-04-05 23:21:59 +00:00
|
|
|
auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdkmath.Int{}},
|
2020-02-28 22:16:22 +00:00
|
|
|
nil,
|
|
|
|
bidArgs{buyer, c("token1", 20)},
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrLotTooLarge,
|
2020-02-28 22:16:22 +00:00
|
|
|
types.DistantFuture,
|
2022-01-08 00:39:27 +00:00
|
|
|
authtypes.NewModuleAddress(modName),
|
2020-02-28 22:16:22 +00:00
|
|
|
c("token2", 100),
|
|
|
|
false,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-02-28 22:16:22 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"debt: invalid lot size (larger than min increment)",
|
2023-04-05 23:21:59 +00:00
|
|
|
auctionArgs{Debt, modName, c("token1", 60), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdkmath.Int{}},
|
2020-02-28 22:16:22 +00:00
|
|
|
nil,
|
|
|
|
bidArgs{buyer, c("token1", 58)}, // max lot at default 5% is 57
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrLotTooLarge,
|
2020-02-28 22:16:22 +00:00
|
|
|
types.DistantFuture,
|
2022-01-08 00:39:27 +00:00
|
|
|
authtypes.NewModuleAddress(modName),
|
2020-02-28 22:16:22 +00:00
|
|
|
c("token2", 100),
|
2020-04-23 16:35:58 +00:00
|
|
|
false, false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"collateral [forward]: normal",
|
2020-02-28 22:16:22 +00:00
|
|
|
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
|
|
|
nil,
|
|
|
|
bidArgs{buyer, c("token2", 10)},
|
2020-04-23 16:35:58 +00:00
|
|
|
nil,
|
2022-02-08 17:03:47 +00:00
|
|
|
someTime.Add(types.DefaultForwardBidDuration),
|
2020-01-14 15:04:47 +00:00
|
|
|
buyer,
|
|
|
|
c("token2", 10),
|
|
|
|
true,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"collateral [forward]: second bidder",
|
2020-02-28 22:16:22 +00:00
|
|
|
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
|
|
|
[]bidArgs{{buyer, c("token2", 10)}},
|
|
|
|
bidArgs{secondBuyer, c("token2", 11)},
|
2020-04-23 16:35:58 +00:00
|
|
|
nil,
|
2022-02-08 17:03:47 +00:00
|
|
|
someTime.Add(types.DefaultForwardBidDuration),
|
2020-01-14 15:04:47 +00:00
|
|
|
secondBuyer,
|
|
|
|
c("token2", 11),
|
|
|
|
true,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
2022-02-08 17:03:47 +00:00
|
|
|
{
|
|
|
|
"collateral [forward]: convert to reverse (reach maxBid)",
|
|
|
|
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
|
|
|
[]bidArgs{{buyer, c("token2", 10)}},
|
|
|
|
bidArgs{secondBuyer, c("token2", 100)},
|
|
|
|
nil,
|
|
|
|
someTime.Add(types.DefaultReverseBidDuration),
|
|
|
|
secondBuyer,
|
|
|
|
c("token2", 100),
|
|
|
|
true,
|
|
|
|
false,
|
|
|
|
},
|
2020-01-14 15:04:47 +00:00
|
|
|
{
|
|
|
|
"collateral [forward]: invalid bid denom",
|
2020-02-28 22:16:22 +00:00
|
|
|
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
|
|
|
nil,
|
|
|
|
bidArgs{buyer, c("badtoken", 10)},
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrInvalidBidDenom,
|
2020-02-28 22:16:22 +00:00
|
|
|
types.DistantFuture,
|
|
|
|
nil,
|
|
|
|
c("token2", 0),
|
|
|
|
false,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-02-28 22:16:22 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"collateral [forward]: invalid bid size (smaller)",
|
|
|
|
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
|
|
|
[]bidArgs{{buyer, c("token2", 10)}},
|
|
|
|
bidArgs{buyer, c("token2", 9)},
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrBidTooSmall,
|
2022-02-08 17:03:47 +00:00
|
|
|
someTime.Add(types.DefaultForwardBidDuration),
|
2020-01-14 15:04:47 +00:00
|
|
|
buyer,
|
|
|
|
c("token2", 10),
|
|
|
|
false,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
|
|
|
{
|
2020-02-28 22:16:22 +00:00
|
|
|
"collateral [forward]: invalid bid size (equal)",
|
|
|
|
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
|
|
|
nil,
|
|
|
|
bidArgs{buyer, c("token2", 0)},
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrBidTooSmall,
|
2020-02-28 22:16:22 +00:00
|
|
|
types.DistantFuture,
|
|
|
|
nil,
|
|
|
|
c("token2", 0),
|
|
|
|
false,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-02-28 22:16:22 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"collateral [forward]: invalid bid size (less than min increment)",
|
|
|
|
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
|
|
|
[]bidArgs{{buyer, c("token2", 50)}},
|
|
|
|
bidArgs{buyer, c("token2", 51)},
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrBidTooSmall,
|
2022-02-08 17:03:47 +00:00
|
|
|
someTime.Add(types.DefaultForwardBidDuration),
|
2020-01-14 15:04:47 +00:00
|
|
|
buyer,
|
2020-02-28 22:16:22 +00:00
|
|
|
c("token2", 50),
|
2020-01-14 15:04:47 +00:00
|
|
|
false,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
|
|
|
{
|
2020-02-28 22:16:22 +00:00
|
|
|
"collateral [forward]: less than min increment but equal to maxBid",
|
|
|
|
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
|
|
|
[]bidArgs{{buyer, c("token2", 99)}},
|
|
|
|
bidArgs{buyer, c("token2", 100)}, // min bid at default 5% is 104
|
2020-04-23 16:35:58 +00:00
|
|
|
nil,
|
2022-02-08 17:03:47 +00:00
|
|
|
someTime.Add(types.DefaultReverseBidDuration), // Converts to a reverse bid when max reached
|
2020-01-14 15:04:47 +00:00
|
|
|
buyer,
|
2020-02-28 22:16:22 +00:00
|
|
|
c("token2", 100),
|
|
|
|
true,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-02-28 22:16:22 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"collateral [forward]: invalid bid size (greater than max)",
|
|
|
|
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
|
|
|
nil,
|
|
|
|
bidArgs{buyer, c("token2", 101)},
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrBidTooLarge,
|
2020-02-28 22:16:22 +00:00
|
|
|
types.DistantFuture,
|
|
|
|
nil,
|
|
|
|
c("token2", 0),
|
2020-01-14 15:04:47 +00:00
|
|
|
false,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
2022-02-08 16:42:00 +00:00
|
|
|
{
|
|
|
|
"collateral [forward]: bidder replaces previous bid with only funds for difference",
|
|
|
|
auctionArgs{Collateral, modName, c("token1", 1000), c("token2", 2000), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
|
|
|
[]bidArgs{{buyer, c("token2", 900)}},
|
|
|
|
bidArgs{buyer, c("token2", 1000)}, // buyer only has enough to cover the increase from previous bid
|
|
|
|
nil,
|
2022-02-08 17:33:42 +00:00
|
|
|
someTime.Add(types.DefaultForwardBidDuration),
|
2022-02-08 16:42:00 +00:00
|
|
|
buyer,
|
|
|
|
c("token2", 1000),
|
|
|
|
true,
|
|
|
|
false,
|
|
|
|
},
|
2020-01-14 15:04:47 +00:00
|
|
|
{
|
|
|
|
"collateral [reverse]: normal",
|
2020-02-28 22:16:22 +00:00
|
|
|
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
|
|
|
[]bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase
|
|
|
|
bidArgs{buyer, c("token1", 15)},
|
2020-04-23 16:35:58 +00:00
|
|
|
nil,
|
2022-02-08 17:03:47 +00:00
|
|
|
someTime.Add(types.DefaultReverseBidDuration),
|
2020-01-14 15:04:47 +00:00
|
|
|
buyer,
|
|
|
|
c("token2", 50),
|
|
|
|
true,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"collateral [reverse]: second bidder",
|
2020-02-28 22:16:22 +00:00
|
|
|
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
|
|
|
[]bidArgs{{buyer, c("token2", 50)}, {buyer, c("token1", 15)}}, // put auction into reverse phase, and add a reverse phase bid
|
|
|
|
bidArgs{secondBuyer, c("token1", 14)},
|
2020-04-23 16:35:58 +00:00
|
|
|
nil,
|
2022-02-08 17:03:47 +00:00
|
|
|
someTime.Add(types.DefaultReverseBidDuration),
|
2020-01-14 15:04:47 +00:00
|
|
|
secondBuyer,
|
|
|
|
c("token2", 50),
|
|
|
|
true,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"collateral [reverse]: invalid lot denom",
|
2020-02-28 22:16:22 +00:00
|
|
|
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
|
|
|
[]bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase
|
|
|
|
bidArgs{buyer, c("badtoken", 15)},
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrInvalidLotDenom,
|
2022-02-08 17:03:47 +00:00
|
|
|
someTime.Add(types.DefaultReverseBidDuration),
|
2020-01-14 15:04:47 +00:00
|
|
|
buyer,
|
|
|
|
c("token2", 50),
|
|
|
|
false,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
|
|
|
{
|
2020-02-28 22:16:22 +00:00
|
|
|
"collateral [reverse]: invalid lot size (greater)",
|
|
|
|
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
|
|
|
[]bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase
|
|
|
|
bidArgs{buyer, c("token1", 21)},
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrLotTooLarge,
|
2022-02-08 17:03:47 +00:00
|
|
|
someTime.Add(types.DefaultReverseBidDuration),
|
2020-01-14 15:04:47 +00:00
|
|
|
buyer,
|
|
|
|
c("token2", 50),
|
|
|
|
false,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
|
|
|
{
|
2020-02-28 22:16:22 +00:00
|
|
|
"collateral [reverse]: invalid lot size (equal)",
|
|
|
|
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
|
|
|
[]bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase
|
|
|
|
bidArgs{buyer, c("token1", 20)},
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrLotTooLarge,
|
2022-02-08 17:03:47 +00:00
|
|
|
someTime.Add(types.DefaultReverseBidDuration),
|
2020-01-14 15:04:47 +00:00
|
|
|
buyer,
|
|
|
|
c("token2", 50),
|
|
|
|
false,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
|
|
|
{
|
2020-02-28 22:16:22 +00:00
|
|
|
"collateral [reverse]: invalid lot size (larger than min increment)",
|
|
|
|
auctionArgs{Collateral, modName, c("token1", 60), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
|
|
|
[]bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase
|
|
|
|
bidArgs{buyer, c("token1", 58)}, // max lot at default 5% is 57
|
2020-04-23 16:35:58 +00:00
|
|
|
types.ErrLotTooLarge,
|
2022-02-08 17:03:47 +00:00
|
|
|
someTime.Add(types.DefaultReverseBidDuration),
|
2020-01-14 15:04:47 +00:00
|
|
|
buyer,
|
2020-02-28 22:16:22 +00:00
|
|
|
c("token2", 50),
|
2020-01-14 15:04:47 +00:00
|
|
|
false,
|
2020-04-23 16:35:58 +00:00
|
|
|
false,
|
2020-01-14 15:04:47 +00:00
|
|
|
},
|
2022-02-08 16:42:00 +00:00
|
|
|
{
|
|
|
|
"collateral [reverse]: bidder replaces previous bid without funds",
|
|
|
|
auctionArgs{Collateral, modName, c("token1", 1000), c("token2", 1000), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
|
|
|
[]bidArgs{{buyer, c("token2", 1000)}},
|
|
|
|
bidArgs{buyer, c("token1", 100)}, // buyer has already bid all of their token2
|
|
|
|
nil,
|
2022-02-08 17:33:42 +00:00
|
|
|
someTime.Add(types.DefaultReverseBidDuration),
|
2022-02-08 16:42:00 +00:00
|
|
|
buyer,
|
|
|
|
c("token2", 1000),
|
|
|
|
true,
|
|
|
|
false,
|
|
|
|
},
|
2020-01-14 15:04:47 +00:00
|
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
2020-01-21 10:06:07 +00:00
|
|
|
// Setup test
|
|
|
|
tApp := app.NewTestApp()
|
2022-01-08 00:39:27 +00:00
|
|
|
|
|
|
|
// Set up module account
|
|
|
|
modName := "liquidator"
|
|
|
|
modBaseAcc := authtypes.NewBaseAccount(authtypes.NewModuleAddress(modName), nil, 0, 0)
|
|
|
|
modAcc := authtypes.NewModuleAccount(modBaseAcc, modName, []string{authtypes.Minter, authtypes.Burner}...)
|
|
|
|
|
|
|
|
// Set up normal accounts
|
|
|
|
addrs := []sdk.AccAddress{buyer, secondBuyer, collateralAddrs[0], collateralAddrs[1], collateralAddrs[2]}
|
|
|
|
|
|
|
|
// Initialize app
|
2022-02-08 16:42:00 +00:00
|
|
|
authGS := app.NewFundedGenStateWithSameCoinsWithModuleAccount(tApp.AppCodec(), initialBalance, addrs, modAcc)
|
2022-01-08 00:39:27 +00:00
|
|
|
params := types.NewParams(
|
|
|
|
types.DefaultMaxAuctionDuration,
|
2022-02-08 17:03:47 +00:00
|
|
|
types.DefaultForwardBidDuration,
|
|
|
|
types.DefaultReverseBidDuration,
|
2022-01-08 00:39:27 +00:00
|
|
|
types.DefaultIncrement,
|
|
|
|
types.DefaultIncrement,
|
|
|
|
types.DefaultIncrement,
|
2020-01-21 10:06:07 +00:00
|
|
|
)
|
2022-01-08 00:39:27 +00:00
|
|
|
|
|
|
|
auctionGs, err := types.NewGenesisState(types.DefaultNextAuctionID, params, []types.GenesisAuction{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
moduleGs := tApp.AppCodec().MustMarshalJSON(auctionGs)
|
|
|
|
gs := app.GenesisState{types.ModuleName: moduleGs}
|
|
|
|
tApp.InitializeFromGenesisStates(authGS, gs)
|
|
|
|
|
|
|
|
ctx := tApp.NewContext(true, tmproto.Header{Height: 1, Time: someTime})
|
2020-01-21 10:06:07 +00:00
|
|
|
keeper := tApp.GetAuctionKeeper()
|
2020-02-28 22:16:22 +00:00
|
|
|
bank := tApp.GetBankKeeper()
|
2020-01-21 10:06:07 +00:00
|
|
|
|
2022-01-08 00:39:27 +00:00
|
|
|
err = tApp.FundModuleAccount(ctx, modName, cs(c("token1", 1000), c("token2", 1000), c("debt", 1000)))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-01-14 15:04:47 +00:00
|
|
|
// Start Auction
|
|
|
|
var id uint64
|
|
|
|
switch tc.auctionArgs.auctionType {
|
|
|
|
case Surplus:
|
2020-04-23 16:35:58 +00:00
|
|
|
if tc.expectPanic {
|
|
|
|
require.Panics(t, func() {
|
|
|
|
id, err = keeper.StartSurplusAuction(ctx, tc.auctionArgs.seller, tc.auctionArgs.lot, tc.auctionArgs.bid.Denom)
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
id, err = keeper.StartSurplusAuction(ctx, tc.auctionArgs.seller, tc.auctionArgs.lot, tc.auctionArgs.bid.Denom)
|
|
|
|
}
|
2020-01-14 15:04:47 +00:00
|
|
|
case Debt:
|
2020-04-23 16:35:58 +00:00
|
|
|
id, err = keeper.StartDebtAuction(ctx, tc.auctionArgs.seller, tc.auctionArgs.bid, tc.auctionArgs.lot, tc.auctionArgs.debt)
|
2020-02-28 22:16:22 +00:00
|
|
|
case Collateral:
|
2020-04-23 16:35:58 +00:00
|
|
|
id, err = keeper.StartCollateralAuction(ctx, tc.auctionArgs.seller, tc.auctionArgs.lot, tc.auctionArgs.bid, tc.auctionArgs.addresses, tc.auctionArgs.weights, tc.auctionArgs.debt) // seller, lot, maxBid, otherPerson
|
2020-01-14 15:04:47 +00:00
|
|
|
default:
|
|
|
|
t.Fail()
|
|
|
|
}
|
2020-04-23 16:35:58 +00:00
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-02-28 22:16:22 +00:00
|
|
|
// Place setup bids
|
|
|
|
for _, b := range tc.setupBids {
|
|
|
|
require.NoError(t, keeper.PlaceBid(ctx, id, b.bidder, b.amount))
|
|
|
|
}
|
2020-01-14 15:04:47 +00:00
|
|
|
|
|
|
|
// Close the auction early to test late bidding (if applicable)
|
|
|
|
if strings.Contains(tc.name, "closed") {
|
|
|
|
ctx = ctx.WithBlockTime(types.DistantFuture.Add(1))
|
|
|
|
}
|
|
|
|
|
2020-02-28 22:16:22 +00:00
|
|
|
// Store some state for use in checks
|
|
|
|
var oldBidder sdk.AccAddress
|
2023-04-04 00:08:45 +00:00
|
|
|
var oldBidderOldCoins sdk.Coins
|
|
|
|
|
|
|
|
oldAuction, found := keeper.GetAuction(ctx, id)
|
2020-02-28 22:16:22 +00:00
|
|
|
if found {
|
|
|
|
oldBidder = oldAuction.GetBidder()
|
|
|
|
}
|
2022-01-08 00:39:27 +00:00
|
|
|
|
2023-04-04 00:08:45 +00:00
|
|
|
if !oldBidder.Empty() {
|
|
|
|
oldBidderOldCoins = bank.GetAllBalances(ctx, oldBidder)
|
|
|
|
}
|
|
|
|
|
2022-01-08 00:39:27 +00:00
|
|
|
newBidderOldCoins := bank.GetAllBalances(ctx, tc.bidArgs.bidder)
|
2020-02-28 22:16:22 +00:00
|
|
|
|
2020-01-14 15:04:47 +00:00
|
|
|
// Place bid on auction
|
|
|
|
err = keeper.PlaceBid(ctx, id, tc.bidArgs.bidder, tc.bidArgs.amount)
|
|
|
|
|
|
|
|
// Check success/failure
|
2020-04-23 16:35:58 +00:00
|
|
|
if tc.expectPass {
|
2022-02-08 16:42:00 +00:00
|
|
|
require.NoError(t, err)
|
2020-02-28 22:16:22 +00:00
|
|
|
// Check auction was found
|
|
|
|
newAuction, found := keeper.GetAuction(ctx, id)
|
2020-01-14 15:04:47 +00:00
|
|
|
require.True(t, found)
|
|
|
|
// Check auction values
|
2020-02-28 22:16:22 +00:00
|
|
|
require.Equal(t, modName, newAuction.GetInitiator())
|
|
|
|
require.Equal(t, tc.expectedBidder, newAuction.GetBidder())
|
|
|
|
require.Equal(t, tc.expectedBid, newAuction.GetBid())
|
|
|
|
require.Equal(t, tc.expectedEndTime, newAuction.GetEndTime())
|
|
|
|
|
|
|
|
// Check coins have moved between bidder and previous bidder
|
|
|
|
bidAmt := tc.bidArgs.amount
|
|
|
|
switch tc.auctionArgs.auctionType {
|
|
|
|
case Debt:
|
|
|
|
bidAmt = oldAuction.GetBid()
|
|
|
|
case Collateral:
|
2022-01-08 00:39:27 +00:00
|
|
|
collatAuction, ok := oldAuction.(*types.CollateralAuction)
|
2020-04-23 16:35:58 +00:00
|
|
|
require.True(t, ok, tc.name)
|
2020-02-28 22:16:22 +00:00
|
|
|
if collatAuction.IsReversePhase() {
|
|
|
|
bidAmt = oldAuction.GetBid()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if oldBidder.Equals(tc.bidArgs.bidder) { // same bidder
|
2023-04-04 00:08:45 +00:00
|
|
|
require.Equal(t, newBidderOldCoins.Sub(bidAmt.Sub(oldAuction.GetBid())), bank.GetAllBalances(ctx, tc.bidArgs.bidder))
|
2022-01-08 00:39:27 +00:00
|
|
|
} else { // different bidder
|
2023-04-04 00:08:45 +00:00
|
|
|
require.Equal(t, newBidderOldCoins.Sub(bidAmt), bank.GetAllBalances(ctx, tc.bidArgs.bidder)) // wrapping in cs() to avoid comparing nil and empty coins
|
2022-01-08 00:39:27 +00:00
|
|
|
|
|
|
|
// handle checking debt coins for case debt auction has had no bids placed yet TODO make this less confusing
|
|
|
|
if oldBidder.Equals(authtypes.NewModuleAddress(oldAuction.GetInitiator())) {
|
|
|
|
require.Equal(t, oldBidderOldCoins.Add(oldAuction.GetBid()).Add(c("debt", oldAuction.GetBid().Amount.Int64())), bank.GetAllBalances(ctx, oldBidder))
|
|
|
|
} else if oldBidder.Empty() {
|
|
|
|
require.Equal(t, oldBidderOldCoins.Add(oldAuction.GetBid()).Add(c("debt", oldAuction.GetBid().Amount.Int64())), oldBidderOldCoins)
|
2020-02-28 22:16:22 +00:00
|
|
|
} else {
|
2022-01-08 00:39:27 +00:00
|
|
|
require.Equal(t, cs(oldBidderOldCoins.Add(oldAuction.GetBid())...), bank.GetAllBalances(ctx, oldBidder))
|
2020-02-28 22:16:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-14 15:04:47 +00:00
|
|
|
} else {
|
2020-01-15 10:39:55 +00:00
|
|
|
// Check expected error code type
|
2022-02-08 16:42:00 +00:00
|
|
|
require.Error(t, err, "PlaceBid did not return an error")
|
|
|
|
require.ErrorIs(t, err, tc.expectedError)
|
2020-02-28 22:16:22 +00:00
|
|
|
|
|
|
|
// Check auction values
|
|
|
|
newAuction, found := keeper.GetAuction(ctx, id)
|
|
|
|
if found {
|
|
|
|
require.Equal(t, modName, newAuction.GetInitiator())
|
|
|
|
require.Equal(t, tc.expectedBidder, newAuction.GetBidder())
|
|
|
|
require.Equal(t, tc.expectedBid, newAuction.GetBid())
|
|
|
|
require.Equal(t, tc.expectedEndTime, newAuction.GetEndTime())
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check coins have not moved
|
2022-01-08 00:39:27 +00:00
|
|
|
require.Equal(t, newBidderOldCoins, bank.GetAllBalances(ctx, tc.bidArgs.bidder))
|
2023-04-04 00:08:45 +00:00
|
|
|
if !oldBidder.Empty() {
|
|
|
|
require.Equal(t, oldBidderOldCoins, bank.GetAllBalances(ctx, oldBidder))
|
|
|
|
}
|
2020-01-14 15:04:47 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|