Skip to content

Commit

Permalink
created osmostake contract
Browse files Browse the repository at this point in the history
  • Loading branch information
kakucodes committed Feb 2, 2024
1 parent 48da7ba commit 4e2b93b
Show file tree
Hide file tree
Showing 21 changed files with 1,318 additions and 6 deletions.
35 changes: 35 additions & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion contracts/junostake/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use cosmwasm_schema::{cw_serde, QueryResponses};
use cosmwasm_std::{Addr, Api, Decimal, Timestamp};
use cw_grant_spec::grants::{GrantRequirement, RevokeRequirement};

use wyndex::asset::AssetInfo;
use juno_destinations::comp_prefs::{DestinationProjectAddresses, DestinationProjectAddrs, JunoCompPrefs};
use wyndex::asset::AssetInfo;

use crate::ContractError;

Expand Down
8 changes: 4 additions & 4 deletions contracts/osmodca/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Junostake Outpost
# Osmodca Outpost

Compounding outpost that allows users to specify how they would like to manage their juno staking rewards by percentage. It is intended to be called on a regular basis by Yieldmos so that delegators can manage their rewards in whatever way they would like.
Compounding outpost that allows users to specify how they would like to manage OSMO dcaing by percentage. It is intended to be called on a regular basis by Yieldmos so that delegators can manage their rewards in whatever way they would like.

Care has been taken to made the Destination projects modular and easily extendable when new projects/targets become available

## Available Destination Projects
<!-- ## Available Destination Projects
The things you can do with your rewards during any given compounding.
Expand All @@ -14,4 +14,4 @@ The things you can do with your rewards during any given compounding.
| `Wynd Staking` | `working` | Can specify any valid unbonding period |
| `Neta Staking` | `working` | |
| `Token Swap` | `working` | Can pick any token that's on Wyndex |
| `Wyndex LPs` | `working` | Must specify the given pool contract address |
| `Wyndex LPs` | `working` | Must specify the given pool contract address | -->
2 changes: 1 addition & 1 deletion contracts/osmodca/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use outpost_utils::helpers::CompoundingFrequency;
use semver::Version;

// version info for migration info
const CONTRACT_NAME: &str = "crates.io:ac-outpost-junodca";
const CONTRACT_NAME: &str = "crates.io:ac-outpost-osmodca";
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");

#[cfg_attr(not(feature = "library"), entry_point)]
Expand Down
73 changes: 73 additions & 0 deletions contracts/osmostake/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
[package]
name = "ymos-osmostake-outpost"
authors = ["Marc <marc@yieldmos.com>"]
version = { workspace = true }
edition = { workspace = true }
description = "Yieldmos Juno Staking Outpost"

exclude = [
# Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication.
"contract.wasm",
"hash.txt",
]


[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 more explicit tests, cargo test --features=backtraces
backtraces = ["cosmwasm-std/backtraces"]
# use library feature to disable all instantiate/execute/query exports
library = []
interface = ["dep:cw-orch"]


[dependencies]
cosmwasm-schema = { workspace = true }
cosmwasm-std = { workspace = true, features = [
"stargate",
# "staking",
"cosmwasm_1_4",
] }
cosmwasm-storage = { workspace = true }
cw-storage-plus = { workspace = true }
cw2 = { workspace = true }
schemars = { workspace = true }
serde = { workspace = true }
thiserror = { workspace = true }
semver = { workspace = true }
cosmos-sdk-proto = { workspace = true }
cw20 = { workspace = true }
cw20-stake = { workspace = true }
cw20-vesting = { workspace = true }
wyndex = { workspace = true }
wyndex-multi-hop = { workspace = true }
wynd-stake = { workspace = true }
wynd-helpers = { workspace = true }
outpost-utils = { workspace = true }
universal-destinations = { workspace = true }
osmosis-destinations = { workspace = true }
sail-destinations = { workspace = true }
osmosis-std = { workspace = true }
cw-grant-spec = { workspace = true }
cw-orch = { workspace = true, optional = true }
terraswap-helpers = { workspace = true }
white-whale = { workspace = true }
osmosis-helpers = { workspace = true }
withdraw-rewards-tax-grant = { workspace = true }


[dev-dependencies]
cw-multi-test = { workspace = true }
17 changes: 17 additions & 0 deletions contracts/osmostake/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Osmostake Outpost

Compounding outpost that allows users to specify how they would like to manage OSMO staking rewards by percentage. It is intended to be called on a regular basis by Yieldmos so that delegators can manage their rewards in whatever way they would like.

Care has been taken to made the Destination projects modular and easily extendable when new projects/targets become available

<!-- ## Available Destination Projects
The things you can do with your rewards during any given compounding.
| Destination Project | Status | Note |
| ------------------- | --------- | -------------------------------------------- |
| `Juno Staking` | `working` | Can specify any validator address |
| `Wynd Staking` | `working` | Can specify any valid unbonding period |
| `Neta Staking` | `working` | |
| `Token Swap` | `working` | Can pick any token that's on Wyndex |
| `Wyndex LPs` | `working` | Must specify the given pool contract address | -->
1 change: 1 addition & 0 deletions contracts/osmostake/rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
max_width = 125
11 changes: 11 additions & 0 deletions contracts/osmostake/src/bin/osmostake_schema.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use cosmwasm_schema::write_api;

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

fn main() {
write_api! {
instantiate: InstantiateMsg,
execute: ExecuteMsg,
query: QueryMsg,
}
}
167 changes: 167 additions & 0 deletions contracts/osmostake/src/contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
use crate::error::ContractError;
use crate::msg::{CompPrefsWithAddresses, ExecuteMsg, InstantiateMsg, MigrateMsg, OsmostakeCompoundPrefs, QueryMsg};
use crate::state::{ADMIN, AUTHORIZED_ADDRS, PROJECT_ADDRS};
use crate::{execute, queries};
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{
to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdError, StdResult, Timestamp,
};
use cw2::{get_contract_version, set_contract_version};
use cw_grant_spec::grantable_trait::{GrantStructure, Grantable};
use outpost_utils::helpers::CompoundingFrequency;
use semver::Version;

// version info for migration info
const CONTRACT_NAME: &str = "crates.io:ac-outpost-osmostake";
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn reply(_deps: DepsMut, _env: Env, msg: Reply) -> Result<Response, ContractError> {
match msg {
// an id of 0 means we don't care about the response
Reply { id: 0, .. } => Ok(Response::default()),
// TODO handle non-zero ids
_ => Err(ContractError::Unauthorized {}),
}
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn instantiate(deps: DepsMut, _env: Env, info: MessageInfo, msg: InstantiateMsg) -> Result<Response, ContractError> {
cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;

let InstantiateMsg {
admin,
project_addresses,
} = msg;

let admin_addr = match admin {
Some(admin) => deps
.api
.addr_validate(&admin)
.map_err(|_| ContractError::InvalidAuthorizedAddress(admin.to_string()))?,
None => info.sender,
};

ADMIN.save(deps.storage, &admin_addr)?;
AUTHORIZED_ADDRS.save(deps.storage, &vec![])?;
PROJECT_ADDRS.save(deps.storage, &project_addresses.validate_addrs(deps.api)?)?;

Ok(Response::default())
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn migrate(deps: DepsMut, _env: Env, msg: MigrateMsg) -> Result<Response, ContractError> {
let version: Version = CONTRACT_VERSION.parse()?;
let storage_version: Version = get_contract_version(deps.storage)?.version.parse()?;

if storage_version < version {
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
}

if let MigrateMsg {
project_addresses: Some(addresses),
} = msg
{
PROJECT_ADDRS.save(deps.storage, &addresses.validate_addrs(deps.api)?)?
}

Ok(Response::default())
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> Result<Response, ContractError> {
match msg {
ExecuteMsg::UpdateProjectAddresses(addresses) => {
if info.sender != ADMIN.load(deps.storage)? {
return Err(ContractError::Unauthorized {});
}
PROJECT_ADDRS.save(deps.storage, &addresses.validate_addrs(deps.api)?)?;

Ok(Response::default())
}
ExecuteMsg::AddAuthorizedCompounder(address) => {
if info.sender != ADMIN.load(deps.storage)? {
return Err(ContractError::Unauthorized {});
}
let authorized_addr = deps
.api
.addr_validate(&address)
.map_err(|_| ContractError::InvalidAuthorizedAddress(address.to_string()))?;

AUTHORIZED_ADDRS.update(deps.storage, |mut addrs| {
if addrs.contains(&authorized_addr) {
Err(ContractError::DuplicateAuthorizedAddress(authorized_addr.to_string()))
} else {
addrs.push(authorized_addr.clone());
Ok(addrs)
}
})?;

Ok(Response::default())
}
ExecuteMsg::RemoveAuthorizedCompounder(address) => {
if info.sender != ADMIN.load(deps.storage)? {
return Err(ContractError::Unauthorized {});
}
let authorized_addr = deps
.api
.addr_validate(&address)
.map_err(|_| ContractError::InvalidAuthorizedAddress(address.to_string()))?;

AUTHORIZED_ADDRS.update(deps.storage, |mut addrs| -> Result<_, StdError> {
addrs.retain(|x| x != authorized_addr);
Ok(addrs)
})?;

Ok(Response::default())
}
ExecuteMsg::Compound(OsmostakeCompoundPrefs {
user_address,
comp_prefs,
tax_fee,
}) => {
let addresses = PROJECT_ADDRS.load(deps.storage)?;

execute::compound(deps, env, info, addresses, user_address, comp_prefs, tax_fee)
}
}
}

#[cfg_attr(not(feature = "library"), entry_point)]

pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult<Binary> {
match msg {
QueryMsg::Version {} => to_json_binary(&queries::query_version()),
QueryMsg::AuthorizedCompounders {} => to_json_binary(&queries::query_authorized_compounders(deps)),
QueryMsg::GrantSpec { comp_prefs, expiration } => {
let project_addresses = PROJECT_ADDRS.load(deps.storage)?;
to_json_binary(&QueryMsg::query_grants(
GrantStructure {
grantee: env.contract.address.clone(),
granter: deps.api.addr_validate(&comp_prefs.user_address)?,
expiration,
grant_contract: env.contract.address,
grant_data: CompPrefsWithAddresses {
comp_prefs,
project_addresses,
},
},
env.block.time,
)?)
}
QueryMsg::RevokeSpec { comp_prefs } => {
let project_addresses = PROJECT_ADDRS.load(deps.storage)?;
to_json_binary(&QueryMsg::query_revokes(GrantStructure {
grantee: env.contract.address.clone(),
granter: deps.api.addr_validate(&comp_prefs.user_address)?,
expiration: Timestamp::default(),
grant_contract: env.contract.address,
grant_data: CompPrefsWithAddresses {
comp_prefs,
project_addresses,
},
})?)
}
}
}
Loading

0 comments on commit 4e2b93b

Please sign in to comment.