Skip to content

Commit

Permalink
started adding x/onft staking module
Browse files Browse the repository at this point in the history
  • Loading branch information
NoahSaso committed Jun 7, 2024
1 parent bb8224e commit 829a626
Show file tree
Hide file tree
Showing 13 changed files with 1,446 additions and 2 deletions.
33 changes: 33 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ overflow-checks = true
[workspace.dependencies]
anyhow = { version = "1.0" }
assert_matches = "1.5"
chrono = { version = "0.4.27", default-features = false }
cosm-orc = { version = "4.0" }
cosm-tome = "0.2"
cosmos-sdk-proto = "0.19"
Expand Down
2 changes: 1 addition & 1 deletion contracts/voting/dao-voting-cw721-roles/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub enum ContractError {
#[error("New cw721-roles contract must be instantiated with at least one NFT")]
NoInitialNfts {},

#[error("Only the owner of this contract my execute this message")]
#[error("Only the owner of this contract may execute this message")]
NotOwner {},

#[error("Got a submessage reply with unknown id: {id}")]
Expand Down
2 changes: 1 addition & 1 deletion contracts/voting/dao-voting-cw721-staked/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub enum ContractError {
#[error("Nothing to claim")]
NothingToClaim {},

#[error("Only the owner of this contract my execute this message")]
#[error("Only the owner of this contract may execute this message")]
NotOwner {},

#[error("Can not unstake that which you have not staked (unstaking {token_id})")]
Expand Down
58 changes: 58 additions & 0 deletions contracts/voting/dao-voting-onft-staked/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
[package]
name = "dao-voting-onft-staked"
authors = [
"CypherApe cypherape@protonmail.com",
"Jake Hartnell",
"ekez",
"noah <noah@daodao.zone>",
]
description = "A DAO DAO voting module based on staked x/onft tokens."
edition = { workspace = true }
license = { workspace = true }
repository = { workspace = true }
version = { workspace = true }

[lib]
crate-type = ["cdylib", "rlib"]

[features]
# for more explicit tests, cargo test --features=backtraces
backtraces = ["cosmwasm-std/backtraces"]
# use library feature to disable all instantiate/execute/query exports
library = []
# use test tube feature to enable test-tube integration tests, for example
# cargo test --features "test-tube"
test-tube = []
# when writing tests you may wish to enable test-tube as a default feature
# default = ["test-tube"]

[dependencies]
chrono = { workspace = true }
cosmwasm-std = { workspace = true }
cosmwasm-schema = { workspace = true }
cw-storage-plus = { workspace = true }
cw-controllers = { workspace = true }
cw-hooks = { workspace = true }
cw721-controllers = { workspace = true }
cw-utils = { workspace = true }
cw2 = { workspace = true }
dao-dao-macros = { workspace = true }
dao-hooks = { workspace = true }
dao-interface = { workspace = true }
dao-voting = { workspace = true }
osmosis-std = { workspace = true }
osmosis-std-derive = { workspace = true }
prost = { workspace = true }
prost-types = { workspace = true }
schemars = { workspace = true }
serde = { workspace = true }
thiserror = { workspace = true }

[dev-dependencies]
anyhow = { workspace = true }
cw-multi-test = { workspace = true }
dao-proposal-single = { workspace = true }
dao-proposal-hook-counter = { workspace = true }
dao-test-custom-factory = { workspace = true }
dao-testing = { workspace = true, features = ["test-tube"] }
osmosis-test-tube = { workspace = true }
43 changes: 43 additions & 0 deletions contracts/voting/dao-voting-onft-staked/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# `dao-voting-onft-staked`

This is a basic implementation of an NFT staking contract that supports
OmniFlix's NFT standard:
[x/onft](https://github.com/OmniFlix/omniflixhub/tree/main/x/onft).

Staked tokens can be unbonded with a configurable unbonding period. Staked balances can be queried at any arbitrary height by external contracts. This contract implements the interface needed to be a DAO DAO [voting module](https://github.com/DA0-DA0/dao-contracts/wiki/DAO-DAO-Contracts-Design#the-voting-module).

### Stake process

Unlike the base cw721 smart contract, the x/onft SDK module doesn't support
executing a smart contract on NFT transfer, so the stake process is broken up
into three steps:

1. The sender calls `PrepareStake` to inform this staking contract of the NFTs
that are about to be staked. This will succeed only if the sender currently
owns the NFT(s).
2. The sender then transfers the NFT(s) to the staking contract.
3. The sender calls `ConfirmStake` on this staking contract which confirms the
NFTs were transferred to it and registers the stake.

In case this process is interrupted, or executed incorrectly (e.g. the sender
accidentally transfers an NFT to the staking contract without first preparing
it), there is also a `CancelStake` action to help recover NFTs. If called by:

- the original stake preparer, the preparation will be canceled, and the NFT(s)
will be sent back if the staking contract owns them.
- the current NFT(s) owner, the preparation will be canceled, if any.
- the DAO, the preparation will be canceled (if any exists), and the NFT(s) will
be sent to the specified recipient (if the staking contract owns them).

The recipient field only applies when the sender is the DAO. In the other cases,
the NFT(s) will always be sent back to the sender. Note: if the NFTs were sent
to the staking contract, but no stake was prepared, only the DAO will be able to
correct this and send them somewhere.

The `PrepareStake` step overrides any previous `PrepareStake` calls as long as
the new sender owns the NFT(s) and the first stake was never confirmed (which
should be impossible if someone else now owns the NFT(s)). Thus there is no
combination of messages or steps where someone can stake nor prevent stake when
it would otherwise be valid. A stake is only ever confirmed if it was prepared
and transferred by the same address confirming, and the DAO can always recover
an NFT that accidentally skipped the preparation step.
10 changes: 10 additions & 0 deletions contracts/voting/dao-voting-onft-staked/examples/schema.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use cosmwasm_schema::write_api;
use dao_voting_onft_staked::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};

fn main() {
write_api! {
instantiate: InstantiateMsg,
query: QueryMsg,
execute: ExecuteMsg,
}
}
Loading

0 comments on commit 829a626

Please sign in to comment.