code.vegaprotocol.io/vega@v0.79.0/core/governance/engine_new_automated_purchase_test.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package governance_test 17 18 import ( 19 "testing" 20 "time" 21 22 "code.vegaprotocol.io/vega/core/datasource" 23 "code.vegaprotocol.io/vega/core/datasource/definition" 24 "code.vegaprotocol.io/vega/core/netparams" 25 "code.vegaprotocol.io/vega/core/types" 26 "code.vegaprotocol.io/vega/libs/crypto" 27 "code.vegaprotocol.io/vega/libs/num" 28 vgrand "code.vegaprotocol.io/vega/libs/rand" 29 vgtest "code.vegaprotocol.io/vega/libs/test" 30 "code.vegaprotocol.io/vega/protos/vega" 31 v1 "code.vegaprotocol.io/vega/protos/vega/data/v1" 32 33 "github.com/golang/mock/gomock" 34 "github.com/stretchr/testify/require" 35 ) 36 37 func defaultPriceOracle() *datasource.Spec { 38 dp := uint64(5) 39 spec := &vega.DataSourceSpec{ 40 Data: &vega.DataSourceDefinition{ 41 SourceType: vega.DataSourceDefinition{ 42 SourceType: &vega.DataSourceDefinition_External{ 43 External: &vega.DataSourceDefinitionExternal{ 44 SourceType: &vega.DataSourceDefinitionExternal_Oracle{ 45 Oracle: &vega.DataSourceSpecConfiguration{ 46 Signers: []*v1.Signer{ 47 { 48 Signer: &v1.Signer_PubKey{ 49 PubKey: &v1.PubKey{ 50 Key: "0xiBADC0FFEE0DDF00D", 51 }, 52 }, 53 }, 54 }, 55 Filters: []*v1.Filter{ 56 { 57 Key: &v1.PropertyKey{ 58 Name: "oracle.price", 59 Type: v1.PropertyKey_TYPE_INTEGER, 60 NumberDecimalPlaces: &dp, 61 }, 62 Conditions: []*v1.Condition{ 63 { 64 Operator: v1.Condition_OPERATOR_UNSPECIFIED, 65 }, 66 }, 67 }, 68 }, 69 }, 70 }, 71 }, 72 }, 73 }.SourceType, 74 }, 75 } 76 specDef, _ := definition.FromProto(spec.Data, nil) 77 return datasource.SpecFromDefinition(*definition.NewWith(specDef)) 78 } 79 80 func defaultTimeTrigger() definition.Definition { 81 spec := &vega.DataSourceSpec{ 82 Data: &vega.DataSourceDefinition{ 83 SourceType: vega.DataSourceDefinition{ 84 SourceType: &vega.DataSourceDefinition_Internal{ 85 Internal: &vega.DataSourceDefinitionInternal{ 86 SourceType: &vega.DataSourceDefinitionInternal_TimeTrigger{ 87 TimeTrigger: &vega.DataSourceSpecConfigurationTimeTrigger{ 88 Triggers: []*v1.InternalTimeTrigger{ 89 { 90 Every: 10, 91 }, 92 }, 93 }, 94 }, 95 }, 96 }, 97 }.SourceType, 98 }, 99 } 100 101 specDef, _ := definition.FromProto(spec.Data, nil) 102 return datasource.SpecFromDefinition(*definition.NewWith(specDef)).GetDefinition() 103 } 104 105 func TestProposalForNewProtocolAutomatedPurchase(t *testing.T) { 106 t.Run("Submitting a proposal for new automated purchase succeeds", testSubmittingProposalForNewProtocolAutomatedPurchaseSucceeds) 107 t.Run("Submitting a proposal for new automated purchase with invalid asset fails", testSubmittingProposalForNewProtocolAutomatedPurchaseInvalidAssetFails) 108 t.Run("Submitting a proposal for new automated purchase with invalid market fails", testSubmittingProposalForNewProtocolAutomatedPurchaseInvalidMarketFails) 109 t.Run("Submitting a proposal for new automated purchase with a market that is not a spot market fails", testSubmittingProposalForNewProtocolAutomatedPurchaseNotSpotMarketFails) 110 t.Run("Submitting a proposal for new automated purchase with invalid asset for spot market fails", testSubmittingProposalForNewProtocolAutomatedPurchaseInvalidAssetForMarketFails) 111 t.Run("Submitting a proposal for new automated purchase to a stopped market fails", testSubmittingProposalForNewProtocolAutomatedPurchaseStoppedMarketWithStateFails) 112 t.Run("Submitting a proposal for new automated purchase to a market which already has an active pap fails", testSubmittingPAPToMarketWithActivePAPFails) 113 } 114 115 func testSubmittingProposalForNewProtocolAutomatedPurchaseSucceeds(t *testing.T) { 116 now := time.Now() 117 ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64()) 118 eng := getTestEngine(t, now) 119 120 // setup 121 eng.broker.EXPECT().Send(gomock.Any()).Times(3) 122 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinClose, "48h") 123 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinEnact, "48h") 124 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinProposerBalance, "1000") 125 126 eng.markets.EXPECT().GetMarket(gomock.Any(), gomock.Any()).Return(types.Market{ 127 TradableInstrument: types.TradableInstrumentFromProto(&vega.TradableInstrument{ 128 RiskModel: &vega.TradableInstrument_SimpleRiskModel{ 129 SimpleRiskModel: &vega.SimpleRiskModel{ 130 Params: &vega.SimpleModelParams{}, 131 }, 132 }, 133 Instrument: &vega.Instrument{ 134 Product: &vega.Instrument_Spot{ 135 Spot: &vega.Spot{ 136 BaseAsset: "base", 137 QuoteAsset: "quote", 138 }, 139 }, 140 Metadata: &vega.InstrumentMetadata{}, 141 }, 142 }), 143 }, true).AnyTimes() 144 eng.assets.EXPECT().IsEnabled(gomock.Any()).Return(true).AnyTimes() 145 eng.markets.EXPECT().MarketHasActivePAP(gomock.Any()).Return(false, nil).AnyTimes() 146 147 // given 148 proposer := vgrand.RandomStr(5) 149 proposal := eng.newProposalForNewProtocolAutomatedPurchase(proposer, now, &types.NewProtocolAutomatedPurchaseChanges{ 150 ExpiryTimestamp: now.Add(4 * 48 * time.Hour), 151 From: "base", 152 FromAccountType: types.AccountTypeBuyBackFees, 153 ToAccountType: types.AccountTypeBuyBackFees, 154 MarketID: crypto.RandomHash(), 155 PriceOracle: defaultPriceOracle(), 156 PriceOracleBinding: &vega.SpecBindingForCompositePrice{ 157 PriceSourceProperty: "oracle.price", 158 }, 159 OracleOffsetFactor: num.DecimalFromFloat(0.1), 160 AuctionSchedule: defaultTimeTrigger(), 161 AuctionVolumeSnapshotSchedule: defaultTimeTrigger(), 162 AutomatedPurchaseSpecBinding: &vega.DataSourceSpecToAutomatedPurchaseBinding{}, 163 AuctionDuration: time.Hour, 164 MinimumAuctionSize: num.NewUint(1000), 165 MaximumAuctionSize: num.NewUint(2000), 166 }) 167 168 // setup 169 eng.ensureTokenBalanceForParty(t, proposer, 1000) 170 171 // expect 172 eng.expectOpenProposalEvent(t, proposer, proposal.ID) 173 174 // when 175 toSubmit, err := eng.submitProposal(t, proposal) 176 177 // then 178 require.NoError(t, err) 179 require.NotNil(t, toSubmit) 180 } 181 182 func setupPAP(t *testing.T) (*tstEngine, types.Proposal) { 183 t.Helper() 184 now := time.Now() 185 ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64()) 186 eng := getTestEngine(t, now) 187 188 // setup 189 eng.broker.EXPECT().Send(gomock.Any()).Times(3) 190 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinClose, "48h") 191 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinEnact, "48h") 192 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinProposerBalance, "1000") 193 194 eng.markets.EXPECT().GetMarket(gomock.Any(), gomock.Any()).Return(types.Market{ 195 TradableInstrument: types.TradableInstrumentFromProto(&vega.TradableInstrument{ 196 RiskModel: &vega.TradableInstrument_SimpleRiskModel{ 197 SimpleRiskModel: &vega.SimpleRiskModel{ 198 Params: &vega.SimpleModelParams{}, 199 }, 200 }, 201 Instrument: &vega.Instrument{ 202 Product: &vega.Instrument_Spot{ 203 Spot: &vega.Spot{ 204 BaseAsset: "base", 205 QuoteAsset: "quote", 206 }, 207 }, 208 Metadata: &vega.InstrumentMetadata{}, 209 }, 210 }), 211 }, true).AnyTimes() 212 eng.assets.EXPECT().IsEnabled(gomock.Any()).Return(true).AnyTimes() 213 214 // given 215 proposer := vgrand.RandomStr(5) 216 proposal := eng.newProposalForNewProtocolAutomatedPurchase(proposer, now, &types.NewProtocolAutomatedPurchaseChanges{ 217 ExpiryTimestamp: now.Add(4 * 48 * time.Hour), 218 From: "base", 219 FromAccountType: types.AccountTypeBuyBackFees, 220 ToAccountType: types.AccountTypeBuyBackFees, 221 MarketID: crypto.RandomHash(), 222 PriceOracle: defaultPriceOracle(), 223 PriceOracleBinding: &vega.SpecBindingForCompositePrice{ 224 PriceSourceProperty: "oracle.price", 225 }, 226 OracleOffsetFactor: num.DecimalFromFloat(0.1), 227 AuctionSchedule: defaultTimeTrigger(), 228 AuctionVolumeSnapshotSchedule: defaultTimeTrigger(), 229 AutomatedPurchaseSpecBinding: &vega.DataSourceSpecToAutomatedPurchaseBinding{}, 230 AuctionDuration: time.Hour, 231 MinimumAuctionSize: num.NewUint(1000), 232 MaximumAuctionSize: num.NewUint(2000), 233 }) 234 return eng, proposal 235 } 236 237 func testSubmittingPAPToMarketWithActivePAPFails(t *testing.T) { 238 eng, proposal := setupPAP(t) 239 // setup 240 eng.markets.EXPECT().MarketHasActivePAP(gomock.Any()).Return(false, nil).Times(1) 241 eng.ensureTokenBalanceForParty(t, proposal.Party, 1000) 242 243 // expect 244 eng.expectOpenProposalEvent(t, proposal.Party, proposal.ID) 245 246 // when 247 toSubmit, err := eng.submitProposal(t, proposal) 248 249 // then 250 require.NoError(t, err) 251 require.NotNil(t, toSubmit) 252 253 // now resubmit to the same market when this one is already active 254 proposal.ID = crypto.RandomHash() 255 eng.markets.EXPECT().MarketHasActivePAP(gomock.Any()).Return(true, nil).Times(1) 256 eng.ensureTokenBalanceForParty(t, proposal.Party, 1000) 257 // expect 258 eng.expectRejectedProposalEvent(t, proposal.Party, proposal.ID, types.ProposalErrorInvalidMarket) 259 260 // when 261 _, err = eng.submitProposal(t, proposal) 262 263 // then 264 require.Equal(t, "market already has an active protocol automated purchase program", err.Error()) 265 } 266 267 func testSubmittingProposalForNewProtocolAutomatedPurchaseInvalidAssetFails(t *testing.T) { 268 now := time.Now() 269 ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64()) 270 eng := getTestEngine(t, now) 271 272 // setup 273 eng.broker.EXPECT().Send(gomock.Any()).Times(3) 274 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinClose, "48h") 275 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinEnact, "48h") 276 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinProposerBalance, "1000") 277 278 eng.markets.EXPECT().GetMarket(gomock.Any(), gomock.Any()).Return(types.Market{ 279 TradableInstrument: types.TradableInstrumentFromProto(&vega.TradableInstrument{ 280 RiskModel: &vega.TradableInstrument_SimpleRiskModel{ 281 SimpleRiskModel: &vega.SimpleRiskModel{ 282 Params: &vega.SimpleModelParams{}, 283 }, 284 }, 285 Instrument: &vega.Instrument{ 286 Product: &vega.Instrument_Spot{ 287 Spot: &vega.Spot{ 288 BaseAsset: "base", 289 QuoteAsset: "quote", 290 }, 291 }, 292 Metadata: &vega.InstrumentMetadata{}, 293 }, 294 }), 295 }, true).AnyTimes() 296 eng.assets.EXPECT().IsEnabled(gomock.Any()).Return(false).AnyTimes() 297 298 // given 299 proposer := vgrand.RandomStr(5) 300 proposal := eng.newProposalForNewProtocolAutomatedPurchase(proposer, now, &types.NewProtocolAutomatedPurchaseChanges{ 301 ExpiryTimestamp: now.Add(4 * 48 * time.Hour), 302 From: "base", 303 FromAccountType: types.AccountTypeBuyBackFees, 304 ToAccountType: types.AccountTypeBuyBackFees, 305 MarketID: crypto.RandomHash(), 306 PriceOracle: defaultPriceOracle(), 307 PriceOracleBinding: &vega.SpecBindingForCompositePrice{ 308 PriceSourceProperty: "oracle.price", 309 }, 310 OracleOffsetFactor: num.DecimalFromFloat(0.1), 311 AuctionSchedule: defaultTimeTrigger(), 312 AuctionVolumeSnapshotSchedule: defaultTimeTrigger(), 313 AutomatedPurchaseSpecBinding: &vega.DataSourceSpecToAutomatedPurchaseBinding{}, 314 AuctionDuration: time.Hour, 315 MinimumAuctionSize: num.NewUint(1000), 316 MaximumAuctionSize: num.NewUint(2000), 317 }) 318 319 // setup 320 eng.ensureTokenBalanceForParty(t, proposer, 1000) 321 322 // expect 323 eng.expectRejectedProposalEvent(t, proposer, proposal.ID, types.ProposalErrorInvalidAsset) 324 325 // when 326 _, err := eng.submitProposal(t, proposal) 327 328 // then 329 require.Error(t, err) 330 require.Equal(t, "asset does not exist", err.Error()) 331 } 332 333 func testSubmittingProposalForNewProtocolAutomatedPurchaseInvalidMarketFails(t *testing.T) { 334 now := time.Now() 335 ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64()) 336 eng := getTestEngine(t, now) 337 338 // setup 339 eng.broker.EXPECT().Send(gomock.Any()).Times(3) 340 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinClose, "48h") 341 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinEnact, "48h") 342 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinProposerBalance, "1000") 343 344 eng.markets.EXPECT().GetMarket(gomock.Any(), gomock.Any()).Return(types.Market{}, false).AnyTimes() 345 eng.assets.EXPECT().IsEnabled(gomock.Any()).Return(true).AnyTimes() 346 347 // given 348 proposer := vgrand.RandomStr(5) 349 proposal := eng.newProposalForNewProtocolAutomatedPurchase(proposer, now, &types.NewProtocolAutomatedPurchaseChanges{ 350 ExpiryTimestamp: now.Add(4 * 48 * time.Hour), 351 From: "base", 352 FromAccountType: types.AccountTypeBuyBackFees, 353 ToAccountType: types.AccountTypeBuyBackFees, 354 MarketID: crypto.RandomHash(), 355 PriceOracle: defaultPriceOracle(), 356 PriceOracleBinding: &vega.SpecBindingForCompositePrice{ 357 PriceSourceProperty: "oracle.price", 358 }, 359 OracleOffsetFactor: num.DecimalFromFloat(0.1), 360 AuctionSchedule: defaultTimeTrigger(), 361 AuctionVolumeSnapshotSchedule: defaultTimeTrigger(), 362 AutomatedPurchaseSpecBinding: &vega.DataSourceSpecToAutomatedPurchaseBinding{}, 363 AuctionDuration: time.Hour, 364 MinimumAuctionSize: num.NewUint(1000), 365 MaximumAuctionSize: num.NewUint(2000), 366 }) 367 368 // setup 369 eng.ensureTokenBalanceForParty(t, proposer, 1000) 370 371 // expect 372 eng.expectRejectedProposalEvent(t, proposer, proposal.ID, types.ProposalErrorInvalidMarket) 373 374 // when 375 _, err := eng.submitProposal(t, proposal) 376 377 // then 378 require.Error(t, err) 379 require.Equal(t, "market does not exist", err.Error()) 380 } 381 382 func testSubmittingProposalForNewProtocolAutomatedPurchaseInvalidAssetForMarketFails(t *testing.T) { 383 now := time.Now() 384 ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64()) 385 eng := getTestEngine(t, now) 386 387 // setup 388 eng.broker.EXPECT().Send(gomock.Any()).Times(3) 389 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinClose, "48h") 390 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinEnact, "48h") 391 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinProposerBalance, "1000") 392 393 eng.markets.EXPECT().GetMarket(gomock.Any(), gomock.Any()).Return(types.Market{ 394 TradableInstrument: types.TradableInstrumentFromProto(&vega.TradableInstrument{ 395 RiskModel: &vega.TradableInstrument_SimpleRiskModel{ 396 SimpleRiskModel: &vega.SimpleRiskModel{ 397 Params: &vega.SimpleModelParams{}, 398 }, 399 }, 400 Instrument: &vega.Instrument{ 401 Product: &vega.Instrument_Spot{ 402 Spot: &vega.Spot{ 403 BaseAsset: "base", 404 QuoteAsset: "quote", 405 }, 406 }, 407 Metadata: &vega.InstrumentMetadata{}, 408 }, 409 }), 410 }, true).AnyTimes() 411 eng.assets.EXPECT().IsEnabled(gomock.Any()).Return(true).AnyTimes() 412 413 // given 414 proposer := vgrand.RandomStr(5) 415 proposal := eng.newProposalForNewProtocolAutomatedPurchase(proposer, now, &types.NewProtocolAutomatedPurchaseChanges{ 416 ExpiryTimestamp: now.Add(4 * 48 * time.Hour), 417 From: "neither_base_nor_quote", 418 FromAccountType: types.AccountTypeBuyBackFees, 419 ToAccountType: types.AccountTypeBuyBackFees, 420 MarketID: crypto.RandomHash(), 421 PriceOracle: defaultPriceOracle(), 422 PriceOracleBinding: &vega.SpecBindingForCompositePrice{ 423 PriceSourceProperty: "oracle.price", 424 }, 425 OracleOffsetFactor: num.DecimalFromFloat(0.1), 426 AuctionSchedule: defaultTimeTrigger(), 427 AuctionVolumeSnapshotSchedule: defaultTimeTrigger(), 428 AutomatedPurchaseSpecBinding: &vega.DataSourceSpecToAutomatedPurchaseBinding{}, 429 AuctionDuration: time.Hour, 430 MinimumAuctionSize: num.NewUint(1000), 431 MaximumAuctionSize: num.NewUint(2000), 432 }) 433 434 // setup 435 eng.ensureTokenBalanceForParty(t, proposer, 1000) 436 437 // expect 438 eng.expectRejectedProposalEvent(t, proposer, proposal.ID, types.ProposalErrorInvalidMarket) 439 440 // when 441 _, err := eng.submitProposal(t, proposal) 442 443 // then 444 require.Error(t, err) 445 require.Equal(t, "mismatch between asset for automated purchase and the spot market configuration - asset is not one of base/quote assets of the market", err.Error()) 446 } 447 448 func testSubmittingProposalForNewProtocolAutomatedPurchaseNotSpotMarketFails(t *testing.T) { 449 now := time.Now() 450 ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64()) 451 eng := getTestEngine(t, now) 452 453 // setup 454 eng.broker.EXPECT().Send(gomock.Any()).Times(3) 455 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinClose, "48h") 456 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinEnact, "48h") 457 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinProposerBalance, "1000") 458 459 eng.markets.EXPECT().GetMarket(gomock.Any(), gomock.Any()).Return(types.Market{ 460 TradableInstrument: types.TradableInstrumentFromProto(&vega.TradableInstrument{ 461 RiskModel: &vega.TradableInstrument_SimpleRiskModel{ 462 SimpleRiskModel: &vega.SimpleRiskModel{ 463 Params: &vega.SimpleModelParams{}, 464 }, 465 }, 466 Instrument: &vega.Instrument{ 467 Product: &vega.Instrument_Future{ 468 Future: &vega.Future{ 469 SettlementAsset: "some_future", 470 DataSourceSpecForSettlementData: &vega.DataSourceSpec{}, 471 DataSourceSpecForTradingTermination: &vega.DataSourceSpec{}, 472 DataSourceSpecBinding: &vega.DataSourceSpecToFutureBinding{}, 473 }, 474 }, 475 Metadata: &vega.InstrumentMetadata{}, 476 }, 477 }), 478 }, true).AnyTimes() 479 eng.assets.EXPECT().IsEnabled(gomock.Any()).Return(true).AnyTimes() 480 481 // given 482 proposer := vgrand.RandomStr(5) 483 proposal := eng.newProposalForNewProtocolAutomatedPurchase(proposer, now, &types.NewProtocolAutomatedPurchaseChanges{ 484 ExpiryTimestamp: now.Add(4 * 48 * time.Hour), 485 From: "neither_base_nor_quote", 486 FromAccountType: types.AccountTypeBuyBackFees, 487 ToAccountType: types.AccountTypeBuyBackFees, 488 MarketID: crypto.RandomHash(), 489 PriceOracle: defaultPriceOracle(), 490 PriceOracleBinding: &vega.SpecBindingForCompositePrice{ 491 PriceSourceProperty: "oracle.price", 492 }, 493 OracleOffsetFactor: num.DecimalFromFloat(0.1), 494 AuctionSchedule: defaultTimeTrigger(), 495 AuctionVolumeSnapshotSchedule: defaultTimeTrigger(), 496 AutomatedPurchaseSpecBinding: &vega.DataSourceSpecToAutomatedPurchaseBinding{}, 497 AuctionDuration: time.Hour, 498 MinimumAuctionSize: num.NewUint(1000), 499 MaximumAuctionSize: num.NewUint(2000), 500 }) 501 502 // setup 503 eng.ensureTokenBalanceForParty(t, proposer, 1000) 504 505 // expect 506 eng.expectRejectedProposalEvent(t, proposer, proposal.ID, types.ProposalErrorInvalidMarket) 507 508 // when 509 _, err := eng.submitProposal(t, proposal) 510 511 // then 512 require.Error(t, err) 513 require.Equal(t, "market for automated purchase must be a spot market", err.Error()) 514 } 515 516 func testSubmittingProposalForNewProtocolAutomatedPurchaseStoppedMarketFailes(t *testing.T, state types.MarketState) { 517 t.Helper() 518 now := time.Now() 519 ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64()) 520 eng := getTestEngine(t, now) 521 522 // setup 523 eng.broker.EXPECT().Send(gomock.Any()).Times(3) 524 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinClose, "48h") 525 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinEnact, "48h") 526 eng.netp.Update(ctx, netparams.GovernanceProposalAutomatedPurchaseConfigMinProposerBalance, "1000") 527 528 eng.markets.EXPECT().GetMarket(gomock.Any(), gomock.Any()).Return(types.Market{ 529 State: state, 530 TradableInstrument: types.TradableInstrumentFromProto(&vega.TradableInstrument{ 531 RiskModel: &vega.TradableInstrument_SimpleRiskModel{ 532 SimpleRiskModel: &vega.SimpleRiskModel{ 533 Params: &vega.SimpleModelParams{}, 534 }, 535 }, 536 Instrument: &vega.Instrument{ 537 Product: &vega.Instrument_Spot{ 538 Spot: &vega.Spot{ 539 BaseAsset: "base", 540 QuoteAsset: "quote", 541 }, 542 }, 543 Metadata: &vega.InstrumentMetadata{}, 544 }, 545 }), 546 }, true).AnyTimes() 547 eng.assets.EXPECT().IsEnabled(gomock.Any()).Return(true).AnyTimes() 548 eng.markets.EXPECT().MarketHasActivePAP(gomock.Any()).Return(false, nil).AnyTimes() 549 550 // given 551 proposer := vgrand.RandomStr(5) 552 proposal := eng.newProposalForNewProtocolAutomatedPurchase(proposer, now, &types.NewProtocolAutomatedPurchaseChanges{ 553 ExpiryTimestamp: now.Add(4 * 48 * time.Hour), 554 From: "base", 555 FromAccountType: types.AccountTypeBuyBackFees, 556 ToAccountType: types.AccountTypeBuyBackFees, 557 MarketID: crypto.RandomHash(), 558 PriceOracle: defaultPriceOracle(), 559 PriceOracleBinding: &vega.SpecBindingForCompositePrice{ 560 PriceSourceProperty: "oracle.price", 561 }, 562 OracleOffsetFactor: num.DecimalFromFloat(0.1), 563 AuctionSchedule: defaultTimeTrigger(), 564 AuctionVolumeSnapshotSchedule: defaultTimeTrigger(), 565 AutomatedPurchaseSpecBinding: &vega.DataSourceSpecToAutomatedPurchaseBinding{}, 566 AuctionDuration: time.Hour, 567 MinimumAuctionSize: num.NewUint(1000), 568 MaximumAuctionSize: num.NewUint(2000), 569 }) 570 571 // setup 572 eng.ensureTokenBalanceForParty(t, proposer, 1000) 573 574 // expect 575 eng.expectRejectedProposalEvent(t, proposer, proposal.ID, types.ProposalErrorInvalidMarket) 576 577 // when 578 _, err := eng.submitProposal(t, proposal) 579 580 // then 581 require.Error(t, err) 582 require.Equal(t, "market for automated purchase must be active", err.Error()) 583 } 584 585 func testSubmittingProposalForNewProtocolAutomatedPurchaseStoppedMarketWithStateFails(t *testing.T) { 586 stoppedStates := []types.MarketState{types.MarketStateCancelled, types.MarketStateClosed, types.MarketStateRejected, types.MarketStateSettled, types.MarketStateTradingTerminated} 587 for _, state := range stoppedStates { 588 testSubmittingProposalForNewProtocolAutomatedPurchaseStoppedMarketFailes(t, state) 589 } 590 }