Skip to content

Commit 3209d48

Browse files
committed
feat: buy back auctions
1 parent 62066e8 commit 3209d48

File tree

90 files changed

+15698
-8715
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+15698
-8715
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- [11644](https://github.com/vegaprotocol/vega/issues/11644) - `liveOnly` flag has been added to the `AMM` API to show only active `AMMs`.
1616
- [11519](https://github.com/vegaprotocol/vega/issues/11519) - Add fees to position API types.
1717
- [11642](https://github.com/vegaprotocol/vega/issues/11642) - `AMMs` with empty price levels are now allowed.
18+
- [11685](https://github.com/vegaprotocol/vega/issues/11685) - Automated purchase support added.
1819
- [11711](https://github.com/vegaprotocol/vega/issues/11711) - Manage closed team membership by updating the allow list.
1920

2021
### 🐛 Fixes

commands/proposal_submission.go

Lines changed: 287 additions & 163 deletions
Large diffs are not rendered by default.

commands/proposal_submission_pap_test.go

Lines changed: 588 additions & 0 deletions
Large diffs are not rendered by default.

core/collateral/checkpoint_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ func TestCheckPointWithUndistributedLPFees(t *testing.T) {
252252
},
253253
Type: types.TransferTypeLiquidityFeeUnpaidCollect,
254254
}
255-
_, err = e.TransferSpotFees(context.Background(), "market1", "MYASSET1", &feesTransfer{transfers: []*types.Transfer{lpSpotTransfers}})
255+
_, err = e.TransferSpotFees(context.Background(), "market1", "MYASSET1", &feesTransfer{transfers: []*types.Transfer{lpSpotTransfers}}, types.AccountTypeGeneral)
256256
require.NoError(t, err)
257257

258258
// setup some balance on the LP fee pay account for MYASSET1/market2

core/collateral/engine.go

Lines changed: 145 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ type Engine struct {
102102
timeService TimeService
103103
broker Broker
104104

105+
earmarkedBalance map[string]*num.Uint
106+
105107
partiesAccsBalanceCache map[string]*num.Uint
106108
partiesAccsBalanceCacheLock sync.RWMutex
107109

@@ -151,6 +153,7 @@ func New(log *logging.Logger, conf Config, ts TimeService, broker Broker) *Engin
151153
nextBalancesSnapshot: time.Time{},
152154
partyAssetCache: map[string]map[string]*num.Uint{},
153155
partyMarketCache: map[string]map[string]*num.Uint{},
156+
earmarkedBalance: map[string]*num.Uint{},
154157
}
155158
}
156159

@@ -731,14 +734,14 @@ func (e *Engine) TransferSpotFeesContinuousTrading(ctx context.Context, marketID
731734
}
732735
}
733736

734-
return e.transferSpotFees(ctx, marketID, assetID, ft)
737+
return e.transferSpotFees(ctx, marketID, assetID, ft, types.AccountTypeGeneral)
735738
}
736739

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)
739742
}
740743

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) {
742745
makerFee, infraFee, liquiFee, err := e.getFeesAccounts(marketID, assetID)
743746
if err != nil {
744747
return nil, err
@@ -749,7 +752,7 @@ func (e *Engine) transferSpotFees(ctx context.Context, marketID string, assetID
749752

750753
for _, transfer := range transfers {
751754
req, err := e.getSpotFeeTransferRequest(
752-
ctx, transfer, makerFee, infraFee, liquiFee, marketID, assetID)
755+
ctx, transfer, makerFee, infraFee, liquiFee, marketID, assetID, fromAccountType)
753756
if err != nil {
754757
e.log.Error("Failed to build transfer request for event",
755758
logging.Error(err))
@@ -784,6 +787,7 @@ func (e *Engine) getSpotFeeTransferRequest(
784787
t *types.Transfer,
785788
makerFee, infraFee, liquiFee *types.Account,
786789
marketID, assetID string,
790+
sourceAccountType types.AccountType,
787791
) (*types.TransferRequest, error) {
788792
getAccount := func(marketID, owner string, accountType vega.AccountType) (*types.Account, error) {
789793
acc, err := e.GetAccountByID(e.accountID(marketID, owner, assetID, accountType))
@@ -808,7 +812,13 @@ func (e *Engine) getSpotFeeTransferRequest(
808812
return getAccount(marketID, systemOwner, types.AccountTypeLiquidityFeesBonusDistribution)
809813
}
810814

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)
812822
if err != nil {
813823
return nil, err
814824
}
@@ -2736,7 +2746,7 @@ func (e *Engine) getGovernanceTransferFundsTransferRequest(ctx context.Context,
27362746
case types.AccountTypeGlobalReward, types.AccountTypeLPFeeReward, types.AccountTypeMakerReceivedFeeReward,
27372747
types.AccountTypeMakerPaidFeeReward, types.AccountTypeMarketProposerReward, types.AccountTypeAverageNotionalReward,
27382748
types.AccountTypeRelativeReturnReward, types.AccountTypeReturnVolatilityReward, types.AccountTypeRealisedReturnReward,
2739-
types.AccountTypeValidatorRankingReward, types.AccountTypeEligibleEntitiesReward:
2749+
types.AccountTypeValidatorRankingReward, types.AccountTypeEligibleEntitiesReward, types.AccountTypeBuyBackFees:
27402750
market := noMarket
27412751
if len(t.Market) > 0 {
27422752
market = t.Market
@@ -2843,7 +2853,7 @@ func (e *Engine) getTransferFundsTransferRequest(ctx context.Context, t *types.T
28432853
case types.AccountTypeGlobalReward, types.AccountTypeLPFeeReward, types.AccountTypeMakerReceivedFeeReward, types.AccountTypeNetworkTreasury,
28442854
types.AccountTypeMakerPaidFeeReward, types.AccountTypeMarketProposerReward, types.AccountTypeAverageNotionalReward,
28452855
types.AccountTypeRelativeReturnReward, types.AccountTypeReturnVolatilityReward, types.AccountTypeRealisedReturnReward,
2846-
types.AccountTypeValidatorRankingReward, types.AccountTypeEligibleEntitiesReward:
2856+
types.AccountTypeValidatorRankingReward, types.AccountTypeEligibleEntitiesReward, types.AccountTypeBuyBackFees:
28472857
market := noMarket
28482858
if len(t.Market) > 0 {
28492859
market = t.Market
@@ -4688,6 +4698,10 @@ func (e *Engine) GetNetworkTreasuryAccount(asset string) (*types.Account, error)
46884698
return e.GetAccountByID(e.accountID(noMarket, systemOwner, asset, types.AccountTypeNetworkTreasury))
46894699
}
46904700

4701+
func (e *Engine) GetOrCreateBuyBackFeesAccountID(ctx context.Context, asset string) string {
4702+
return e.getOrCreateBuyBackFeesAccount(ctx, asset).ID
4703+
}
4704+
46914705
func (e *Engine) getOrCreateBuyBackFeesAccount(ctx context.Context, asset string) *types.Account {
46924706
accID := e.accountID(noMarket, systemOwner, asset, types.AccountTypeBuyBackFees)
46934707
acc, err := e.GetAccountByID(accID)
@@ -4728,6 +4742,26 @@ func (e *Engine) GetOrCreateNetworkTreasuryAccount(ctx context.Context, asset st
47284742
return ntAcc
47294743
}
47304744

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+
47314765
func (e *Engine) GetGlobalInsuranceAccount(asset string) (*types.Account, error) {
47324766
return e.GetAccountByID(e.accountID(noMarket, systemOwner, asset, types.AccountTypeGlobalInsurance))
47334767
}
@@ -4801,19 +4835,23 @@ func (e *Engine) GetSystemAccountBalance(asset, market string, accountType types
48014835
return account.Balance.Clone(), nil
48024836
}
48034837

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)
48084846
if err != nil {
48094847
return nil, err
48104848
}
48114849

4812-
holdingAccountID := e.accountID(noMarket, transfer.Owner, transfer.Amount.Asset, types.AccountTypeHolding)
4850+
holdingAccountID := e.accountID(noMarket, party, transfer.Amount.Asset, types.AccountTypeHolding)
48134851
holdingAccount, err := e.GetAccountByID(holdingAccountID)
48144852
if err != nil {
48154853
// 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)
48174855
if err != nil {
48184856
return nil, err
48194857
}
@@ -4825,7 +4863,7 @@ func (e *Engine) TransferToHoldingAccount(ctx context.Context, transfer *types.T
48254863
MinAmount: transfer.Amount.Amount.Clone(),
48264864
Asset: transfer.Amount.Asset,
48274865
Type: types.TransferTypeHoldingAccount,
4828-
FromAccount: []*types.Account{generalAccount},
4866+
FromAccount: []*types.Account{sourceAccount},
48294867
ToAccount: []*types.Account{holdingAccount},
48304868
}
48314869

@@ -4845,15 +4883,19 @@ func (e *Engine) TransferToHoldingAccount(ctx context.Context, transfer *types.T
48454883
return res, nil
48464884
}
48474885

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)
48514893
holdingAccount, err := e.GetAccountByID(holdingAccountID)
48524894
if err != nil {
48534895
return nil, err
48544896
}
48554897

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))
48574899
if err != nil {
48584900
return nil, err
48594901
}
@@ -4864,7 +4906,7 @@ func (e *Engine) ReleaseFromHoldingAccount(ctx context.Context, transfer *types.
48644906
Asset: transfer.Amount.Asset,
48654907
Type: types.TransferTypeReleaseHoldingAccount,
48664908
FromAccount: []*types.Account{holdingAccount},
4867-
ToAccount: []*types.Account{generalAccount},
4909+
ToAccount: []*types.Account{targetAccount},
48684910
}
48694911

48704912
res, err := e.getLedgerEntries(ctx, req)
@@ -5018,9 +5060,14 @@ func (e *Engine) CreateSpotMarketAccounts(ctx context.Context, marketID, quoteAs
50185060
return err
50195061
}
50205062

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)
50245071
if err != nil {
50255072
return err
50265073
}
@@ -5056,28 +5103,42 @@ func (e *Engine) CreatePartyHoldingAccount(ctx context.Context, partyID, asset s
50565103
}
50575104

50585105
// 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)
50635120
if err != nil {
50645121
return nil, err
50655122
}
50665123

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)
50695126
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+
}
50725133
}
50735134

50745135
req := &types.TransferRequest{
50755136
Amount: quantity.Clone(),
50765137
MinAmount: quantity.Clone(),
50775138
Asset: asset,
50785139
Type: types.TransferTypeSpot,
5079-
FromAccount: []*types.Account{generalAccount},
5080-
ToAccount: []*types.Account{toGeneralAccount},
5140+
FromAccount: []*types.Account{fromAccount},
5141+
ToAccount: []*types.Account{toAccount},
50815142
}
50825143

50835144
res, err := e.getLedgerEntries(ctx, req)
@@ -5130,3 +5191,54 @@ func (e *Engine) GetVestingAccounts() []*types.Account {
51305191
})
51315192
return accs
51325193
}
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

Comments
 (0)