Skip to content
Open
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
3 changes: 3 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion smart_contracts/common/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,7 @@
ERROR_NOT_OWNER = "NOT_OWNER"

# The requested operation could not be completed because not enough value is vested
ERROR_NOT_VESTED = "NOT_VESTED"
ERROR_NOT_VESTED = "NOT_VESTED"

# A given parameter was an unacceptable value
ERROR_BAD_DAO_PARAM = "ERROR_BAD_DAO_PARAM"
189 changes: 189 additions & 0 deletions smart_contracts/dao.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,20 @@ def setParameters(self, newGovernanceParameters):
# Only the DAO can change its own parameters.
sp.verify(sp.sender == sp.self_address, Errors.ERROR_NOT_DAO)

# Validate that upper quorum cap is less than 100. Values greater than 100 are unachievable
# and will result in the DAO being unable to pass proposals.
# NOTE: Lower quorum cap can't be less than 0, because the Michelson `nat` type ensures numbers are
# always positive
sp.verify(newGovernanceParameters.quorumCap.upper <= 100, Errors.ERROR_BAD_DAO_PARAM)

# Validate that percentages for super majority is less than 100. Values greater than
# 100 are unachievable and will result in the DAO being unable to pass proposals.
sp.verify(newGovernanceParameters.percentageForSuperMajority <= 100, Errors.ERROR_BAD_DAO_PARAM)

# Validate that the percentage of yay votes for escrow return is less than 100. Values greater than
# 100 are unachievable, and will result in Escrow always being confiscated.
sp.verify(newGovernanceParameters.minYayVotesPercentForEscrowReturn <= 100, Errors.ERROR_BAD_DAO_PARAM)

# Update parameters.
self.data.governanceParameters = newGovernanceParameters

Expand Down Expand Up @@ -2867,4 +2881,179 @@ def test():
valid = False
)

@sp.add_test(name="setParameters - fails if upper quorum cap is above 100")
def test():
scenario = sp.test_scenario()

# Given governance parameters with a quorum cap greater than 100
escrowAmount = sp.nat(10)
voteDelayBlocks = sp.nat(1)
voteLengthBlocks = sp.nat(10)
minYayVotesPercentForEscrowReturn = sp.nat(20)
blocksInTimelockForExecution = sp.nat(30)
blocksInTimelockForCancellation = sp.nat(40)
percentageForSuperMajority = sp.nat(80)
quorumCap = sp.record(lower = 1, upper = 99)
governanceParameters = sp.record(
escrowAmount = escrowAmount,
voteDelayBlocks = voteDelayBlocks,
voteLengthBlocks = voteLengthBlocks,
minYayVotesPercentForEscrowReturn = minYayVotesPercentForEscrowReturn,
blocksInTimelockForExecution = blocksInTimelockForExecution,
blocksInTimelockForCancellation = blocksInTimelockForCancellation,
percentageForSuperMajority = percentageForSuperMajority,
quorumCap = quorumCap
)

# AND a dao contract.
dao = DaoContract(
governanceParameters = governanceParameters,
)
scenario += dao

# WHEN the DAO contract tries to rotate the parameters to have a quorum cap
# that is above 100.
newQuorumCap = sp.record(lower = 2, upper = 105)

newEscrowAmount = sp.nat(12)
newVoteDelayBlocks = sp.nat(2)
newVoteLengthBlocks = sp.nat(11)
newminYayVotesPercentForEscrowReturn = sp.nat(21)
newblocksInTimelockForExecution = sp.nat(31)
newblocksInTimelockForCancellation = sp.nat(41)
newPercentageForSuperMajority = sp.nat(81)
newGovernanceParameters = sp.record(
escrowAmount = newEscrowAmount,
voteDelayBlocks = newVoteDelayBlocks,
voteLengthBlocks = newVoteLengthBlocks,
minYayVotesPercentForEscrowReturn = newminYayVotesPercentForEscrowReturn,
blocksInTimelockForExecution = newblocksInTimelockForExecution,
blocksInTimelockForCancellation = newblocksInTimelockForCancellation,
percentageForSuperMajority = newPercentageForSuperMajority,
quorumCap = newQuorumCap
)

# THEN the call fails
scenario += dao.setParameters(newGovernanceParameters).run(
sender = dao.address,
valid = False
)

@sp.add_test(name="setParameters - fails if super majority is above 100")
def test():
scenario = sp.test_scenario()

# Given governance parameters with a quorum cap greater than 100
escrowAmount = sp.nat(10)
voteDelayBlocks = sp.nat(1)
voteLengthBlocks = sp.nat(10)
minYayVotesPercentForEscrowReturn = sp.nat(20)
blocksInTimelockForExecution = sp.nat(30)
blocksInTimelockForCancellation = sp.nat(40)
percentageForSuperMajority = sp.nat(80)
quorumCap = sp.record(lower = 1, upper = 99)
governanceParameters = sp.record(
escrowAmount = escrowAmount,
voteDelayBlocks = voteDelayBlocks,
voteLengthBlocks = voteLengthBlocks,
minYayVotesPercentForEscrowReturn = minYayVotesPercentForEscrowReturn,
blocksInTimelockForExecution = blocksInTimelockForExecution,
blocksInTimelockForCancellation = blocksInTimelockForCancellation,
percentageForSuperMajority = percentageForSuperMajority,
quorumCap = quorumCap
)

# AND a dao contract.
dao = DaoContract(
governanceParameters = governanceParameters,
)
scenario += dao

# WHEN the DAO contract tries to rotate the parameters to have a super majority
# that is above 100.
newPercentageForSuperMajority = sp.nat(105)

newEscrowAmount = sp.nat(12)
newVoteDelayBlocks = sp.nat(2)
newVoteLengthBlocks = sp.nat(11)
newminYayVotesPercentForEscrowReturn = sp.nat(21)
newblocksInTimelockForExecution = sp.nat(31)
newblocksInTimelockForCancellation = sp.nat(41)
newQuorumCap = sp.record(lower = 2, upper = 105)
newGovernanceParameters = sp.record(
escrowAmount = newEscrowAmount,
voteDelayBlocks = newVoteDelayBlocks,
voteLengthBlocks = newVoteLengthBlocks,
minYayVotesPercentForEscrowReturn = newminYayVotesPercentForEscrowReturn,
blocksInTimelockForExecution = newblocksInTimelockForExecution,
blocksInTimelockForCancellation = newblocksInTimelockForCancellation,
percentageForSuperMajority = newPercentageForSuperMajority,
quorumCap = newQuorumCap
)

# THEN the call fails
scenario += dao.setParameters(newGovernanceParameters).run(
sender = dao.address,
valid = False
)

@sp.add_test(name="setParameters - fails if min yay votes for escrow return is above 100")
def test():
scenario = sp.test_scenario()

# Given governance parameters with a quorum cap greater than 100
escrowAmount = sp.nat(10)
voteDelayBlocks = sp.nat(1)
voteLengthBlocks = sp.nat(10)
minYayVotesPercentForEscrowReturn = sp.nat(20)
blocksInTimelockForExecution = sp.nat(30)
blocksInTimelockForCancellation = sp.nat(40)
percentageForSuperMajority = sp.nat(80)
quorumCap = sp.record(lower = 1, upper = 99)
governanceParameters = sp.record(
escrowAmount = escrowAmount,
voteDelayBlocks = voteDelayBlocks,
voteLengthBlocks = voteLengthBlocks,
minYayVotesPercentForEscrowReturn = minYayVotesPercentForEscrowReturn,
blocksInTimelockForExecution = blocksInTimelockForExecution,
blocksInTimelockForCancellation = blocksInTimelockForCancellation,
percentageForSuperMajority = percentageForSuperMajority,
quorumCap = quorumCap
)

# AND a dao contract.
dao = DaoContract(
governanceParameters = governanceParameters,
)
scenario += dao

# WHEN the DAO contract tries to rotate the parameters to have a min yay votes
# for escrow return that is above 100.
newminYayVotesPercentForEscrowReturn = sp.nat(105)

newEscrowAmount = sp.nat(12)
newVoteDelayBlocks = sp.nat(2)
newVoteLengthBlocks = sp.nat(11)
newblocksInTimelockForExecution = sp.nat(31)
newblocksInTimelockForCancellation = sp.nat(41)
newPercentageForSuperMajority = sp.nat(105)
newQuorumCap = sp.record(lower = 2, upper = 105)
newGovernanceParameters = sp.record(
escrowAmount = newEscrowAmount,
voteDelayBlocks = newVoteDelayBlocks,
voteLengthBlocks = newVoteLengthBlocks,
minYayVotesPercentForEscrowReturn = newminYayVotesPercentForEscrowReturn,
blocksInTimelockForExecution = newblocksInTimelockForExecution,
blocksInTimelockForCancellation = newblocksInTimelockForCancellation,
percentageForSuperMajority = newPercentageForSuperMajority,
quorumCap = newQuorumCap
)

# THEN the call fails
scenario += dao.setParameters(newGovernanceParameters).run(
sender = dao.address,
valid = False
)


sp.add_compilation_target("dao", DaoContract())
39 changes: 39 additions & 0 deletions smart_contracts/dao.tz
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,45 @@ code
PUSH string "NOT_DAO"; # string : @parameter%setParameters : @storage
FAILWITH; # FAILED
}; # @parameter%setParameters : @storage
# sp.verify(params.quorumCap.upper <= 100, message = 'ERROR_BAD_DAO_PARAM') # @parameter%setParameters : @storage
DUP; # @parameter%setParameters : @parameter%setParameters : @storage
GET 16; # nat : @parameter%setParameters : @storage
PUSH nat 100; # nat : nat : @parameter%setParameters : @storage
SWAP; # nat : nat : @parameter%setParameters : @storage
COMPARE; # int : @parameter%setParameters : @storage
LE; # bool : @parameter%setParameters : @storage
IF
{}
{
PUSH string "ERROR_BAD_DAO_PARAM"; # string : @parameter%setParameters : @storage
FAILWITH; # FAILED
}; # @parameter%setParameters : @storage
# sp.verify(params.percentageForSuperMajority <= 100, message = 'ERROR_BAD_DAO_PARAM') # @parameter%setParameters : @storage
DUP; # @parameter%setParameters : @parameter%setParameters : @storage
GET 13; # nat : @parameter%setParameters : @storage
PUSH nat 100; # nat : nat : @parameter%setParameters : @storage
SWAP; # nat : nat : @parameter%setParameters : @storage
COMPARE; # int : @parameter%setParameters : @storage
LE; # bool : @parameter%setParameters : @storage
IF
{}
{
PUSH string "ERROR_BAD_DAO_PARAM"; # string : @parameter%setParameters : @storage
FAILWITH; # FAILED
}; # @parameter%setParameters : @storage
# sp.verify(params.minYayVotesPercentForEscrowReturn <= 100, message = 'ERROR_BAD_DAO_PARAM') # @parameter%setParameters : @storage
DUP; # @parameter%setParameters : @parameter%setParameters : @storage
GET 7; # nat : @parameter%setParameters : @storage
PUSH nat 100; # nat : nat : @parameter%setParameters : @storage
SWAP; # nat : nat : @parameter%setParameters : @storage
COMPARE; # int : @parameter%setParameters : @storage
LE; # bool : @parameter%setParameters : @storage
IF
{}
{
PUSH string "ERROR_BAD_DAO_PARAM"; # string : @parameter%setParameters : @storage
FAILWITH; # FAILED
}; # @parameter%setParameters : @storage
SWAP; # @storage : @parameter%setParameters
# self.data.governanceParameters = params # @storage : @parameter%setParameters
UNPAIR; # pair (pair (address %communityFundAddress) (pair %governanceParameters (nat %escrowAmount) (pair (nat %voteDelayBlocks) (pair (nat %voteLengthBlocks) (pair (nat %minYayVotesPercentForEscrowReturn) (pair (nat %blocksInTimelockForExecution) (pair (nat %blocksInTimelockForCancellation) (pair (nat %percentageForSuperMajority) (pair %quorumCap (nat %lower) (nat %upper)))))))))) (pair (big_map %metadata string bytes) (pair (nat %nextProposalId) (big_map %outcomes nat (pair (nat %outcome) (pair %poll (nat %id) (pair (pair %proposal (string %title) (pair (string %descriptionLink) (pair (string %descriptionHash) (lambda %proposalLambda unit (list operation))))) (pair (nat %votingStartBlock) (pair (nat %votingEndBlock) (pair (nat %yayVotes) (pair (nat %nayVotes) (pair (nat %abstainVotes) (pair (nat %totalVotes) (pair (map %voters address (pair (nat %voteValue) (pair (nat %level) (nat %votes)))) (pair (address %author) (pair (nat %escrowAmount) (pair (nat %quorum) (pair %quorumCap (nat %lower) (nat %upper)))))))))))))))))) : pair (pair (option %poll (pair (nat %id) (pair (pair %proposal (string %title) (pair (string %descriptionLink) (pair (string %descriptionHash) (lambda %proposalLambda unit (list operation))))) (pair (nat %votingStartBlock) (pair (nat %votingEndBlock) (pair (nat %yayVotes) (pair (nat %nayVotes) (pair (nat %abstainVotes) (pair (nat %totalVotes) (pair (map %voters address (pair (nat %voteValue) (pair (nat %level) (nat %votes)))) (pair (address %author) (pair (nat %escrowAmount) (pair (nat %quorum) (pair %quorumCap (nat %lower) (nat %upper))))))))))))))) (pair (nat %quorum) (nat %state))) (pair (option %timelockItem (pair (nat %id) (pair (pair %proposal (string %title) (pair (string %descriptionLink) (pair (string %descriptionHash) (lambda %proposalLambda unit (list operation))))) (pair (nat %endBlock) (pair (nat %cancelBlock) (address %author)))))) (pair (address %tokenContractAddress) (option %votingState (pair (nat %voteValue) (pair (address %address) (nat %level)))))) : @parameter%setParameters
Expand Down