use cosmwasm_std::{
attr, to_json_binary, Addr, BankMsg, Coin, CosmosMsg, Decimal, DepsMut, Empty, Env,
MessageInfo, StdResult, Uint128, Uint64, WasmMsg,
};
use crate::error::ContractError;
use crate::helpers::{update_coefficient, verify_merkle_proof};
use crate::msg::{AddressResponse, SignatureResponse};
use crate::state::{
ClaimState, ReleaseState, CLAIM, CONFIG, MERKLE_ROOT, RELEASE, RELEASES_STATS, STATE,
};
use cw1_subkeys::msg::ExecuteMsg as Cw1ExecuteMsg;
use cw_cyber_passport::msg::QueryMsg as PassportQueryMsg;
use cw_utils::Expiration;
use cyber_std::CyberMsg;
use std::ops::{Add, Mul, Sub};
type Response = cosmwasm_std::Response<CyberMsg>;
pub fn execute_execute(
deps: DepsMut,
_env: Env,
info: MessageInfo,
msgs: Vec<CosmosMsg<CyberMsg>>,
) -> Result<Response, ContractError> {
let mut res = Response::new().add_attribute("action", "execute");
let cfg = CONFIG.load(deps.storage)?;
let owner = cfg.owner.ok_or(ContractError::Unauthorized {})?;
if info.sender != owner {
return Err(ContractError::Unauthorized {});
}
res = res.add_messages(msgs);
Ok(res)
}
pub fn execute_update_owner(
deps: DepsMut,
_env: Env,
info: MessageInfo,
new_owner: Option<String>,
) -> Result<Response, ContractError> {
let cfg = CONFIG.load(deps.storage)?;
let owner = cfg.owner.ok_or(ContractError::Unauthorized {})?;
if info.sender != owner {
return Err(ContractError::Unauthorized {});
}
let mut tmp_owner = None;
if let Some(addr) = new_owner {
tmp_owner = Some(deps.api.addr_validate(&addr)?)
}
CONFIG.update(deps.storage, |mut exists| -> StdResult<_> {
exists.owner = tmp_owner;
Ok(exists)
})?;
Ok(Response::new().add_attributes(vec![attr("action", "update_owner")]))
}
pub fn execute_update_treasury(
deps: DepsMut,
_env: Env,
info: MessageInfo,
new_treasury: String,
) -> Result<Response, ContractError> {
let cfg = CONFIG.load(deps.storage)?;
let owner = cfg.owner.ok_or(ContractError::Unauthorized {})?;
if info.sender != owner {
return Err(ContractError::Unauthorized {});
}
let treasury = deps.api.addr_validate(&new_treasury)?;
CONFIG.update(deps.storage, |mut cfg| -> StdResult<_> {
cfg.treasury_addr = treasury;
Ok(cfg)
})?;
Ok(Response::new().add_attributes(vec![
attr("action", "update_treasury"),
attr("treasury", new_treasury),
]))
}
pub fn execute_update_target(
deps: DepsMut,
_env: Env,
info: MessageInfo,
new_target: Uint64,
) -> Result<Response, ContractError> {
let cfg = CONFIG.load(deps.storage)?;
let owner = cfg.owner.ok_or(ContractError::Unauthorized {})?;
if info.sender != owner {
return Err(ContractError::Unauthorized {});
}
CONFIG.update(deps.storage, |mut cfg| -> StdResult<_> {
cfg.target_claim = new_target;
Ok(cfg)
})?;
Ok(Response::new().add_attributes(vec![
attr("action", "update_target"),
attr("target", new_target.to_string()),
]))
}
pub fn execute_update_coefficients(
deps: DepsMut,
_env: Env,
info: MessageInfo,
new_coefficient_up: Uint128,
new_coefficient_down: Uint128,
) -> Result<Response, ContractError> {
let cfg = CONFIG.load(deps.storage)?;
let owner = cfg.clone().owner.ok_or(ContractError::Unauthorized {})?;
if info.sender != owner {
return Err(ContractError::Unauthorized {});
}
CONFIG.update(deps.storage, |mut cfg| -> StdResult<_> {
cfg.coefficient_up = new_coefficient_up;
cfg.coefficient_down = new_coefficient_down;
Ok(cfg)
})?;
let config = CONFIG.load(deps.storage)?;
let mut state = STATE.load(deps.storage)?;
update_coefficient(deps.storage, Uint128::zero(), &config, &mut state)?;
Ok(Response::new().add_attributes(vec![
attr("action", "update_coefficients"),
attr("new_coefficient_up", new_coefficient_up.to_string()),
attr("new_coefficient_down", new_coefficient_down.to_string()),
]))
}
pub fn execute_register_merkle_root(
deps: DepsMut,
_env: Env,
info: MessageInfo,
merkle_root: String,
) -> Result<Response, ContractError> {
let cfg = CONFIG.load(deps.storage)?;
let owner = cfg.owner.ok_or(ContractError::Unauthorized {})?;
if info.sender != owner {
return Err(ContractError::Unauthorized {});
}
let mut root_buf: [u8; 32] = [0; 32];
hex::decode_to_slice(merkle_root.to_string(), &mut root_buf)?;
MERKLE_ROOT.save(deps.storage, &merkle_root)?;
Ok(Response::new().add_attributes(vec![
attr("action", "register_merkle_root"),
attr("merkle_root", merkle_root),
]))
}
const CLAIM_BOUNTY: u128 = 100000;
pub fn execute_claim(
deps: DepsMut,
_env: Env,
info: MessageInfo,
nickname: String,
mut gift_claiming_address: String,
gift_amount: Uint128,
proof: Vec<String>,
) -> Result<Response, ContractError> {
gift_claiming_address = gift_claiming_address.to_lowercase();
let claimed = CLAIM.may_load(deps.storage, gift_claiming_address.clone())?;
if claimed.is_some() {
return Err(ContractError::Claimed {});
}
let config = CONFIG.load(deps.storage)?;
let mut state = STATE.load(deps.storage)?;
let claim_amount = gift_amount * state.coefficient;
if state.current_balance < claim_amount {
return Err(ContractError::GiftIsOver {});
}
let res: SignatureResponse = deps.querier.query_wasm_smart(
config.clone().passport_addr,
&PassportQueryMsg::PassportSigned {
nickname: nickname.clone(),
address: gift_claiming_address.clone(),
},
)?;
if res.signed == false {
return Err(ContractError::IsNotProved {});
}
// returns error of proof is invalid
verify_merkle_proof(
&deps,
&info,
gift_claiming_address.clone(),
gift_amount.clone(),
proof,
)?;
// only claim once by given verified address
CLAIM.save(
deps.storage,
gift_claiming_address.clone(),
&ClaimState {
claim: claim_amount,
multiplier: state.coefficient,
},
)?;
update_coefficient(deps.storage, claim_amount, &config, &mut state)?;
// get address of the passport by nickname
let res: AddressResponse = deps.querier.query_wasm_smart(
config.passport_addr,
&PassportQueryMsg::AddressByNickname {
nickname: nickname.clone(),
},
)?;
let release_state = ReleaseState {
address: deps.api.addr_validate(&res.address)?,
balance_claim: claim_amount.checked_sub(Uint128::new(CLAIM_BOUNTY))?,
stage: Uint64::zero(),
stage_expiration: Expiration::Never {},
};
RELEASE.save(deps.storage, gift_claiming_address.clone(), &release_state)?;
STATE.update(deps.storage, |mut stt| -> StdResult<_> {
stt.claims = stt.claims.add(Uint64::new(1));
Ok(stt)
})?;
// send funds from treasury controlled by Congress
Ok(Response::new()
.add_message(WasmMsg::Execute {
contract_addr: config.treasury_addr.to_string(),
msg: to_json_binary(&Cw1ExecuteMsg::Execute::<Empty> {
msgs: vec![CosmosMsg::Bank(BankMsg::Send {
to_address: res.address.clone(),
amount: vec![Coin {
denom: config.allowed_native,
amount: Uint128::new(CLAIM_BOUNTY),
}],
})
.into()],
})?,
funds: vec![],
})
.add_attributes(vec![
attr("action", "claim"),
attr("original", gift_claiming_address),
attr("target", res.address),
attr("amount", claim_amount),
]))
}
pub fn execute_release(
deps: DepsMut,
_env: Env,
info: MessageInfo,
mut gift_address: String,
) -> Result<Response, ContractError> {
gift_address = gift_address.to_lowercase();
let claimed = CLAIM.may_load(deps.storage, gift_address.clone())?;
if claimed.is_none() {
return Err(ContractError::NotClaimed {});
}
let config = CONFIG.load(deps.storage)?;
let state = STATE.load(deps.storage)?;
let mut state_stage =
Uint128::new(100u128).mul(Decimal::from_ratio(state.claims, config.target_claim));
if state_stage.ge(&Uint128::new(100u128)) {
state_stage = Uint128::new(100u128);
}
let mut release_state = RELEASE.load(deps.storage, gift_address.clone())?;
if release_state.address != info.sender {
return Err(ContractError::Unauthorized {});
}
if release_state.balance_claim.is_zero() {
return Err(ContractError::GiftReleased {});
}
if release_state
.stage
.eq(&Uint64::new(state_stage.clone().u128() as u64))
{
return Err(ContractError::StageReleased {});
}
if release_state
.stage
.gt(&Uint64::new(state_stage.clone().u128() as u64))
{
return Err(ContractError::Unauthorized {});
}
let amount;
if release_state.stage.is_zero() {
amount = release_state
.balance_claim
.mul(Decimal::percent(state_stage.u128() as u64));
} else {
if state_stage.ne(&Uint128::new(100u128)) {
amount = CLAIM
.load(deps.storage, gift_address.clone())?
.claim
.sub(Uint128::from(CLAIM_BOUNTY))
.mul(Decimal::from_ratio(
state_stage.sub(Uint128::from(release_state.stage)),
100u128,
))
} else {
amount = release_state.balance_claim;
}
}
for i in (release_state.stage.u64())..(state_stage.u128() as u64) {
RELEASES_STATS.update(deps.storage, i as u8, |count| -> StdResult<_> {
Ok(count.unwrap_or(0) + 1u32)
})?;
}
release_state.stage = Uint64::from(state_stage.u128() as u64);
release_state.balance_claim = release_state.balance_claim - amount;
RELEASE.save(deps.storage, gift_address.clone(), &release_state)?;
STATE.update(deps.storage, |mut stt| -> StdResult<_> {
stt.releases = stt.releases.add(Uint64::new(1));
Ok(stt)
})?;
// send funds from treasury controlled by Congress
Ok(Response::new()
.add_message(WasmMsg::Execute {
contract_addr: config.treasury_addr.to_string(),
msg: to_json_binary(&Cw1ExecuteMsg::Execute::<Empty> {
msgs: vec![CosmosMsg::Bank(BankMsg::Send {
to_address: release_state.clone().address.into(),
amount: vec![Coin {
denom: config.allowed_native,
amount: amount,
}],
})
.into()],
})?,
funds: vec![],
})
.add_attributes(vec![
attr("action", "release"),
attr("address", release_state.clone().address.to_string()),
attr("gift_address", gift_address),
attr("stage", release_state.stage.to_string()),
attr("amount", amount),
]))
}
cw-cyber/contracts/cw-cyber-gift/src/execute.rs
ฯ 0.0%
use ;
use crateContractError;
use crate;
use crate;
use crate;
use ExecuteMsg as Cw1ExecuteMsg;
use QueryMsg as PassportQueryMsg;
use Expiration;
use CyberMsg;
use ;
type Response = Response;
const CLAIM_BOUNTY: u128 = 100000;