@@ -102,6 +102,8 @@ type Engine struct {
102
102
timeService TimeService
103
103
broker Broker
104
104
105
+ earmarkedBalance map [string ]* num.Uint
106
+
105
107
partiesAccsBalanceCache map [string ]* num.Uint
106
108
partiesAccsBalanceCacheLock sync.RWMutex
107
109
@@ -151,6 +153,7 @@ func New(log *logging.Logger, conf Config, ts TimeService, broker Broker) *Engin
151
153
nextBalancesSnapshot : time.Time {},
152
154
partyAssetCache : map [string ]map [string ]* num.Uint {},
153
155
partyMarketCache : map [string ]map [string ]* num.Uint {},
156
+ earmarkedBalance : map [string ]* num.Uint {},
154
157
}
155
158
}
156
159
@@ -731,14 +734,14 @@ func (e *Engine) TransferSpotFeesContinuousTrading(ctx context.Context, marketID
731
734
}
732
735
}
733
736
734
- return e .transferSpotFees (ctx , marketID , assetID , ft )
737
+ return e .transferSpotFees (ctx , marketID , assetID , ft , types . AccountTypeGeneral )
735
738
}
736
739
737
- func (e * Engine ) TransferSpotFees (ctx context.Context , marketID string , assetID string , ft events.FeesTransfer ) ([]* types.LedgerMovement , error ) {
738
- return e .transferSpotFees (ctx , marketID , assetID , ft )
740
+ func (e * Engine ) TransferSpotFees (ctx context.Context , marketID string , assetID string , ft events.FeesTransfer , fromAccountType types. AccountType ) ([]* types.LedgerMovement , error ) {
741
+ return e .transferSpotFees (ctx , marketID , assetID , ft , fromAccountType )
739
742
}
740
743
741
- func (e * Engine ) transferSpotFees (ctx context.Context , marketID string , assetID string , ft events.FeesTransfer ) ([]* types.LedgerMovement , error ) {
744
+ func (e * Engine ) transferSpotFees (ctx context.Context , marketID string , assetID string , ft events.FeesTransfer , fromAccountType types. AccountType ) ([]* types.LedgerMovement , error ) {
742
745
makerFee , infraFee , liquiFee , err := e .getFeesAccounts (marketID , assetID )
743
746
if err != nil {
744
747
return nil , err
@@ -749,7 +752,7 @@ func (e *Engine) transferSpotFees(ctx context.Context, marketID string, assetID
749
752
750
753
for _ , transfer := range transfers {
751
754
req , err := e .getSpotFeeTransferRequest (
752
- ctx , transfer , makerFee , infraFee , liquiFee , marketID , assetID )
755
+ ctx , transfer , makerFee , infraFee , liquiFee , marketID , assetID , fromAccountType )
753
756
if err != nil {
754
757
e .log .Error ("Failed to build transfer request for event" ,
755
758
logging .Error (err ))
@@ -784,6 +787,7 @@ func (e *Engine) getSpotFeeTransferRequest(
784
787
t * types.Transfer ,
785
788
makerFee , infraFee , liquiFee * types.Account ,
786
789
marketID , assetID string ,
790
+ sourceAccountType types.AccountType ,
787
791
) (* types.TransferRequest , error ) {
788
792
getAccount := func (marketID , owner string , accountType vega.AccountType ) (* types.Account , error ) {
789
793
acc , err := e .GetAccountByID (e .accountID (marketID , owner , assetID , accountType ))
@@ -808,7 +812,13 @@ func (e *Engine) getSpotFeeTransferRequest(
808
812
return getAccount (marketID , systemOwner , types .AccountTypeLiquidityFeesBonusDistribution )
809
813
}
810
814
811
- general , err := getAccount (noMarket , t .Owner , types .AccountTypeGeneral )
815
+ accTypeForGeneral := types .AccountTypeGeneral
816
+ owner := t .Owner
817
+ if t .Owner == types .NetworkParty {
818
+ owner = systemOwner
819
+ accTypeForGeneral = sourceAccountType
820
+ }
821
+ general , err := getAccount (noMarket , owner , accTypeForGeneral )
812
822
if err != nil {
813
823
return nil , err
814
824
}
@@ -2736,7 +2746,7 @@ func (e *Engine) getGovernanceTransferFundsTransferRequest(ctx context.Context,
2736
2746
case types .AccountTypeGlobalReward , types .AccountTypeLPFeeReward , types .AccountTypeMakerReceivedFeeReward ,
2737
2747
types .AccountTypeMakerPaidFeeReward , types .AccountTypeMarketProposerReward , types .AccountTypeAverageNotionalReward ,
2738
2748
types .AccountTypeRelativeReturnReward , types .AccountTypeReturnVolatilityReward , types .AccountTypeRealisedReturnReward ,
2739
- types .AccountTypeValidatorRankingReward , types .AccountTypeEligibleEntitiesReward :
2749
+ types .AccountTypeValidatorRankingReward , types .AccountTypeEligibleEntitiesReward , types . AccountTypeBuyBackFees :
2740
2750
market := noMarket
2741
2751
if len (t .Market ) > 0 {
2742
2752
market = t .Market
@@ -2843,7 +2853,7 @@ func (e *Engine) getTransferFundsTransferRequest(ctx context.Context, t *types.T
2843
2853
case types .AccountTypeGlobalReward , types .AccountTypeLPFeeReward , types .AccountTypeMakerReceivedFeeReward , types .AccountTypeNetworkTreasury ,
2844
2854
types .AccountTypeMakerPaidFeeReward , types .AccountTypeMarketProposerReward , types .AccountTypeAverageNotionalReward ,
2845
2855
types .AccountTypeRelativeReturnReward , types .AccountTypeReturnVolatilityReward , types .AccountTypeRealisedReturnReward ,
2846
- types .AccountTypeValidatorRankingReward , types .AccountTypeEligibleEntitiesReward :
2856
+ types .AccountTypeValidatorRankingReward , types .AccountTypeEligibleEntitiesReward , types . AccountTypeBuyBackFees :
2847
2857
market := noMarket
2848
2858
if len (t .Market ) > 0 {
2849
2859
market = t .Market
@@ -4688,6 +4698,10 @@ func (e *Engine) GetNetworkTreasuryAccount(asset string) (*types.Account, error)
4688
4698
return e .GetAccountByID (e .accountID (noMarket , systemOwner , asset , types .AccountTypeNetworkTreasury ))
4689
4699
}
4690
4700
4701
+ func (e * Engine ) GetOrCreateBuyBackFeesAccountID (ctx context.Context , asset string ) string {
4702
+ return e .getOrCreateBuyBackFeesAccount (ctx , asset ).ID
4703
+ }
4704
+
4691
4705
func (e * Engine ) getOrCreateBuyBackFeesAccount (ctx context.Context , asset string ) * types.Account {
4692
4706
accID := e .accountID (noMarket , systemOwner , asset , types .AccountTypeBuyBackFees )
4693
4707
acc , err := e .GetAccountByID (accID )
@@ -4728,6 +4742,26 @@ func (e *Engine) GetOrCreateNetworkTreasuryAccount(ctx context.Context, asset st
4728
4742
return ntAcc
4729
4743
}
4730
4744
4745
+ func (e * Engine ) getOrCreateNetworkAccount (ctx context.Context , asset string , accountType types.AccountType ) * types.Account {
4746
+ accID := e .accountID (noMarket , systemOwner , asset , accountType )
4747
+ acc , err := e .GetAccountByID (accID )
4748
+ if err == nil {
4749
+ return acc
4750
+ }
4751
+ ntAcc := & types.Account {
4752
+ ID : accID ,
4753
+ Asset : asset ,
4754
+ Owner : systemOwner ,
4755
+ Balance : num .UintZero (),
4756
+ MarketID : noMarket ,
4757
+ Type : accountType ,
4758
+ }
4759
+ e .accs [accID ] = ntAcc
4760
+ e .addAccountToHashableSlice (ntAcc )
4761
+ e .broker .Send (events .NewAccountEvent (ctx , * ntAcc ))
4762
+ return ntAcc
4763
+ }
4764
+
4731
4765
func (e * Engine ) GetGlobalInsuranceAccount (asset string ) (* types.Account , error ) {
4732
4766
return e .GetAccountByID (e .accountID (noMarket , systemOwner , asset , types .AccountTypeGlobalInsurance ))
4733
4767
}
@@ -4801,19 +4835,23 @@ func (e *Engine) GetSystemAccountBalance(asset, market string, accountType types
4801
4835
return account .Balance .Clone (), nil
4802
4836
}
4803
4837
4804
- // TransferToHoldingAccount locks funds from general account into holding account account of the party.
4805
- func (e * Engine ) TransferToHoldingAccount (ctx context.Context , transfer * types.Transfer ) (* types.LedgerMovement , error ) {
4806
- generalAccountID := e .accountID (transfer .Market , transfer .Owner , transfer .Amount .Asset , types .AccountTypeGeneral )
4807
- generalAccount , err := e .GetAccountByID (generalAccountID )
4838
+ // TransferToHoldingAccount locks funds from accountTypeFrom into holding account account of the party.
4839
+ func (e * Engine ) TransferToHoldingAccount (ctx context.Context , transfer * types.Transfer , accountTypeFrom types.AccountType ) (* types.LedgerMovement , error ) {
4840
+ party := transfer .Owner
4841
+ if party == types .NetworkParty {
4842
+ party = systemOwner
4843
+ }
4844
+ sourceAccountID := e .accountID (transfer .Market , party , transfer .Amount .Asset , accountTypeFrom )
4845
+ sourceAccount , err := e .GetAccountByID (sourceAccountID )
4808
4846
if err != nil {
4809
4847
return nil , err
4810
4848
}
4811
4849
4812
- holdingAccountID := e .accountID (noMarket , transfer . Owner , transfer .Amount .Asset , types .AccountTypeHolding )
4850
+ holdingAccountID := e .accountID (noMarket , party , transfer .Amount .Asset , types .AccountTypeHolding )
4813
4851
holdingAccount , err := e .GetAccountByID (holdingAccountID )
4814
4852
if err != nil {
4815
4853
// if the holding account doesn't exist yet we create it here
4816
- holdingAccountID , err := e .CreatePartyHoldingAccount (ctx , transfer . Owner , transfer .Amount .Asset )
4854
+ holdingAccountID , err := e .CreatePartyHoldingAccount (ctx , party , transfer .Amount .Asset )
4817
4855
if err != nil {
4818
4856
return nil , err
4819
4857
}
@@ -4825,7 +4863,7 @@ func (e *Engine) TransferToHoldingAccount(ctx context.Context, transfer *types.T
4825
4863
MinAmount : transfer .Amount .Amount .Clone (),
4826
4864
Asset : transfer .Amount .Asset ,
4827
4865
Type : types .TransferTypeHoldingAccount ,
4828
- FromAccount : []* types.Account {generalAccount },
4866
+ FromAccount : []* types.Account {sourceAccount },
4829
4867
ToAccount : []* types.Account {holdingAccount },
4830
4868
}
4831
4869
@@ -4845,15 +4883,19 @@ func (e *Engine) TransferToHoldingAccount(ctx context.Context, transfer *types.T
4845
4883
return res , nil
4846
4884
}
4847
4885
4848
- // ReleaseFromHoldingAccount releases locked funds from holding account back to the general account of the party.
4849
- func (e * Engine ) ReleaseFromHoldingAccount (ctx context.Context , transfer * types.Transfer ) (* types.LedgerMovement , error ) {
4850
- holdingAccountID := e .accountID (noMarket , transfer .Owner , transfer .Amount .Asset , types .AccountTypeHolding )
4886
+ // ReleaseFromHoldingAccount releases locked funds from holding account back to the toAccount of the party.
4887
+ func (e * Engine ) ReleaseFromHoldingAccount (ctx context.Context , transfer * types.Transfer , toAccountType types.AccountType ) (* types.LedgerMovement , error ) {
4888
+ party := transfer .Owner
4889
+ if party == types .NetworkParty {
4890
+ party = systemOwner
4891
+ }
4892
+ holdingAccountID := e .accountID (noMarket , party , transfer .Amount .Asset , types .AccountTypeHolding )
4851
4893
holdingAccount , err := e .GetAccountByID (holdingAccountID )
4852
4894
if err != nil {
4853
4895
return nil , err
4854
4896
}
4855
4897
4856
- generalAccount , err := e .GetAccountByID (e .accountID (noMarket , transfer . Owner , transfer .Amount .Asset , types . AccountTypeGeneral ))
4898
+ targetAccount , err := e .GetAccountByID (e .accountID (noMarket , party , transfer .Amount .Asset , toAccountType ))
4857
4899
if err != nil {
4858
4900
return nil , err
4859
4901
}
@@ -4864,7 +4906,7 @@ func (e *Engine) ReleaseFromHoldingAccount(ctx context.Context, transfer *types.
4864
4906
Asset : transfer .Amount .Asset ,
4865
4907
Type : types .TransferTypeReleaseHoldingAccount ,
4866
4908
FromAccount : []* types.Account {holdingAccount },
4867
- ToAccount : []* types.Account {generalAccount },
4909
+ ToAccount : []* types.Account {targetAccount },
4868
4910
}
4869
4911
4870
4912
res , err := e .getLedgerEntries (ctx , req )
@@ -5018,9 +5060,14 @@ func (e *Engine) CreateSpotMarketAccounts(ctx context.Context, marketID, quoteAs
5018
5060
return err
5019
5061
}
5020
5062
5021
- // PartyHasSufficientBalance checks if the party has sufficient amount in the general account.
5022
- func (e * Engine ) PartyHasSufficientBalance (asset , partyID string , amount * num.Uint ) error {
5023
- acc , err := e .GetPartyGeneralAccount (partyID , asset )
5063
+ // PartyHasSufficientBalance checks if the party has sufficient amount in the <fromAccountType> account.
5064
+ func (e * Engine ) PartyHasSufficientBalance (asset , partyID string , amount * num.Uint , fromAccountType types.AccountType ) error {
5065
+ party := partyID
5066
+ if party == types .NetworkParty {
5067
+ party = systemOwner
5068
+ }
5069
+ accId := e .accountID (noMarket , party , asset , fromAccountType )
5070
+ acc , err := e .GetAccountByID (accId )
5024
5071
if err != nil {
5025
5072
return err
5026
5073
}
@@ -5056,28 +5103,42 @@ func (e *Engine) CreatePartyHoldingAccount(ctx context.Context, partyID, asset s
5056
5103
}
5057
5104
5058
5105
// TransferSpot transfers the given asset/quantity from partyID to partyID.
5059
- // The source partyID general account must exist in the asset, the target partyID general account in the asset is created if it doesn't yet exist.
5060
- func (e * Engine ) TransferSpot (ctx context.Context , partyID , toPartyID , asset string , quantity * num.Uint ) (* types.LedgerMovement , error ) {
5061
- generalAccountID := e .accountID (noMarket , partyID , asset , types .AccountTypeGeneral )
5062
- generalAccount , err := e .GetAccountByID (generalAccountID )
5106
+ // The source partyID fromAccountType account must exist in the asset, the target partyID account in the asset is created if it doesn't yet exist.
5107
+ func (e * Engine ) TransferSpot (ctx context.Context , party , toParty , asset string , quantity * num.Uint , fromAccountType types.AccountType , toAccountType types.AccountType ) (* types.LedgerMovement , error ) {
5108
+ partyID := party
5109
+ if party == types .NetworkParty {
5110
+ partyID = systemOwner
5111
+ }
5112
+
5113
+ toPartyID := toParty
5114
+ if toParty == types .NetworkParty {
5115
+ toPartyID = systemOwner
5116
+ }
5117
+
5118
+ fromAccountID := e .accountID (noMarket , partyID , asset , fromAccountType )
5119
+ fromAccount , err := e .GetAccountByID (fromAccountID )
5063
5120
if err != nil {
5064
5121
return nil , err
5065
5122
}
5066
5123
5067
- targetGeneralAccountID := e .accountID (noMarket , toPartyID , asset , types . AccountTypeGeneral )
5068
- toGeneralAccount , err := e .GetAccountByID (targetGeneralAccountID )
5124
+ toAccountID := e .accountID (noMarket , toPartyID , asset , toAccountType )
5125
+ toAccount , err := e .GetAccountByID (toAccountID )
5069
5126
if err != nil {
5070
- targetGeneralAccountID , _ = e .CreatePartyGeneralAccount (ctx , toPartyID , asset )
5071
- toGeneralAccount , _ = e .GetAccountByID (targetGeneralAccountID )
5127
+ if toAccountType == types .AccountTypeGeneral {
5128
+ toAccountID , _ = e .CreatePartyGeneralAccount (ctx , toPartyID , asset )
5129
+ toAccount , _ = e .GetAccountByID (toAccountID )
5130
+ } else if toPartyID == types .NetworkParty {
5131
+ toAccount = e .getOrCreateNetworkAccount (ctx , asset , toAccountType )
5132
+ }
5072
5133
}
5073
5134
5074
5135
req := & types.TransferRequest {
5075
5136
Amount : quantity .Clone (),
5076
5137
MinAmount : quantity .Clone (),
5077
5138
Asset : asset ,
5078
5139
Type : types .TransferTypeSpot ,
5079
- FromAccount : []* types.Account {generalAccount },
5080
- ToAccount : []* types.Account {toGeneralAccount },
5140
+ FromAccount : []* types.Account {fromAccount },
5141
+ ToAccount : []* types.Account {toAccount },
5081
5142
}
5082
5143
5083
5144
res , err := e .getLedgerEntries (ctx , req )
@@ -5130,3 +5191,54 @@ func (e *Engine) GetVestingAccounts() []*types.Account {
5130
5191
})
5131
5192
return accs
5132
5193
}
5194
+
5195
+ func (e * Engine ) EarmarkForAutomatedPurchase (asset string , accountType types.AccountType , min , max * num.Uint ) (* num.Uint , error ) {
5196
+ id := e .accountID (noMarket , systemOwner , asset , accountType )
5197
+ acc , err := e .GetAccountByID (id )
5198
+ if err != nil {
5199
+ return num .UintZero (), err
5200
+ }
5201
+ earmarked , ok := e .earmarkedBalance [id ]
5202
+ if ! ok {
5203
+ earmarked = num .UintZero ()
5204
+ }
5205
+
5206
+ balanceToEarmark := acc .Balance .Clone ()
5207
+ if earmarked .GT (balanceToEarmark ) {
5208
+ e .log .Panic ("earmarked balance is greater than account balance, this should never happen" )
5209
+ }
5210
+ balanceToEarmark = balanceToEarmark .Sub (balanceToEarmark , earmarked )
5211
+
5212
+ if balanceToEarmark .IsZero () || balanceToEarmark .LT (min ) {
5213
+ return num .UintZero (), fmt .Errorf ("insufficient balance to earmark" )
5214
+ }
5215
+ if balanceToEarmark .GT (max ) {
5216
+ balanceToEarmark = num .Min (balanceToEarmark , max )
5217
+ }
5218
+
5219
+ earmarked .AddSum (balanceToEarmark )
5220
+ e .earmarkedBalance [id ] = earmarked
5221
+ e .state .updateEarmarked (e .earmarkedBalance )
5222
+ return balanceToEarmark , nil
5223
+ }
5224
+
5225
+ func (e * Engine ) UnearmarkForAutomatedPurchase (asset string , accountType types.AccountType , releaseRequest * num.Uint ) error {
5226
+ id := e .accountID (noMarket , systemOwner , asset , accountType )
5227
+ acc , err := e .GetAccountByID (id )
5228
+ if err != nil {
5229
+ return err
5230
+ }
5231
+ if releaseRequest .GT (acc .Balance ) {
5232
+ e .log .Panic ("trying to unearmark an amount that is greater than the balance of the account" )
5233
+ }
5234
+ earmarked , ok := e .earmarkedBalance [id ]
5235
+ if ! ok || releaseRequest .GT (earmarked ) {
5236
+ e .log .Panic ("trying to unearmark an amount that is greater than the earmarked balance" )
5237
+ }
5238
+ earmarked .Sub (earmarked , releaseRequest )
5239
+ if earmarked .IsZero () {
5240
+ delete (e .earmarkedBalance , id )
5241
+ }
5242
+ e .state .updateEarmarked (e .earmarkedBalance )
5243
+ return nil
5244
+ }
0 commit comments