Skip to content

Commit

Permalink
feat: refactor token
Browse files Browse the repository at this point in the history
  • Loading branch information
ratik committed Dec 14, 2023
1 parent 33980f4 commit 95f7eaf
Show file tree
Hide file tree
Showing 9 changed files with 251 additions and 226 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

142 changes: 142 additions & 0 deletions contracts/token/src/contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
use cosmwasm_std::{
attr, ensure_eq, ensure_ne, entry_point, to_json_binary, Binary, Deps, DepsMut, Env,
MessageInfo, Reply, Response, SubMsg, Uint128,
};

use lido_staking_base::{
helpers::answer::{attr_coin, response},
msg::token::{ConfigResponse, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg},
state::token::{CORE_ADDRESS, DENOM},
};
use neutron_sdk::{
bindings::{msg::NeutronMsg, query::NeutronQuery},
query::token_factory::query_full_denom,
};

use crate::error::{ContractError, ContractResult};

pub const CONTRACT_NAME: &str = env!("CARGO_PKG_NAME");
pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
pub const CREATE_DENOM_REPLY_ID: u64 = 1;

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

let core = deps.api.addr_validate(&msg.core_address)?;
CORE_ADDRESS.save(deps.storage, &core)?;

DENOM.save(deps.storage, &msg.subdenom)?;
let create_denom_msg = SubMsg::reply_on_success(
NeutronMsg::submit_create_denom(&msg.subdenom),
CREATE_DENOM_REPLY_ID,
);

Ok(response(
"instantiate",
CONTRACT_NAME,
[attr("core_address", core), attr("subdenom", msg.subdenom)],
)
.add_submessage(create_denom_msg))
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
deps: DepsMut<NeutronQuery>,
_env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> ContractResult<Response<NeutronMsg>> {
let core = CORE_ADDRESS.load(deps.storage)?;
ensure_eq!(info.sender, core, ContractError::Unauthorized);

match msg {
ExecuteMsg::Mint { amount, receiver } => mint(deps, amount, receiver),
ExecuteMsg::Burn {} => burn(deps, info),
}
}

fn mint(
deps: DepsMut<NeutronQuery>,
amount: Uint128,
receiver: String,
) -> ContractResult<Response<NeutronMsg>> {
ensure_ne!(amount, Uint128::zero(), ContractError::NothingToMint);

let denom = DENOM.load(deps.storage)?;
let mint_msg = NeutronMsg::submit_mint_tokens(&denom, amount, &receiver);

Ok(response(
"execute-mint",
CONTRACT_NAME,
[
attr_coin("amount", amount, denom),
attr("receiver", receiver),
],
)
.add_message(mint_msg))
}

fn burn(deps: DepsMut<NeutronQuery>, info: MessageInfo) -> ContractResult<Response<NeutronMsg>> {
let denom = DENOM.load(deps.storage)?;
let amount = cw_utils::must_pay(&info, &denom)?;

let burn_msg = NeutronMsg::submit_burn_tokens(&denom, amount);

Ok(response(
"execute-burn",
CONTRACT_NAME,
[attr_coin("amount", amount, denom)],
)
.add_message(burn_msg))
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(deps: Deps<NeutronQuery>, _env: Env, msg: QueryMsg) -> ContractResult<Binary> {
match msg {
QueryMsg::Config {} => {
let core_address = CORE_ADDRESS.load(deps.storage)?.into_string();
let denom = DENOM.load(deps.storage)?;
Ok(to_json_binary(&ConfigResponse {
core_address,
denom,
})?)
}
}
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn migrate(
_deps: DepsMut,
_env: Env,
_msg: MigrateMsg,
) -> ContractResult<Response<NeutronMsg>> {
Ok(Response::new())
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn reply(
deps: DepsMut<NeutronQuery>,
env: Env,
msg: Reply,
) -> ContractResult<Response<NeutronMsg>> {
match msg.id {
CREATE_DENOM_REPLY_ID => {
let subdenom = DENOM.load(deps.storage)?;
let full_denom = query_full_denom(deps.as_ref(), env.contract.address, subdenom)?;
DENOM.save(deps.storage, &full_denom.denom)?;

Ok(response(
"reply-create-denom",
CONTRACT_NAME,
[attr("denom", full_denom.denom)],
))
}
id => Err(ContractError::UnknownReplyId { id }),
}
}
24 changes: 24 additions & 0 deletions contracts/token/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use cosmwasm_std::StdError;

#[derive(thiserror::Error, Debug, PartialEq)]
pub enum ContractError {
#[error("{0}")]
Std(#[from] StdError),

#[error("{0}")]
NeutronError(#[from] neutron_sdk::NeutronError),

#[error("{0}")]
PaymentError(#[from] cw_utils::PaymentError),

#[error("unauthorized")]
Unauthorized,

#[error("nothing to mint")]
NothingToMint,

#[error("unknown reply id: {id}")]
UnknownReplyId { id: u64 },
}

pub type ContractResult<T> = Result<T, ContractError>;
172 changes: 2 additions & 170 deletions contracts/token/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,173 +1,5 @@
use cosmwasm_std::{
attr, ensure_eq, ensure_ne, to_json_binary, Attribute, Binary, Deps, DepsMut, Env, Event,
MessageInfo, Reply, Response, StdError, SubMsg, Uint128,
};

use lido_staking_base::{
msg::token::{ConfigResponse, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg},
state::token::{CORE_ADDRESS, DENOM},
};
use neutron_sdk::{
bindings::{msg::NeutronMsg, query::NeutronQuery},
query::token_factory::query_full_denom,
};

#[cfg(test)]
mod tests;

#[derive(thiserror::Error, Debug, PartialEq)]
pub enum ContractError {
#[error("{0}")]
Std(#[from] StdError),

#[error("{0}")]
NeutronError(#[from] neutron_sdk::NeutronError),

#[error("{0}")]
PaymentError(#[from] cw_utils::PaymentError),

#[error("unauthorized")]
Unauthorized,

#[error("nothing to mint")]
NothingToMint,

#[error("unknown reply id: {id}")]
UnknownReplyId { id: u64 },
}

pub type ContractResult<T> = Result<T, ContractError>;

const CONTRACT_NAME: &str = env!("CARGO_PKG_NAME");
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");

const CREATE_DENOM_REPLY_ID: u64 = 1;

fn response<A: Into<Attribute>>(
ty: &str,
attrs: impl IntoIterator<Item = A>,
) -> Response<NeutronMsg> {
Response::new().add_event(Event::new(format!("{}-{}", CONTRACT_NAME, ty)).add_attributes(attrs))
}

fn attr_coin(
key: impl Into<String>,
amount: impl std::fmt::Display,
denom: impl std::fmt::Display,
) -> Attribute {
attr(key, format!("{}{}", amount, denom))
}

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

let core = deps.api.addr_validate(&msg.core_address)?;
CORE_ADDRESS.save(deps.storage, &core)?;

DENOM.save(deps.storage, &msg.subdenom)?;
let create_denom_msg = SubMsg::reply_on_success(
NeutronMsg::submit_create_denom(&msg.subdenom),
CREATE_DENOM_REPLY_ID,
);

Ok(response(
"instantiate",
[attr("core_address", core), attr("subdenom", msg.subdenom)],
)
.add_submessage(create_denom_msg))
}

#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)]
pub fn execute(
deps: DepsMut<NeutronQuery>,
_env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> ContractResult<Response<NeutronMsg>> {
let core = CORE_ADDRESS.load(deps.storage)?;
ensure_eq!(info.sender, core, ContractError::Unauthorized);

match msg {
ExecuteMsg::Mint { amount, receiver } => mint(deps, amount, receiver),
ExecuteMsg::Burn {} => burn(deps, info),
}
}

fn mint(
deps: DepsMut<NeutronQuery>,
amount: Uint128,
receiver: String,
) -> ContractResult<Response<NeutronMsg>> {
ensure_ne!(amount, Uint128::zero(), ContractError::NothingToMint);

let denom = DENOM.load(deps.storage)?;
let mint_msg = NeutronMsg::submit_mint_tokens(&denom, amount, &receiver);

Ok(response(
"execute-mint",
[
attr_coin("amount", amount, denom),
attr("receiver", receiver),
],
)
.add_message(mint_msg))
}

fn burn(deps: DepsMut<NeutronQuery>, info: MessageInfo) -> ContractResult<Response<NeutronMsg>> {
let denom = DENOM.load(deps.storage)?;
let amount = cw_utils::must_pay(&info, &denom)?;

let burn_msg = NeutronMsg::submit_burn_tokens(&denom, amount);

Ok(response("execute-burn", [attr_coin("amount", amount, denom)]).add_message(burn_msg))
}

#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)]
pub fn query(deps: Deps<NeutronQuery>, _env: Env, msg: QueryMsg) -> ContractResult<Binary> {
match msg {
QueryMsg::Config {} => {
let core_address = CORE_ADDRESS.load(deps.storage)?.into_string();
let denom = DENOM.load(deps.storage)?;
Ok(to_json_binary(&ConfigResponse {
core_address,
denom,
})?)
}
}
}

#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)]
pub fn migrate(
_deps: DepsMut,
_env: Env,
_msg: MigrateMsg,
) -> ContractResult<Response<NeutronMsg>> {
Ok(Response::new())
}

#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)]
pub fn reply(
deps: DepsMut<NeutronQuery>,
env: Env,
msg: Reply,
) -> ContractResult<Response<NeutronMsg>> {
match msg.id {
CREATE_DENOM_REPLY_ID => {
let subdenom = DENOM.load(deps.storage)?;
let full_denom = query_full_denom(deps.as_ref(), env.contract.address, subdenom)?;
DENOM.save(deps.storage, &full_denom.denom)?;

Ok(response(
"reply-create-denom",
[attr("denom", full_denom.denom)],
))
}
id => Err(ContractError::UnknownReplyId { id }),
}
}
pub mod contract;
pub mod error;
Loading

0 comments on commit 95f7eaf

Please sign in to comment.