Skip to content

Commit

Permalink
staking error resolved in snip20-stake
Browse files Browse the repository at this point in the history
  • Loading branch information
Abhishek-1857 committed Jan 6, 2024
1 parent f1fbd4a commit d97694a
Show file tree
Hide file tree
Showing 53 changed files with 14,741 additions and 146 deletions.
249 changes: 193 additions & 56 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ members = [
# "./contracts/test/*",
# "./contracts/voting/*",
"./packages/*",
"./dummy/"
"./dummy/",
"./snip20-reference-impl/"

# "ci/*",
]
Expand Down Expand Up @@ -96,7 +97,7 @@ cw-tokenfactory-issuer = { path = "./contracts/external/cw-tokenfactory-issuer",
cw-tokenfactory-types = { path = "./packages/cw-tokenfactory-types", version = "2.4.0", default-features = false }
cw-vesting = { path = "./contracts/external/cw-vesting", version = "2.4.0" }
cw-wormhole = { path = "./packages/cw-wormhole", version = "2.4.0" }
cw20-stake = { path = "./contracts/staking/cw20-stake", version = "2.4.0" }
snip20-stake = { path = "./contracts/staking/snip20-stake", version = "2.4.0" }
cw721-controllers = { path = "./packages/cw721-controllers", version = "2.4.0" }
cw721-roles = { path = "./contracts/external/cw721-roles", version = "2.4.0" }
dao-cw721-extensions = { path = "./packages/dao-cw721-extensions", version = "2.4.0" }
Expand Down Expand Up @@ -151,4 +152,5 @@ cosmwasm-storage = { git = "https://github.com/scrtlabs/cosmwasm", tag = "v1.1.9
schemars = { version = "0.8.11" }
serde = { version = "1.0" }
thiserror = { version = "1.0" }
cosmwasm-schema = "1.0.0"
cosmwasm-schema = "1.0.0"
snip20-reference-impl ={ path = "./snip20-reference-impl/"}
2 changes: 1 addition & 1 deletion contracts/external/cw-fund-distributor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ cw20 = { workspace = true }
thiserror = { workspace = true }
cw-utils = { workspace = true }
dao-voting-cw20-staked = { workspace = true }
cw20-stake = { workspace = true, features = ["library"] }
snip20-stake = { workspace = true, features = ["library"] }
dao-interface = { workspace = true }
cw-paginate-storage = { workspace = true }

Expand Down
4 changes: 2 additions & 2 deletions contracts/external/dao-migrator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ dao-dao-core = { workspace = true, features = ["library"] }
dao-voting = { workspace = true }
dao-proposal-single = { workspace = true, features = ["library"] }
dao-voting-cw4 = { workspace = true, features = ["library"] }
cw20-stake = { workspace = true, features = ["library"] }
snip20-stake = { workspace = true, features = ["library"] }
dao-voting-cw20-staked = { workspace = true, features = ["library"] }
cw20-base = { workspace = true, features = ["library"] }

Expand All @@ -39,7 +39,7 @@ voting-v1 = { workspace = true }
cw-core-v1 = { workspace = true, features = ["library"] }
cw-proposal-single-v1 = { workspace = true, features = ["library"] }
cw20-staked-balance-voting-v1 = { workspace = true, features = ["library"] }
cw20-stake-v1 = { workspace = true, features = ["library"] }
snip20-stake-v1 = { workspace = true, features = ["library"] }
cw-core-interface-v1 = { package = "cw-core-interface", version = "0.1.0", git = "https://github.com/DA0-DA0/dao-contracts.git", tag = "v1.0.0" }
cw4-voting-v1 = { package = "cw4-voting", version = "0.1.0", git = "https://github.com/DA0-DA0/dao-contracts.git", tag = "v1.0.0" }
cw20-v1 = { version = "0.13", package = "cw20" }
Expand Down
2 changes: 1 addition & 1 deletion contracts/proposal/dao-proposal-multiple/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ dao-voting-token-staked = { workspace = true }
dao-voting-cw721-staked = { workspace = true }
cw-denom = { workspace = true }
dao-testing = { workspace = true }
cw20-stake = { workspace = true }
snip20-stake = { workspace = true }
cw20-base = { workspace = true }
cw721-base = { workspace = true }
cw4 = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion contracts/proposal/dao-proposal-single/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ dao-voting-cw721-staked = { workspace = true }
dao-pre-propose-single = { workspace = true }
cw-denom = { workspace = true }
dao-testing = { workspace = true }
cw20-stake = { workspace = true }
snip20-stake = { workspace = true }
cw20-base = { workspace = true }
cw721-base = { workspace = true }
cw4 = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion contracts/staking/cw20-stake-external-rewards/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ cw-utils = { workspace = true }
cw20-base = { workspace = true, features = ["library"] }
cw2 = { workspace = true }
thiserror = { workspace = true }
cw20-stake = { workspace = true, features = ["library"]}
snip20-stake = { workspace = true, features = ["library"]}
cw-ownable = { workspace = true }
dao-hooks = { workspace = true }

Expand Down
2 changes: 1 addition & 1 deletion contracts/staking/cw20-stake-reward-distributor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ cw2 = { workspace = true }
cw20 = { workspace = true }
cw-utils = { workspace = true }
cw20-base = { workspace = true, features = ["library"] }
cw20-stake = { workspace = true, features = ["library"]}
snip20-stake = { workspace = true, features = ["library"]}
thiserror = { workspace = true }
cw-ownable = { workspace = true }
cw20-stake-reward-distributor-v1 = { workspace = true, features = ["library"] }
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "cw20-stake"
name = "snip20-stake"
authors = ["Ben2x4 <[email protected]>"]
description = "CW20 token that can be staked and staked balance can be queried at any height"
description = "SNIP20 token that can be staked and staked balance can be queried at any height"
edition = "2018"
license = { workspace = true }
repository = { workspace = true }
Expand All @@ -26,6 +26,7 @@ cw-paginate-storage = { workspace = true }
cw-ownable = { workspace = true }
dao-hooks = { workspace = true }
dao-voting = { workspace = true }
snip20-reference-impl={ workspace=true }

cw20-stake-v1 = { workspace = true, features = ["library"] }
cw-utils-v1 = { workspace = true }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
[![cw20-stake on crates.io](https://img.shields.io/crates/v/cw20-stake.svg?logo=rust)](https://crates.io/crates/cw20-stake)
[![docs.rs](https://img.shields.io/docsrs/cw20-stake?logo=docsdotrs)](https://docs.rs/cw20-stake/latest/cw20_stake/)

This is a basic implementation of a cw20 staking contract. Staked
This is a basic implementation of a snip20 staking contract. Staked
tokens can be unbonded with a configurable unbonding period. Staked
balances can be queried at any arbitrary height by external contracts.
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
use crate::math;
use crate::msg::{ExecuteAnswer, Snip20ReceiveMsg, ListStakersResponse, StakerBalanceResponse, GetHooksResponse, TotalValueResponse, StakedValueResponse, QueryMsg};
use crate::msg::{
ExecuteMsg, InstantiateMsg , ReceiveMsg,
ResponseStatus::Success,
ExecuteAnswer, GetHooksResponse, InstantiateAnswer, ListStakersResponse, QueryMsg,
Snip20ReceiveMsg, StakedValueResponse, StakerBalanceResponse, TotalValueResponse,
};
use crate::msg::{ExecuteMsg, InstantiateMsg, ReceiveMsg, ResponseStatus::Success};
use crate::state::{
Config, BALANCE, CLAIMS, CONFIG, HOOKS, MAX_CLAIMS, STAKED_BALANCES, STAKED_TOTAL,
};
use crate::ContractError;
use cosmwasm_std::{
entry_point, from_binary, to_binary, Addr, DepsMut, Empty, Env, MessageInfo,
Response, StdError, StdResult, Uint128, Deps, Binary,
entry_point, from_binary, to_binary, Addr, Binary, Deps, DepsMut, Empty, Env, MessageInfo,
Response, StdError, StdResult, Uint128,
};
use snip20_reference_impl::msg::ExecuteMsg::Transfer;
use dao_hooks::stake::{stake_hook_msgs, unstake_hook_msgs};
use dao_voting::duration::validate_duration;
use secret_cw2::set_contract_version;
Expand All @@ -27,31 +28,31 @@ pub use secret_toolkit::snip20::query::{
use secret_toolkit::viewing_key::{ViewingKey, ViewingKeyStore};
use secret_utils::Duration;

pub(crate) const CONTRACT_NAME: &str = "crates.io:cw20-stake";
pub(crate) const CONTRACT_NAME: &str = "crates.io:snip20-stake";
pub(crate) const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");

#[entry_point]
pub fn instantiate(
deps: DepsMut,
_env: Env,
env: Env,
_info: MessageInfo,
msg: InstantiateMsg,
) -> Result<Response<Empty>, ContractError> {
cw_ownable::initialize_owner(deps.storage, deps.api, msg.owner.as_deref())?;
// Smoke test that the provided cw20 contract responds to a
// Smoke test that the provided snip20 contract responds to a
// token_info query. It is not possible to determine if the
// contract implements the entire cw20 standard and runtime,
// contract implements the entire snip20 standard and runtime,
// though this provides some protection against mistakes where the
// wrong address is provided.
let token_address = deps.api.addr_validate(&msg.token_address)?;
// let _: secret_toolkit::snip20::TokenInfoResponse = deps
// .querier
// .query_wasm_smart(
// env.contract.code_hash,
// env.contract.code_hash.clone(),
// &token_address,
// &secret_toolkit::snip20::QueryMsg::TokenInfo {},
// )
// .map_err(|_| ContractError::InvalidCw20 {})?;
// .map_err(|_| ContractError::InvalidSnip20 {})?;

validate_duration(msg.unstaking_duration)?;
let config = Config {
Expand All @@ -69,7 +70,9 @@ pub fn instantiate(

set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;

Ok(Response::new())
Ok(Response::new().set_data(to_binary(&InstantiateAnswer {
code_hash: env.contract.code_hash,
})?))
}

#[entry_point]
Expand Down Expand Up @@ -129,8 +132,8 @@ pub fn execute_receive(
expected: config.token_address,
});
}
let msg: ReceiveMsg = from_binary(&wrapper.msg)?;
let sender = deps.api.addr_validate(&wrapper.sender)?;
let msg: ReceiveMsg = from_binary(&wrapper.msg.unwrap())?;
let sender: Addr = deps.api.addr_validate(wrapper.sender.as_ref())?;
match msg {
ReceiveMsg::Stake {} => execute_stake(deps, env, sender, wrapper.amount),
ReceiveMsg::Fund {} => execute_fund(deps, env, &sender, wrapper.amount),
Expand All @@ -143,26 +146,28 @@ pub fn execute_stake(
sender: Addr,
amount: Uint128,
) -> Result<Response, ContractError> {
let balance = BALANCE.load(deps.storage)?;
let staked_total = STAKED_TOTAL.load(deps.storage)?;
let balance = BALANCE.load(deps.storage).unwrap_or_default();
let staked_total = STAKED_TOTAL.load(deps.storage).unwrap_or_default();
let amount_to_stake = math::amount_to_stake(staked_total, balance, amount);
let prev_balance = STAKED_BALANCES.get(deps.storage, &sender);
let prev_balance = STAKED_BALANCES.get(deps.storage, &sender).unwrap_or_default();
STAKED_BALANCES.insert(
deps.storage,
&sender,
&prev_balance
.unwrap_or_default()
.checked_add(amount_to_stake)
.unwrap(),
.map_err(StdError::overflow)?,
)?;
STAKED_TOTAL.update(deps.storage, |total| -> StdResult<Uint128> {
// Initialized during instantiate - OK to unwrap.
Ok(total.checked_add(amount_to_stake)?)
})?;
BALANCE.save(
deps.storage,
&balance.checked_add(amount).map_err(StdError::overflow)?,
)?;
STAKED_TOTAL.save(
deps.storage,
&staked_total
.checked_add(amount_to_stake)
.map_err(StdError::overflow)?,
)?;
// STAKED_BALANCES.
let hook_msgs = stake_hook_msgs(
HOOKS,
deps.storage,
Expand All @@ -184,14 +189,14 @@ pub fn execute_unstake(
amount: Uint128,
) -> Result<Response, ContractError> {
let config = CONFIG.load(deps.storage)?;
let balance = BALANCE.load(deps.storage)?;
let staked_total = STAKED_TOTAL.load(deps.storage)?;
let balance = BALANCE.load(deps.storage).unwrap_or_default();
let staked_total = STAKED_TOTAL.load(deps.storage).unwrap_or_default();
// invariant checks for amount_to_claim
if staked_total.is_zero() {
return Err(ContractError::NothingStaked {});
}
if amount.checked_add(balance).unwrap() == Uint128::MAX {
return Err(ContractError::Cw20InvaraintViolation {});
return Err(ContractError::Snip20InvaraintViolation {});
}
if amount > staked_total {
return Err(ContractError::ImpossibleUnstake {});
Expand Down Expand Up @@ -225,16 +230,18 @@ pub fn execute_unstake(
)?;
match config.unstaking_duration {
None => {
let cw_send_msg = secret_toolkit::snip20::HandleMsg::Transfer {
let snip_send_msg = Transfer{
recipient: info.sender.to_string(),
amount: amount_to_claim,
memo: None,
padding: None,
decoys: None,
entropy:None,
};
let wasm_msg = cosmwasm_std::WasmMsg::Execute {
contract_addr: config.token_address.to_string(),
code_hash: env.contract.code_hash,
msg: to_binary(&cw_send_msg)?,
msg: to_binary(&snip_send_msg)?,
funds: vec![],
};
Ok(Response::new()
Expand Down Expand Up @@ -277,11 +284,13 @@ pub fn execute_claim(
return Err(ContractError::NothingToClaim {});
}
let config = CONFIG.load(deps.storage)?;
let cw_send_msg = secret_toolkit::snip20::HandleMsg::Transfer {
let cw_send_msg =Transfer {
recipient: info.sender.to_string(),
amount: release,
memo: None,
padding: None,
decoys: None,
entropy: None,
};
let wasm_msg = cosmwasm_std::WasmMsg::Execute {
contract_addr: config.token_address.to_string(),
Expand Down Expand Up @@ -406,10 +415,7 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult<Binary> {
}
QueryMsg::Claims { key, address } => to_binary(&query_claims(deps, key, address)?),
QueryMsg::GetHooks { key, address } => to_binary(&query_hooks(deps, address, key)?),
QueryMsg::ListStakers {
key,
address,
} => query_list_stakers(deps, key, address),
QueryMsg::ListStakers { key, address } => query_list_stakers(deps, key, address),
QueryMsg::Ownership {} => to_binary(&cw_ownable::get_ownership(deps.storage)?),
}
}
Expand Down Expand Up @@ -460,7 +466,8 @@ pub fn query_staked_value(
let address = deps.api.addr_validate(&address)?;
let balance = BALANCE.load(deps.storage).unwrap_or_default();
let staked = STAKED_BALANCES
.get(deps.storage, &address).unwrap_or_default();
.get(deps.storage, &address)
.unwrap_or_default();
let total = STAKED_TOTAL.load(deps.storage).unwrap_or_default();
if balance == Uint128::zero() || staked == Uint128::zero() || total == Uint128::zero() {
Ok(StakedValueResponse {
Expand All @@ -484,7 +491,7 @@ pub fn query_total_value(
) -> StdResult<TotalValueResponse> {
authenticate(deps, deps.api.addr_validate(&address)?, key)?;

let balance = BALANCE.load(deps.storage)?;
let balance = BALANCE.load(deps.storage).unwrap_or_default();
Ok(TotalValueResponse { total: balance })
}

Expand All @@ -509,11 +516,7 @@ pub fn query_hooks(deps: Deps, address: String, key: String) -> StdResult<GetHoo
})
}

pub fn query_list_stakers(
deps: Deps,
key: String,
address: String,
) -> StdResult<Binary> {
pub fn query_list_stakers(deps: Deps, key: String, address: String) -> StdResult<Binary> {
authenticate(deps, deps.api.addr_validate(&address)?, key)?;
// let start_at = start_after
// .map(|addr| deps.api.addr_validate(&addr))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub enum ContractError {
Std(#[from] StdError),

#[error(transparent)]
Cw20Error(#[from] Snip20ContractError),
Snip20Error(#[from] Snip20ContractError),

#[error(transparent)]
Ownership(#[from] cw_ownable::OwnershipError),
Expand All @@ -21,14 +21,14 @@ pub enum ContractError {
#[error("can not migrate. current version is up to date")]
AlreadyMigrated {},

#[error("Unstaking this amount violates the invariant: (cw20 total_supply <= 2^128)")]
Cw20InvaraintViolation {},
#[error("Unstaking this amount violates the invariant: (snip20 total_supply <= 2^128)")]
Snip20InvaraintViolation {},

#[error("Can not unstake more than has been staked")]
ImpossibleUnstake {},

#[error("Provided cw20 errored in response to TokenInfo query")]
InvalidCw20 {},
#[error("Provided snip20 errored in response to TokenInfo query")]
InvalidSnip20 {},

#[error("Invalid token")]
InvalidToken { received: Addr, expected: Addr },
Expand Down
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit d97694a

Please sign in to comment.