use cosmwasm_std::{
entry_point, to_json_binary, Binary, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo,
Response, Uint128, WasmMsg,
};
use cw2::{get_contract_version, set_contract_version};
use cw20::{Cw20ExecuteMsg, Cw20ReceiveMsg};
use cyber_std::CyberMsg;
use crate::error::ContractError;
use crate::msg::{
ConfigResponse, ExecuteMsg, InstantiateMsg, QueryMsg, TestingOverrides, WrappedSupplyResponse,
};
use crate::state::{WrapConfig, CONFIG, WRAPPED_SUPPLY};
const CONTRACT_NAME: &str = "crates.io:litium-wrap";
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn instantiate(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: InstantiateMsg,
) -> Result<Response<CyberMsg>, ContractError> {
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
let admin = msg
.admin
.map(|a| deps.api.addr_validate(&a))
.transpose()?
.unwrap_or(info.sender.clone());
let native_denom = format!("factory/{}/{}", env.contract.address, msg.token_subdenom);
let config = WrapConfig {
cw20_contract: deps.api.addr_validate(&msg.cw20_contract)?,
native_denom: native_denom.clone(),
admin,
};
CONFIG.save(deps.storage, &config)?;
WRAPPED_SUPPLY.save(deps.storage, &Uint128::zero())?;
let create_denom = CyberMsg::create_contract_denom(msg.token_subdenom, None);
Ok(Response::new()
.add_message(create_denom)
.add_attribute("action", "instantiate")
.add_attribute("native_denom", native_denom)
.add_attribute("admin", config.admin.to_string()))
}
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
deps: DepsMut,
_env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response<CyberMsg>, ContractError> {
match msg {
ExecuteMsg::Receive(cw20_msg) => execute_receive(deps, info, cw20_msg),
ExecuteMsg::UnwrapNative {} => execute_unwrap_native(deps, info),
ExecuteMsg::UpdateConfig {
cw20_contract,
admin,
} => execute_update_config(deps, info, cw20_contract, admin),
ExecuteMsg::ApplyTestingOverrides { overrides } => {
execute_apply_testing_overrides(deps, info, overrides)
}
}
}
/// CW-20 โ native wrap. Called when litium-core sends CW-20 tokens to this contract.
fn execute_receive(
deps: DepsMut,
info: MessageInfo,
cw20_msg: Cw20ReceiveMsg,
) -> Result<Response<CyberMsg>, ContractError> {
let config = CONFIG.load(deps.storage)?;
// Only accept CW-20 tokens from litium-core
if info.sender != config.cw20_contract {
return Err(ContractError::InvalidCw20Sender {});
}
let amount = cw20_msg.amount;
if amount.is_zero() {
return Err(ContractError::InvalidAmount {});
}
let user = cw20_msg.sender;
WRAPPED_SUPPLY.update(deps.storage, |v| -> Result<_, ContractError> {
Ok(v + amount)
})?;
// Mint native tokens 1:1 (spec ยง8.3: agents can freely convert between representations)
let mint_msg =
CyberMsg::mint_contract_tokens(config.native_denom.clone(), amount, user.clone());
Ok(Response::new()
.add_message(mint_msg)
.add_attribute("action", "wrap_cw20_to_native")
.add_attribute("address", &user)
.add_attribute("amount", amount.to_string()))
}
/// Native โ CW-20 unwrap. User sends native LI tokens in funds.
fn execute_unwrap_native(
deps: DepsMut,
info: MessageInfo,
) -> Result<Response<CyberMsg>, ContractError> {
let config = CONFIG.load(deps.storage)?;
let amount = sent_amount_for_denom(&info, &config.native_denom)?;
if amount.is_zero() {
return Err(ContractError::InvalidAmount {});
}
WRAPPED_SUPPLY.update(deps.storage, |v| -> Result<_, ContractError> {
v.checked_sub(amount)
.map_err(|_| ContractError::WrappedSupplyUnderflow {})
})?;
// Burn the native tokens
let burn_msg =
CyberMsg::burn_contract_tokens(config.native_denom.clone(), amount, String::new());
// Transfer CW-20 tokens from wrap's balance to user
let transfer_msg = CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: config.cw20_contract.to_string(),
msg: cosmwasm_std::to_json_binary(&Cw20ExecuteMsg::Transfer {
recipient: info.sender.to_string(),
amount,
})?,
funds: vec![],
});
Ok(Response::new()
.add_message(burn_msg)
.add_message(transfer_msg)
.add_attribute("action", "unwrap_native_to_cw20")
.add_attribute("address", info.sender.to_string())
.add_attribute("amount", amount.to_string()))
}
fn execute_update_config(
deps: DepsMut,
info: MessageInfo,
cw20_contract: Option<String>,
admin: Option<String>,
) -> Result<Response<CyberMsg>, ContractError> {
let mut config = CONFIG.load(deps.storage)?;
if info.sender != config.admin {
return Err(ContractError::Unauthorized {});
}
if let Some(c) = cw20_contract {
config.cw20_contract = deps.api.addr_validate(&c)?;
}
if let Some(a) = admin {
config.admin = deps.api.addr_validate(&a)?;
}
CONFIG.save(deps.storage, &config)?;
Ok(Response::new().add_attribute("action", "update_config"))
}
fn execute_apply_testing_overrides(
deps: DepsMut,
info: MessageInfo,
overrides: TestingOverrides,
) -> Result<Response<CyberMsg>, ContractError> {
let config = CONFIG.load(deps.storage)?;
if info.sender != config.admin {
return Err(ContractError::Unauthorized {});
}
if let Some(v) = overrides.wrapped_supply {
WRAPPED_SUPPLY.save(deps.storage, &v)?;
}
Ok(Response::new().add_attribute("action", "apply_testing_overrides"))
}
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> Result<Response<CyberMsg>, ContractError> {
let stored = get_contract_version(deps.storage)?;
let stored_ver = stored
.version
.parse::<semver::Version>()
.map_err(|_| ContractError::MigrationError {})?;
let current_ver = CONTRACT_VERSION
.parse::<semver::Version>()
.map_err(|_| ContractError::MigrationError {})?;
if stored_ver >= current_ver {
return Err(ContractError::MigrationError {});
}
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
Ok(Response::default())
}
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> cosmwasm_std::StdResult<Binary> {
match msg {
QueryMsg::Config {} => to_json_binary(&query_config(deps)?),
QueryMsg::WrappedSupply {} => to_json_binary(&query_wrapped_supply(deps)?),
}
}
fn query_config(deps: Deps) -> cosmwasm_std::StdResult<ConfigResponse> {
let config = CONFIG.load(deps.storage)?;
Ok(ConfigResponse {
cw20_contract: config.cw20_contract.to_string(),
native_denom: config.native_denom,
admin: config.admin.to_string(),
})
}
fn query_wrapped_supply(deps: Deps) -> cosmwasm_std::StdResult<WrappedSupplyResponse> {
let wrapped_supply = WRAPPED_SUPPLY
.may_load(deps.storage)?
.unwrap_or_else(Uint128::zero);
Ok(WrappedSupplyResponse { wrapped_supply })
}
fn sent_amount_for_denom(info: &MessageInfo, denom: &str) -> Result<Uint128, ContractError> {
let mut amount = Uint128::zero();
for coin in &info.funds {
if coin.denom == denom {
amount += coin.amount;
} else if !coin.amount.is_zero() {
return Err(ContractError::UnexpectedFunds {});
}
}
Ok(amount)
}
cw-cyber/contracts/litium-wrap/src/contract.rs
ฯ 0.0%
use ;
use ;
use ;
use CyberMsg;
use crateContractError;
use crate;
use crate;
const CONTRACT_NAME: &str = "crates.io:litium-wrap";
const CONTRACT_VERSION: &str = env!;
/// CW-20 โ native wrap. Called when litium-core sends CW-20 tokens to this contract.
/// Native โ CW-20 unwrap. User sends native LI tokens in funds.