8000 Airdrop | completion flags by FloppyDisck · Pull Request #127 · securesecrets/shade · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Airdrop | completion flags #127

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 31 additions & 5 deletions contracts/airdrop/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,46 @@
use cosmwasm_std::{to_binary, Api, Binary, Env, Extern, HandleResponse, InitResponse, Querier, StdResult, Storage};
use cosmwasm_std::{to_binary, Api, Binary, Env, Extern, HandleResponse, InitResponse, Querier, StdResult, Storage, Uint128, StdError};
use shade_protocol::{
airdrop::{
InitMsg, HandleMsg,
QueryMsg, Config
}
};
use crate::{state::{config_w, reward_w, claim_status_w},
handle::{try_update_config, try_claim},
handle::{try_update_config, try_add_tasks, try_complete_task, try_claim},
query };
use shade_protocol::airdrop::RequiredTask;

pub fn init<S: Storage, A: Api, Q: Querier>(
deps: &mut Extern<S, A, Q>,
env: Env,
msg: InitMsg,
) -> StdResult<InitResponse> {

// Setup task claim
let mut task_claim= vec![RequiredTask {
address: env.contract.address,
percent: msg.default_claim
}];
let mut claim = msg.task_claim;
task_claim.append(&mut claim);

// Validate claim percentage
let mut count = Uint128::zero();
for claim in task_claim.iter() {
count += claim.percent;
}

if count > Uint128(100) {
return Err(StdError::GenericErr { msg: "tasks above 100%".to_string(), backtrace: None })
}
Comment on lines +33 to +35
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you switch to decimal this can be

if count > Decimal::one() {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You would need to convert everything to decimal for that since Uint128 and Decimal dont match when comparing

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But for the purposes of a percentage, integer precision is entirely inadequate and is guaranteed to introduce error into the calculation. It also disallows having any kind of resolution when setting/using these values.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering the amount is already in uShade, any "decimal" value will still be ignored when claiming so it wouldn't make a difference

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see no reason for this to be integers, the calculation will be inaccurate and there will be lots of error. But if that doesn't matter I will approve.

Copy link
Contributor Author
8000

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does matter but decimals doesn't provide a solution for when the number is inevitably converted back into Uint128. Maybe a final calculation once that user's airdrop completion is 100% could give him the possible 1-2 uToken loss


let config = Config{
admin: match msg.admin {
None => { env.message.sender.clone() }
Some(admin) => { admin }
},
airdrop_snip20: msg.airdrop_snip20.clone(),
airdrop_snip20: msg.airdrop_token.clone(),
task_claim,
start_date: match msg.start_time {
None => env.block.time,
Some(date) => date
Expand All @@ -34,7 +55,8 @@ pub fn init<S: Storage, A: Api, Q: Querier>(
let key = reward.address.to_string();

reward_w(&mut deps.storage).save(key.as_bytes(), &reward)?;
claim_status_w(&mut deps.storage).save(key.as_bytes(), &false)?;
// Save the initial claim
claim_status_w(&mut deps.storage, 0).save(key.as_bytes(), &false)?;
}

Ok(InitResponse {
Expand All @@ -52,6 +74,10 @@ pub fn handle<S: Storage, A: Api, Q: Querier>(
HandleMsg::UpdateConfig {
admin, start_date, end_date
} => try_update_config(deps, env, admin, start_date, end_date),
HandleMsg::AddTasks { tasks
} => try_add_tasks(deps, &env, tasks),
HandleMsg::CompleteTask { address
} => try_complete_task(deps, &env, address),
HandleMsg::Claim { } => try_claim(deps, &env),
}
}
Expand All @@ -66,4 +92,4 @@ pub fn query<S: Storage, A: Api, Q: Querier>(
QueryMsg::GetEligibility { address } => to_binary(
&query::airdrop_amount(&deps, address)?),
}
}
}
110 changes: 92 additions & 18 deletions contracts/airdrop/src/handle.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use cosmwasm_std::{to_binary, Api, Env, Extern, HandleResponse, Querier, StdError, StdResult, Storage, HumanAddr};
use cosmwasm_std::{to_binary, Api, Env, Extern, HandleResponse, Querier, StdError, StdResult, Storage, HumanAddr, Uint128};
use crate::state::{config_r, config_w, reward_r, claim_status_w, claim_status_r};
use shade_protocol::airdrop::{HandleAnswer};
use shade_protocol::airdrop::{HandleAnswer, RequiredTask};
use shade_protocol::generic_response::ResponseStatus;
use secret_toolkit::snip20::mint_msg;

Expand Down Expand Up @@ -41,6 +41,77 @@ pub fn try_update_config<S: Storage, A: Api, Q: Querier>(
})
}

pub fn try_add_tasks<S: Storage, A: Api, Q: Querier>(
deps: &mut Extern<S, A, Q>,
env: &Env,
tasks: Vec<RequiredTask>
) -> StdResult<HandleResponse> {

let config = config_r(&deps.storage).load()?;
// Check if admin
if env.message.sender != config.adm 6D40 in {
return Err(StdError::Unauthorized { backtrace: None });
}

config_w(&mut deps.storage).update(|mut config| {
let mut task_list = tasks;
config.task_claim.append(&mut task_list);

//Validate that they do not excede 100
let mut count = Uint128::zero();
for task in config.task_claim.iter() {
count += task.percent;
}

if count > Uint128(100) {
return Err(StdError::GenericErr { msg: "tasks above 100%".to_string(), backtrace: None })
}

Ok(config)
})?;

Ok(HandleResponse {
messages: vec![],
log: vec![],
data: Some( to_binary( &HandleAnswer::AddTask {
status: ResponseStatus::Success } )? )
})
}

pub fn try_complete_task<S: Storage, A: Api, Q: Querier>(
deps: &mut Extern<S, A, Q>,
env: &Env,
address: HumanAddr,
) -> StdResult<HandleResponse> {

let config = config_r(&deps.storage).load()?;

for (i, item) in config.task_claim.iter().enumerate() {
if item.address == env.message.sender {
claim_status_w(&mut deps.storage, i).update(
address.to_string().as_bytes(), |status| {
// If there was a state then ignore
if status.is_none() {
Ok(false)
}
else {
Err(StdError::Unauthorized { backtrace: None })
}
})?;

return Ok(HandleResponse {
messages: vec![],
log: vec![],
data: Some( to_binary( &HandleAnswer::Claim {
status: ResponseStatus::Success } )? )
})
}
}

// if not found
Err(StdError::NotFound { kind: "task".to_string(), backtrace: None })
}

pub fn try_claim<S: Storage, A: Api, Q: Querier>(
deps: &mut Extern<S, A, Q>,
env: &Env,
Expand All @@ -57,34 +128,37 @@ pub fn try_claim<S: Storage, A: Api, Q: Querier>(
}
}

let key = env.message.sender.to_string();
let user = env.message.sender.clone();
let user_key = user.to_string();

// Check if user is eligible
match claim_status_r(&deps.storage).load(key.as_bytes()) {
Ok(claimed) => {
if claimed {
return Err(StdError::GenericErr { msg: "Already Claimed".to_string(), backtrace: None })
let eligible_amount = reward_r(&deps.storage).load(
user.to_string().as_bytes())?.amount;

let mut total = Uint128::zero();
for (i, task) in config.task_claim.iter().enumerate() {
// Check if completed
let state = claim_status_r(&deps.storage, i).may_load(user_key.as_bytes())?;
match state {
None => {}
Some(claimed) => {
if !claimed {
claim_status_w(&mut deps.storage, i).save(user_key.as_bytes(), &true)?;
total += task.percent.multiply_ratio(eligible_amount, Uint128(100));
}
}
}
Err(_) => return Err(StdError::GenericErr { msg: "Not eligible".to_string(), backtrace: None })
};
}

// Load the user's reward
let airdrop = reward_r(&deps.storage).load(key.as_bytes())?;

// Redeem
let messages = vec![mint_msg(env.message.sender.clone(), airdrop.amount,
let messages = vec![mint_msg(user, total,
None, 1,
config.airdrop_snip20.code_hash,
config.airdrop_snip20.address)?];

// F438 Mark reward as redeemed
claim_status_w(&mut deps.storage).save(key.as_bytes(), &true)?;

Ok(HandleResponse {
messages,
log: vec![],
data: Some( to_binary( &HandleAnswer::Claim {
status: ResponseStatus::Success } )? )
})
}
}
30 changes: 27 additions & 3 deletions contracts/airdrop/src/query.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use cosmwasm_std::{Api, Extern, Querier, StdResult, Storage, HumanAddr};
use cosmwasm_std::{Api, Extern, Querier, StdResult, Storage, HumanAddr, Uint128};
use shade_protocol::airdrop::{QueryAnswer};
use crate::{state::{config_r, reward_r}};
use crate::state::claim_status_r;
Expand All @@ -19,8 +19,32 @@ pub fn dates<S: Storage, A: Api, Q: Querier>
pub fn airdrop_amount<S: Storage, A: Api, Q: Querier>
(deps: &Extern<S, A, Q>, address: HumanAddr) -> StdResult<QueryAnswer> {
let key = address.to_string();

let eligible_amount = reward_r(&deps.storage).load(key.as_bytes())?.amount;

let mut finished_tasks = vec![];
let mut claimed = Uint128::zero();
let mut unclaimed = Uint128::zero();

let config = config_r(&deps.storage).load()?;
for (i, task) in config.task_claim.iter().enumerate() {
let state = claim_status_r(&deps.storage, i).may_load(key.as_bytes())?;

if let Some(task_claimed) = state {
finished_tasks.push(task.clone());
let calc = task.percent.multiply_ratio(eligible_amount.clone(),
Uint128(100));
match task_claimed {
true => claimed += calc,
false => unclaimed += calc
};
}
}

Ok(QueryAnswer::Eligibility {
amount: reward_r(&deps.storage).load(key.as_bytes())?.amount,
claimed: claim_status_r(&deps.storage).load(key.as_bytes())?
total: eligible_amount,
claimed,
unclaimed,
finished_tasks
})
}
12 changes: 6 additions & 6 deletions contracts/airdrop/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use shade_protocol::airdrop::{Config, Reward};

pub static CONFIG_KEY: &[u8] = b"config";
pub 10000 static REWARDS_KEY: &[u8] = b"rewards";
pub static CLAIM_STATUS_KEY: &[u8] = b"claim_status";

pub fn config_w<S: Storage>(storage: &mut S) -> Singleton<S, Config> {
singleton(storage, CONFIG_KEY)
Expand All @@ -22,10 +21,11 @@ pub fn reward_w<S: Storage>(storage: &mut S) -> Bucket<S, Reward> {
bucket(REWARDS_KEY, storage)
}

pub fn claim_status_r<S: Storage>(storage: & S) -> ReadonlyBucket<S, bool> {
bucket_read(CLAIM_STATUS_KEY, storage)
// If not found then its unrewarded; if true then claimed
pub fn claim_status_r<S: Storage>(storage: & S, index: usize) -> ReadonlyBucket<S, bool> {
bucket_read(&[index as u8], storage)
}

pub fn claim_status_w<S: Storage>(storage: &mut S) -> Bucket<S, bool> {
bucket(CLAIM_STATUS_KEY, storage)
}
pub fn claim_status_w<S: Storage>(storage: &mut S, index: usize) -> Bucket<S, bool> {
bucket(&[index as u8], storage)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ use cosmwasm_std::{HumanAddr, Uint128};
use shade_protocol::{snip20::{InitialBalance}, snip20,
initializer, initializer::Snip20ContractInfo};
use crate::{utils::{print_header, generate_label, print_contract, print_warning,
STORE_GAS, GAS, VIEW_KEY, ACCOUNT_KEY},
STORE_GAS, GAS, VIEW_KEY, ACCOUNT_KEY, INITIALIZER_FILE},
contract_helpers::governance::add_contract,
contract_helpers::minter::get_balance};
use secretcli::{cli_types::NetContract,
secretcli::{test_contract_handle, test_inst_init}};
use secretcli::secretcli::list_contracts_by_code;
secretcli::{test_contract_handle, test_inst_init, list_contracts_by_code}};

pub fn initialize_initializer(
governance: &NetContract, sscrt: &NetContract, account: String) -> Result<()> {
Expand Down Expand Up @@ -45,7 +44,7 @@ pub fn initialize_initializer(
}
};

let initializer = test_inst_init(&init_msg, "../../compiled/initializer.wasm.gz", &*generate_label(8),
let initializer = test_inst_init(&init_msg, INITIALIZER_FILE, &*generate_label(8),
ACCOUNT_KEY, Some(STORE_GAS), Some(GAS),
Some("test"))?;
print_contract(&initializer);
Expand Down Expand Up @@ -98,4 +97,4 @@ pub fn initialize_initializer(
add_contract("silk".to_string(), &silk, &governance)?;

Ok(())
}
}
4 changes: 2 additions & 2 deletions packages/network_integration/src/contract_helpers/minter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use serde_json::Result;
use cosmwasm_std::{HumanAddr, Uint128, to_binary};
use shade_protocol::{snip20, micro_mint, mint, asset::Contract};
use crate::{utils::{print_header, print_contract, print_epoch_info, print_vec,
GAS, VIEW_KEY},
GAS, VIEW_KEY, MICRO_MINT_FILE},
contract_helpers::governance::{init_contract, get_contract,
create_and_trigger_proposal}};
use secretcli::{cli_types::NetContract,
Expand All @@ -11,7 +11,7 @@ use secretcli::{cli_types::NetContract,
pub fn initialize_minter(governance: &NetContract, contract_name: String,
native_asset: &Contract) -> Result<NetContract> {
let minter = init_contract(governance, contract_name,
"../../compiled/micro_mint.wasm.gz",
MICRO_MINT_FILE,
micro_mint::InitMsg {
admin: Some(HumanAddr::from(governance.address.clone())),
native_asset: native_asset.clone(),
Expand Down
6 changes: 3 additions & 3 deletions packages/network_integration/src/contract_helpers/stake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use serde_json::Result;
use cosmwasm_std::{HumanAddr, Uint128};
use shade_protocol::{staking, snip20, asset::Contract};
use crate::{utils::{print_header, print_contract,
GAS, ACCOUNT_KEY},
contract_helpers::governance::init_contract};
GAS, ACCOUNT_KEY, STAKING_FILE},
contract_helpers::governance::{init_contract}};
use secretcli::{cli_types::NetContract,
secretcli::{query_contract, test_contract_handle}};
use crate::contract_helpers::minter::get_balance;
Expand All @@ -13,7 +13,7 @@ use std::time::UNIX_EPOCH;
pub fn setup_staker(governance: &NetContract, shade: &Contract,
staking_account: String) -> Result<NetContract> {
let staker = init_contract(&governance, "staking".to_string(),
"../../compiled/staking.wasm.gz",
STAKING_FILE,
staking::InitMsg{
admin: Some(Contract{
address: HumanAddr::from(governance.address.clone()),
Expand Down
11 changes: 11 additions & 0 deletions packages/network_integration/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ use serde::Serialize;
use secretcli::{cli_types::NetContract,
secretcli::{query_contract}};

// Smart contracts
pub const SNIP20_FILE: &str = "../../compiled/snip20.wasm.gz";
pub const AIRDROP_FILE: &str = "../../compiled/airdrop.wasm.gz";
pub const GOVERNANCE_FILE: &str = "../../compiled/governance.wasm.gz";
pub const MOCK_BAND_FILE: &str = "../../compiled/mock_band.wasm.gz";
pub const ORACLE_FILE: &str = "../../compiled/oracle.wasm.gz";
pub const INITIALIZER_FILE: &str = "../../compiled/initializer.wasm.gz";
pub const MICRO_MINT_FILE: &str = "../../compiled/micro_mint.wasm.gz";
pub const STAKING_FILE: &str = "../../compiled/staking.wasm.gz";


pub const STORE_GAS: &str = "10000000";
pub const GAS: &str = "800000";
pub const VIEW_KEY: &str = "password";
Expand Down
Loading
0