Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow update market proposal submission with only ELS #8638

Merged
merged 1 commit into from
Jun 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
- [8508](https://github.com/vegaprotocol/vega/issues/8508) - Add network parameters for SLA.
- [8468](https://github.com/vegaprotocol/vega/issues/8468) - Wire in stop orders in markets
- [8528](https://github.com/vegaprotocol/vega/issues/8528) - Add support for Stop Orders in the data node.
- [8635](https://github.com/vegaprotocol/vega/issues/8635) - Allow market update proposal with ELS only

### 🐛 Fixes

Expand Down
42 changes: 24 additions & 18 deletions core/governance/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -792,35 +792,41 @@ func (e *Engine) validateOpenProposal(proposal *types.Proposal) (types.ProposalE
fmt.Errorf("proposal enactment time cannot be before closing time, expected > %v got %v", closeTime.UTC(), enactTime.UTC())
}

proposerTokens, err := getGovernanceTokens(e.accs, proposal.Party)
if err != nil {
e.log.Debug("proposer have no governance token",
logging.PartyID(proposal.Party),
logging.ProposalID(proposal.ID))
return types.ProposalErrorInsufficientTokens, err
}
if proposerTokens.LT(params.MinProposerBalance) {
e.log.Debug("proposer have insufficient governance token",
logging.BigUint("expect-balance", params.MinProposerBalance),
logging.String("proposer-balance", proposerTokens.String()),
logging.PartyID(proposal.Party),
logging.ProposalID(proposal.ID))
return types.ProposalErrorInsufficientTokens,
fmt.Errorf("proposer have insufficient governance token, expected >= %v got %v", params.MinProposerBalance, proposerTokens)
}
checkProposerToken := true

if proposal.IsMarketUpdate() {
proposalError, err := e.validateMarketUpdate(proposal, params)
if err != nil {
if err != nil && proposalError != types.ProposalErrorInsufficientEquityLikeShare {
return proposalError, err
}
checkProposerToken = proposalError == types.ProposalErrorInsufficientEquityLikeShare
}

if proposal.IsSpotMarketUpdate() {
proposalError, err := e.validateSpotMarketUpdate(proposal, params)
if err != nil {
if err != nil && proposalError != types.ProposalErrorInsufficientEquityLikeShare {
return proposalError, err
}
checkProposerToken = proposalError == types.ProposalErrorInsufficientEquityLikeShare
}

if checkProposerToken {
proposerTokens, err := getGovernanceTokens(e.accs, proposal.Party)
if err != nil {
e.log.Debug("proposer have no governance token",
logging.PartyID(proposal.Party),
logging.ProposalID(proposal.ID))
return types.ProposalErrorInsufficientTokens, err
}
if proposerTokens.LT(params.MinProposerBalance) {
e.log.Debug("proposer have insufficient governance token",
logging.BigUint("expect-balance", params.MinProposerBalance),
logging.String("proposer-balance", proposerTokens.String()),
logging.PartyID(proposal.Party),
logging.ProposalID(proposal.ID))
return types.ProposalErrorInsufficientTokens,
fmt.Errorf("proposer have insufficient governance token, expected >= %v got %v", params.MinProposerBalance, proposerTokens)
}
}

return e.validateChange(proposal.Terms)
Expand Down
84 changes: 70 additions & 14 deletions core/governance/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ func TestSubmitProposals(t *testing.T) {
t.Run("Submitting a proposal with non-existing account fails", testSubmittingProposalWithNonExistingAccountFails)
t.Run("Submitting a proposal with internal time termination with non-existing account fails", testSubmittingProposalWithInternalTimeTerminationWithNonExistingAccountFails)
t.Run("Submitting a proposal without enough stake fails", testSubmittingProposalWithoutEnoughStakeFails)
t.Run("Submitting an update market proposal without enough stake and els fails", testSubmittingUpdateMarketProposalWithoutEnoughStakeAndELSFails)
t.Run("Submitting a proposal with internal time termination without enough stake fails", testSubmittingProposalWithInternalTimeTerminationWithoutEnoughStakeFails)

t.Run("Submitting a time-triggered proposal for new market with termination time before enactment time fails", testSumittingTimeTriggeredProposalNewMarketTerminationBeforeEnactmentFails)
Expand All @@ -82,6 +83,7 @@ func TestSubmitProposals(t *testing.T) {
t.Run("Updating voters key on votes with internal time termination succeeds", testUpdatingVotersKeyOnVotesWithInternalTimeTerminationSucceeds)

t.Run("Computing the governance state hash is deterministic", testComputingGovernanceStateHashIsDeterministic)
t.Run("Submit proposal update market", testSubmitProposalMarketUpdate)
}

func testUpdatingVotersKeyOnVotesSucceeds(t *testing.T) {
Expand Down Expand Up @@ -239,9 +241,6 @@ func testSubmittingProposalWithNonExistingAccountFails(t *testing.T) {
{
name: "For new market",
proposal: eng.newProposalForNewMarket(party, now, nil, nil, true),
}, {
name: "For market update",
proposal: eng.newProposalForMarketUpdate("", party, now, nil, nil, true),
}, {
name: "For new asset",
proposal: eng.newProposalForNewAsset(party, now),
Expand All @@ -268,6 +267,38 @@ func testSubmittingProposalWithNonExistingAccountFails(t *testing.T) {
}
}

func testSubmitProposalMarketUpdate(t *testing.T) {
eng := getTestEngine(t)
defer eng.ctrl.Finish()

// given
party := vgrand.RandomStr(5)
now := eng.tsvc.GetTimeNow()
tc := struct {
name string
proposal types.Proposal
}{
name: "For market update",
proposal: eng.newProposalForMarketUpdate("", party, now, nil, nil, true),
}

// test that with no account but equity like share, a market update proposal goes through
t.Run(tc.name, func(tt *testing.T) {
// setup
eng.ensureAllAssetEnabled(tt)
eng.ensureNoAccountForParty(tt, party)
eng.expectOpenProposalEvent(tt, party, tc.proposal.ID)

eng.markets.EXPECT().MarketExists(gomock.Any()).Return(true)
eng.markets.EXPECT().GetEquityLikeShareForMarketAndParty(gomock.Any(), gomock.Any()).Return(num.DecimalOne(), true)
// when
_, err := eng.submitProposal(tt, tc.proposal)

// then
require.NoError(tt, err)
})
}

func testSubmittingProposalWithInternalTimeTerminationWithNonExistingAccountFails(t *testing.T) {
eng := getTestEngine(t)
defer eng.ctrl.Finish()
Expand All @@ -283,9 +314,6 @@ func testSubmittingProposalWithInternalTimeTerminationWithNonExistingAccountFail
{
name: "For new market",
proposal: eng.newProposalForNewMarket(party, now, nil, nil, false),
}, {
name: "For market update",
proposal: eng.newProposalForMarketUpdate("", party, now, nil, nil, false),
}, {
name: "For new asset",
proposal: eng.newProposalForNewAsset(party, now),
Expand Down Expand Up @@ -329,10 +357,6 @@ func testSubmittingProposalWithoutEnoughStakeFails(t *testing.T) {
name: "For new market",
minProposerBalanceParam: netparams.GovernanceProposalMarketMinProposerBalance,
proposal: eng.newProposalForNewMarket(party, now, nil, nil, true),
}, {
name: "For market update",
minProposerBalanceParam: netparams.GovernanceProposalUpdateMarketMinProposerBalance,
proposal: eng.newProposalForMarketUpdate("market-1", party, now, nil, nil, true),
}, {
name: "For new asset",
minProposerBalanceParam: netparams.GovernanceProposalAssetMinProposerBalance,
Expand Down Expand Up @@ -362,6 +386,42 @@ func testSubmittingProposalWithoutEnoughStakeFails(t *testing.T) {
}
}

func testSubmittingUpdateMarketProposalWithoutEnoughStakeAndELSFails(t *testing.T) {
eng := getTestEngine(t)
defer eng.ctrl.Finish()

// given
party := vgrand.RandomStr(5)
now := eng.tsvc.GetTimeNow()

tc := struct {
name string
minProposerBalanceParam string
proposal types.Proposal
}{
name: "For market update",
minProposerBalanceParam: netparams.GovernanceProposalUpdateMarketMinProposerBalance,
proposal: eng.newProposalForMarketUpdate("market-1", party, now, nil, nil, true),
}

t.Run(tc.name, func(tt *testing.T) {
// setup
eng.ensureTokenBalanceForParty(tt, party, 10)
eng.ensureNetworkParameter(tt, tc.minProposerBalanceParam, "10000")
eng.ensureAllAssetEnabled(tt)
eng.expectRejectedProposalEvent(tt, party, tc.proposal.ID, types.ProposalErrorInsufficientTokens)

// when
eng.markets.EXPECT().MarketExists(gomock.Any()).Return(true)
eng.markets.EXPECT().GetEquityLikeShareForMarketAndParty(gomock.Any(), gomock.Any()).Return(num.DecimalZero(), true)
_, err := eng.submitProposal(tt, tc.proposal)

// then
require.Error(tt, err)
assert.Contains(t, err.Error(), "proposer have insufficient governance token, expected >=")
})
}

func testSubmittingProposalWithInternalTimeTerminationWithoutEnoughStakeFails(t *testing.T) {
eng := getTestEngine(t)
defer eng.ctrl.Finish()
Expand All @@ -379,10 +439,6 @@ func testSubmittingProposalWithInternalTimeTerminationWithoutEnoughStakeFails(t
name: "For new market",
minProposerBalanceParam: netparams.GovernanceProposalMarketMinProposerBalance,
proposal: eng.newProposalForNewMarket(party, now, nil, nil, false),
}, {
name: "For market update",
minProposerBalanceParam: netparams.GovernanceProposalUpdateMarketMinProposerBalance,
proposal: eng.newProposalForMarketUpdate("market-1", party, now, nil, nil, false),
}, {
name: "For new asset",
minProposerBalanceParam: netparams.GovernanceProposalAssetMinProposerBalance,
Expand Down
6 changes: 3 additions & 3 deletions core/governance/engine_update_market_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -622,19 +622,19 @@ func testSubmittingProposalForMarketUpdateWithInsufficientEquityLikeShareFails(t
marketID := proposal.MarketUpdate().MarketID

// setup
eng.ensureTokenBalanceForParty(t, party, 100)
// eng.ensureTokenBalanceForParty(t, party, 100)
eng.ensureExistingMarket(t, marketID)
eng.ensureEquityLikeShareForMarketAndParty(t, marketID, party, 0.05)

// expect
eng.expectRejectedProposalEvent(t, party, proposal.ID, types.ProposalErrorInsufficientEquityLikeShare)
eng.expectRejectedProposalEvent(t, party, proposal.ID, types.ProposalErrorInsufficientTokens)

// when
toSubmit, err := eng.submitProposal(t, proposal)

// then
require.Error(t, err)
assert.Contains(t, err.Error(), "proposer have insufficient equity-like share, expected >=")
assert.Contains(t, err.Error(), "no balance for party")
require.Nil(t, toSubmit)
}

Expand Down
6 changes: 3 additions & 3 deletions core/governance/engine_update_spot_market_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,19 +142,19 @@ func testSubmittingProposalForSpotMarketUpdateWithInsufficientEquityLikeShareFai
marketID := proposal.MarketUpdate().MarketID

// setup
eng.ensureTokenBalanceForParty(t, party, 100)
// eng.ensureTokenBalanceForParty(t, party, 100)
eng.ensureExistingMarket(t, marketID)
eng.ensureEquityLikeShareForMarketAndParty(t, marketID, party, 0.05)

// expect
eng.expectRejectedProposalEvent(t, party, proposal.ID, types.ProposalErrorInsufficientEquityLikeShare)
eng.expectRejectedProposalEvent(t, party, proposal.ID, types.ProposalErrorInsufficientTokens)

// when
toSubmit, err := eng.submitProposal(t, proposal)

// then
require.Error(t, err)
assert.Contains(t, err.Error(), "proposer have insufficient equity-like share, expected >=")
assert.Contains(t, err.Error(), "no balance for party")
require.Nil(t, toSubmit)
}

Expand Down
Loading