code.vegaprotocol.io/vega@v0.79.0/core/governance/engine_update_spot_market_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 "context" 20 "testing" 21 "time" 22 23 "code.vegaprotocol.io/vega/core/governance" 24 "code.vegaprotocol.io/vega/core/netparams" 25 "code.vegaprotocol.io/vega/core/types" 26 vgrand "code.vegaprotocol.io/vega/libs/rand" 27 28 "github.com/stretchr/testify/assert" 29 "github.com/stretchr/testify/require" 30 ) 31 32 func TestProposalForSpotMarketUpdate(t *testing.T) { 33 t.Run("Submitting a proposal for spot market update succeeds", testSubmittingProposalForSpotMarketUpdateSucceeds) 34 t.Run("Submitting a proposal for market update on unknown spot market fails", testSubmittingProposalForMarketUpdateForUnknownSpotMarketFails) 35 36 t.Run("Submitting a proposal for market update for not-enacted market fails", testSubmittingProposalForSpotMarketUpdateForNotEnactedMarketFails) 37 t.Run("Submitting a proposal for spot market update with insufficient equity-like share fails", testSubmittingProposalForSpotMarketUpdateWithInsufficientEquityLikeShareFails) 38 t.Run("Pre-enactment of spot market update proposal succeeds", testPreEnactmentOfSpotMarketUpdateSucceeds) 39 40 t.Run("Rejecting a proposal for market update succeeds", testRejectingProposalForSpotMarketUpdateSucceeds) 41 42 t.Run("Voting without reaching minimum of tokens and equity-like shares makes the spot market update proposal declined", testVotingWithoutMinimumTokenHoldersAndEquityLikeShareMakesSpotMarketUpdateProposalPassed) 43 t.Run("Voting with a majority of 'yes' from tokens makes the spot market update proposal passed", testVotingWithMajorityOfYesFromTokenHoldersMakesSpotMarketUpdateProposalPassed) 44 t.Run("Voting with a majority of 'no' from tokens makes the spot market update proposal declined", testVotingWithMajorityOfNoFromTokenHoldersMakesSpotMarketUpdateProposalDeclined) 45 t.Run("Voting without reaching minimum of tokens and a majority of 'yes' from equity-like shares makes the spot market update proposal passed", testVotingWithoutTokenAndMajorityOfYesFromEquityLikeShareHoldersMakesSpotMarketUpdateProposalPassed) 46 t.Run("Voting without reaching minimum of tokens and a majority of 'no' from equity-like shares makes the spot market update proposal declined", testVotingWithoutTokenAndMajorityOfNoFromEquityLikeShareHoldersMakesSpotMarketUpdateProposalDeclined) 47 } 48 49 func testSubmittingProposalForSpotMarketUpdateSucceeds(t *testing.T) { 50 eng := getTestEngine(t, time.Now()) 51 52 // given 53 proposer := vgrand.RandomStr(5) 54 proposal := eng.newProposalForSpotMarketUpdate("market-1", proposer, eng.tsvc.GetTimeNow()) 55 marketID := proposal.SpotMarketUpdate().MarketID 56 57 // setup 58 eng.ensureTokenBalanceForParty(t, proposer, 1000) 59 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, proposer, 0.1) 60 eng.ensureExistingMarket(t, marketID) 61 eng.ensureGetMarketSpot(t, marketID) 62 63 // expect 64 eng.expectOpenProposalEvent(t, proposer, proposal.ID) 65 66 // when 67 toSubmit, err := eng.submitProposal(t, proposal) 68 69 // then 70 require.NoError(t, err) 71 require.NotNil(t, toSubmit) 72 } 73 74 func testSubmittingProposalForMarketUpdateForUnknownSpotMarketFails(t *testing.T) { 75 eng := getTestEngine(t, time.Now()) 76 77 // given 78 proposer := vgrand.RandomStr(5) 79 proposal := eng.newProposalForSpotMarketUpdate("״market-1", proposer, eng.tsvc.GetTimeNow()) 80 marketID := proposal.SpotMarketUpdate().MarketID 81 82 // setup 83 eng.ensureTokenBalanceForParty(t, proposer, 123456789) 84 eng.ensureNonExistingMarket(t, marketID) 85 86 // expect 87 eng.expectRejectedProposalEvent(t, proposer, proposal.ID, types.ProposalErrorInvalidMarket) 88 89 // when 90 toSubmit, err := eng.submitProposal(t, proposal) 91 92 // then 93 require.ErrorIs(t, governance.ErrMarketDoesNotExist, err) 94 require.Nil(t, toSubmit) 95 } 96 97 func testSubmittingProposalForSpotMarketUpdateForNotEnactedMarketFails(t *testing.T) { 98 eng := getTestEngine(t, time.Now()) 99 100 // given 101 proposer := vgrand.RandomStr(5) 102 newMarketProposal := eng.newProposalForNewSpotMarket(proposer, eng.tsvc.GetTimeNow().Add(2*time.Hour)) 103 marketID := newMarketProposal.ID 104 105 // setup 106 eng.ensureAllAssetEnabled(t) 107 eng.ensureTokenBalanceForParty(t, proposer, 123456789) 108 eng.expectOpenProposalEvent(t, proposer, marketID) 109 110 // when 111 toSubmit, err := eng.submitProposal(t, newMarketProposal) 112 113 // then 114 require.NoError(t, err) 115 require.NotNil(t, toSubmit) 116 assert.True(t, toSubmit.IsNewSpotMarket()) 117 118 // given 119 updateMarketProposal := eng.newProposalForSpotMarketUpdate("״market-1", proposer, eng.tsvc.GetTimeNow()) 120 updateMarketProposal.SpotMarketUpdate().MarketID = marketID 121 122 // setup 123 eng.ensureTokenBalanceForParty(t, proposer, 123456789) 124 eng.ensureExistingMarket(t, marketID) 125 126 // expect 127 eng.expectRejectedProposalEvent(t, proposer, updateMarketProposal.ID, types.ProposalErrorInvalidMarket) 128 129 // when 130 toSubmit, err = eng.submitProposal(t, updateMarketProposal) 131 132 // then 133 require.ErrorIs(t, governance.ErrMarketProposalStillOpen, err) 134 require.Nil(t, toSubmit) 135 136 // now the original market proposal passes 137 // given 138 voter1 := vgrand.RandomStr(5) 139 eng.ensureTokenBalanceForParty(t, voter1, 7) 140 eng.expectVoteEvent(t, voter1, marketID) 141 err = eng.addYesVote(t, voter1, marketID) 142 require.NoError(t, err) 143 144 afterClosing := time.Unix(newMarketProposal.Terms.ClosingTimestamp, 0).Add(time.Second) 145 eng.ensureStakingAssetTotalSupply(t, 10) 146 eng.ensureTokenBalanceForParty(t, voter1, 7) 147 eng.expectPassedProposalEvent(t, marketID) 148 eng.expectTotalGovernanceTokenFromVoteEvents(t, "1", "7") 149 eng.expectGetMarketState(t, marketID) 150 eng.OnTick(context.Background(), afterClosing) 151 152 // submitting now the market proposal has passed should work 153 eng.ensureTokenBalanceForParty(t, proposer, 1000) 154 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, proposer, 0.1) 155 eng.ensureExistingMarket(t, marketID) 156 eng.ensureGetMarketFuture(t, marketID) 157 eng.expectOpenProposalEvent(t, proposer, updateMarketProposal.ID) 158 toSubmit, err = eng.submitProposal(t, updateMarketProposal) 159 require.NoError(t, err) 160 require.NotNil(t, toSubmit) 161 } 162 163 func testSubmittingProposalForSpotMarketUpdateWithInsufficientEquityLikeShareFails(t *testing.T) { 164 eng := getTestEngine(t, time.Now()) 165 166 // given 167 party := vgrand.RandomStr(5) 168 proposal := eng.newProposalForSpotMarketUpdate("״market-1", party, eng.tsvc.GetTimeNow()) 169 marketID := proposal.SpotMarketUpdate().MarketID 170 171 // setup 172 // eng.ensureTokenBalanceForParty(t, party, 100) 173 eng.ensureExistingMarket(t, marketID) 174 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, party, 0.05) 175 176 // expect 177 eng.expectRejectedProposalEvent(t, party, proposal.ID, types.ProposalErrorInsufficientTokens) 178 179 // when 180 toSubmit, err := eng.submitProposal(t, proposal) 181 182 // then 183 require.Error(t, err) 184 assert.Contains(t, err.Error(), "no balance for party") 185 require.Nil(t, toSubmit) 186 } 187 188 func testPreEnactmentOfSpotMarketUpdateSucceeds(t *testing.T) { 189 eng := getTestEngine(t, time.Now()) 190 191 // Submit proposal. 192 // given 193 proposer := vgrand.RandomStr(5) 194 proposal := eng.newProposalForSpotMarketUpdate("״market-1", proposer, eng.tsvc.GetTimeNow()) 195 marketID := proposal.SpotMarketUpdate().MarketID 196 197 // setup 198 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, proposer, 0.7) 199 eng.ensureExistingMarket(t, marketID) 200 eng.ensureGetMarketSpot(t, marketID) 201 eng.ensureTokenBalanceForParty(t, proposer, 1) 202 eng.ensureAllAssetEnabled(t) 203 204 // expect 205 eng.expectOpenProposalEvent(t, proposer, proposal.ID) 206 207 // when 208 _, err := eng.submitProposal(t, proposal) 209 210 // then 211 require.NoError(t, err) 212 213 // Vote 'YES' with 10 tokens. 214 // given 215 voterWithToken1 := vgrand.RandomStr(5) 216 217 // setup 218 eng.ensureTokenBalanceForParty(t, voterWithToken1, 10) 219 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithToken1, 0) 220 221 // expect 222 eng.expectVoteEvent(t, voterWithToken1, proposal.ID) 223 224 // when 225 err = eng.addYesVote(t, voterWithToken1, proposal.ID) 226 227 // then 228 require.NoError(t, err) 229 230 // Vote 'NO' with 2 tokens. 231 // given 232 voterWithToken2 := vgrand.RandomStr(5) 233 234 // setup 235 eng.ensureTokenBalanceForParty(t, voterWithToken2, 2) 236 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithToken2, 0) 237 238 // expect 239 eng.expectVoteEvent(t, voterWithToken2, proposal.ID) 240 241 // then 242 err = eng.addNoVote(t, voterWithToken2, proposal.ID) 243 244 // then 245 require.NoError(t, err) 246 247 // Close the proposal. 248 // given 249 afterClosing := time.Unix(proposal.Terms.ClosingTimestamp, 0).Add(time.Second) 250 251 // setup 252 eng.ensureStakingAssetTotalSupply(t, 13) 253 eng.ensureTokenBalanceForParty(t, voterWithToken1, 10) 254 eng.ensureTokenBalanceForParty(t, voterWithToken2, 2) 255 256 // expect 257 eng.expectPassedProposalEvent(t, proposal.ID) 258 eng.expectVoteEvents(t) 259 eng.expectGetMarketState(t, marketID) 260 261 // when 262 eng.OnTick(context.Background(), afterClosing) 263 264 // Enact the proposal. 265 // given 266 afterEnactment := time.Unix(proposal.Terms.EnactmentTimestamp, 0).Add(time.Second) 267 existingMarket := types.Market{ 268 ID: marketID, 269 TradableInstrument: &types.TradableInstrument{ 270 Instrument: &types.Instrument{ 271 Name: vgrand.RandomStr(10), 272 Product: &types.InstrumentSpot{ 273 Spot: &types.Spot{ 274 Name: "BTC/USDT", 275 BaseAsset: "BTC", 276 QuoteAsset: "USDT", 277 }, 278 }, 279 }, 280 }, 281 DecimalPlaces: 3, 282 PositionDecimalPlaces: 4, 283 OpeningAuction: &types.AuctionDuration{ 284 Duration: 42, 285 }, 286 } 287 288 // setup 289 eng.ensureGetMarket(t, marketID, existingMarket) 290 291 // when 292 enacted, _ := eng.OnTick(context.Background(), afterEnactment) 293 294 // then 295 require.NotEmpty(t, enacted) 296 require.True(t, enacted[0].IsUpdateSpotMarket()) 297 updatedMarket := enacted[0].UpdateSpotMarket() 298 assert.Equal(t, existingMarket.ID, updatedMarket.ID) 299 assert.Equal(t, existingMarket.TradableInstrument.Instrument.Product.(*types.InstrumentSpot).Spot.BaseAsset, updatedMarket.TradableInstrument.Instrument.Product.(*types.InstrumentSpot).Spot.BaseAsset) 300 assert.Equal(t, existingMarket.TradableInstrument.Instrument.Product.(*types.InstrumentSpot).Spot.QuoteAsset, updatedMarket.TradableInstrument.Instrument.Product.(*types.InstrumentSpot).Spot.QuoteAsset) 301 assert.Equal(t, existingMarket.DecimalPlaces, updatedMarket.DecimalPlaces) 302 assert.Equal(t, existingMarket.PositionDecimalPlaces, updatedMarket.PositionDecimalPlaces) 303 assert.Equal(t, existingMarket.OpeningAuction.Duration, updatedMarket.OpeningAuction.Duration) 304 } 305 306 func testRejectingProposalForSpotMarketUpdateSucceeds(t *testing.T) { 307 eng := getTestEngine(t, time.Now()) 308 309 // given 310 party := vgrand.RandomStr(5) 311 proposal := eng.newProposalForSpotMarketUpdate("market-1", party, eng.tsvc.GetTimeNow()) 312 marketID := proposal.SpotMarketUpdate().MarketID 313 314 // setup 315 eng.ensureAllAssetEnabled(t) 316 eng.ensureExistingMarket(t, marketID) 317 eng.ensureGetMarketSpot(t, marketID) 318 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, party, 0.7) 319 eng.ensureNetworkParameter(t, netparams.GovernanceProposalUpdateMarketMinProposerEquityLikeShare, "0.1") 320 eng.ensureTokenBalanceForParty(t, party, 10000) 321 322 // expect 323 eng.expectOpenProposalEvent(t, party, proposal.ID) 324 325 // when 326 toSubmit, err := eng.submitProposal(t, proposal) 327 328 // then 329 require.NoError(t, err) 330 require.NotNil(t, toSubmit) 331 332 // expect 333 eng.expectRejectedProposalEvent(t, party, proposal.ID, types.ProposalErrorCouldNotInstantiateMarket) 334 335 // when 336 err = eng.RejectProposal(context.Background(), toSubmit.Proposal(), types.ProposalErrorCouldNotInstantiateMarket, assert.AnError) 337 338 // then 339 require.NoError(t, err) 340 341 // when 342 // Just one more time to make sure it was removed from proposals. 343 err = eng.RejectProposal(context.Background(), toSubmit.Proposal(), types.ProposalErrorCouldNotInstantiateMarket, assert.AnError) 344 345 // then 346 assert.EqualError(t, err, governance.ErrProposalDoesNotExist.Error()) 347 } 348 349 func testVotingWithoutMinimumTokenHoldersAndEquityLikeShareMakesSpotMarketUpdateProposalPassed(t *testing.T) { 350 eng := getTestEngine(t, time.Now()) 351 352 // Submit proposal. 353 // given 354 proposer := vgrand.RandomStr(5) 355 proposal := eng.newProposalForSpotMarketUpdate("״market-1", proposer, eng.tsvc.GetTimeNow()) 356 marketID := proposal.SpotMarketUpdate().MarketID 357 358 // setup 359 eng.ensureNetworkParameter(t, netparams.GovernanceProposalUpdateMarketRequiredParticipation, "0.5") 360 eng.ensureNetworkParameter(t, netparams.GovernanceProposalUpdateMarketRequiredParticipationLP, "0.5") 361 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, proposer, 0.1) 362 eng.ensureExistingMarket(t, marketID) 363 eng.ensureGetMarketSpot(t, marketID) 364 eng.ensureTokenBalanceForParty(t, proposer, 1) 365 eng.ensureAllAssetEnabled(t) 366 367 // expect 368 eng.expectOpenProposalEvent(t, proposer, proposal.ID) 369 370 // when 371 _, err := eng.submitProposal(t, proposal) 372 373 // then 374 require.NoError(t, err) 375 376 // Vote using a token holder without equity-like share. 377 // when 378 voterWithToken := vgrand.RandomStr(5) 379 380 // setup 381 eng.ensureTokenBalanceForParty(t, voterWithToken, 1) 382 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithToken, 0) 383 384 // expect 385 eng.expectVoteEvent(t, voterWithToken, proposal.ID) 386 387 // when 388 err = eng.addYesVote(t, voterWithToken, proposal.ID) 389 390 // then 391 require.NoError(t, err) 392 393 // Vote using equity-like share holder without tokens. 394 // given 395 voterWithELS := vgrand.RandomStr(5) 396 397 // setup 398 eng.ensureTokenBalanceForParty(t, voterWithELS, 0) 399 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithELS, 0.1) 400 401 // expect 402 eng.expectVoteEvent(t, voterWithELS, proposal.ID) 403 404 // when 405 err = eng.addNoVote(t, voterWithELS, proposal.ID) 406 407 // then 408 require.NoError(t, err) 409 410 // Closing the proposal. 411 // given 412 afterClosing := time.Unix(proposal.Terms.ClosingTimestamp, 0).Add(time.Second) 413 414 // setup 415 eng.ensureStakingAssetTotalSupply(t, 10) 416 eng.ensureTokenBalanceForParty(t, voterWithToken, 1) 417 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithToken, 0) 418 eng.ensureTokenBalanceForParty(t, voterWithELS, 0) 419 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithELS, 0.1) 420 421 // expect 422 eng.expectDeclinedProposalEvent(t, proposal.ID, types.ProposalErrorParticipationThresholdNotReached) 423 eng.expectVoteEvents(t) 424 eng.expectGetMarketState(t, proposal.ID) 425 426 // when 427 eng.OnTick(context.Background(), afterClosing) 428 } 429 430 func testVotingWithMajorityOfYesFromTokenHoldersMakesSpotMarketUpdateProposalPassed(t *testing.T) { 431 eng := getTestEngine(t, time.Now()) 432 433 // Submit proposal. 434 // given 435 proposer := vgrand.RandomStr(5) 436 proposal := eng.newProposalForSpotMarketUpdate("״market-1", proposer, eng.tsvc.GetTimeNow()) 437 marketID := proposal.SpotMarketUpdate().MarketID 438 439 // setup 440 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, proposer, 0.7) 441 eng.ensureExistingMarket(t, marketID) 442 eng.ensureGetMarketSpot(t, marketID) 443 eng.ensureTokenBalanceForParty(t, proposer, 1) 444 eng.ensureAllAssetEnabled(t) 445 446 // expect 447 eng.expectOpenProposalEvent(t, proposer, proposal.ID) 448 449 // when 450 _, err := eng.submitProposal(t, proposal) 451 452 // then 453 require.NoError(t, err) 454 455 // Vote 'YES' with 10 tokens. 456 // given 457 voterWithToken1 := vgrand.RandomStr(5) 458 459 // setup 460 eng.ensureTokenBalanceForParty(t, voterWithToken1, 10) 461 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithToken1, 0) 462 463 // expect 464 eng.expectVoteEvent(t, voterWithToken1, proposal.ID) 465 466 // when 467 err = eng.addYesVote(t, voterWithToken1, proposal.ID) 468 469 // then 470 require.NoError(t, err) 471 472 // Vote 'NO' with 2 tokens. 473 // given 474 voterWithToken2 := vgrand.RandomStr(5) 475 476 // setup 477 eng.ensureTokenBalanceForParty(t, voterWithToken2, 2) 478 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithToken2, 0) 479 480 // expect 481 eng.expectVoteEvent(t, voterWithToken2, proposal.ID) 482 483 // then 484 err = eng.addNoVote(t, voterWithToken2, proposal.ID) 485 486 // then 487 require.NoError(t, err) 488 489 // Vote 'NO' with 0.1 of equity-like share. 490 // given 491 voterWithELS1 := vgrand.RandomStr(5) 492 493 // setup 494 eng.ensureTokenBalanceForParty(t, voterWithELS1, 0) 495 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithELS1, 0.1) 496 497 // expect 498 eng.expectVoteEvent(t, voterWithELS1, proposal.ID) 499 500 // when 501 err = eng.addNoVote(t, voterWithELS1, proposal.ID) 502 503 // then 504 require.NoError(t, err) 505 506 // Vote 'NO' with 0.5 of equity-like share. 507 // given 508 voterWithELS2 := vgrand.RandomStr(5) 509 510 // setup 511 eng.ensureTokenBalanceForParty(t, voterWithELS2, 0) 512 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithELS2, 0.7) 513 514 // expect 515 eng.expectVoteEvent(t, voterWithELS2, proposal.ID) 516 517 // when 518 err = eng.addNoVote(t, voterWithELS2, proposal.ID) 519 520 // then 521 require.NoError(t, err) 522 523 // Close the proposal. 524 // given 525 afterClosing := time.Unix(proposal.Terms.ClosingTimestamp, 0).Add(time.Second) 526 527 // setup 528 eng.ensureStakingAssetTotalSupply(t, 13) 529 eng.ensureTokenBalanceForParty(t, voterWithToken1, 10) 530 eng.ensureTokenBalanceForParty(t, voterWithToken2, 2) 531 eng.ensureTokenBalanceForParty(t, voterWithELS1, 0) 532 eng.ensureTokenBalanceForParty(t, voterWithELS2, 0) 533 534 // expect 535 eng.expectPassedProposalEvent(t, proposal.ID) 536 eng.expectVoteEvents(t) 537 eng.expectGetMarketState(t, proposal.ID) 538 539 // when 540 eng.OnTick(context.Background(), afterClosing) 541 } 542 543 func testVotingWithMajorityOfNoFromTokenHoldersMakesSpotMarketUpdateProposalDeclined(t *testing.T) { 544 eng := getTestEngine(t, time.Now()) 545 546 // Submit proposal. 547 // given 548 proposer := vgrand.RandomStr(5) 549 proposal := eng.newProposalForSpotMarketUpdate("market-1", proposer, eng.tsvc.GetTimeNow()) 550 marketID := proposal.SpotMarketUpdate().MarketID 551 552 // setup 553 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, proposer, 0.7) 554 eng.ensureExistingMarket(t, marketID) 555 eng.ensureGetMarketSpot(t, marketID) 556 eng.ensureTokenBalanceForParty(t, proposer, 1) 557 eng.ensureAllAssetEnabled(t) 558 559 // expect 560 eng.expectOpenProposalEvent(t, proposer, proposal.ID) 561 562 // when 563 _, err := eng.submitProposal(t, proposal) 564 565 // then 566 require.NoError(t, err) 567 568 // Vote 'NO' with 10 tokens. 569 // given 570 voterWithToken1 := vgrand.RandomStr(5) 571 572 // setup 573 eng.ensureTokenBalanceForParty(t, voterWithToken1, 10) 574 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithToken1, 0) 575 576 // expect 577 eng.expectVoteEvent(t, voterWithToken1, proposal.ID) 578 579 // when 580 err = eng.addNoVote(t, voterWithToken1, proposal.ID) 581 582 // then 583 require.NoError(t, err) 584 585 // Vote 'YES' with 2 tokens. 586 // given 587 voterWithToken2 := vgrand.RandomStr(5) 588 589 // setup 590 eng.ensureTokenBalanceForParty(t, voterWithToken2, 2) 591 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithToken2, 0) 592 593 // expect 594 eng.expectVoteEvent(t, voterWithToken2, proposal.ID) 595 596 // then 597 err = eng.addYesVote(t, voterWithToken2, proposal.ID) 598 599 // then 600 require.NoError(t, err) 601 602 // Vote 'YES' with 0.1 of equity-like share. 603 // given 604 voterWithELS1 := vgrand.RandomStr(5) 605 606 // setup 607 eng.ensureTokenBalanceForParty(t, voterWithELS1, 0) 608 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithELS1, 0.1) 609 610 // expect 611 eng.expectVoteEvent(t, voterWithELS1, proposal.ID) 612 613 // when 614 err = eng.addYesVote(t, voterWithELS1, proposal.ID) 615 616 // then 617 require.NoError(t, err) 618 619 // Vote 'YES' with 0.5 of equity-like share. 620 // given 621 voterWithELS2 := vgrand.RandomStr(5) 622 623 // setup 624 eng.ensureTokenBalanceForParty(t, voterWithELS2, 0) 625 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithELS2, 0.7) 626 627 // expect 628 eng.expectVoteEvent(t, voterWithELS2, proposal.ID) 629 630 // when 631 err = eng.addYesVote(t, voterWithELS2, proposal.ID) 632 633 // then 634 require.NoError(t, err) 635 636 // Close the proposal. 637 // given 638 afterClosing := time.Unix(proposal.Terms.ClosingTimestamp, 0).Add(time.Second) 639 640 // setup 641 eng.ensureStakingAssetTotalSupply(t, 13) 642 eng.ensureTokenBalanceForParty(t, voterWithToken1, 10) 643 eng.ensureTokenBalanceForParty(t, voterWithToken2, 2) 644 eng.ensureTokenBalanceForParty(t, voterWithELS1, 0) 645 eng.ensureTokenBalanceForParty(t, voterWithELS2, 0) 646 647 // expect 648 eng.expectDeclinedProposalEvent(t, proposal.ID, types.ProposalErrorMajorityThresholdNotReached) 649 eng.expectVoteEvents(t) 650 eng.expectGetMarketState(t, proposal.ID) 651 652 // when 653 eng.OnTick(context.Background(), afterClosing) 654 } 655 656 func testVotingWithoutTokenAndMajorityOfYesFromEquityLikeShareHoldersMakesSpotMarketUpdateProposalPassed(t *testing.T) { 657 eng := getTestEngine(t, time.Now()) 658 659 eng.ensureNetworkParameter(t, netparams.GovernanceProposalUpdateMarketRequiredParticipation, "0.5") 660 661 // Submit proposal. 662 // given 663 proposer := vgrand.RandomStr(5) 664 proposal := eng.newProposalForSpotMarketUpdate("market-1", proposer, eng.tsvc.GetTimeNow()) 665 marketID := proposal.SpotMarketUpdate().MarketID 666 667 // setup 668 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, proposer, 0.7) 669 eng.ensureExistingMarket(t, marketID) 670 eng.ensureTokenBalanceForParty(t, proposer, 1) 671 eng.ensureAllAssetEnabled(t) 672 eng.ensureGetMarketSpot(t, marketID) 673 674 // expect 675 eng.expectOpenProposalEvent(t, proposer, proposal.ID) 676 677 // when 678 _, err := eng.submitProposal(t, proposal) 679 680 // then 681 require.NoError(t, err) 682 683 // Vote 'NO' with 2 tokens. 684 // given 685 voterWithToken := vgrand.RandomStr(5) 686 687 // setup 688 eng.ensureTokenBalanceForParty(t, voterWithToken, 2) 689 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithToken, 0) 690 691 // expect 692 eng.expectVoteEvent(t, voterWithToken, proposal.ID) 693 694 // when 695 err = eng.addNoVote(t, voterWithToken, proposal.ID) 696 697 // then 698 require.NoError(t, err) 699 700 // Vote 'NO' with 0.1 of equity-like share. 701 // given 702 voterWithELS1 := vgrand.RandomStr(5) 703 704 // setup 705 eng.ensureTokenBalanceForParty(t, voterWithELS1, 0) 706 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithELS1, 0.1) 707 708 // expect 709 eng.expectVoteEvent(t, voterWithELS1, proposal.ID) 710 711 // when 712 err = eng.addNoVote(t, voterWithELS1, proposal.ID) 713 714 // then 715 require.NoError(t, err) 716 717 // Vote 'YES' with 0.5 of equity-like share. 718 // given 719 voterWithELS2 := vgrand.RandomStr(5) 720 721 // setup 722 eng.ensureTokenBalanceForParty(t, voterWithELS2, 0) 723 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithELS2, 0.7) 724 725 // expect 726 eng.expectVoteEvent(t, voterWithELS2, proposal.ID) 727 728 // when 729 err = eng.addYesVote(t, voterWithELS2, proposal.ID) 730 731 // then 732 require.NoError(t, err) 733 734 // Close the proposal. 735 // given 736 afterClosing := time.Unix(proposal.Terms.ClosingTimestamp, 0).Add(time.Second) 737 738 // setup 739 eng.ensureStakingAssetTotalSupply(t, 13) 740 eng.ensureTokenBalanceForParty(t, voterWithToken, 2) 741 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithToken, 0) 742 eng.ensureTokenBalanceForParty(t, voterWithELS1, 0) 743 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithELS1, 0.1) 744 eng.ensureTokenBalanceForParty(t, voterWithELS2, 0) 745 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithELS2, 0.7) 746 747 // expect 748 eng.expectPassedProposalEvent(t, proposal.ID) 749 eng.expectVoteEvents(t) 750 eng.expectGetMarketState(t, proposal.ID) 751 752 // when 753 eng.OnTick(context.Background(), afterClosing) 754 } 755 756 func testVotingWithoutTokenAndMajorityOfNoFromEquityLikeShareHoldersMakesSpotMarketUpdateProposalDeclined(t *testing.T) { 757 eng := getTestEngine(t, time.Now()) 758 759 // Submit proposal. 760 // given 761 762 eng.ensureNetworkParameter(t, netparams.GovernanceProposalUpdateMarketRequiredParticipation, "0.5") 763 764 proposer := vgrand.RandomStr(5) 765 proposal := eng.newProposalForSpotMarketUpdate("market-1", proposer, eng.tsvc.GetTimeNow()) 766 marketID := proposal.SpotMarketUpdate().MarketID 767 768 // setup 769 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, proposer, 0.7) 770 eng.ensureExistingMarket(t, marketID) 771 eng.ensureTokenBalanceForParty(t, proposer, 1) 772 eng.ensureAllAssetEnabled(t) 773 eng.ensureGetMarketSpot(t, marketID) 774 775 // expect 776 eng.expectOpenProposalEvent(t, proposer, proposal.ID) 777 778 // when 779 _, err := eng.submitProposal(t, proposal) 780 781 // then 782 require.NoError(t, err) 783 784 // Vote 'YES' with 2 tokens. 785 // given 786 voterWithToken := vgrand.RandomStr(5) 787 788 // setup 789 eng.ensureTokenBalanceForParty(t, voterWithToken, 2) 790 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithToken, 0) 791 792 // expect 793 eng.expectVoteEvent(t, voterWithToken, proposal.ID) 794 795 // when 796 err = eng.addYesVote(t, voterWithToken, proposal.ID) 797 798 // then 799 require.NoError(t, err) 800 801 // Vote 'YES' with 0.1 of equity-like share. 802 // given 803 voterWithELS1 := vgrand.RandomStr(5) 804 805 // setup 806 eng.ensureTokenBalanceForParty(t, voterWithELS1, 0) 807 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithELS1, 0.1) 808 809 // expect 810 eng.expectVoteEvent(t, voterWithELS1, proposal.ID) 811 812 // when 813 err = eng.addYesVote(t, voterWithELS1, proposal.ID) 814 815 // then 816 require.NoError(t, err) 817 818 // Vote 'NO' with 0.5 of equity-like share. 819 // given 820 voterWithELS2 := vgrand.RandomStr(5) 821 822 // setup 823 eng.ensureTokenBalanceForParty(t, voterWithELS2, 0) 824 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithELS2, 0.7) 825 826 // expect 827 eng.expectVoteEvent(t, voterWithELS2, proposal.ID) 828 829 // when 830 err = eng.addNoVote(t, voterWithELS2, proposal.ID) 831 832 // then 833 require.NoError(t, err) 834 835 // Close the proposal. 836 // given 837 afterClosing := time.Unix(proposal.Terms.ClosingTimestamp, 0).Add(time.Second) 838 839 // setup 840 eng.ensureStakingAssetTotalSupply(t, 13) 841 eng.ensureTokenBalanceForParty(t, voterWithToken, 2) 842 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithToken, 0) 843 eng.ensureTokenBalanceForParty(t, voterWithELS1, 0) 844 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithELS1, 0.1) 845 eng.ensureTokenBalanceForParty(t, voterWithELS2, 0) 846 eng.ensureEquityLikeShareForMarketAndParty(t, marketID, voterWithELS2, 0.7) 847 848 // ensure setting again the values have no effect 849 eng.ensureNetworkParameter(t, netparams.GovernanceProposalUpdateMarketRequiredParticipation, "0") 850 851 // expect 852 eng.expectDeclinedProposalEvent(t, proposal.ID, types.ProposalErrorMajorityThresholdNotReached) 853 eng.expectVoteEvents(t) 854 eng.expectGetMarketState(t, proposal.ID) 855 856 // when 857 eng.OnTick(context.Background(), afterClosing) 858 }