Skip to content
This repository has been archived by the owner on Dec 17, 2024. It is now read-only.

draft-delegator-incentive-contract #90

Merged
merged 16 commits into from
Nov 21, 2022
Merged
Show file tree
Hide file tree
Changes from 10 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
30 changes: 30 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ workflows:
- contract_nois_demo
- contract_nois_proxy
- contract_nois_oracle
- contract_nois_delegator
- package_nois_protocol
- lint
- wasm-build
Expand All @@ -18,6 +19,7 @@ workflows:
- contract_nois_demo
- contract_nois_proxy
- contract_nois_oracle
- contract_nois_delegator
deploy:
jobs:
- build_and_upload_contracts:
Expand Down Expand Up @@ -115,6 +117,33 @@ jobs:
- target
key: cargocache-nois-oracle-rust:1.63.0-{{ checksum "~/project/Cargo.lock" }}

contract_nois_delegator:
docker:
- image: rust:1.63.0
working_directory: ~/project/contracts/nois-delegator
steps:
- checkout:
path: ~/project
- run:
name: Version information
command: rustc --version; cargo --version; rustup --version
- restore_cache:
keys:
- cargocache-nois-delegator-rust:1.63.0-{{ checksum "~/project/Cargo.lock" }}
- run:
name: Unit Tests
environment:
RUST_BACKTRACE: 1
command: cargo unit-test --locked
- run:
name: Build and run schema generator
command: cargo schema --locked
- save_cache:
paths:
- /usr/local/cargo/registry
- target
key: cargocache-nois-delegator-rust:1.63.0-{{ checksum "~/project/Cargo.lock" }}

package_nois_protocol:
docker:
- image: rust:1.63.0
Expand Down Expand Up @@ -210,6 +239,7 @@ jobs:
- nois_demo.wasm
- nois_proxy.wasm
- nois_oracle.wasm
- nois_delegator.wasm

ts-build:
docker:
Expand Down
13 changes: 13 additions & 0 deletions Cargo.lock

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

11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,19 @@ There are two CosmWasm-enabled blockchains running locally.
## The contracts

- nois-oracle (runs on the randomness chain; one instance globally)
- nois-oracle is the entrypoint to the randomness beacon coming from drand through the drand bots.
- it verifies the randomness before it is stored on chain.
- it initiates the callback messages to consumer DAPPS on randomness consumer chains (juno, stargaze ...) whenever the randomness is available. this callback is sent to the nois-proxy which is deployed on the consumer chain.
- nois-delegator (runs on the randomness chain; one instance globally)
- nois-delegator gets called by nois-oracle to incentivise the fast drand bots upon submissions of the randomness.
- it has an initial nois coin supply that an admin multisig can delegate, unbond or redelegate but cannot withdraw.
- nois-proxy (runs on the app chain; one instance per app chain)
- nois-proxy receives randomness requests from the consumer DAPPs and submits those requests to the nois chain via IBC.
- Once the randomness is available, the nois-proxy receives a callback and forwards it to the DAPP
- nois-demo (runs on the app chain; a demo app)
- nois-demo is a demo/example consumer app used as a test to estimate the value of pi.
- it submits a request to the proxy to get randomness.
- The randomness is then received to the nois-demo as a callback.

The IBC interaction is only between nois-oracle and nois-proxy, such that
the user (nois-demo) does not need to worry about that part.
Expand Down
5 changes: 5 additions & 0 deletions contracts/nois-delegator/.cargo/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[alias]
wasm = "build --release --target wasm32-unknown-unknown"
wasm-debug = "build --target wasm32-unknown-unknown"
unit-test = "test --lib"
schema = "run --example schema"
38 changes: 38 additions & 0 deletions contracts/nois-delegator/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[package]
name = "nois-delegator"
version = "0.7.2"
authors = []
edition = "2021"
publish = false
license = "Apache-2.0"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

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

[profile.release]
opt-level = 3
debug = false
rpath = false
lto = true
debug-assertions = false
codegen-units = 1
panic = 'abort'
incremental = false
overflow-checks = true

[features]
# for quicker tests, cargo test --lib
# for more explicit tests, cargo test --features=backtraces
backtraces = ["cosmwasm-std/backtraces"]

[dependencies]
cosmwasm-std = { version = "1.1.5", features = ["staking"] }
cosmwasm-schema = { version = "1.1.5" }
cw-storage-plus = { version = "0.16.0" }
schemars = "0.8.10"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
thiserror = { version = "1.0.23" }

[dev-dependencies]
1 change: 1 addition & 0 deletions contracts/nois-delegator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Nois Delegator
11 changes: 11 additions & 0 deletions contracts/nois-delegator/examples/schema.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use cosmwasm_schema::write_api;

use nois_delegator::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};

fn main() {
write_api! {
instantiate: InstantiateMsg,
query: QueryMsg,
execute: ExecuteMsg,
}
}
217 changes: 217 additions & 0 deletions contracts/nois-delegator/src/contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
use cosmwasm_std::{
ensure_eq, entry_point, to_binary, BankMsg, Coin, Deps, DepsMut, DistributionMsg, Env,
MessageInfo, QueryResponse, Response, StakingMsg, StdResult, Uint128,
};

use crate::error::ContractError;
use crate::msg::{ConfigResponse, ExecuteMsg, InstantiateMsg, QueryMsg};
use crate::state::{Config, CONFIG};

#[entry_point]
pub fn instantiate(
deps: DepsMut,
_env: Env,
_info: MessageInfo,
msg: InstantiateMsg,
) -> StdResult<Response> {
let config = Config {
admin_addr: msg.admin_addr,
incentive_amount: msg.incentive_amount,
incentive_denom: msg.incentive_denom,
staking_denom: msg.staking_denom,
nois_oracle_contract_addr: None,
};
CONFIG.save(deps.storage, &config)?;
Ok(Response::default())
}

#[entry_point]
pub fn execute(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
match msg {
ExecuteMsg::IncentiviseBot { addr } => execute_incentivise_bot(deps, info, addr),
ExecuteMsg::Stake { addr, amount } => execute_stake(deps, addr, amount),
ExecuteMsg::Unbond { addr, amount } => execute_unbond(deps, addr, amount),
ExecuteMsg::Redelegate {
src_addr,
dest_addr,
amount,
} => execute_redelegate(deps, src_addr, dest_addr, amount),
ExecuteMsg::ClaimRewards { addr } => execute_claim_rewards(addr),
ExecuteMsg::SetNoisOracleContractAddr { addr } => {
execute_set_nois_oracle_contract_addr(deps, env, addr)
}
}
}

#[entry_point]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<QueryResponse> {
let response = match msg {
QueryMsg::Config {} => to_binary(&query_config(deps)?)?,
};
Ok(response)
}

fn execute_incentivise_bot(
deps: DepsMut,
info: MessageInfo,
addr: String,
) -> Result<Response, ContractError> {
let config = CONFIG.load(deps.storage)?;
if config.nois_oracle_contract_addr.is_none() {
return Err(ContractError::NoisOracleContractAddressUnset);
}
let nois_oracle_contract = config.nois_oracle_contract_addr.unwrap();
webmaster128 marked this conversation as resolved.
Show resolved Hide resolved

ensure_eq!(
info.sender,
nois_oracle_contract,
ContractError::Unauthorized
);

Ok(Response::new().add_messages(vec![BankMsg::Send {
to_address: addr, //Not sure if here we can exract the drand_bot addr by info.sender. Is info.sender here the nois-oracle or the drand bot?
amount: vec![Coin::new(
config.incentive_amount.into(),
config.incentive_denom,
)],
}]))
}

fn execute_stake(deps: DepsMut, addr: String, amount: Uint128) -> Result<Response, ContractError> {
webmaster128 marked this conversation as resolved.
Show resolved Hide resolved
let config = CONFIG.load(deps.storage).unwrap();

Ok(Response::new().add_messages(vec![StakingMsg::Delegate {
webmaster128 marked this conversation as resolved.
Show resolved Hide resolved
validator: addr,
amount: Coin {
denom: config.staking_denom,
webmaster128 marked this conversation as resolved.
Show resolved Hide resolved
amount,
},
}]))
}

fn execute_unbond(deps: DepsMut, addr: String, amount: Uint128) -> Result<Response, ContractError> {
webmaster128 marked this conversation as resolved.
Show resolved Hide resolved
let config = CONFIG.load(deps.storage).unwrap();

Ok(Response::new().add_messages(vec![StakingMsg::Undelegate {
validator: addr,
amount: Coin {
denom: config.staking_denom,
amount,
},
}]))
}

fn execute_redelegate(
deps: DepsMut,
src_addr: String,
dest_addr: String,
amount: Uint128,
) -> Result<Response, ContractError> {
let config = CONFIG.load(deps.storage).unwrap();

Ok(Response::new().add_messages(vec![StakingMsg::Redelegate {
src_validator: src_addr,
dst_validator: dest_addr,
amount: Coin {
denom: config.staking_denom,
amount,
},
}]))
}

fn execute_claim_rewards(addr: String) -> Result<Response, ContractError> {
Ok(
Response::new().add_messages(vec![DistributionMsg::WithdrawDelegatorReward {
validator: addr,
}]),
)
}

fn execute_set_nois_oracle_contract_addr(
deps: DepsMut,
_env: Env,
addr: String,
) -> Result<Response, ContractError> {
let mut config: Config = CONFIG.load(deps.storage)?;
if config.nois_oracle_contract_addr.is_some() {
return Err(ContractError::ContractAlreadySet {});
}
let nois_contract = deps
.api
.addr_validate(&addr)
.map_err(|_| ContractError::InvalidAddress)?;
config.nois_oracle_contract_addr = Some(nois_contract);

CONFIG.save(deps.storage, &config)?;

Ok(Response::default())
}

fn query_config(deps: Deps) -> StdResult<ConfigResponse> {
let config = CONFIG.load(deps.storage)?;
Ok(config)
}

#[cfg(test)]
mod tests {
use super::*;
use cosmwasm_std::{
from_binary,
testing::{mock_dependencies, mock_env, mock_info},
Uint128,
};

const CREATOR: &str = "creator";

#[test]
fn instantiate_works() {
let mut deps = mock_dependencies();
let msg = InstantiateMsg {
admin_addr: "admin".to_string(),
incentive_denom: "unois".to_string(),
staking_denom: "unois".to_string(),
incentive_amount: Uint128::new(1_000_000),
};
let info = mock_info(CREATOR, &[]);
let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(0, res.messages.len());
let config: ConfigResponse =
from_binary(&query(deps.as_ref(), mock_env(), QueryMsg::Config {}).unwrap()).unwrap();
assert_eq!(
config,
ConfigResponse {
incentive_amount: Uint128::new(1_000_000),
incentive_denom: "unois".to_string(),
admin_addr: "admin".to_string(),
staking_denom: "unois".to_string(),
nois_oracle_contract_addr: None,
}
);
}

//#[test]
//fn staking_works() {
// let mut deps = mock_dependencies();
// let msg = InstantiateMsg {
// admin_addr: "admin".to_string(),
// incentive_denom:"unois".to_string(),
// staking_denom:"unois".to_string(),
// incentive_amount:Uint128::new(1_000_000),
//
// };
// let env = mock_env();
// let info = mock_info(CREATOR, &[]);
// instantiate(deps.as_mut(), env.to_owned(), info.clone(), msg).unwrap();
// let addr="validator_addr".to_string();
// let amount=Uint128::new(100);
// let msg = ExecuteMsg::Stake { addr: addr.to_owned(), amount } ;
// execute(deps.as_mut(),env.to_owned() , info, msg).unwrap();
// let msg= StakingQuery::Delegation { delegator: env.to_owned().contract.address.into_string(), validator: addr.to_string() };
//
//}
}
Loading