From 8f36ca07f44cb00e76a138cb4dfaa9e63b0ea010 Mon Sep 17 00:00:00 2001 From: Shrenuj Bansal Date: Wed, 6 Mar 2024 00:25:24 -0500 Subject: [PATCH 1/5] Move SA module address transfers to use perpetual based SA accounts Signed-off-by: Shrenuj Bansal --- protocol/testutil/constants/positions.go | 7 + protocol/x/clob/abci_test.go | 2 +- protocol/x/clob/keeper/liquidations_test.go | 28 ++- protocol/x/clob/keeper/mev_test.go | 7 + protocol/x/clob/keeper/orders_test.go | 4 +- .../process_operations_liquidations_test.go | 94 +++---- .../process_operations_long_term_test.go | 74 +++--- ...ess_operations_stateful_validation_test.go | 12 +- .../x/clob/keeper/process_single_match.go | 1 + protocol/x/clob/types/expected_keepers.go | 6 +- protocol/x/subaccounts/keeper/subaccount.go | 13 + protocol/x/subaccounts/keeper/transfer.go | 47 ++-- .../x/subaccounts/keeper/transfer_test.go | 232 +++++++++++++----- .../x/subaccounts/types/expected_keepers.go | 1 + 14 files changed, 342 insertions(+), 186 deletions(-) diff --git a/protocol/testutil/constants/positions.go b/protocol/testutil/constants/positions.go index 1489bb4770..125af3e227 100644 --- a/protocol/testutil/constants/positions.go +++ b/protocol/testutil/constants/positions.go @@ -73,6 +73,13 @@ var ( PerpetualId: 1, Quantums: dtypes.NewIntFromBigInt(BigNegMaxUint64()), // 18,446,744,070 ETH, -$55,340,232,210,000 notional. } + // Long position for arbitrary isolated market + PerpetualPosition_OneISOLong = satypes.PerpetualPosition{ + PerpetualId: 3, + Quantums: dtypes.NewInt(100_000_000), + FundingIndex: dtypes.NewInt(0), + } + // Asset Positions Usdc_Asset_0 = satypes.AssetPosition{ AssetId: 0, diff --git a/protocol/x/clob/abci_test.go b/protocol/x/clob/abci_test.go index 7af637abc2..44d2d9af36 100644 --- a/protocol/x/clob/abci_test.go +++ b/protocol/x/clob/abci_test.go @@ -1338,7 +1338,7 @@ func TestPrepareCheckState(t *testing.T) { constants.Usdc.Denom, ).Return(sdk.NewCoin(constants.Usdc.Denom, sdkmath.NewIntFromBigInt(new(big.Int)))) mockBankKeeper.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, mock.Anything, mock.Anything, diff --git a/protocol/x/clob/keeper/liquidations_test.go b/protocol/x/clob/keeper/liquidations_test.go index a69a7c817d..ec916312e1 100644 --- a/protocol/x/clob/keeper/liquidations_test.go +++ b/protocol/x/clob/keeper/liquidations_test.go @@ -235,25 +235,25 @@ func TestPlacePerpetualLiquidation(t *testing.T) { memClob := memclob.NewMemClobPriceTimePriority(false) mockBankKeeper := &mocks.BankKeeper{} mockBankKeeper.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.Anything, ).Return(nil) mockBankKeeper.On( "SendCoins", mock.Anything, authtypes.NewModuleAddress(satypes.ModuleName), - authtypes.NewModuleAddress(perptypes.InsuranceFundName), + perptypes.InsuranceFundModuleAddress, mock.Anything, ).Return(nil) // Fee collector does not have any funds. mockBankKeeper.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - authtypes.FeeCollectorName, - satypes.ModuleName, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), + satypes.ModuleAddress, mock.Anything, ).Return(sdkerrors.ErrInsufficientFunds) // Give the insurance fund a 1M USDC balance. @@ -793,6 +793,13 @@ func TestPlacePerpetualLiquidation_PreexistingLiquidation(t *testing.T) { mock.Anything, mock.Anything, ).Return(nil) + bk.On( + "SendCoins", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + ).Return(nil) bk.On( "GetBalance", mock.Anything, @@ -833,6 +840,13 @@ func TestPlacePerpetualLiquidation_PreexistingLiquidation(t *testing.T) { mock.Anything, mock.Anything, ).Return(nil) + bk.On( + "SendCoins", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + ).Return(nil) bk.On( "GetBalance", mock.Anything, diff --git a/protocol/x/clob/keeper/mev_test.go b/protocol/x/clob/keeper/mev_test.go index 9c12550d27..6f0cd44d16 100644 --- a/protocol/x/clob/keeper/mev_test.go +++ b/protocol/x/clob/keeper/mev_test.go @@ -1244,6 +1244,13 @@ func TestGetMidPrices(t *testing.T) { mock.Anything, mock.Anything, ).Return(nil) + mockBankKeeper.On( + "SendCoins", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + ).Return(nil) ks := keepertest.NewClobKeepersTestContext(t, memclob, mockBankKeeper, indexer_manager.NewIndexerEventManagerNoop()) ctx := ks.Ctx.WithIsCheckTx(true) diff --git a/protocol/x/clob/keeper/orders_test.go b/protocol/x/clob/keeper/orders_test.go index 79998ab3fe..3bf0795743 100644 --- a/protocol/x/clob/keeper/orders_test.go +++ b/protocol/x/clob/keeper/orders_test.go @@ -647,7 +647,7 @@ func TestPlaceShortTermOrder(t *testing.T) { memClob := memclob.NewMemClobPriceTimePriority(false) mockBankKeeper := &mocks.BankKeeper{} mockBankKeeper.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, mock.Anything, mock.Anything, @@ -875,7 +875,7 @@ func TestAddPreexistingStatefulOrder(t *testing.T) { memClob := memclob.NewMemClobPriceTimePriority(false) mockBankKeeper := &mocks.BankKeeper{} mockBankKeeper.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, mock.Anything, mock.Anything, diff --git a/protocol/x/clob/keeper/process_operations_liquidations_test.go b/protocol/x/clob/keeper/process_operations_liquidations_test.go index ef86f581f1..b73dac4170 100644 --- a/protocol/x/clob/keeper/process_operations_liquidations_test.go +++ b/protocol/x/clob/keeper/process_operations_liquidations_test.go @@ -193,17 +193,17 @@ func TestProcessProposerMatches_Liquidation_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(10_000_000)), ).Return(nil) bk.On( "SendCoins", mock.Anything, - authtypes.NewModuleAddress(satypes.ModuleName), - authtypes.NewModuleAddress(perptypes.InsuranceFundName), + satypes.ModuleAddress, + perptypes.InsuranceFundModuleAddress, // Subaccount pays $250 to insurance fund for liquidating 1 BTC. mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(250_000_000)), ).Return(nil).Once() @@ -271,10 +271,10 @@ func TestProcessProposerMatches_Liquidation_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(10_100_000)), ).Return(nil) bk.On( @@ -286,8 +286,8 @@ func TestProcessProposerMatches_Liquidation_Success(t *testing.T) { bk.On( "SendCoins", mock.Anything, - authtypes.NewModuleAddress(perptypes.InsuranceFundName), - authtypes.NewModuleAddress(satypes.ModuleName), + perptypes.InsuranceFundModuleAddress, + satypes.ModuleAddress, // Insurance fund covers $1 loss for liquidating 1 BTC. mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(1_000_000)), ).Return(nil).Once() @@ -357,17 +357,17 @@ func TestProcessProposerMatches_Liquidation_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(2_500_000)), ).Return(nil) bk.On( "SendCoins", mock.Anything, - authtypes.NewModuleAddress(satypes.ModuleName), - authtypes.NewModuleAddress(perptypes.InsuranceFundName), + satypes.ModuleAddress, + perptypes.InsuranceFundModuleAddress, // Subaccount pays $62.5 to insurance fund for liquidating 0.25 BTC. mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(62_500_000)), ).Return(nil).Twice() @@ -455,10 +455,10 @@ func TestProcessProposerMatches_Liquidation_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(2_525_000)), ).Return(nil) bk.On( @@ -470,8 +470,8 @@ func TestProcessProposerMatches_Liquidation_Success(t *testing.T) { bk.On( "SendCoins", mock.Anything, - authtypes.NewModuleAddress(perptypes.InsuranceFundName), - authtypes.NewModuleAddress(satypes.ModuleName), + perptypes.InsuranceFundModuleAddress, + satypes.ModuleAddress, // Insurance fund covers $0.25 loss for liquidating 0.25 BTC. mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(250_000)), ).Return(nil).Twice() @@ -560,10 +560,10 @@ func TestProcessProposerMatches_Liquidation_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.Anything, ).Return(nil) bk.On( @@ -575,16 +575,16 @@ func TestProcessProposerMatches_Liquidation_Success(t *testing.T) { bk.On( "SendCoins", mock.Anything, - authtypes.NewModuleAddress(satypes.ModuleName), - authtypes.NewModuleAddress(perptypes.InsuranceFundName), + satypes.ModuleAddress, + perptypes.InsuranceFundModuleAddress, // Pays insurance fund $0.75 for liquidating 0.75 BTC. mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(750_000)), ).Return(nil).Once() bk.On( "SendCoins", mock.Anything, - authtypes.NewModuleAddress(perptypes.InsuranceFundName), - authtypes.NewModuleAddress(satypes.ModuleName), + perptypes.InsuranceFundModuleAddress, + satypes.ModuleAddress, // Insurance fund covers $0.25 loss for liquidating 0.25 BTC. mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(250_000)), ).Return(nil).Once() @@ -664,10 +664,10 @@ func TestProcessProposerMatches_Liquidation_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.Anything, ).Return(nil) bk.On( @@ -679,8 +679,8 @@ func TestProcessProposerMatches_Liquidation_Success(t *testing.T) { bk.On( "SendCoins", mock.Anything, - authtypes.NewModuleAddress(satypes.ModuleName), - authtypes.NewModuleAddress(perptypes.InsuranceFundName), + satypes.ModuleAddress, + perptypes.InsuranceFundModuleAddress, // Pays insurance fund $0.378735 (capped by MaxLiquidationFeePpm) // for liquidating 0.75 BTC. mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(378_735)), @@ -688,8 +688,8 @@ func TestProcessProposerMatches_Liquidation_Success(t *testing.T) { bk.On( "SendCoins", mock.Anything, - authtypes.NewModuleAddress(satypes.ModuleName), - authtypes.NewModuleAddress(perptypes.InsuranceFundName), + satypes.ModuleAddress, + perptypes.InsuranceFundModuleAddress, // Pays insurance fund $0.121265. mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(121_265)), ).Return(nil).Once() @@ -777,17 +777,17 @@ func TestProcessProposerMatches_Liquidation_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(5_000_000)), ).Return(nil) bk.On( "SendCoins", mock.Anything, - authtypes.NewModuleAddress(satypes.ModuleName), - authtypes.NewModuleAddress(perptypes.InsuranceFundName), + satypes.ModuleAddress, + perptypes.InsuranceFundModuleAddress, // Subaccount pays $125 to insurance fund for liquidating 0.5 BTC. mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(125_000_000)), ).Return(nil).Once() @@ -890,17 +890,17 @@ func TestProcessProposerMatches_Liquidation_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(1)), ).Return(nil) bk.On( "SendCoins", mock.Anything, - authtypes.NewModuleAddress(satypes.ModuleName), - authtypes.NewModuleAddress(perptypes.InsuranceFundName), + satypes.ModuleAddress, + perptypes.InsuranceFundModuleAddress, mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(25)), ).Return(nil) }, @@ -1263,17 +1263,17 @@ func TestProcessProposerMatches_Liquidation_Failure(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, mock.Anything, - authtypes.FeeCollectorName, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.Anything, ).Return(fmt.Errorf("transfer failed")) bk.On( "SendCoins", mock.Anything, mock.Anything, - authtypes.NewModuleAddress(perptypes.InsuranceFundName), + perptypes.InsuranceFundModuleAddress, mock.Anything, ).Return(nil) }, diff --git a/protocol/x/clob/keeper/process_operations_long_term_test.go b/protocol/x/clob/keeper/process_operations_long_term_test.go index 13f1f8de11..f2ecafc3a5 100644 --- a/protocol/x/clob/keeper/process_operations_long_term_test.go +++ b/protocol/x/clob/keeper/process_operations_long_term_test.go @@ -37,10 +37,10 @@ func TestProcessProposerMatches_LongTerm_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy( testutil_bank.MatchUsdcOfAmount( 25_000_000+10_000_000, @@ -106,10 +106,10 @@ func TestProcessProposerMatches_LongTerm_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy( testutil_bank.MatchUsdcOfAmount( 25_000_000+10_000_000, @@ -186,10 +186,10 @@ func TestProcessProposerMatches_LongTerm_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy( testutil_bank.MatchUsdcOfAmount( 25_000_000+10_000_000, @@ -259,10 +259,10 @@ func TestProcessProposerMatches_LongTerm_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy( testutil_bank.MatchUsdcOfAmount( 25_000_000+10_000_000, @@ -333,10 +333,10 @@ func TestProcessProposerMatches_LongTerm_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy( testutil_bank.MatchUsdcOfAmount( 25_000_000+10_000_000, @@ -406,10 +406,10 @@ func TestProcessProposerMatches_LongTerm_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy( testutil_bank.MatchUsdcOfAmount( 12_500_000+5_000_000, @@ -484,10 +484,10 @@ func TestProcessProposerMatches_LongTerm_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy( testutil_bank.MatchUsdcOfAmount( 12_500_000+5_000_000, @@ -571,17 +571,17 @@ func TestProcessProposerMatches_LongTerm_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(10_000_000)), ).Return(nil) bk.On( "SendCoins", mock.Anything, - authtypes.NewModuleAddress(satypes.ModuleName), - authtypes.NewModuleAddress(perptypes.InsuranceFundName), + satypes.ModuleAddress, + perptypes.InsuranceFundModuleAddress, // Subaccount pays $250 to insurance fund for liquidating 1 BTC. mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(250_000_000)), ).Return(nil).Once() @@ -659,17 +659,17 @@ func TestProcessProposerMatches_LongTerm_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(10_000_000)), ).Return(nil) bk.On( "SendCoins", mock.Anything, - authtypes.NewModuleAddress(satypes.ModuleName), - authtypes.NewModuleAddress(perptypes.InsuranceFundName), + satypes.ModuleAddress, + perptypes.InsuranceFundModuleAddress, // Subaccount pays $250 to insurance fund for liquidating 1 BTC. mock.MatchedBy(testutil_bank.MatchUsdcOfAmount(250_000_000)), ).Return(nil).Once() @@ -747,10 +747,10 @@ func TestProcessProposerMatches_LongTerm_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy( testutil_bank.MatchUsdcOfAmount( 12_500_000+5_000_000, @@ -838,10 +838,10 @@ func TestProcessProposerMatches_LongTerm_Success(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy( testutil_bank.MatchUsdcOfAmount( 12_500_000+5_000_000, diff --git a/protocol/x/clob/keeper/process_operations_stateful_validation_test.go b/protocol/x/clob/keeper/process_operations_stateful_validation_test.go index 3dfff5254c..f944523dc0 100644 --- a/protocol/x/clob/keeper/process_operations_stateful_validation_test.go +++ b/protocol/x/clob/keeper/process_operations_stateful_validation_test.go @@ -339,10 +339,10 @@ func TestProcessProposerMatches_LongTerm_StatefulValidation_Failure(t *testing.T }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy( testutil_bank.MatchUsdcOfAmount( 12_500_000+5_000_000, @@ -635,10 +635,10 @@ func TestProcessProposerMatches_Conditional_Validation_Failure(t *testing.T) { }, setupMockBankKeeper: func(bk *mocks.BankKeeper) { bk.On( - "SendCoinsFromModuleToModule", + "SendCoins", mock.Anything, - satypes.ModuleName, - authtypes.FeeCollectorName, + satypes.ModuleAddress, + authtypes.NewModuleAddress(authtypes.FeeCollectorName), mock.MatchedBy( testutil_bank.MatchUsdcOfAmount( 12_500_000+5_000_000, diff --git a/protocol/x/clob/keeper/process_single_match.go b/protocol/x/clob/keeper/process_single_match.go index 189465d3a5..9cd19a36b8 100644 --- a/protocol/x/clob/keeper/process_single_match.go +++ b/protocol/x/clob/keeper/process_single_match.go @@ -442,6 +442,7 @@ func (k Keeper) persistMatchedOrders( ctx, assettypes.AssetUsdc.Id, bigTotalFeeQuoteQuantums, + 0, ); err != nil { return takerUpdateResult, makerUpdateResult, errorsmod.Wrapf( types.ErrSubaccountFeeTransferFailed, diff --git a/protocol/x/clob/types/expected_keepers.go b/protocol/x/clob/types/expected_keepers.go index 81b4aef392..3c4c8b86a2 100644 --- a/protocol/x/clob/types/expected_keepers.go +++ b/protocol/x/clob/types/expected_keepers.go @@ -63,11 +63,7 @@ type SubaccountsKeeper interface { ctx sdk.Context, blockHeight uint32, ) - TransferFeesToFeeCollectorModule( - ctx sdk.Context, - assetId uint32, - amount *big.Int, - ) error + TransferFeesToFeeCollectorModule(ctx sdk.Context, assetId uint32, amount *big.Int, perpetualId uint32) error TransferInsuranceFundPayments( ctx sdk.Context, amount *big.Int, diff --git a/protocol/x/subaccounts/keeper/subaccount.go b/protocol/x/subaccounts/keeper/subaccount.go index 4ec9bb9158..57d37006b2 100644 --- a/protocol/x/subaccounts/keeper/subaccount.go +++ b/protocol/x/subaccounts/keeper/subaccount.go @@ -69,6 +69,19 @@ func (k Keeper) GetCollateralPoolForSubaccount(ctx sdk.Context, subaccountId typ return authtypes.NewModuleAddress(poolName), nil } +func (k Keeper) GetCollateralPoolFromPerpetualId(ctx sdk.Context, perpetualId uint32) (sdk.AccAddress, error) { + perpetual, err := k.perpetualsKeeper.GetPerpetual(ctx, perpetualId) + if err != nil { + return nil, err + } + + if perpetual.Params.MarketType == perptypes.PerpetualMarketType_PERPETUAL_MARKET_TYPE_ISOLATED { + return authtypes.NewModuleAddress(types.ModuleName + ":" + lib.UintToString(perpetual.GetId())), nil + } + + return authtypes.NewModuleAddress(types.ModuleName), nil +} + func (k Keeper) GetCollateralPoolNameForSubaccount(ctx sdk.Context, subaccountId types.SubaccountId) (string, error) { subaccount := k.GetSubaccount(ctx, subaccountId) if len(subaccount.PerpetualPositions) == 0 { diff --git a/protocol/x/subaccounts/keeper/transfer.go b/protocol/x/subaccounts/keeper/transfer.go index 6e6ef31e3b..8f7d474c28 100644 --- a/protocol/x/subaccounts/keeper/transfer.go +++ b/protocol/x/subaccounts/keeper/transfer.go @@ -123,11 +123,16 @@ func (k Keeper) DepositFundsFromAccountToSubaccount( return err } + collateralPoolAddr, err := k.GetCollateralPoolForSubaccount(ctx, toSubaccountId) + if err != nil { + return err + } + // Send coins from `fromModule` to the `subaccounts` module account. - if err := k.bankKeeper.SendCoinsFromAccountToModule( + if err := k.bankKeeper.SendCoins( ctx, fromAccount, - types.ModuleName, + collateralPoolAddr, []sdk.Coin{coinToTransfer}, ); err != nil { return err @@ -143,7 +148,7 @@ func (k Keeper) DepositFundsFromAccountToSubaccount( // WithdrawFundsFromSubaccountToAccount returns an error if the call to `k.CanUpdateSubaccounts()` // fails. Otherwise, deducts the asset quantums from the subaccount, translates the -// `assetId` and `quantums` into a `sdk.Coin`, and calls `bankKeeper.SendCoinsFromModuleToAccount()`. +// `assetId` and `quantums` into a `sdk.Coin`, and calls `bankKeeper.SendCoins()`. func (k Keeper) WithdrawFundsFromSubaccountToAccount( ctx sdk.Context, fromSubaccountId types.SubaccountId, @@ -181,10 +186,15 @@ func (k Keeper) WithdrawFundsFromSubaccountToAccount( return err } + collateralPoolAddr, err := k.GetCollateralPoolForSubaccount(ctx, fromSubaccountId) + if err != nil { + return err + } + // Send coins from `fromModule` to the `subaccounts` module account. - if err := k.bankKeeper.SendCoinsFromModuleToAccount( + if err := k.bankKeeper.SendCoins( ctx, - types.ModuleName, + collateralPoolAddr, toAccount, []sdk.Coin{coinToTransfer}, ); err != nil { @@ -201,11 +211,12 @@ func (k Keeper) WithdrawFundsFromSubaccountToAccount( // TransferFeesToFeeCollectorModule translates the assetId and quantums into a sdk.Coin, // and moves the funds from subaccounts module to the `fee_collector` module account by calling -// bankKeeper.SendCoinsFromModuleToModule(). Does not change any individual subaccount state. +// bankKeeper.SendCoins(). Does not change any individual subaccount state. func (k Keeper) TransferFeesToFeeCollectorModule( ctx sdk.Context, assetId uint32, quantums *big.Int, + perpetualId uint32, ) error { // TODO(DEC-715): Support non-USDC assets. if assetId != assettypes.AssetUsdc.Id { @@ -225,16 +236,21 @@ func (k Keeper) TransferFeesToFeeCollectorModule( return err } + collateralPoolAddr, err := k.GetCollateralPoolFromPerpetualId(ctx, perpetualId) + if err != nil { + return err + } + // Send coins from `subaccounts` to the `auth` module fee collector account. - fromModule := types.ModuleName - toModule := authtypes.FeeCollectorName + fromModule := collateralPoolAddr + toModule := authtypes.NewModuleAddress(authtypes.FeeCollectorName) if quantums.Sign() < 0 { // In the case of a liquidation, net fees can be negative if the maker gets a rebate. fromModule, toModule = toModule, fromModule } - if err := k.bankKeeper.SendCoinsFromModuleToModule( + if err := k.bankKeeper.SendCoins( ctx, fromModule, toModule, @@ -247,7 +263,7 @@ func (k Keeper) TransferFeesToFeeCollectorModule( } // TransferInsuranceFundPayments transfers funds in and out of the insurance fund to the subaccounts -// module by calling `bankKeeper.SendCoinsFromModuleToModule`. +// module by calling `bankKeeper.SendCoins`. // This function transfers funds // - from the insurance fund to the subaccounts module when `insuranceFundDelta` is negative. // - from the subaccounts module to the insurance fund when `insuranceFundDelta` is positive. @@ -276,8 +292,11 @@ func (k Keeper) TransferInsuranceFundPayments( // Determine the sender and receiver. // Send coins from `subaccounts` to the `insurance_fund` module account by default. - fromModule := types.ModuleName - toModule, err := k.perpetualsKeeper.GetInsuranceFundName(ctx, perpetualId) + fromModule, err := k.GetCollateralPoolFromPerpetualId(ctx, perpetualId) + if err != nil { + panic(err) + } + toModule, err := k.perpetualsKeeper.GetInsuranceFundModuleAddress(ctx, perpetualId) if err != nil { panic(err) } @@ -292,8 +311,8 @@ func (k Keeper) TransferInsuranceFundPayments( // module account features return k.bankKeeper.SendCoins( ctx, - authtypes.NewModuleAddress(fromModule), - authtypes.NewModuleAddress(toModule), + fromModule, + toModule, []sdk.Coin{coinToTransfer}, ) } diff --git a/protocol/x/subaccounts/keeper/transfer_test.go b/protocol/x/subaccounts/keeper/transfer_test.go index 58ed6ff53c..4913108407 100644 --- a/protocol/x/subaccounts/keeper/transfer_test.go +++ b/protocol/x/subaccounts/keeper/transfer_test.go @@ -30,7 +30,8 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun asset asstypes.Asset // Subaccount state. - assetPositions []*types.AssetPosition + assetPositions []*types.AssetPosition + perpetualPositions []*types.PerpetualPosition // Module account state. subaccountModuleAccBalance *big.Int @@ -46,12 +47,29 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun expectedAccAddressBalance *big.Int }{ "WithdrawFundsFromSubaccountToAccount: send from subaccount to an account address": { - testTransferFundToAccount: true, - asset: *constants.Usdc, - accAddressBalance: big.NewInt(2500), - subaccountModuleAccBalance: big.NewInt(600), - quantums: big.NewInt(500), - assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(500)), + testTransferFundToAccount: true, + asset: *constants.Usdc, + accAddressBalance: big.NewInt(2500), + subaccountModuleAccBalance: big.NewInt(600), + quantums: big.NewInt(500), + assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(500)), + perpetualPositions: []*types.PerpetualPosition{ + &constants.PerpetualPosition_OneBTCLong, + }, + expectedQuoteBalance: big.NewInt(0), // 500 - 500 + expectedSubaccountsModuleAccBalance: big.NewInt(100), // 600 - 100 + expectedAccAddressBalance: big.NewInt(3000), // 500 + 2500 + }, + "WithdrawFundsFromSubaccountToAccount: send from isolated subaccount to an account address": { + testTransferFundToAccount: true, + asset: *constants.Usdc, + accAddressBalance: big.NewInt(2500), + subaccountModuleAccBalance: big.NewInt(600), + quantums: big.NewInt(500), + assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(500)), + perpetualPositions: []*types.PerpetualPosition{ + &constants.PerpetualPosition_OneISOLong, + }, expectedQuoteBalance: big.NewInt(0), // 500 - 500 expectedSubaccountsModuleAccBalance: big.NewInt(100), // 600 - 100 expectedAccAddressBalance: big.NewInt(3000), // 500 + 2500 @@ -73,17 +91,37 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun assetPositions: keepertest.CreateUsdcAssetPosition( big.NewInt(30_000_001), ), // $3.0001 + perpetualPositions: []*types.PerpetualPosition{ + &constants.PerpetualPosition_OneBTCLong, + }, expectedQuoteBalance: big.NewInt(10_000_001), // $1.0001, untransfered $0.0001 remains. expectedSubaccountsModuleAccBalance: big.NewInt(8_000_000), // $8 expectedAccAddressBalance: big.NewInt(4_500_000), // $2.5 + $2 }, "DepositFundsFromAccountToSubaccount: send from account to subaccount": { - testTransferFundToAccount: false, - asset: *constants.Usdc, - subaccountModuleAccBalance: big.NewInt(200), - accAddressBalance: big.NewInt(2000), - quantums: big.NewInt(500), - assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(150)), + testTransferFundToAccount: false, + asset: *constants.Usdc, + subaccountModuleAccBalance: big.NewInt(200), + accAddressBalance: big.NewInt(2000), + quantums: big.NewInt(500), + assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(150)), + perpetualPositions: []*types.PerpetualPosition{ + &constants.PerpetualPosition_OneBTCLong, + }, + expectedQuoteBalance: big.NewInt(650), // 150 + 500 + expectedSubaccountsModuleAccBalance: big.NewInt(700), // 200 + 500 + expectedAccAddressBalance: big.NewInt(1500), // 2000 - 500 + }, + "DepositFundsFromAccountToSubaccount: send from account to isolated subaccount": { + testTransferFundToAccount: false, + asset: *constants.Usdc, + subaccountModuleAccBalance: big.NewInt(200), + accAddressBalance: big.NewInt(2000), + quantums: big.NewInt(500), + assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(150)), + perpetualPositions: []*types.PerpetualPosition{ + &constants.PerpetualPosition_OneISOLong, + }, expectedQuoteBalance: big.NewInt(650), // 150 + 500 expectedSubaccountsModuleAccBalance: big.NewInt(700), // 200 + 500 expectedAccAddressBalance: big.NewInt(1500), // 2000 - 500 @@ -99,13 +137,16 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun MarketId: uint32(0), AtomicResolution: int32(-5), // $1 = 100_000 quantums }, - subaccountModuleAccBalance: big.NewInt(2_000_000), // $2 - accAddressBalance: big.NewInt(9_000_000), // $9 - quantums: big.NewInt(502_100), // $5.021 - assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(105_000)), // $1.05 - expectedQuoteBalance: big.NewInt(607_100), // $1.05 + $5.021 - expectedSubaccountsModuleAccBalance: big.NewInt(7_021_000), // $2 + $5.021 - expectedAccAddressBalance: big.NewInt(3_979_000), // $9 - $5.021 + subaccountModuleAccBalance: big.NewInt(2_000_000), // $2 + accAddressBalance: big.NewInt(9_000_000), // $9 + quantums: big.NewInt(502_100), // $5.021 + assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(105_000)), // $1.05 + perpetualPositions: []*types.PerpetualPosition{ + &constants.PerpetualPosition_OneBTCLong, + }, + expectedQuoteBalance: big.NewInt(607_100), // $1.05 + $5.021 + expectedSubaccountsModuleAccBalance: big.NewInt(7_021_000), // $2 + $5.021 + expectedAccAddressBalance: big.NewInt(3_979_000), // $9 - $5.021 }, "DepositFundsFromAccountToSubaccount: new balance reaches max int64": { testTransferFundToAccount: false, @@ -116,6 +157,9 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun assetPositions: keepertest.CreateUsdcAssetPosition( new(big.Int).SetUint64(math.MaxUint64 - 100), ), + perpetualPositions: []*types.PerpetualPosition{ + &constants.PerpetualPosition_OneBTCLong, + }, expectedQuoteBalance: new(big.Int).Add( new(big.Int).SetUint64(math.MaxUint64), big.NewInt(400), @@ -135,9 +179,14 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun for name, tc := range tests { t.Run(name, func(t *testing.T) { - ctx, keeper, pricesKeeper, _, accountKeeper, bankKeeper, assetsKeeper, _, _ := keepertest.SubaccountsKeepers(t, true) + ctx, keeper, pricesKeeper, perpetualsKeeper, accountKeeper, bankKeeper, assetsKeeper, _, _ := + keepertest.SubaccountsKeepers(t, true) keepertest.CreateTestMarkets(t, ctx, pricesKeeper) + keepertest.CreateTestLiquidityTiers(t, ctx, perpetualsKeeper) + + keepertest.CreateTestPerpetuals(t, ctx, perpetualsKeeper) + // Set up Subaccounts module account. auth_testutil.CreateTestModuleAccount(ctx, accountKeeper, types.ModuleName, []string{}) @@ -162,18 +211,6 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun require.NoError(t, err) } - if tc.subaccountModuleAccBalance.Sign() > 0 { - err := bank_testutil.FundModuleAccount( - ctx, - types.ModuleName, - sdk.Coins{ - sdk.NewCoin(tc.asset.Denom, sdkmath.NewIntFromBigInt(tc.subaccountModuleAccBalance)), - }, - *bankKeeper, - ) - require.NoError(t, err) - } - _, err = assetsKeeper.CreateAsset( ctx, tc.asset.Id, @@ -188,9 +225,25 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun subaccount := createNSubaccount(keeper, ctx, 1, big.NewInt(1_000))[0] subaccount.AssetPositions = tc.assetPositions + subaccount.PerpetualPositions = tc.perpetualPositions keeper.SetSubaccount(ctx, subaccount) + collateralPoolAddr, err := keeper.GetCollateralPoolForSubaccount(ctx, *subaccount.Id) + require.NoError(t, err) + + if tc.subaccountModuleAccBalance.Sign() > 0 { + err := bank_testutil.FundAccount( + ctx, + collateralPoolAddr, + sdk.Coins{ + sdk.NewCoin(tc.asset.Denom, sdkmath.NewIntFromBigInt(tc.subaccountModuleAccBalance)), + }, + *bankKeeper, + ) + require.NoError(t, err) + } + // Test either WithdrawFundsFromSubaccountToAccount or DepositFundsFromAccountToSubaccount. if tc.testTransferFundToAccount { err = keeper.WithdrawFundsFromSubaccountToAccount( @@ -226,7 +279,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun ) // Check the subaccount module balance. - subaccountsModuleAccBalance := bankKeeper.GetBalance(ctx, types.ModuleAddress, tc.asset.Denom) + subaccountsModuleAccBalance := bankKeeper.GetBalance(ctx, collateralPoolAddr, tc.asset.Denom) require.Equal(t, sdk.NewCoin(tc.asset.Denom, sdkmath.NewIntFromBigInt(tc.expectedSubaccountsModuleAccBalance)), subaccountsModuleAccBalance, @@ -252,7 +305,8 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun asset asstypes.Asset // Subaccount state. - assetPositions []*types.AssetPosition + assetPositions []*types.AssetPosition + perpetualPositions []*types.PerpetualPosition // Module account state. subaccountModuleAccBalance *big.Int @@ -282,6 +336,18 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(500)), expectedErr: sdkerrors.ErrInsufficientFunds, }, + "WithdrawFundsFromSubaccountToAccount: isolated market subaccounts module account does not have enough balance": { + testTransferFundToAccount: true, + asset: *constants.Usdc, + subaccountModuleAccBalance: big.NewInt(400), + accAddressBalance: big.NewInt(5000), + quantums: big.NewInt(500), + assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(500)), + perpetualPositions: []*types.PerpetualPosition{ + &constants.PerpetualPosition_OneISOLong, + }, + expectedErr: sdkerrors.ErrInsufficientFunds, + }, "WithdrawFundsFromSubaccountToAccount: transfer quantums is zero": { testTransferFundToAccount: true, asset: *constants.Usdc, @@ -362,8 +428,12 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun for name, tc := range tests { t.Run(name, func(t *testing.T) { - ctx, keeper, pricesKeeper, _, accountKeeper, bankKeeper, assetsKeeper, _, _ := keepertest.SubaccountsKeepers(t, true) + ctx, keeper, pricesKeeper, perpetualsKeeper, accountKeeper, bankKeeper, assetsKeeper, _, _ := + keepertest.SubaccountsKeepers(t, true) keepertest.CreateTestMarkets(t, ctx, pricesKeeper) + keepertest.CreateTestLiquidityTiers(t, ctx, perpetualsKeeper) + + keepertest.CreateTestPerpetuals(t, ctx, perpetualsKeeper) // Set up Subaccounts module account. auth_testutil.CreateTestModuleAccount(ctx, accountKeeper, types.ModuleName, []string{}) @@ -389,18 +459,6 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun require.NoError(t, err) } - if tc.subaccountModuleAccBalance.Sign() > 0 { - err := bank_testutil.FundModuleAccount( - ctx, - types.ModuleName, - sdk.Coins{ - sdk.NewCoin(tc.asset.Denom, sdkmath.NewIntFromBigInt(tc.subaccountModuleAccBalance)), - }, - *bankKeeper, - ) - require.NoError(t, err) - } - if !tc.skipSetUpUsdc { // Always create USDC as the first asset unless specificed to skip. err := keepertest.CreateUsdcAsset(ctx, assetsKeeper) @@ -423,9 +481,25 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun subaccount := createNSubaccount(keeper, ctx, 1, big.NewInt(1_000))[0] subaccount.AssetPositions = tc.assetPositions + subaccount.PerpetualPositions = tc.perpetualPositions keeper.SetSubaccount(ctx, subaccount) + collateralPoolAddr, err := keeper.GetCollateralPoolForSubaccount(ctx, *subaccount.Id) + require.NoError(t, err) + + if tc.subaccountModuleAccBalance.Sign() > 0 { + err := bank_testutil.FundAccount( + ctx, + collateralPoolAddr, + sdk.Coins{ + sdk.NewCoin(tc.asset.Denom, sdkmath.NewIntFromBigInt(tc.subaccountModuleAccBalance)), + }, + *bankKeeper, + ) + require.NoError(t, err) + } + // Test either WithdrawFundsFromSubaccountToAccount or DepositFundsFromAccountToSubaccount. if tc.testTransferFundToAccount { err = keeper.WithdrawFundsFromSubaccountToAccount( @@ -459,7 +533,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun ) // Check the subaccount module balance stays the same. - subaccountsModuleAccBalance := bankKeeper.GetBalance(ctx, types.ModuleAddress, tc.asset.Denom) + subaccountsModuleAccBalance := bankKeeper.GetBalance(ctx, collateralPoolAddr, tc.asset.Denom) require.Equal(t, sdk.NewCoin(tc.asset.Denom, sdkmath.NewIntFromBigInt(tc.subaccountModuleAccBalance)), subaccountsModuleAccBalance, @@ -487,8 +561,9 @@ func TestTransferFeesToFeeCollectorModule(t *testing.T) { feeModuleAccBalance *big.Int // Transfer details. - asset asstypes.Asset - quantums *big.Int + asset asstypes.Asset + quantums *big.Int + perpetualId uint32 // Expectations. expectedErr error @@ -503,6 +578,15 @@ func TestTransferFeesToFeeCollectorModule(t *testing.T) { expectedSubaccountsModuleAccBalance: big.NewInt(100), // 600 - 500 expectedFeeModuleAccBalance: big.NewInt(3000), // 500 + 2500 }, + "success - send to fee-collector module account from isolated market account": { + asset: *constants.Usdc, + feeModuleAccBalance: big.NewInt(2500), + subaccountModuleAccBalance: big.NewInt(600), + quantums: big.NewInt(500), + perpetualId: 3, // Isolated market perpetual ID + expectedSubaccountsModuleAccBalance: big.NewInt(100), // 600 - 500 + expectedFeeModuleAccBalance: big.NewInt(3000), // 500 + 2500 + }, "success - quantums is zero": { asset: *constants.Usdc, feeModuleAccBalance: big.NewInt(2500), @@ -520,6 +604,16 @@ func TestTransferFeesToFeeCollectorModule(t *testing.T) { expectedFeeModuleAccBalance: big.NewInt(2500), expectedErr: sdkerrors.ErrInsufficientFunds, }, + "failure - isolated markets subaccounts module does not have sufficient funds": { + asset: *constants.Usdc, + feeModuleAccBalance: big.NewInt(2500), + subaccountModuleAccBalance: big.NewInt(300), + quantums: big.NewInt(500), + perpetualId: 3, // Isolated market perpetual ID + expectedSubaccountsModuleAccBalance: big.NewInt(300), + expectedFeeModuleAccBalance: big.NewInt(2500), + expectedErr: sdkerrors.ErrInsufficientFunds, + }, "failure - asset ID doesn't exist": { feeModuleAccBalance: big.NewInt(1500), skipSetUpUsdc: true, @@ -553,9 +647,11 @@ func TestTransferFeesToFeeCollectorModule(t *testing.T) { for name, tc := range tests { t.Run(name, func(t *testing.T) { - ctx, keeper, pricesKeeper, _, accountKeeper, bankKeeper, assetsKeeper, _, _ := keepertest.SubaccountsKeepers(t, true) + ctx, keeper, pricesKeeper, perpetualsKeeper, accountKeeper, bankKeeper, assetsKeeper, _, _ := + keepertest.SubaccountsKeepers(t, true) keepertest.CreateTestMarkets(t, ctx, pricesKeeper) - + keepertest.CreateTestLiquidityTiers(t, ctx, perpetualsKeeper) + keepertest.CreateTestPerpetuals(t, ctx, perpetualsKeeper) // Set up Subaccounts module account. auth_testutil.CreateTestModuleAccount(ctx, accountKeeper, types.ModuleName, []string{}) // Set up receiver module account. @@ -588,10 +684,13 @@ func TestTransferFeesToFeeCollectorModule(t *testing.T) { require.NoError(t, err) } + collateralPoolAddr, err := keeper.GetCollateralPoolFromPerpetualId(ctx, tc.perpetualId) + require.NoError(t, err) + if tc.subaccountModuleAccBalance.Sign() > 0 { - err := bank_testutil.FundModuleAccount( + err := bank_testutil.FundAccount( ctx, - types.ModuleName, + collateralPoolAddr, sdk.Coins{ sdk.NewCoin(tc.asset.Denom, sdkmath.NewIntFromBigInt(tc.subaccountModuleAccBalance)), }, @@ -620,11 +719,7 @@ func TestTransferFeesToFeeCollectorModule(t *testing.T) { require.NoError(t, err) } - err := keeper.TransferFeesToFeeCollectorModule( - ctx, - tc.asset.Id, - tc.quantums, - ) + err = keeper.TransferFeesToFeeCollectorModule(ctx, tc.asset.Id, tc.quantums, tc.perpetualId) if tc.expectedErr != nil { require.ErrorIs(t, @@ -636,7 +731,7 @@ func TestTransferFeesToFeeCollectorModule(t *testing.T) { } // Check the subaccount module balance. - subaccountsModuleAccBalance := bankKeeper.GetBalance(ctx, types.ModuleAddress, tc.asset.Denom) + subaccountsModuleAccBalance := bankKeeper.GetBalance(ctx, collateralPoolAddr, tc.asset.Denom) require.Equal(t, sdk.NewCoin(tc.asset.Denom, sdkmath.NewIntFromBigInt(tc.expectedSubaccountsModuleAccBalance)), subaccountsModuleAccBalance, @@ -790,14 +885,17 @@ func TestTransferInsuranceFundPayments(t *testing.T) { ) require.NoError(t, err) - insuranceFundName, err := perpsKeeper.GetInsuranceFundName(ctx, tc.perpetual.GetId()) + insuranceFundAddr, err := perpsKeeper.GetInsuranceFundModuleAddress(ctx, tc.perpetual.GetId()) + require.NoError(t, err) + + collateralPoolAddr, err := keeper.GetCollateralPoolFromPerpetualId(ctx, tc.perpetual.GetId()) require.NoError(t, err) // Mint asset in the receipt/sender module account for transfer. if tc.insuranceFundBalance > 0 { err := bank_testutil.FundAccount( ctx, - authtypes.NewModuleAddress(insuranceFundName), + insuranceFundAddr, sdk.Coins{ sdk.NewInt64Coin(constants.Usdc.Denom, tc.insuranceFundBalance), }, @@ -807,9 +905,9 @@ func TestTransferInsuranceFundPayments(t *testing.T) { } if tc.subaccountModuleAccBalance > 0 { - err := bank_testutil.FundModuleAccount( + err := bank_testutil.FundAccount( ctx, - types.ModuleName, + collateralPoolAddr, sdk.Coins{ sdk.NewInt64Coin(constants.Usdc.Denom, tc.subaccountModuleAccBalance), }, @@ -845,7 +943,7 @@ func TestTransferInsuranceFundPayments(t *testing.T) { } // Check the subaccount module balance. - subaccountsModuleAccBalance := bankKeeper.GetBalance(ctx, types.ModuleAddress, constants.Usdc.Denom) + subaccountsModuleAccBalance := bankKeeper.GetBalance(ctx, collateralPoolAddr, constants.Usdc.Denom) require.Equal( t, sdk.NewInt64Coin(constants.Usdc.Denom, tc.expectedSubaccountsModuleAccBalance), @@ -854,7 +952,7 @@ func TestTransferInsuranceFundPayments(t *testing.T) { // Check the fee module account balance has been updated as expected. toModuleBalance := bankKeeper.GetBalance( - ctx, authtypes.NewModuleAddress(insuranceFundName), + ctx, insuranceFundAddr, constants.Usdc.Denom, ) require.Equal(t, diff --git a/protocol/x/subaccounts/types/expected_keepers.go b/protocol/x/subaccounts/types/expected_keepers.go index 40a21e203d..4d30eb8174 100644 --- a/protocol/x/subaccounts/types/expected_keepers.go +++ b/protocol/x/subaccounts/types/expected_keepers.go @@ -73,6 +73,7 @@ type PerpetualsKeeper interface { ) GetAllPerpetuals(ctx sdk.Context) []perptypes.Perpetual GetInsuranceFundName(ctx sdk.Context, perpetualId uint32) (string, error) + GetInsuranceFundModuleAddress(ctx sdk.Context, perpetualId uint32) (sdk.AccAddress, error) } // BankKeeper defines the expected interface needed to retrieve account balances. From 7dfad366a6d561dba2a5e2b75ca0a60bc1b14f06 Mon Sep 17 00:00:00 2001 From: Shrenuj Bansal Date: Wed, 6 Mar 2024 01:01:02 -0500 Subject: [PATCH 2/5] slight refactor in apis Signed-off-by: Shrenuj Bansal --- protocol/x/subaccounts/keeper/subaccount.go | 40 +++++---------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/protocol/x/subaccounts/keeper/subaccount.go b/protocol/x/subaccounts/keeper/subaccount.go index 57d37006b2..a6d4415029 100644 --- a/protocol/x/subaccounts/keeper/subaccount.go +++ b/protocol/x/subaccounts/keeper/subaccount.go @@ -62,13 +62,17 @@ func (k Keeper) GetCollateralPoolForSubaccount(ctx sdk.Context, subaccountId typ sdk.AccAddress, error, ) { - poolName, err := k.GetCollateralPoolNameForSubaccount(ctx, subaccountId) - if err != nil { - return nil, err + // Use the default collateral pool if the subaccount has no perpetual positions. + subaccount := k.GetSubaccount(ctx, subaccountId) + if len(subaccount.PerpetualPositions) == 0 { + return types.ModuleAddress, nil } - return authtypes.NewModuleAddress(poolName), nil + + return k.GetCollateralPoolFromPerpetualId(ctx, subaccount.PerpetualPositions[0].PerpetualId) } +// GetCollateralPoolForSubaccountWithPerpetuals returns the collateral pool address based on the +// perpetual passes in as an argument. func (k Keeper) GetCollateralPoolFromPerpetualId(ctx sdk.Context, perpetualId uint32) (sdk.AccAddress, error) { perpetual, err := k.perpetualsKeeper.GetPerpetual(ctx, perpetualId) if err != nil { @@ -82,34 +86,6 @@ func (k Keeper) GetCollateralPoolFromPerpetualId(ctx sdk.Context, perpetualId ui return authtypes.NewModuleAddress(types.ModuleName), nil } -func (k Keeper) GetCollateralPoolNameForSubaccount(ctx sdk.Context, subaccountId types.SubaccountId) (string, error) { - subaccount := k.GetSubaccount(ctx, subaccountId) - if len(subaccount.PerpetualPositions) == 0 { - return types.ModuleName, nil - } - - // Get the first perpetual position and return the collateral pool name. - perpetual, err := k.perpetualsKeeper.GetPerpetual(ctx, subaccount.PerpetualPositions[0].PerpetualId) - if err != nil { - panic(fmt.Sprintf("GetCollateralPoolNameForSubaccount: %v", err)) - } - - if perpetual.Params.MarketType == perptypes.PerpetualMarketType_PERPETUAL_MARKET_TYPE_ISOLATED { - return types.ModuleName + ":" + lib.UintToString(perpetual.GetId()), nil - } - - return types.ModuleName, nil -} - -// IsIsolatedMarketSubaccount returns whether a subaccount is isolated to a specific market. -func (k Keeper) IsIsolatedMarketSubaccount(ctx sdk.Context, subaccountId types.SubaccountId) (bool, error) { - poolName, err := k.GetCollateralPoolNameForSubaccount(ctx, subaccountId) - if err != nil { - panic(fmt.Sprintf("IsIsolatedMarketSubaccount: %v", err)) - } - return poolName != types.ModuleName, nil -} - // GetSubaccount returns a subaccount from its index. // // Note that this function is getting called very frequently; metrics in this function From 4a3d396cf54fab07d8182b0091eedd09d0c30932 Mon Sep 17 00:00:00 2001 From: Shrenuj Bansal Date: Wed, 6 Mar 2024 12:35:30 -0500 Subject: [PATCH 3/5] fix perpetualId param Signed-off-by: Shrenuj Bansal --- protocol/x/clob/keeper/process_single_match.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/x/clob/keeper/process_single_match.go b/protocol/x/clob/keeper/process_single_match.go index 9cd19a36b8..7410bdd140 100644 --- a/protocol/x/clob/keeper/process_single_match.go +++ b/protocol/x/clob/keeper/process_single_match.go @@ -442,7 +442,7 @@ func (k Keeper) persistMatchedOrders( ctx, assettypes.AssetUsdc.Id, bigTotalFeeQuoteQuantums, - 0, + perpetualId, ); err != nil { return takerUpdateResult, makerUpdateResult, errorsmod.Wrapf( types.ErrSubaccountFeeTransferFailed, From 4a7d3a90fec23eabaaae50cc478b7d01e9cb79a4 Mon Sep 17 00:00:00 2001 From: Shrenuj Bansal Date: Wed, 6 Mar 2024 16:35:20 -0500 Subject: [PATCH 4/5] remove isolated markets from sims until the full order flow is implemented Signed-off-by: Shrenuj Bansal --- protocol/x/perpetuals/simulation/genesis.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/protocol/x/perpetuals/simulation/genesis.go b/protocol/x/perpetuals/simulation/genesis.go index 7addb08818..de97e9bbb4 100644 --- a/protocol/x/perpetuals/simulation/genesis.go +++ b/protocol/x/perpetuals/simulation/genesis.go @@ -190,9 +190,7 @@ func RandomizedGenState(simState *module.SimulationState) { marketId := marketsForPerp[i] marketType := types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS - if i%2 == 0 { - marketType = types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_ISOLATED - } + // TODO: add isolated markets when order placements for isolated markets are supported perpetuals[i] = types.Perpetual{ Params: types.PerpetualParams{ From 78ebcdacba4f88b072abef707e8483a711ab193e Mon Sep 17 00:00:00 2001 From: Shrenuj Bansal Date: Wed, 6 Mar 2024 17:32:06 -0500 Subject: [PATCH 5/5] address comments Signed-off-by: Shrenuj Bansal --- protocol/x/subaccounts/keeper/subaccount.go | 2 +- protocol/x/subaccounts/keeper/transfer.go | 10 +- .../x/subaccounts/keeper/transfer_test.go | 121 ++++++++++++------ 3 files changed, 88 insertions(+), 45 deletions(-) diff --git a/protocol/x/subaccounts/keeper/subaccount.go b/protocol/x/subaccounts/keeper/subaccount.go index a6d4415029..c881a48064 100644 --- a/protocol/x/subaccounts/keeper/subaccount.go +++ b/protocol/x/subaccounts/keeper/subaccount.go @@ -72,7 +72,7 @@ func (k Keeper) GetCollateralPoolForSubaccount(ctx sdk.Context, subaccountId typ } // GetCollateralPoolForSubaccountWithPerpetuals returns the collateral pool address based on the -// perpetual passes in as an argument. +// perpetual passed in as an argument. func (k Keeper) GetCollateralPoolFromPerpetualId(ctx sdk.Context, perpetualId uint32) (sdk.AccAddress, error) { perpetual, err := k.perpetualsKeeper.GetPerpetual(ctx, perpetualId) if err != nil { diff --git a/protocol/x/subaccounts/keeper/transfer.go b/protocol/x/subaccounts/keeper/transfer.go index 8f7d474c28..d556426f4b 100644 --- a/protocol/x/subaccounts/keeper/transfer.go +++ b/protocol/x/subaccounts/keeper/transfer.go @@ -242,18 +242,18 @@ func (k Keeper) TransferFeesToFeeCollectorModule( } // Send coins from `subaccounts` to the `auth` module fee collector account. - fromModule := collateralPoolAddr - toModule := authtypes.NewModuleAddress(authtypes.FeeCollectorName) + fromModuleAddr := collateralPoolAddr + toModuleAddr := authtypes.NewModuleAddress(authtypes.FeeCollectorName) if quantums.Sign() < 0 { // In the case of a liquidation, net fees can be negative if the maker gets a rebate. - fromModule, toModule = toModule, fromModule + fromModuleAddr, toModuleAddr = toModuleAddr, fromModuleAddr } if err := k.bankKeeper.SendCoins( ctx, - fromModule, - toModule, + fromModuleAddr, + toModuleAddr, []sdk.Coin{coinToTransfer}, ); err != nil { return err diff --git a/protocol/x/subaccounts/keeper/transfer_test.go b/protocol/x/subaccounts/keeper/transfer_test.go index 4913108407..831c963368 100644 --- a/protocol/x/subaccounts/keeper/transfer_test.go +++ b/protocol/x/subaccounts/keeper/transfer_test.go @@ -37,6 +37,8 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun subaccountModuleAccBalance *big.Int accAddressBalance *big.Int + collateralPoolAddr sdk.AccAddress + // Transfer details. quantums *big.Int @@ -56,6 +58,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun perpetualPositions: []*types.PerpetualPosition{ &constants.PerpetualPosition_OneBTCLong, }, + collateralPoolAddr: types.ModuleAddress, expectedQuoteBalance: big.NewInt(0), // 500 - 500 expectedSubaccountsModuleAccBalance: big.NewInt(100), // 600 - 100 expectedAccAddressBalance: big.NewInt(3000), // 500 + 2500 @@ -70,6 +73,9 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun perpetualPositions: []*types.PerpetualPosition{ &constants.PerpetualPosition_OneISOLong, }, + collateralPoolAddr: authtypes.NewModuleAddress( + types.ModuleName + ":" + lib.UintToString(constants.PerpetualPosition_OneISOLong.PerpetualId), + ), expectedQuoteBalance: big.NewInt(0), // 500 - 500 expectedSubaccountsModuleAccBalance: big.NewInt(100), // 600 - 100 expectedAccAddressBalance: big.NewInt(3000), // 500 + 2500 @@ -94,6 +100,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun perpetualPositions: []*types.PerpetualPosition{ &constants.PerpetualPosition_OneBTCLong, }, + collateralPoolAddr: types.ModuleAddress, expectedQuoteBalance: big.NewInt(10_000_001), // $1.0001, untransfered $0.0001 remains. expectedSubaccountsModuleAccBalance: big.NewInt(8_000_000), // $8 expectedAccAddressBalance: big.NewInt(4_500_000), // $2.5 + $2 @@ -108,6 +115,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun perpetualPositions: []*types.PerpetualPosition{ &constants.PerpetualPosition_OneBTCLong, }, + collateralPoolAddr: types.ModuleAddress, expectedQuoteBalance: big.NewInt(650), // 150 + 500 expectedSubaccountsModuleAccBalance: big.NewInt(700), // 200 + 500 expectedAccAddressBalance: big.NewInt(1500), // 2000 - 500 @@ -122,6 +130,9 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun perpetualPositions: []*types.PerpetualPosition{ &constants.PerpetualPosition_OneISOLong, }, + collateralPoolAddr: authtypes.NewModuleAddress( + types.ModuleName + ":" + lib.UintToString(constants.PerpetualPosition_OneISOLong.PerpetualId), + ), expectedQuoteBalance: big.NewInt(650), // 150 + 500 expectedSubaccountsModuleAccBalance: big.NewInt(700), // 200 + 500 expectedAccAddressBalance: big.NewInt(1500), // 2000 - 500 @@ -144,6 +155,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun perpetualPositions: []*types.PerpetualPosition{ &constants.PerpetualPosition_OneBTCLong, }, + collateralPoolAddr: types.ModuleAddress, expectedQuoteBalance: big.NewInt(607_100), // $1.05 + $5.021 expectedSubaccountsModuleAccBalance: big.NewInt(7_021_000), // $2 + $5.021 expectedAccAddressBalance: big.NewInt(3_979_000), // $9 - $5.021 @@ -160,6 +172,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun perpetualPositions: []*types.PerpetualPosition{ &constants.PerpetualPosition_OneBTCLong, }, + collateralPoolAddr: types.ModuleAddress, expectedQuoteBalance: new(big.Int).Add( new(big.Int).SetUint64(math.MaxUint64), big.NewInt(400), @@ -229,13 +242,10 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun keeper.SetSubaccount(ctx, subaccount) - collateralPoolAddr, err := keeper.GetCollateralPoolForSubaccount(ctx, *subaccount.Id) - require.NoError(t, err) - if tc.subaccountModuleAccBalance.Sign() > 0 { err := bank_testutil.FundAccount( ctx, - collateralPoolAddr, + tc.collateralPoolAddr, sdk.Coins{ sdk.NewCoin(tc.asset.Denom, sdkmath.NewIntFromBigInt(tc.subaccountModuleAccBalance)), }, @@ -279,7 +289,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun ) // Check the subaccount module balance. - subaccountsModuleAccBalance := bankKeeper.GetBalance(ctx, collateralPoolAddr, tc.asset.Denom) + subaccountsModuleAccBalance := bankKeeper.GetBalance(ctx, tc.collateralPoolAddr, tc.asset.Denom) require.Equal(t, sdk.NewCoin(tc.asset.Denom, sdkmath.NewIntFromBigInt(tc.expectedSubaccountsModuleAccBalance)), subaccountsModuleAccBalance, @@ -312,6 +322,8 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun subaccountModuleAccBalance *big.Int accAddressBalance *big.Int + collateralPoolAddr sdk.AccAddress + // Transfer details quantums *big.Int @@ -325,6 +337,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun subaccountModuleAccBalance: big.NewInt(500), quantums: big.NewInt(500), assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(100)), + collateralPoolAddr: types.ModuleAddress, expectedErr: types.ErrFailedToUpdateSubaccounts, }, "WithdrawFundsFromSubaccountToAccount: subaccounts module account does not have enough balance": { @@ -334,6 +347,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun accAddressBalance: big.NewInt(5000), quantums: big.NewInt(500), assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(500)), + collateralPoolAddr: types.ModuleAddress, expectedErr: sdkerrors.ErrInsufficientFunds, }, "WithdrawFundsFromSubaccountToAccount: isolated market subaccounts module account does not have enough balance": { @@ -346,6 +360,9 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun perpetualPositions: []*types.PerpetualPosition{ &constants.PerpetualPosition_OneISOLong, }, + collateralPoolAddr: authtypes.NewModuleAddress( + types.ModuleName + ":" + lib.UintToString(constants.PerpetualPosition_OneISOLong.PerpetualId), + ), expectedErr: sdkerrors.ErrInsufficientFunds, }, "WithdrawFundsFromSubaccountToAccount: transfer quantums is zero": { @@ -355,6 +372,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun subaccountModuleAccBalance: big.NewInt(600), quantums: big.NewInt(0), assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(500)), + collateralPoolAddr: types.ModuleAddress, expectedErr: types.ErrAssetTransferQuantumsNotPositive, }, "WithdrawFundsFromSubaccountToAccount: transfer quantums is negative": { @@ -364,6 +382,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun subaccountModuleAccBalance: big.NewInt(600), quantums: big.NewInt(-100), assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(500)), + collateralPoolAddr: types.ModuleAddress, expectedErr: types.ErrAssetTransferQuantumsNotPositive, }, "WithdrawFundsFromSubaccountToAccount: do not support assets other than USDC": { @@ -373,6 +392,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun subaccountModuleAccBalance: big.NewInt(500), quantums: big.NewInt(500), assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(500)), + collateralPoolAddr: types.ModuleAddress, expectedErr: types.ErrAssetTransferThroughBankNotImplemented, }, "WithdrawFundsFromSubaccountToAccount: asset ID doesn't exist": { @@ -383,6 +403,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun subaccountModuleAccBalance: big.NewInt(500), quantums: big.NewInt(500), assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(500)), + collateralPoolAddr: types.ModuleAddress, expectedErr: asstypes.ErrAssetDoesNotExist, }, "DepositFundsFromAccountToSubaccount: fee-collector does not have enough balance to transfer": { @@ -392,6 +413,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun subaccountModuleAccBalance: big.NewInt(2000), quantums: big.NewInt(500), assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(500)), + collateralPoolAddr: types.ModuleAddress, expectedErr: sdkerrors.ErrInsufficientFunds, }, "DepositFundsFromAccountToSubaccount: transfer quantums is zero": { @@ -401,6 +423,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun subaccountModuleAccBalance: big.NewInt(600), quantums: big.NewInt(0), assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(500)), + collateralPoolAddr: types.ModuleAddress, expectedErr: types.ErrAssetTransferQuantumsNotPositive, }, "DepositFundsFromAccountToSubaccount: do not support assets other than USDC": { @@ -410,6 +433,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun subaccountModuleAccBalance: big.NewInt(500), quantums: big.NewInt(500), assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(500)), + collateralPoolAddr: types.ModuleAddress, expectedErr: types.ErrAssetTransferThroughBankNotImplemented, }, "DepositFundsFromAccountToSubaccount: failure, asset ID doesn't exist": { @@ -420,6 +444,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun subaccountModuleAccBalance: big.NewInt(500), quantums: big.NewInt(500), assetPositions: keepertest.CreateUsdcAssetPosition(big.NewInt(500)), + collateralPoolAddr: types.ModuleAddress, expectedErr: asstypes.ErrAssetDoesNotExist, }, // TODO(DEC-715): Add more test for non-USDC assets, after asset update @@ -485,13 +510,10 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun keeper.SetSubaccount(ctx, subaccount) - collateralPoolAddr, err := keeper.GetCollateralPoolForSubaccount(ctx, *subaccount.Id) - require.NoError(t, err) - if tc.subaccountModuleAccBalance.Sign() > 0 { err := bank_testutil.FundAccount( ctx, - collateralPoolAddr, + tc.collateralPoolAddr, sdk.Coins{ sdk.NewCoin(tc.asset.Denom, sdkmath.NewIntFromBigInt(tc.subaccountModuleAccBalance)), }, @@ -533,7 +555,7 @@ func TestWithdrawFundsFromSubaccountToAccount_DepositFundsFromAccountToSubaccoun ) // Check the subaccount module balance stays the same. - subaccountsModuleAccBalance := bankKeeper.GetBalance(ctx, collateralPoolAddr, tc.asset.Denom) + subaccountsModuleAccBalance := bankKeeper.GetBalance(ctx, tc.collateralPoolAddr, tc.asset.Denom) require.Equal(t, sdk.NewCoin(tc.asset.Denom, sdkmath.NewIntFromBigInt(tc.subaccountModuleAccBalance)), subaccountsModuleAccBalance, @@ -565,6 +587,8 @@ func TestTransferFeesToFeeCollectorModule(t *testing.T) { quantums *big.Int perpetualId uint32 + collateralPoolAddr sdk.AccAddress + // Expectations. expectedErr error expectedSubaccountsModuleAccBalance *big.Int @@ -575,15 +599,19 @@ func TestTransferFeesToFeeCollectorModule(t *testing.T) { feeModuleAccBalance: big.NewInt(2500), subaccountModuleAccBalance: big.NewInt(600), quantums: big.NewInt(500), + collateralPoolAddr: types.ModuleAddress, expectedSubaccountsModuleAccBalance: big.NewInt(100), // 600 - 500 expectedFeeModuleAccBalance: big.NewInt(3000), // 500 + 2500 }, "success - send to fee-collector module account from isolated market account": { - asset: *constants.Usdc, - feeModuleAccBalance: big.NewInt(2500), - subaccountModuleAccBalance: big.NewInt(600), - quantums: big.NewInt(500), - perpetualId: 3, // Isolated market perpetual ID + asset: *constants.Usdc, + feeModuleAccBalance: big.NewInt(2500), + subaccountModuleAccBalance: big.NewInt(600), + quantums: big.NewInt(500), + perpetualId: 3, // Isolated market perpetual ID + collateralPoolAddr: authtypes.NewModuleAddress( + types.ModuleName + ":" + lib.IntToString(3), + ), expectedSubaccountsModuleAccBalance: big.NewInt(100), // 600 - 500 expectedFeeModuleAccBalance: big.NewInt(3000), // 500 + 2500 }, @@ -592,6 +620,7 @@ func TestTransferFeesToFeeCollectorModule(t *testing.T) { feeModuleAccBalance: big.NewInt(2500), subaccountModuleAccBalance: big.NewInt(600), quantums: big.NewInt(0), + collateralPoolAddr: types.ModuleAddress, expectedSubaccountsModuleAccBalance: big.NewInt(600), // 600 expectedFeeModuleAccBalance: big.NewInt(2500), // 2500 }, @@ -600,16 +629,20 @@ func TestTransferFeesToFeeCollectorModule(t *testing.T) { feeModuleAccBalance: big.NewInt(2500), subaccountModuleAccBalance: big.NewInt(300), quantums: big.NewInt(500), + collateralPoolAddr: types.ModuleAddress, expectedSubaccountsModuleAccBalance: big.NewInt(300), expectedFeeModuleAccBalance: big.NewInt(2500), expectedErr: sdkerrors.ErrInsufficientFunds, }, "failure - isolated markets subaccounts module does not have sufficient funds": { - asset: *constants.Usdc, - feeModuleAccBalance: big.NewInt(2500), - subaccountModuleAccBalance: big.NewInt(300), - quantums: big.NewInt(500), - perpetualId: 3, // Isolated market perpetual ID + asset: *constants.Usdc, + feeModuleAccBalance: big.NewInt(2500), + subaccountModuleAccBalance: big.NewInt(300), + quantums: big.NewInt(500), + perpetualId: 3, // Isolated market perpetual ID + collateralPoolAddr: authtypes.NewModuleAddress( + types.ModuleName + ":" + lib.IntToString(3), + ), expectedSubaccountsModuleAccBalance: big.NewInt(300), expectedFeeModuleAccBalance: big.NewInt(2500), expectedErr: sdkerrors.ErrInsufficientFunds, @@ -620,6 +653,7 @@ func TestTransferFeesToFeeCollectorModule(t *testing.T) { asset: *constants.Usdc, subaccountModuleAccBalance: big.NewInt(500), quantums: big.NewInt(500), + collateralPoolAddr: types.ModuleAddress, expectedErr: asstypes.ErrAssetDoesNotExist, expectedSubaccountsModuleAccBalance: big.NewInt(500), expectedFeeModuleAccBalance: big.NewInt(1500), @@ -629,6 +663,7 @@ func TestTransferFeesToFeeCollectorModule(t *testing.T) { asset: *constants.BtcUsd, subaccountModuleAccBalance: big.NewInt(500), quantums: big.NewInt(500), + collateralPoolAddr: types.ModuleAddress, expectedErr: types.ErrAssetTransferThroughBankNotImplemented, expectedSubaccountsModuleAccBalance: big.NewInt(500), expectedFeeModuleAccBalance: big.NewInt(1500), @@ -638,6 +673,7 @@ func TestTransferFeesToFeeCollectorModule(t *testing.T) { asset: *constants.Usdc, subaccountModuleAccBalance: big.NewInt(500), quantums: big.NewInt(-500), + collateralPoolAddr: types.ModuleAddress, expectedSubaccountsModuleAccBalance: big.NewInt(1000), expectedFeeModuleAccBalance: big.NewInt(1000), }, @@ -684,13 +720,10 @@ func TestTransferFeesToFeeCollectorModule(t *testing.T) { require.NoError(t, err) } - collateralPoolAddr, err := keeper.GetCollateralPoolFromPerpetualId(ctx, tc.perpetualId) - require.NoError(t, err) - if tc.subaccountModuleAccBalance.Sign() > 0 { err := bank_testutil.FundAccount( ctx, - collateralPoolAddr, + tc.collateralPoolAddr, sdk.Coins{ sdk.NewCoin(tc.asset.Denom, sdkmath.NewIntFromBigInt(tc.subaccountModuleAccBalance)), }, @@ -719,7 +752,7 @@ func TestTransferFeesToFeeCollectorModule(t *testing.T) { require.NoError(t, err) } - err = keeper.TransferFeesToFeeCollectorModule(ctx, tc.asset.Id, tc.quantums, tc.perpetualId) + err := keeper.TransferFeesToFeeCollectorModule(ctx, tc.asset.Id, tc.quantums, tc.perpetualId) if tc.expectedErr != nil { require.ErrorIs(t, @@ -731,7 +764,7 @@ func TestTransferFeesToFeeCollectorModule(t *testing.T) { } // Check the subaccount module balance. - subaccountsModuleAccBalance := bankKeeper.GetBalance(ctx, collateralPoolAddr, tc.asset.Denom) + subaccountsModuleAccBalance := bankKeeper.GetBalance(ctx, tc.collateralPoolAddr, tc.asset.Denom) require.Equal(t, sdk.NewCoin(tc.asset.Denom, sdkmath.NewIntFromBigInt(tc.expectedSubaccountsModuleAccBalance)), subaccountsModuleAccBalance, @@ -758,6 +791,7 @@ func TestTransferInsuranceFundPayments(t *testing.T) { subaccountModuleAccBalance int64 insuranceFundBalance int64 perpetual perptypes.Perpetual + collateralPoolAddr sdk.AccAddress // Transfer details. quantums *big.Int @@ -773,6 +807,7 @@ func TestTransferInsuranceFundPayments(t *testing.T) { insuranceFundBalance: 2500, subaccountModuleAccBalance: 600, quantums: big.NewInt(500), + collateralPoolAddr: types.ModuleAddress, expectedSubaccountsModuleAccBalance: 100, // 600 - 500 expectedInsuranceFundBalance: 3000, // 2500 + 500 }, @@ -781,6 +816,7 @@ func TestTransferInsuranceFundPayments(t *testing.T) { insuranceFundBalance: 2500, subaccountModuleAccBalance: 600, quantums: big.NewInt(-500), + collateralPoolAddr: types.ModuleAddress, expectedSubaccountsModuleAccBalance: 1100, // 600 + 500 expectedInsuranceFundBalance: 2000, // 2500 - 500 }, @@ -789,22 +825,29 @@ func TestTransferInsuranceFundPayments(t *testing.T) { insuranceFundBalance: 2500, subaccountModuleAccBalance: 600, quantums: big.NewInt(0), + collateralPoolAddr: types.ModuleAddress, expectedSubaccountsModuleAccBalance: 600, expectedInsuranceFundBalance: 2500, }, "success - send to isolated insurance fund account": { - perpetual: constants.IsoUsd_IsolatedMarket, - insuranceFundBalance: 2500, - subaccountModuleAccBalance: 600, - quantums: big.NewInt(500), + perpetual: constants.IsoUsd_IsolatedMarket, + insuranceFundBalance: 2500, + subaccountModuleAccBalance: 600, + quantums: big.NewInt(500), + collateralPoolAddr: authtypes.NewModuleAddress( + types.ModuleName + ":" + lib.UintToString(constants.IsoUsd_IsolatedMarket.GetId()), + ), expectedSubaccountsModuleAccBalance: 100, // 600 - 500 expectedInsuranceFundBalance: 3000, // 2500 + 500 }, "success - send from isolated insurance fund account": { - perpetual: constants.IsoUsd_IsolatedMarket, - insuranceFundBalance: 2500, - subaccountModuleAccBalance: 600, - quantums: big.NewInt(-500), + perpetual: constants.IsoUsd_IsolatedMarket, + insuranceFundBalance: 2500, + subaccountModuleAccBalance: 600, + quantums: big.NewInt(-500), + collateralPoolAddr: authtypes.NewModuleAddress( + types.ModuleName + ":" + lib.UintToString(constants.IsoUsd_IsolatedMarket.GetId()), + ), expectedSubaccountsModuleAccBalance: 1100, // 600 + 500 expectedInsuranceFundBalance: 2000, // 2500 - 500 }, @@ -813,6 +856,7 @@ func TestTransferInsuranceFundPayments(t *testing.T) { insuranceFundBalance: 2500, subaccountModuleAccBalance: 300, quantums: big.NewInt(500), + collateralPoolAddr: types.ModuleAddress, expectedSubaccountsModuleAccBalance: 300, expectedInsuranceFundBalance: 2500, expectedErr: sdkerrors.ErrInsufficientFunds, @@ -822,6 +866,7 @@ func TestTransferInsuranceFundPayments(t *testing.T) { insuranceFundBalance: 300, subaccountModuleAccBalance: 2500, quantums: big.NewInt(-500), + collateralPoolAddr: types.ModuleAddress, expectedSubaccountsModuleAccBalance: 2500, expectedInsuranceFundBalance: 300, expectedErr: sdkerrors.ErrInsufficientFunds, @@ -841,6 +886,7 @@ func TestTransferInsuranceFundPayments(t *testing.T) { skipSetUpUsdc: true, subaccountModuleAccBalance: 500, quantums: big.NewInt(500), + collateralPoolAddr: types.ModuleAddress, expectedErr: errorsmod.Wrap(asstypes.ErrAssetDoesNotExist, lib.UintToString(uint32(0))), expectedSubaccountsModuleAccBalance: 500, expectedInsuranceFundBalance: 1500, @@ -888,9 +934,6 @@ func TestTransferInsuranceFundPayments(t *testing.T) { insuranceFundAddr, err := perpsKeeper.GetInsuranceFundModuleAddress(ctx, tc.perpetual.GetId()) require.NoError(t, err) - collateralPoolAddr, err := keeper.GetCollateralPoolFromPerpetualId(ctx, tc.perpetual.GetId()) - require.NoError(t, err) - // Mint asset in the receipt/sender module account for transfer. if tc.insuranceFundBalance > 0 { err := bank_testutil.FundAccount( @@ -907,7 +950,7 @@ func TestTransferInsuranceFundPayments(t *testing.T) { if tc.subaccountModuleAccBalance > 0 { err := bank_testutil.FundAccount( ctx, - collateralPoolAddr, + tc.collateralPoolAddr, sdk.Coins{ sdk.NewInt64Coin(constants.Usdc.Denom, tc.subaccountModuleAccBalance), }, @@ -943,7 +986,7 @@ func TestTransferInsuranceFundPayments(t *testing.T) { } // Check the subaccount module balance. - subaccountsModuleAccBalance := bankKeeper.GetBalance(ctx, collateralPoolAddr, constants.Usdc.Denom) + subaccountsModuleAccBalance := bankKeeper.GetBalance(ctx, tc.collateralPoolAddr, constants.Usdc.Denom) require.Equal( t, sdk.NewInt64Coin(constants.Usdc.Denom, tc.expectedSubaccountsModuleAccBalance),