near-daos / sputnik-dao-contract Goto Github PK
View Code? Open in Web Editor NEWSmart contracts for https://app.astrodao.com
Home Page: https://astrodao.com/
License: MIT License
Smart contracts for https://app.astrodao.com
Home Page: https://astrodao.com/
License: MIT License
Currently no tags in this repo - would be great to see the changes over time, to know what has been changed since my DAOs creation to inform of potential upgrades or backward compat issues.
Currently there is nothing stopping a user from calling bounty_claim
on the same bounty ID multiple times. This will likely happen by accident but confuses the logic in the rest of the contract, which assumes that an account only has one claim per bounty.
If a bounty has been paid out via an approval of a BountyDone
proposal, it'll remove one key-value pair, but not additional ones.
It does work for the user to call bounty_giveup
to remove the other, however since this is an strange case, it may not be discoverable via a frontend.
At the end of the day, it just make sense to make this limit for usability.
You can check this in the branch for #28 which takes care of another issue by using this script:
#!/bin/sh
# Change these to your account ids
./build.sh
export CONTRACT_ID=sputnikdao2.mike.testnet
export CONTRACT_PARENT=mike.testnet
# Redo account (if contract already exists)
near delete $CONTRACT_ID $CONTRACT_PARENT
near create-account $CONTRACT_ID --masterAccount $CONTRACT_PARENT
# Set up
near deploy $CONTRACT_ID --wasmFile ~/near/sputnik-dao-contract/sputnikdao2/res/sputnikdao2.wasm
export COUNCIL='["'$CONTRACT_ID'"]'
near call $CONTRACT_ID new '{"config": {"name": "genesis2", "purpose": "test", "metadata": ""}, "policy": '$COUNCIL'}' --accountId $CONTRACT_ID
# Add proposal for a Transfer kind that pays out 19 NEAR
near call $CONTRACT_ID add_proposal '{"proposal": {"description": "test bounty", "kind": {"AddBounty": {"bounty": {"description": "do the thing", "token": "", "amount": "19000000000000000000000000", "times": 3, "max_deadline": "1925376849430593581"}}}}}' --accountId $CONTRACT_PARENT --amount 1
# Show error when a user tries to vote along with log
near call $CONTRACT_ID act_proposal '{"id": 0, "action": "VoteApprove"}' --accountId $CONTRACT_ID
# Someone claims the same bounty twice
near call $CONTRACT_ID bounty_claim '{"id": 0, "deadline": "1925376849430593581"}' --accountId $CONTRACT_PARENT --amount 1
near call $CONTRACT_ID bounty_claim '{"id": 0, "deadline": "1925376849430593581"}' --accountId $CONTRACT_PARENT --amount 1
# Show bounty claims
near view $CONTRACT_ID get_bounty_claims '{"account_id": "'$CONTRACT_PARENT'"}'
# Add BountyDone proposal done
near call $CONTRACT_ID add_proposal '{"proposal": {"description": "test bounty done", "kind": {"BountyDone": {"bounty_id": 0, "receiver_id": "'$CONTRACT_PARENT'"}}}}' --accountId $CONTRACT_PARENT --amount 1
# Vote it in
near call $CONTRACT_ID act_proposal '{"id": 1, "action": "VoteApprove"}' --accountId $CONTRACT_ID
# See how many now. Expect it to be empty but it's not
near view $CONTRACT_ID get_bounty_claims '{"account_id": "'$CONTRACT_PARENT'"}'
When policy is too large, it's not possible to update it via Web Wallet.
Specifically allowing for policy per group and per proposal type.
The main README which pops out when you access https://github.com/near-daos/sputnik-dao-contract is no longer valid since it refers to the V1 version of sputnik.
The main README should be the V2: https://github.com/near-daos/sputnik-dao-contract/tree/main/sputnikdao2
"Hub" functionality on the factory contract:
New proposals types:
New action types:
Upgradability:
Extend Policy:
This allows to have biggest membership list with different permissions, while still maintain smaller list of people who can make actions and decisions.
Token issuance:
One of the critical requirements is to make this code composable, so others can strip down features they don't need for their own version. E.g. token issuance is added as separate module and can be removed by removing few lines of code and trait implementation.
Note that all current DAOs will need to "exit" into new versions while keeping old names unusable.
Even though this issue is known and that the staking contract prevents this issue from happening, I believe it's good to have an issue for it.
Currently the stacked-token weighted votes only consider that user's weight/balance at the time when the users makes the action of voting itself, which is a potential threat to the voting system if some users collude in concentrating delegations/tokens for one user voting (to then proceed to re-delegate to another user to vote, and so on), since the users' undelegation doesn't affects their previous votes.
It should be noted that the staking implementation prevents this problem by defining a next_action_timestamp
state which gets placed when a user undelegates, preventing them from delegating it again (or withdrawing the token) during the time in which any proposal will be alive.
So I believe that, ideally, the DAO wouldn't depend on that kind of behavior from the staking contract, because a bad change on the duration of the proposals on the DAO or on the period in which the users can't delegate/withdraw on the staking contract could enable this threat to the voting system.
Although a change in this would probably require indexing of votes and a lot of increase in gas usage for the overall system (each vote, each un/delegation), perhaps it's good to have an issue for this.
This has been suggested in #69.
More precisely #69 (comment).
This test is failing on main
right now it seems. I saw this by running cargo test -- --nocapture
in the project root.
Create test coverage for the following:
Currently to quit DAO, member needs to propose to get removed and then that needs to pass.
We should have a quit function that immediately removes the person.
Things to consider:
Currently if DAO creation fails via factory - the deposit kept on factory's balance.
To fix this, the callback must be handled and checked if the account creation / deployment was successful.
This is not urgent, but still needs investigation. Check that we don't end up in the following situation:
Since the cross contract calls and the callbacks are async on near, it's very possible that you run into a situation where you claim funds from the DAO multiple times and you'll get the funds each time (instead of getting an error on the second claim). This is because the callback that tells you that the transfer is successful happens long after the actual transfer. So in theory, you can span 10 transactions of the same type until you get the result from the first transaction (if it's successful or not). Conclusion? You could claim and receive 10 times the funds that you should.
Set an auto-kill time -> if there were no passed proposals for X days/weeks/months => it kills the DAO and sends funds to the dedicated account
This might be a good requirement for Treasury DAO investing into other DAOs - they should have auto kill setup toward it, in case the council bails/looses access/or whatever.
These are all the proposal types available in sputnik:
https://github.com/near-daos/sputnik-dao-contract/blob/main/sputnikdao2/src/proposals.rs#L59-L114
Not all of them are covered by simulation tests, so please take a look on the existing ones (https://github.com/near-daos/sputnik-dao-contract/blob/main/sputnikdao2/tests/test_general.rs) and try to cover all of them in the same way.
Lately, we are trying to use more ava
testing. See example here: https://github.com/near-daos/sputnik-dao-contract/blob/main/sputnikdao2/tests-ava/__tests__/proposals.ava.ts
Any addition of simulation/ava tests is a plus 👍 .
All the smart contracts related to sputnik V1 should live in their own repository:
Looks like there are a couple ways to approach bounties with sputnikdao2. The way I've been playing with goes as follows:
AddBounty
proposal is created.BountyDone
proposal is created for the bounty from step 1.BountyDone
proposal, firing off the payout.Handy script to run or copy/paste using NEAR CLI:
#!/bin/sh
# Change these to your account ids
./build.sh
export CONTRACT_ID=sputnikdao2.mike.testnet
export CONTRACT_PARENT=mike.testnet
# Redo account (if contract already exists)
near delete $CONTRACT_ID $CONTRACT_PARENT
near create-account $CONTRACT_ID --masterAccount $CONTRACT_PARENT
# Set up
near deploy $CONTRACT_ID --wasmFile ~/near/sputnik-dao-contract/sputnikdao2/res/sputnikdao2.wasm
export COUNCIL='["'$CONTRACT_ID'"]'
near call $CONTRACT_ID new '{"config": {"name": "genesis2", "purpose": "test", "metadata": ""}, "policy": '$COUNCIL'}' --accountId $CONTRACT_ID
# Add proposal for a Transfer kind that pays out 19 NEAR
near call $CONTRACT_ID add_proposal '{"proposal": {"description": "test bounty", "kind": {"AddBounty": {"bounty": {"description": "do the thing", "token": "near", "amount": "19000000000000000000000000", "times": 3, "max_deadline": "1925376849430593581"}}}}}' --accountId $CONTRACT_PARENT --amount 1
# Show error when a user tries to vote along with log
near call $CONTRACT_ID act_proposal '{"id": 0, "action": "VoteApprove"}' --accountId $CONTRACT_ID
# Someone claims the bounty
near call $CONTRACT_ID bounty_claim '{"id": 0, "deadline": "1925376849430593581"}' --accountId $CONTRACT_PARENT --amount 1
# Show bounty claims
near view $CONTRACT_ID get_bounty_claims '{"account_id": "'$CONTRACT_PARENT'"}'
# Add BountyDone proposal done
near call $CONTRACT_ID add_proposal '{"proposal": {"description": "test bounty done", "kind": {"BountyDone": {"bounty_id": 0, "receiver_id": "'$CONTRACT_PARENT'"}}}}' --accountId $CONTRACT_PARENT --amount 1
# Vote it in
near call $CONTRACT_ID act_proposal '{"id": 1, "action": "VoteApprove"}' --accountId $CONTRACT_ID --gas 300000000000000
# See how many now. Expect it to be empty but it's not
near view $CONTRACT_ID get_bounty_claims '{"account_id": "'$CONTRACT_PARENT'"}'
Here's the bottom part of the output, which shows that it's not clearing:
…
View call: sputnikdao2.mike.testnet.get_bounty_claims({"account_id": "mike.testnet"})
[
{
bounty_id: 0,
start_time: '1625444816555618690',
deadline: '1925376849430593581',
completed: false
}
]
Scheduling a call: sputnikdao2.mike.testnet.add_proposal({"proposal": {"description": "test bounty done", "kind": {"BountyDone": {"bounty_id": 0, "receiver_id": "mike.testnet"}}}}) with attached 1 NEAR
Transaction Id 5Koeb389XEt7kcHq99tSy5TGSNpy1Tr6bj4g16fWBArG
To see the transaction in the transaction explorer, please open this url in your browser
https://explorer.testnet.near.org/transactions/5Koeb389XEt7kcHq99tSy5TGSNpy1Tr6bj4g16fWBArG
1
Scheduling a call: sputnikdao2.mike.testnet.act_proposal({"id": 1, "action": "VoteApprove"})
Transaction Id Bp4jFu31v9XcXZQdWvcjaVmWWTdbLcBCMwG85bBiLTVr
To see the transaction in the transaction explorer, please open this url in your browser
https://explorer.testnet.near.org/transactions/Bp4jFu31v9XcXZQdWvcjaVmWWTdbLcBCMwG85bBiLTVr
''
View call: sputnikdao2.mike.testnet.get_bounty_claims({"account_id": "mike.testnet"})
[
{
bounty_id: 0,
start_time: '1625444816555618690',
deadline: '1925376849430593581',
completed: false
}
]
Tracing through the series of calls:
First, return proposal bond, but this is different than the bounty bond right?
Call internal_execute_bounty_payout
sputnik-dao-contract/sputnikdao2/src/proposals.rs
Lines 345 to 348 in c2cf155
Bounty claimaint is paid the actual bounty, but I don't see the bond being returned
sputnik-dao-contract/sputnikdao2/src/bounties.rs
Lines 77 to 91 in c2cf155
Users can vote on on-going proposals in three different ways: as in approving, as in rejecting or as in removing (for punishing spams) a proposal.
But users cannot undo their votes once they are made, and for on-going proposals, I believe this could be useful since users could individually change their minds after they voted.
If some users would like to "change" their votes, this may be possible by re-creating the proposal and then voting differently, but that requires some coordination.
So I expect this to be a "desired" feature for users, as they would be allowed to "change" or "undo" their votes.
But this also has implications for internals, since this opens the possibility to track users and roles changes more closely. Although consuming more gas and increasing the overall code complexity, this should make the voting system behave in a safer manner.
The way to implement this: https://github.com/referencedev/staking-farm
Problem:
There was a backward compatibility error introduced at some point in the sputnik contracts and we need to find out the exact commit which introduced it.
How to find it?
Basically by picking random commits from https://github.com/near-daos/sputnik-dao-contract/commits/main and see where the error was introduced.
How to do it?
You need to follow the instructions below.
Instructions:
ctindogaru.testnet
with your own testnet account.xsda21da
)cargo clean
and wait for completion.cargo update
and wait for completion../build
and wait for completion.near view ctindogaru-dao.sputnik-factory.ctindogaru.testnet get_proposal '{"id": 0}’
. Please make sure to replace ctindogaru.testnet
with your own testnet account.Cannot deserialize value with Borsh
error, it means that commit id contains a backward compatible issue. Please create a new DAO by following these instructions, but make sure to replace ctindogaru-dao
with another name and ctindogaru.testnet
with your own testnet account.:export COUNCIL='["ctindogaru.testnet"]'
export ARGS=`echo '{"config": {"name": "ctindogaru-dao", "purpose": "ctindogaru DAO", "metadata":""}, "policy": '$COUNCIL'}' | base64`
near call sputnik-factory.ctindogaru.testnet create "{\"name\": \"ctindogaru-dao\", \"args\": \"$ARGS\"}" --accountId sputnik-factory.ctindogaru.testnet --gas 150000000000000 --amount 10
Repeat instructions 2-8 until the errror does not show up anymore and you find the exact commit which introduced this backward compatible issue.
10. If you run out of funds in your wallet, please create a new account by typing near login
and repeat instructions 1-9.
Docs mention mint
as a proposal-kind
- https://github.com/near-daos/sputnik-dao-contract/tree/main/sputnikdao2#proposal-kinds
Source code says otherwise - https://github.com/near-daos/sputnik-dao-contract/blob/main/sputnikdao2/src/proposals.rs#L48
Hello friends I am facing problems when trying to interact with the staking contract to delegate tokens for token voting policy:
Here is a loom video about it: https://www.loom.com/share/6b0ab4a73b5349e4a3aecb69941995b9
Any information about how to work properly with the staking contract would be great.
I have attempted to create a new DAO and it failed.
devx.sputnikdao.near
DAO and pressed Submit
.devx.sputnikdao.near
DAO created without any information;Via Telegram chat... Right now the staking contract is a plug-inable interface to allocate votes. Currently a DAO can only accept a staking contract (and can't replace or add one), which I would like to see happen in the future.
here, store_blob returns base58encoded hash
sputnik-dao-contract/sputnikdao2/src/lib.rs
Line 216 in fad0588
But in the proposal is stored as base64
Also remove_blob requires base64 encoding, so it's not the "hash" returned by store_blob
It's a little confusing
I ran the method bounty_done
on the sputnikdao v2 contract and I received the error ERR_MIN_BOND.
The full command looked like this: NEAR_ENV=mainnet near call mochi.sputnik-dao.near bounty_done '{"id": 0, "account_id": "moses.near", "description": "Fixed issue in PR https://github.com/near-examples/rust-status-message/pull/72"}' --accountId moses.near --amount 1
It appears that the bounty_done
isn't a payable method.
@mikedotexe suggested creating a proposal which worked: NEAR_ENV=mainnet near call mochi.sputnik-dao.near add_proposal '{"proposal": {"description": "Moses completed the bounty", "kind": {"BountyDone": {"bounty_id": 0, "receiver_id": "moses.near"}}}}' --accountId moses.near --amount 1
.
Re: https://github.com/near-daos/sputnik-dao-contract/tree/main/sputnikdao-factory2
Looking for opinion.
Proposal: to add a factory function call to remove an empty DAO from the state (list), and refund the amount to the creator.
There are few DAOs which created with failed call (our of GAS for instance) or deleted off-contract by using full access key, to avoid clogging of DAO list.
Currently DAO only supports voting with it's internal token for voting.
This is because it just uses internal balance without any cross contract calls to fetch state.
Even if we assume that we want to fetch the balance of the given user via cross contract call, this opens up potential issues that user just keep moving tokens from one account to another and vote with them.
To prevent that, tokens must be "frozen" in some way during the vote or alternatively if user moves their tokens - their vote gets nullified.
One option is that user must deposit the tokens into the DAO first to be able to vote (e.g. stake to participate in the governance).
What are other options to handle this?
There is a comment about this in Telegram that I could not reproduce, but when I tried following the directions on my Macbook I ran into this error. See Step 6 of the README at the project root
near call $CONTRACT_ID create "{\"name\": \"genesis\", \"args\": \"$ARGS\"}" --accountId $CONTRACT_ID --amount 5 --gas 150000000000000
Scheduling a call: sputfact.mike.testnet.create({"name": "genesis", "args": "eyJjb25maWciOiB7Im5hbWUiOiAiZ2VuZXNpcyIsICJwdXJwb3NlIjogIkdlbmVzaXMgREFPIiwgIm1ldGFkYXRhIjoiIn0sICJwb2xpY3kiOiBbImNvdW5jaWwtbWVtYmVyLnRlc3RuZXQiLCAiWU9VUl9BQ0NPVU5ULnRlc3RuZXQiXX0K"}) with attached 5 NEAR
Doing account.functionCall()
Receipts: 8pzTSgQNivDtTe27pdnNf3vovrpUPvfWGC7dpJKPNkWF, 5aVK9Uazj5HsMbRNYmrG32ESQFxFycmtj9cZ3P7QNVaz
Failure [sputfact.mike.testnet]: Error: {"index":0,"kind":{"ExecutionError":"Smart contract panicked: panicked at 'Must have code hash', sputnikdao-factory2/src/lib.rs:123:64"}}
ServerTransactionError: {"index":0,"kind":{"ExecutionError":"Smart contract panicked: panicked at 'Must have code hash', sputnikdao-factory2/src/lib.rs:123:64"}}
at Object.parseResultError (/Users/mike/.nvm/versions/node/v14.16.1/lib/node_modules/near-cli/node_modules/near-api-js/lib/utils/rpc_errors.js:31:29)
at Account.signAndSendTransactionV2 (/Users/mike/.nvm/versions/node/v14.16.1/lib/node_modules/near-cli/node_modules/near-api-js/lib/account.js:160:36)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at async scheduleFunctionCall (/Users/mike/.nvm/versions/node/v14.16.1/lib/node_modules/near-cli/commands/call.js:57:38)
at async Object.handler (/Users/mike/.nvm/versions/node/v14.16.1/lib/node_modules/near-cli/utils/exit-on-error.js:52:9) {
type: 'FunctionCallError',
context: undefined,
index: 0,
kind: {
ExecutionError: "Smart contract panicked: panicked at 'Must have code hash', sputnikdao-factory2/src/lib.rs:123:64"
},
I think it's this line:
https://github.com/near-daos/sputnik-dao-contract/blame/90184759ff1fd18212a4cfa638a7a950ba4177e9/sputnikdao-factory2/src/lib.rs#L59
This probably applies to bounties as well, but will keep this issue focused on the Transfer proposal kind. Also, this applies to the original sputnikdao contract for the Payout type, but again, we'll focus on the newer contract here.
First, there's nothing stopping someone from creating a Transfer proposal that pays an amount of native NEAR Ⓝ that exceeds the available balance on the contract. We should probably not allow the creation of a proposal like this. This will encourage people to add a deposit to the call or else transfer Ⓝ before creating the proposal.
This doesn't, however, solve all the problems. Someone could create 10 Transfer proposals for 50 Ⓝ when the contract balance is 100 Ⓝ.
Second, when voting on a Transfer proposal, don't allow the vote logic to continue if the payout in Ⓝ cannot happen. If we don't add a more helpful error message/code, the error appears in Wallet with an ExecutionError
message:
Exceeded the account balance.
This is an unfriendly message to someone who is simply voting on a proposal and happens to be the last person to trigger the payout.
Third, a frontend for these proposal doesn't have a great way to determine if the vote buttons/interface should be enabled, and if they shouldn't be enabled, the reason why.
Steps to reproduce, by placing this in a shell file:
#!/bin/sh
# Change these to your account ids
export CONTRACT_ID=sputnikdao2.mike.testnet
export CONTRACT_PARENT=mike.testnet
# Redo account (if contract already exists)
near delete $CONTRACT_ID $CONTRACT_PARENT
near create-account $CONTRACT_ID --masterAccount $CONTRACT_PARENT
# Set up (change the wasmFile location)
near deploy $CONTRACT_ID --wasmFile ~/near/sputnik-dao-contract/sputnikdao2/res/sputnikdao2.wasm
export COUNCIL='["'$CONTRACT_ID'"]'
near call $CONTRACT_ID new '{"config": {"name": "genesis2", "purpose": "test", "metadata": ""}, "policy": '$COUNCIL'}' --accountId $CONTRACT_ID
# Set up a Transfer proposal for 3,000 NEAR which is more than the account has
# Note that it is allowed and perhaps shouldn't be
near call $CONTRACT_ID add_proposal '{"proposal": {"description": "test", "kind": {"Transfer": {"token_id": "", "receiver_id": "demo.testnet", "amount": "3000000000000000000000000000"}}}}' --accountId $CONTRACT_ID --amount 1
# A vote happens and a deeper error emerges that may confuse folks
near call $CONTRACT_ID act_proposal '{"id": 0, "action": "VoteApprove"}' --accountId $CONTRACT_ID
The last line of voting will result in this kind of output:
…
type: 'FunctionCallError',
context: undefined,
index: 0,
kind: { ExecutionError: 'Exceeded the account balance.' },
transaction_outcome: {
…
internal_execute_proposal can include remote-upgrade & remote-call
if the Promise fails, the proposal ends-up approved but not executed
Proposed solution:) internal_execute_proposal should always return a Promise with a .then callback
and the proposal should be marked as Approved and the last vote counted only if the promise executed correctly
Security enhancement: For function calls the DAO should register target code hash and check before execution. (to avoid a code-swap attack before last vote)
If possible, remove any use of std
inside sputnik.
Alternatives: NEAR's own libraries or implementing a different logic in all the places that use std.
This issue is in regards to the SputnikDAO v2 contract.
Since proposals are not removed when completed, (accepted, rejected…) they take up storage space. This will eventually chip away at the storage on the DAO contract. On a medium-to-long timeframe, this can suddenly make certain DAOs inoperable until someone funds DAO with more NEAR. This is preventable by taking into consideration the amount of storage a proposal uses.
For example, James Waugh set up an AstroDAO for Portland, Oregon. When you go through the interface of Astro, it asks you to start a DAO with 5 Ⓝ, and this is how much we have in that DAO.
Here is a transaction where a person creates a proposal to a DAO:
https://explorer.testnet.near.org/transactions/4i8XGzg8g3TLiZVQPyy8MLjB7RrMJnWKs3aKDkTjq8Gc
This costs the bond amount (1 Ⓝ) plus the transaction fee of:
0.0007097988201294 Ⓝ
Let's pretend that this DAO explicitly does function calls, member addition/removal, and payouts in fungible tokens.
After the above proposal is accepted or rejected, the bond is returned to the proposer, but the storage of the proposal persists. If you compare before and after the proposal, you'll see that the DAO contract loses:
0.000665812311892 Ⓝ
This is a low amount but means after a few thousand proposals the DAO will run out of the default 5 Ⓝ that AstroDAO asked for in the creation wizard process. Then no more proposals can be added until someone figures out they need to add more Ⓝ.
Solution
For the various proposal types, come up with expected or worst-case-scenario storage fees, and subtract that from the bond when it's being returned. This is not web2; not everything is free.
Do we plan to support nested groups with different weights inside of a group?
For example, if I have a group called Engineering and I have 2 child groups: [Senior, Junior] of the weight I'd allocate to the parent group, I'd like to re-allocate new weights to children [Senior: 70%, Junior 30%], instead of creating a bunch of sibling groups.
Not sure if this is something we should support in the contract itself or use the existing primitives but use Astro UI to created nested groups.
I know a proposal can be created to add a member, but can add multiple members at the initialization of the contract?
Or is there a special function to do this?
If not, in your opinion, would it be a good addition?
I'm currently coming up to a use case where I need to batch add members to a DAO. Say depositors of an Escrow, where the Escrow will transfer the funds to a new DAO contract, and each depositor will become a member of the DAO.
How would you handle this? ☝️
When trying to run the build.sh
script in the sputnikdao
directory I get a number of errors.
error[E0369]: binary operation `!=` cannot be applied to type `&ProposalStatus`
--> src/lib.rs:85:22
|
85 | self.clone() != &ProposalStatus::Vote && self != &ProposalStatus::Delay
| ------------ ^^ --------------------- &ProposalStatus
| |
| &ProposalStatus
|
= note: an implementation of `std::cmp::PartialEq` might be missing for `&ProposalStatus`
error[E0369]: binary operation `!=` cannot be applied to type `&ProposalStatus`
--> src/lib.rs:85:55
|
85 | self.clone() != &ProposalStatus::Vote && self != &ProposalStatus::Delay
| ---- ^^ ---------------------- &ProposalStatus
| |
| &ProposalStatus
|
= note: an implementation of `std::cmp::PartialEq` might be missing for `&ProposalStatus`
…
Hackathon participant here
Can I fork this repo and publish to docs.rs
in pr?
docs.rs
is the best place for rust documentation and this would greatly improves developer experience here. Onboarding rust developers into smart-contract-development without that is not even viable in my opinion. Need a birds eye view on rust primitives and no good way to currently do that.
I'd modify the github ci workflow and cargo packages to achieve this. I'd need input from you on the cargo metadata. Apart from that I can send a pr?
If not I'd still push to docs.rs
, it is needed.
At the top of proposal_status
is an assertion that doesn't seem to belong there. It will panic if the status is not InProgress
It seems that this can easily be removed as the only two places where it's called are guarded against the same assertion.
Not a difficult ticket, just documenting here for a small PR, and so we don't combine a bunch of changes into on PR.
After this assertion is removed, users can expect to call this public function and not get an error.
I have just run a Poll on our DAO https://app.astrodao.com/dao/swine-dao.sputnik-dao.near/proposals/swine-dao.sputnik-dao.near-26
When the majority (51%) of the council members had voted the Poll was automatically approved. This means that the other council members did not have the opportunity to vote.
I would like to suggest that this is changed to enable a Vote (Poll) proposals to stay open after the threshold of votes are cast.
This should only apply to this one category of Poll proposals and not affect the general Voting Policy set for the DAO
Imagine that scenario:
roles: [
{
name: "all",
kind: "Everyone",
permissions: ["*:AddProposal",
"*:VoteApprove"],
vote_policy: {}
}
];
...
default_vote_policy:
{
weight_kind: "TokenWeight",
....
So all that matters is delegaions
2. Delegaions on 'alice' >= threshold
3. Some proposal
4. And 'alice' tries to VoteApprove via act_proposal().
The issue is that this part is unreachable for RoleKind::Everyone(alice)
So RoleKind::Everyone can't execute proposal it seems
near call cryptdao3.kula.testnet add_proposal '{"proposal": {"target": "illia", "description": "test", "kind": {"type": "ChangePolicy", "policy": [{"max_amount": "100", "votes": 2}, {"max_amount": "1000", "votes": 3}, {"max_amount": "2000", "votes": [1, 2]}, {"max_amount": "10000000", "votes": [2, 3]}]}}}' --accountId=kula.testnet --amount=0.1
ExecutionError: 'Smart contract panicked: panicked at \'Failed to deserialize input from JSON.: Error("unknown variant `type`, expected one of `ChangeConfig`, `ChangePolicy`, `AddMemberToRole`, `RemoveMemberFromRole`, `FunctionCall`, `UpgradeSelf`, `UpgradeRemote`, `Transfer`, `Vote`", line: 1, column: 65)\', src/proposols.rs:181:1'
how can i set kind with the proposal?
Currently Transfer
and BountyDone
proposals have payouts that eventually hit the method internal_payout
.
This method will attempt to pay out with native NEAR Ⓝ or a fungible token. In the case of fungible tokens, it uses cross-contract calls here:
sputnik-dao-contract/sputnikdao2/src/proposals.rs
Lines 239 to 260 in 317ea4f
Since there is no callback provided, the transfer might fail but the bounty is considered completed. There may be times where individuals forget to top up their fungible tokens and make an honest mistake that will confuse folks.
Ideally, if a fungible token transfer fails, we can have some way of letting it be known that this proposal needs more tokens to complete the transfer.
I think the best solution might be to add an item to the ProposalStatus
enum, something like PayoutFailed
.
In the case of a plain transfer (with ft_transfer
) we'd simply check for a promise failure.
For the transfer-and-call functionality (with ft_transfer_call
) we'll have to implement ft_resolve_transfer
(see Nomicon for details) and ensure that the amount
argument given is always 0
. We expect that the full bounty amount will always be transferred and none will be returned.
To add support for FT, Sputnik contracts must be implementing FT Receiver pattern to keep track of the received balance.
The received balance is then can be used internally to identify which tokens this DAO have and how much value.
E.g.
/// Keeps track of balances per FT account.
ft_balances: LookupMap<AccountId, Balance>,
Payout proposal then can select asset_account_id
. Empty asset name is considered base token.
Increase unit test coverage of the factory:
https://github.com/near-daos/sputnik-dao-contract/blob/main/sputnikdao-factory2/src/lib.rs
Every method should be tested with at least one happy scenario. Please also add a failure scenario where possible.
There are missing methods get_grace_period and ChangeVotePeriod in the contract.
Bounties is a way for a DAO to request work and show prepaid amount.
Bounty usually would contain next information:
description
amount
-- amount to be paid outasset_name
-- accountId for asset to be paid (empty for native token?)repeat
-- how many times this bounty can be donemax_deadline
-- maximum time from claim that can be spent on this bountyBounty life cycle:
bounty_claim(id, deadline)
to identify they want to work on it. Claim requires a bond that will be held for the deadline. Deadline must be less or equal than max_deadline
set by bounty maker.
repeat
times at the same time.bounty_giveup(id)
, receiving back their bond. Within first X
days - they receive 100% of their bond. After that, bond size gets linearly reduced to 0 at deadline
.bounty_done(id, details)
, which marks bounty claim resolved and creates a proposal to payout the bounty reward. Bond is moved from claim to payout proposal. If proposal passes - the bond gets returned in full.deadline
, the bond is withheld and another person can claim it.All bounties must be accounted for in the DAO to make sure that DAO can't spent money below outstanding bounties.
Generally, any payout that would withdraw more money than is available should fail at the adding proposal time.
Mike had some good suggestions on #69.
Please create a PR addressing all of them.
My comment on this:
We should definitely fix that in the contract.
To have the smoothest experience while maintaining security for fungible tokens, the function would be have a Batch Action on the contract that does two function calls.
Create test coverage for the following:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.