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

Add simple proposal voting example #12

Merged
merged 11 commits into from
Jul 28, 2023
Merged

Add simple proposal voting example #12

merged 11 commits into from
Jul 28, 2023

Conversation

eloylp
Copy link
Member

@eloylp eloylp commented Jul 7, 2023

This PR adds a basic voting smart contract with the following features:

  • Allows voting on multiple proposals
  • Each proposal is configurable by:
    • Timelock
    • Target approval rate
    • Maximum number of participants
  • Only designated admin is able to create proposals

This is a simplified version of https://github.com/eigerco/smart-proposals

pub fn create_proposal(env: Env, id: u64) -> Result<(), Error> {
let voting_period_secs = 3600; // one hour
let target_approval_rate_bps = 50_00; // At least 50% of the votes to be approved.
let total_voters = 1000; // Up to 1000 participants.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this parameters could be easily configured in the Wizard.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn this happen in init?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make them init parameters.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can move them to the init. Lets just take into account if we move them there, we need to store them in the ledger for later retrieval in the create_proposal function. Like we are doing here.

I have doubts regarding this, because adding/retrieving elements from the storage, has consequences in fees. See this docs. So maybe they are just good as hardcoded values ? I really dont know.

I will proceed on moving them to init in the meanwhile 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. Maybe add a comment in the code for future consideration of making them hardcoded if the fee is too high :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed at e3cf2f7

.set(&DataKey::Proposals, &Map::<u64, Proposal>::new(&env));
}

pub fn create_proposal(env: Env, id: u64) -> Result<(), Error> {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently its an ID .. but maybe adding a hash field would be better. Let me know your thoughts.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn this happen in init?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You said this is not doable in init?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SOrry missed this reply, i replied here : #12 (comment)

);
}

fn setup_test<'a>() -> (Env, ProposalVotingContractClient<'a>, Address) {
Copy link
Member Author

@eloylp eloylp Jul 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could make this kind of helpers more generic in the future, whenever we see this patterns repeating.

assert_eq!(Err(Error::VotingClosed), result)
}

fn advance_ledger_time_in(time: u64, env: &mut Env) {
Copy link
Member Author

@eloylp eloylp Jul 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is another test helper i found useful.

@eloylp eloylp mentioned this pull request Jul 10, 2023
@eloylp eloylp marked this pull request as ready for review July 10, 2023 21:29
@eloylp eloylp force-pushed the add-simple-voting-example branch from 7e3eb6f to 5b38e9d Compare July 20, 2023 16:28
@eloylp eloylp self-assigned this Jul 26, 2023
Copy link
Contributor

@geofmureithi geofmureithi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

.set(&DataKey::Proposals, &Map::<u64, Proposal>::new(&env));
}

pub fn create_proposal(env: Env, id: u64) -> Result<(), Error> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn this happen in init?

#[contractimpl]
impl ProposalVotingContract {
pub fn init(env: Env, admin: Address) {
env.storage().set(&DataKey::Admin, &admin);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to ensure you are logged in as admin

Suggested change
env.storage().set(&DataKey::Admin, &admin);
admin.require_auth();
env.storage().set(&DataKey::Admin, &admin);

pub fn create_proposal(env: Env, id: u64) -> Result<(), Error> {
let voting_period_secs = 3600; // one hour
let target_approval_rate_bps = 50_00; // At least 50% of the votes to be approved.
let total_voters = 1000; // Up to 1000 participants.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn this happen in init?

contracts/Cargo.toml Outdated Show resolved Hide resolved
@eloylp eloylp force-pushed the add-simple-voting-example branch from 7bbab66 to a170e98 Compare July 27, 2023 16:49
@eloylp
Copy link
Member Author

eloylp commented Jul 27, 2023

@geofmureithi just added rust docs and checked add. See last 2 commits.

Requesting re-review !

@eloylp eloylp requested a review from geofmureithi July 27, 2023 16:51
Copy link
Contributor

@geofmureithi geofmureithi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is a specific reason not to run creation in init, please highlight it. Otherwise, LGTM

Copy link
Contributor

@geofmureithi geofmureithi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is a specific reason not to run creation in init, please highlight it. Otherwise, LGTM

@eloylp
Copy link
Member Author

eloylp commented Jul 28, 2023

If there is a specific reason not to run creation in init, please highlight it. Otherwise, LGTM

Thanks for review @geofmureithi . This contract has the capability of tracking multiple proposals during its lifecycle. The parameters we store in the init function are only intended as "defaults", for later use in create_proposal function, that way its not needed to specify all proposal parameters on each call, just the id of the new proposal, which i think is convenient.

If an user, wants different parameters for an specific proposal during the lifecycle of this contract, it can invoke directly the create_custom_proposal as that function will require all proposal parameters, bypassing defaults.

@eloylp eloylp merged commit dbba7bd into main Jul 28, 2023
@eloylp eloylp deleted the add-simple-voting-example branch July 28, 2023 10:56
@geofmureithi
Copy link
Contributor

But once you deploy you get a contact id, shouldn't we be using that?

@eloylp
Copy link
Member Author

eloylp commented Jul 28, 2023

But once you deploy you get a contact id, shouldn't we be using that?

@geofmureithi

With the current example, we can have multiple proposals in the same smart contract. So for voting we would need the contract id + the proposal id.

An example of how to invoke the contract can be checked here: #5 (comment)

@geofmureithi
Copy link
Contributor

I have not seen any other examples approach it that way. Especially because everything else is already hardcoded hence it wont create a new proposal but rather a clone of the same proposal just with different id.

@eloylp
Copy link
Member Author

eloylp commented Jul 28, 2023

I have not seen any other examples approach it that way. Especially because everything else is already hardcoded hence it wont create a new proposal but rather a clone of the same proposal just with different id.

I was probably influenced by this . Although is true eth is a different environment.

There are other examples, like the multi swap or auth . They use multiple data structures to represent different entities.

Anyway, if you think there is something wrong with the current design, let me know and we can change it.

@geofmureithi
Copy link
Contributor

I think the problem you ate trying to solve is already solved by wasm. I see how you can see it that way but instead of your approach we would rather have a single proposal per contract. I think there is no objectively better one because it matters in use case.
Yet we are building for developers. You created a two part process where one is needed. If someone wants to reuse then they can write a bash script.
IMO lets not reinvent the wheel.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Choose/elaborate a configurable smart contract to add to Nebula's UI
3 participants