Skip to content

Commit

Permalink
feat: allow update market proposal submission with only ELS
Browse files Browse the repository at this point in the history
Signed-off-by: Jeremy Letang <me@jeremyletang.com>
  • Loading branch information
jeremyletang committed Jun 29, 2023
1 parent 3daabbb commit 5a70d80
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 28 deletions.
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
80 changes: 70 additions & 10 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 Down

0 comments on commit 5a70d80

Please sign in to comment.