-
Notifications
You must be signed in to change notification settings - Fork 5
Preliminary BurgerGov for governance token #3
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
Open
Hecate2
wants to merge
34
commits into
neoburger:main
Choose a base branch
from
Hecate2:BurgerGov
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
b9a89fa
Preliminary BurgerGov for governance token
Hecate2 a1a155c
throw "The proposal does not exist" when voting_deadline == 0
Hecate2 138228a
Update BurgerGov.cs
vang1ong7ang de82d6a
Change filename, class name and token symbol; remove owner;
Hecate2 023ca02
Merge branch 'BurgerGov' of github.com:Hecate2/code into BurgerGov
Hecate2 5102dd8
remove comments
Hecate2 f9e385b
NOT PRODUCTION READY. Examine votes on chain with delegation and defa…
Hecate2 56e58a4
mint tokens to a given address when deployed
Hecate2 79dfa84
BecomeDefaultDelegate manually
Hecate2 55bc1bc
GetDefaultDelegateBalance
Hecate2 b8680cf
vote[proposal_id][from_account] == True/False;
Hecate2 86b79a6
Preliminarily tested convenient method `CountVote`; robust method `Is…
Hecate2 139527d
Let `ExecuteProposal` reuse `CountVote` if no voter list provided
Hecate2 8fd4515
More robust and efficient `CountVote` and `ExecuteProposal`
Hecate2 8bd71d4
Attempt to regularize keys to raw bytes
Hecate2 db4d4b5
vote couting logic: I voted || I have valid delegate and delegate vot…
Hecate2 c47cb40
optimized `GetVotersOfProposal` and `CountVote` using FindOptions
Hecate2 5929488
arg count starts from 0; optimzed GAS with args[(uint)j]
Hecate2 6abfa3c
clearer exceptions
Hecate2 807cb15
Update NeoBurgerGovernanceToken.cs
vang1ong7ang f17807c
proposal attributes stored as structs
Hecate2 ada94f2
Merge branch 'neoburger:main' into BurgerGov
Hecate2 85c96c2
Merge branch 'main' of github.com:Hecate2/code into BurgerGov
Hecate2 5be7f74
Merge branch 'BurgerGov' of github.com:Hecate2/code into BurgerGov
Hecate2 a9d0ec5
check voting deadline in refactored storage
Hecate2 0b662d0
method GetNextProposalID
Hecate2 623ed81
proposal id given by user
Hecate2 0aae44f
robust check for `NewProposal`
Hecate2 95db3f7
fix method `Vote`
Hecate2 525c015
Update NeoBurgerGovernanceToken.cs
vang1ong7ang 149ddee
leave VOTING_PERIOD a readonly const
Hecate2 2ed8b81
initially set readonly byte[] for prefixes
Hecate2 95c7b87
remove useless `if (voting_deadline == 0)`
Hecate2 bed3983
use const instead of bytearray
Hecate2 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,217 @@ | ||
| using System; | ||
| using System.Numerics; | ||
| using Neo; | ||
| using Neo.SmartContract.Framework; | ||
| using Neo.SmartContract.Framework.Native; | ||
| using Neo.SmartContract.Framework.Services; | ||
| using Neo.SmartContract.Framework.Attributes; | ||
| using Neo.SmartContract; | ||
|
|
||
| namespace NeoBurger | ||
| { | ||
| [ManifestExtra("Author", "NEOBURGER")] | ||
| [ManifestExtra("Email", "developer@neo.org")] | ||
| [ManifestExtra("Description", "NeoBurger Governance Token")] | ||
| [SupportedStandards("NEP-17")] | ||
| [ContractPermission("*", "*")] | ||
| public class NeoBurgerGovernanceToken : Nep17Token | ||
| { | ||
| [InitialValue("[TODO]: ARGS", ContractParameterType.Hash160)] | ||
| private const UInt160 INITIAL_HOLDER = default; | ||
| private const ulong VOTING_PERIOD = 86400000 * 7; | ||
| private const byte PREFIX_PROPOSAL = 0x03; | ||
| private const byte PREFIX_PROPOSAL_EXECUTED_TIME = 0x05; | ||
| private const byte PREFIX_DELEGATE = 0x81; | ||
| private const byte PREFIX_DEFAULT_DELEGATE = 0x82; | ||
| private const byte PREFIX_DELEGATE_THRESHOLD = 0x83; | ||
| private const byte PREFIX_VOTE = 0xc1; | ||
|
|
||
| public override byte Decimals() => 8; | ||
| public override string Symbol() => "NOBUG"; | ||
| public static BigInteger GetVotingPeriod() => VOTING_PERIOD; | ||
|
|
||
| public static object[] ProposalAttributes(BigInteger id) | ||
| { | ||
| StorageMap proposal_id_map = new(Storage.CurrentContext, new byte[] { PREFIX_PROPOSAL }); | ||
| ProposalAttributesStruct proposal_attributes = (ProposalAttributesStruct)proposal_id_map.GetObject((ByteString)id); | ||
| byte[] proposal_executed_time_bytearray = new byte[] { PREFIX_PROPOSAL_EXECUTED_TIME }; | ||
| StorageMap proposal_executed_time_map = new(Storage.CurrentContext, proposal_executed_time_bytearray); | ||
| BigInteger executed_time = (BigInteger)proposal_executed_time_map.Get((ByteString)id); | ||
| return new object[] { proposal_attributes.scripthash, proposal_attributes.method, proposal_attributes.args, proposal_attributes.voting_deadline, executed_time }; | ||
| } | ||
|
|
||
| public static UInt160 GetDelegate(UInt160 from) => (UInt160)new StorageMap(Storage.CurrentContext, PREFIX_DELEGATE).Get(from); | ||
| public static UInt160 GetDefaultDelegate() => (UInt160)Storage.Get(Storage.CurrentContext, new byte[] { PREFIX_DEFAULT_DELEGATE }); | ||
| public static BigInteger GetDefaultDelegateBalance() => BalanceOf(GetDefaultDelegate()); | ||
| public static BigInteger GetDelegateThreshold() => (BigInteger)Storage.Get(Storage.CurrentContext, new byte[] { PREFIX_DELEGATE_THRESHOLD }); | ||
| public static bool IsValidDelegate(UInt160 account) => account is not null && account.IsValid && (BalanceOf(account) > GetDelegateThreshold()); | ||
| public static BigInteger GetVote(UInt160 from, BigInteger proposal_index) => (BigInteger)new StorageMap(Storage.CurrentContext, (ByteString)new byte[] { PREFIX_VOTE } + (ByteString)proposal_index).Get(from); | ||
| public static Iterator GetVotersOfProposal(BigInteger proposal_id) => new StorageMap(Storage.CurrentContext, (ByteString)new byte[] { PREFIX_VOTE } + (ByteString)proposal_id).Find((FindOptions)((byte)FindOptions.KeysOnly + (byte)FindOptions.RemovePrefix)); | ||
|
|
||
| struct ProposalAttributesStruct | ||
| { | ||
| public BigInteger id; | ||
| public UInt160 scripthash; | ||
| public string method; | ||
| public ByteString[] args; | ||
| public BigInteger voting_deadline; | ||
| } | ||
|
|
||
| public static void _deploy(object data, bool update) | ||
| { | ||
| StorageMap proposal_id_map = new(Storage.CurrentContext, new byte[] { PREFIX_PROPOSAL }); | ||
| ProposalAttributesStruct proposal_attributes = new(); | ||
| proposal_attributes.id = 0; | ||
| proposal_id_map.PutObject((ByteString)(BigInteger)0, proposal_attributes); | ||
| Mint(INITIAL_HOLDER, 10_000_000_000_000_000); | ||
| Storage.Put(Storage.CurrentContext, new byte[] { PREFIX_DEFAULT_DELEGATE }, INITIAL_HOLDER); | ||
| Storage.Put(Storage.CurrentContext, new byte[] { PREFIX_DELEGATE_THRESHOLD }, 100_000_000_000_000); | ||
| } | ||
| public static void BecomeDefaultDelegate(UInt160 account) | ||
| { | ||
| ExecutionEngine.Assert(Runtime.CheckWitness(account)); | ||
| byte[] default_delegate_bytearray = new byte[] { PREFIX_DEFAULT_DELEGATE }; | ||
| UInt160 default_delegate = (UInt160)Storage.Get(Storage.CurrentContext, default_delegate_bytearray); | ||
| BigInteger to_account_balance = BalanceOf(account); | ||
| BigInteger default_delegate_balance = BalanceOf(default_delegate); | ||
| if (to_account_balance > default_delegate_balance && to_account_balance > GetDelegateThreshold()) | ||
| Storage.Put(Storage.CurrentContext, default_delegate_bytearray, account); | ||
| else | ||
| throw new Exception("No enough tokens. You need "+(ByteString)default_delegate_balance+" NOBUGs to be the default delegate"); | ||
| } | ||
|
|
||
| public static BigInteger NewProposal(BigInteger proposal_id, UInt160 scripthash, string method, ByteString[] args) | ||
| { | ||
| StorageMap proposal_id_map = new(Storage.CurrentContext, new byte[] { PREFIX_PROPOSAL }); | ||
| if ((BigInteger)proposal_id_map.Get((ByteString)proposal_id) != 0 || ((ProposalAttributesStruct)proposal_id_map.GetObject((ByteString)(proposal_id - 1))).id != proposal_id - 1) | ||
| throw new Exception("Invalid proposal id"); | ||
| ProposalAttributesStruct proposal_attributes = new(); | ||
| proposal_attributes.id = proposal_id; | ||
| proposal_attributes.scripthash = scripthash; | ||
| proposal_attributes.method = method; | ||
| proposal_attributes.args = args; | ||
| proposal_attributes.voting_deadline = Runtime.Time + VOTING_PERIOD; | ||
| proposal_id_map.PutObject((ByteString)proposal_id, proposal_attributes); | ||
| return proposal_id; | ||
| } | ||
|
|
||
| public static void Delegate(UInt160 from, UInt160 to) | ||
| { | ||
| ExecutionEngine.Assert(Runtime.CheckWitness(from)); | ||
| StorageMap delegate_map = new(Storage.CurrentContext, PREFIX_DELEGATE); | ||
| if (to == UInt160.Zero || to == from) | ||
| delegate_map.Delete(from); | ||
| else | ||
| delegate_map.Put(from, to); | ||
| } | ||
|
|
||
| public static void Vote(UInt160 from, BigInteger proposal_index, bool for_or_against) | ||
| { | ||
| ExecutionEngine.Assert(Runtime.CheckWitness(from)); | ||
| StorageMap proposal_id_map = new(Storage.CurrentContext, new byte[] { PREFIX_PROPOSAL }); | ||
| ProposalAttributesStruct proposal_attributes = (ProposalAttributesStruct)proposal_id_map.GetObject((ByteString)proposal_index); | ||
| BigInteger voting_deadline = proposal_attributes.voting_deadline; | ||
| if(Runtime.Time > voting_deadline) | ||
| throw new Exception("Cannot vote after the deadline"); | ||
| StorageMap vote_map = new(Storage.CurrentContext, (ByteString)new byte[] { PREFIX_VOTE } + (ByteString)proposal_index); | ||
| if (for_or_against) | ||
| vote_map.Put(from, 1); | ||
| else | ||
| vote_map.Delete(from); | ||
| } | ||
|
|
||
| public static BigInteger CountVote(BigInteger proposal_id) | ||
| { | ||
| BigInteger sum_votes = 0; | ||
| Iterator voters = new StorageMap(Storage.CurrentContext, (ByteString)new byte[] { PREFIX_VOTE } + (ByteString)proposal_id) | ||
| .Find((FindOptions)((byte)FindOptions.KeysOnly + (byte)FindOptions.RemovePrefix)); | ||
| bool default_delegate_voted = GetVote(GetDefaultDelegate(), proposal_id) > 0; | ||
| while (voters.Next()) | ||
| { | ||
| UInt160 current_voter = (UInt160)(byte[])voters.Value; | ||
| if (GetVote(current_voter, proposal_id) > 0) | ||
| sum_votes += BalanceOf(current_voter); | ||
| else { | ||
| UInt160 current_delegate = GetDelegate(current_voter); | ||
| if (IsValidDelegate(current_delegate)) | ||
| { | ||
| if (GetVote(current_delegate, proposal_id) > 0) | ||
| sum_votes += BalanceOf(current_voter); | ||
| } | ||
| else | ||
| { | ||
| if (default_delegate_voted) | ||
| sum_votes += BalanceOf(current_voter); | ||
| } | ||
| } | ||
| } | ||
| return sum_votes; | ||
| } | ||
|
|
||
| public static object ExecuteProposal(BigInteger proposal_id, UInt160[] voters) | ||
| { | ||
| object[] attributes = ProposalAttributes(proposal_id); | ||
| UInt160 scripthash = (UInt160)attributes[0]; | ||
| string method = (string)attributes[1]; | ||
| ByteString[] args = (ByteString[])attributes[2]; | ||
| BigInteger voting_deadline = (BigInteger)attributes[3]; | ||
| BigInteger proposal_executed = (BigInteger)attributes[4]; | ||
| if (Runtime.Time > voting_deadline) | ||
| throw new Exception("Cannot execute proposal after the deadline"); | ||
| if (proposal_executed > 0) | ||
| throw new Exception("Proposal already executed"); | ||
|
|
||
| BigInteger voter_count = voters.Length; | ||
| BigInteger sum_votes = 0; | ||
| if (voter_count == 0) | ||
| sum_votes = CountVote(proposal_id); | ||
| else | ||
| { | ||
| bool default_delegate_voted = GetVote(GetDefaultDelegate(), proposal_id) > 0; | ||
| for (BigInteger i = 0; i < voter_count; i++) | ||
| { | ||
| UInt160 current_voter = voters[(uint)i]; | ||
| //if (current_voter is null || !current_voter.IsValid) | ||
| // throw new Exception(current_voter); | ||
| if (GetVote(current_voter, proposal_id) > 0) | ||
| sum_votes += BalanceOf(current_voter); | ||
| else | ||
| { | ||
| UInt160 current_delegate = GetDelegate(current_voter); | ||
| if (IsValidDelegate(current_delegate)) | ||
| { | ||
| if (GetVote(current_delegate, proposal_id) > 0) | ||
| sum_votes += BalanceOf(current_voter); | ||
| } | ||
| else | ||
| { | ||
| if (default_delegate_voted) | ||
| sum_votes += BalanceOf(current_voter); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (sum_votes > TotalSupply() / 2) | ||
| { | ||
| new StorageMap(Storage.CurrentContext, (ByteString)new byte[] { PREFIX_PROPOSAL } + (ByteString)proposal_id) | ||
| .Put(new byte[] { PREFIX_PROPOSAL_EXECUTED_TIME }, Runtime.Time); | ||
| return Contract.Call(scripthash, method, CallFlags.All, args); | ||
| } | ||
| else | ||
| if(sum_votes != 0) | ||
| throw new Exception("Not enough votes. Got "+(ByteString)sum_votes+ " votes from given array `UInt160[] voters`"); | ||
| else | ||
| throw new Exception("No vote counted from given array `UInt160[] voters`"); | ||
| } | ||
|
|
||
| public static void OnNEP17Payment(UInt160 from, BigInteger amount, object data) | ||
| { | ||
| } | ||
|
|
||
| public static void Update(ByteString nefFile, string manifest) | ||
| { | ||
| ExecutionEngine.Assert(Runtime.CheckWitness(Runtime.ExecutingScriptHash)); | ||
| ContractManagement.Update(nefFile, manifest, null); | ||
| } | ||
| } | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.