-
Notifications
You must be signed in to change notification settings - Fork 41
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
dYdX Airdrop updates #652
Merged
jhernandezb
merged 31 commits into
humanalgorithm/dydx-main-branch-v3.x
from
serkan/dydx-airdrop-updates
Apr 3, 2024
Merged
dYdX Airdrop updates #652
Changes from 15 commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
aec674d
Add name mint discount whitelist address
MightOfOaks dce9d17
Update tests to include name discount wl address
MightOfOaks 33d0943
Merge branch 'humanalgorithm/dydx-main-branch-v3.x' into serkan/dydx-…
MightOfOaks 85a3e51
Update instantiation to accommodate a whitelist-immutable-flex
MightOfOaks 9152288
Use build_messages and validation as common crates for registration &…
MightOfOaks 83b1147
Add mint_count query impl for whitelist-immutable-flex
MightOfOaks df428aa
Implement registration logic
MightOfOaks 4362ad7
Set flag for the registered address
MightOfOaks 88ad59a
Include name collection address among instantiation parameters
MightOfOaks aa6f9ca
Add collection token mint validation
MightOfOaks 868ae49
Add validation for name mint & association
MightOfOaks 7ffa284
Check for previous claims
MightOfOaks 48aacbd
Add claim_airdrop()
MightOfOaks fff2a30
Check for total airdrop count for reward distribution
MightOfOaks f048121
Address clippy issues
MightOfOaks d1df392
Update test-suite/common_setup to include whitelist-flex
MightOfOaks 868355b
Add TS interface & types
MightOfOaks ceb1aa8
Update airdrop & whitelist immutable flex contract instantiation para…
MightOfOaks b57450c
Address issues in test code (tests failing pre-update)
MightOfOaks 576e8b7
Merge branch 'humanalgorithm/dydx-main-branch-v3.x' into serkan/dydx-…
MightOfOaks 5ee3aff
Address issues induced by the merge
MightOfOaks 32a527a
Update error for invalid eth signature
MightOfOaks ee608b9
Update Member query response for whitelist-immutable-flex
MightOfOaks c733a78
Add queries for registration, claim and airdrop count
MightOfOaks db8aa26
Update schema
MightOfOaks 28179ab
Update TS interface & types
MightOfOaks 2b8102d
Add names/flat-rate-whitelist branch as a dependency
MightOfOaks e8a020d
Update dependency for whitelist-updatable-flatrate
MightOfOaks 613978f
eth-verify recovery param
jhernandezb 06bfc80
whitelist updates
jhernandezb 5f1ed3e
Merge pull request #673 from public-awesome/jhernadnezb/dydx-airdrop-…
jhernandezb File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
use cosmwasm_std::{ | ||
coins, to_json_binary, Addr, BankMsg, Deps, DepsMut, Env, MessageInfo, StdResult, WasmMsg, | ||
}; | ||
use sg_std::{CosmosMsg, Response, StargazeMsgWrapper, SubMsg, NATIVE_DENOM}; | ||
use whitelist_updatable::msg::ExecuteMsg; | ||
// TODO: Replace with whitelist_updatable_flatrate | ||
use crate::msg::InstantiateMsg; | ||
use crate::query::{query_collection_whitelist, query_mint_count}; | ||
use crate::state::{Config, CONFIG}; | ||
use crate::ContractError; | ||
use sg_whitelist_flex::helpers::interface::CollectionWhitelistContract; | ||
use sg_whitelist_flex::msg::AddMembersMsg; | ||
use sg_whitelist_flex::msg::{ExecuteMsg as CollectionWhitelistExecuteMsg, Member}; | ||
use whitelist_immutable_flex::msg::InstantiateMsg as WIFInstantiateMsg; | ||
use whitelist_updatable::msg::ExecuteMsg::AddAddresses; | ||
pub const IMMUTABLE_WHITELIST_LABEL: &str = "Whitelist Immutable Flex for Airdrop"; | ||
pub const INIT_WHITELIST_REPLY_ID: u64 = 1; | ||
|
||
pub fn whitelist_instantiate( | ||
env: Env, | ||
msg: InstantiateMsg, | ||
) -> Result<cosmwasm_std::SubMsg<StargazeMsgWrapper>, ContractError> { | ||
let whitelist_instantiate_msg = WIFInstantiateMsg { | ||
members: msg.members, | ||
mint_discount_bps: Some(0), | ||
}; | ||
let wasm_msg = WasmMsg::Instantiate { | ||
code_id: msg.whitelist_code_id, | ||
admin: Some(env.contract.address.to_string()), | ||
funds: vec![], | ||
label: IMMUTABLE_WHITELIST_LABEL.to_string(), | ||
msg: to_json_binary(&whitelist_instantiate_msg)?, | ||
}; | ||
Ok(SubMsg::reply_on_success(wasm_msg, INIT_WHITELIST_REPLY_ID)) | ||
} | ||
|
||
pub fn state_config( | ||
deps: Deps, | ||
info: MessageInfo, | ||
msg: InstantiateMsg, | ||
) -> Result<Config, ContractError> { | ||
Ok(Config { | ||
admin: info.sender, | ||
claim_msg_plaintext: msg.clone().claim_msg_plaintext, | ||
airdrop_amount: crate::validation::validate_airdrop_amount(msg.airdrop_amount)?, | ||
whitelist_address: None, | ||
minter_address: deps.api.addr_validate(msg.minter_address.as_ref())?, | ||
name_discount_wl_address: deps | ||
.api | ||
.addr_validate(msg.name_discount_wl_address.as_ref())?, | ||
name_collection_address: deps | ||
.api | ||
.addr_validate(msg.name_collection_address.as_ref())?, | ||
airdrop_count_limit: msg.airdrop_count_limit, | ||
}) | ||
} | ||
|
||
pub fn claim_reward(info: MessageInfo, airdrop_amount: u128) -> Result<Response, ContractError> { | ||
let mut res = Response::new(); | ||
let bank_msg = SubMsg::new(BankMsg::Send { | ||
to_address: info.sender.to_string(), | ||
amount: coins(airdrop_amount, NATIVE_DENOM), | ||
}); | ||
res = res.add_submessage(bank_msg); | ||
|
||
Ok(res) | ||
} | ||
|
||
pub fn dust_and_whitelist_add( | ||
deps: &DepsMut, | ||
info: MessageInfo, | ||
eth_address: String, | ||
) -> Result<Response, ContractError> { | ||
let res = add_member_to_whitelists(deps, info.clone(), eth_address)?; | ||
let res = res.add_message(dust_member_wallet(info.clone())?); | ||
Ok(res) | ||
} | ||
pub fn add_member_to_whitelists( | ||
deps: &DepsMut, | ||
info: MessageInfo, | ||
eth_address: String, | ||
) -> Result<Response, ContractError> { | ||
let config = CONFIG.load(deps.storage)?; | ||
let collection_whitelist = query_collection_whitelist(deps)?; | ||
let mint_count = query_mint_count(deps, eth_address.clone())?; | ||
let names_discount_whitelist = config.name_discount_wl_address; | ||
|
||
let res = Response::new(); | ||
let res = res.add_message(add_member_to_collection_whitelist( | ||
deps, | ||
info.sender.clone(), | ||
collection_whitelist, | ||
mint_count, | ||
)?); | ||
let res = res.add_message(add_member_to_names_discount_whitelist( | ||
info.sender.clone(), | ||
names_discount_whitelist.clone().to_string(), | ||
)?); | ||
Ok(res) | ||
} | ||
|
||
fn add_member_to_collection_whitelist( | ||
deps: &DepsMut, | ||
wallet_address: Addr, | ||
collection_whitelist: String, | ||
mint_count: u32, | ||
) -> StdResult<CosmosMsg> { | ||
let inner_msg = AddMembersMsg { | ||
to_add: vec![Member { | ||
address: wallet_address.to_string(), | ||
mint_count, | ||
}], | ||
}; | ||
let execute_msg = CollectionWhitelistExecuteMsg::AddMembers(inner_msg); | ||
CollectionWhitelistContract(deps.api.addr_validate(&collection_whitelist)?).call(execute_msg) | ||
} | ||
|
||
fn add_member_to_names_discount_whitelist( | ||
wallet_address: Addr, | ||
name_discount_wl: String, | ||
) -> StdResult<CosmosMsg> { | ||
let execute_msg: ExecuteMsg = AddAddresses { | ||
addresses: vec![wallet_address.to_string()], | ||
}; | ||
let msg = to_json_binary(&execute_msg)?; | ||
Ok(WasmMsg::Execute { | ||
contract_addr: name_discount_wl, | ||
msg, | ||
funds: vec![], | ||
} | ||
.into()) | ||
} | ||
|
||
pub fn dust_member_wallet(info: MessageInfo) -> StdResult<CosmosMsg> { | ||
let inner_msg = BankMsg::Send { | ||
to_address: info.sender.to_string(), | ||
amount: coins(1000000, NATIVE_DENOM), | ||
}; | ||
Ok(CosmosMsg::Bank(inner_msg)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,11 @@ | ||
use crate::query::query_collection_whitelist; | ||
use crate::state::ADDRS_TO_MINT_COUNT; | ||
use crate::build_messages::claim_reward; | ||
use crate::state::{AIRDROP_COUNT, HAS_CLAIMED}; | ||
use crate::{state::CONFIG, ContractError}; | ||
use build_messages::claim_and_whitelist_add; | ||
use cosmwasm_std::DepsMut; | ||
use cosmwasm_std::{coins, Addr, BankMsg, StdResult}; | ||
use cosmwasm_std::{Env, MessageInfo}; | ||
use sg_std::Response; | ||
use sg_std::{CosmosMsg, SubMsg}; | ||
use sg_whitelist::msg::ExecuteMsg as CollectionWhitelistExecuteMsg; | ||
use sg_whitelist::{helpers::interface::CollectionWhitelistContract, msg::AddMembersMsg}; | ||
use validation::validate_claim; | ||
|
||
use crate::validation::validate_claim; | ||
|
||
pub fn claim_airdrop( | ||
deps: DepsMut, | ||
|
@@ -19,158 +15,21 @@ pub fn claim_airdrop( | |
eth_sig: String, | ||
) -> Result<Response, ContractError> { | ||
let config = CONFIG.load(deps.storage)?; | ||
let airdrop_count_limit = config.airdrop_count_limit; | ||
if AIRDROP_COUNT.load(deps.storage)? >= airdrop_count_limit { | ||
return Err(ContractError::AirdropCountLimitExceeded {}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can be a one line assert check |
||
} | ||
validate_claim( | ||
&deps, | ||
info.clone(), | ||
eth_address.clone(), | ||
eth_sig, | ||
config.clone(), | ||
)?; | ||
let res = claim_and_whitelist_add(&deps, info, config.airdrop_amount)?; | ||
increment_local_mint_count_for_address(deps, eth_address)?; | ||
|
||
let res = claim_reward(info, config.airdrop_amount)?; | ||
AIRDROP_COUNT.update(deps.storage, |count: u32| -> Result<u32, ContractError> { | ||
Ok(count + 1) | ||
})?; | ||
HAS_CLAIMED.save(deps.storage, ð_address, &true)?; | ||
Ok(res.add_attribute("claimed_amount", config.airdrop_amount.to_string())) | ||
} | ||
|
||
pub fn increment_local_mint_count_for_address( | ||
deps: DepsMut, | ||
eth_address: String, | ||
) -> Result<Response, ContractError> { | ||
let mint_count_for_address = ADDRS_TO_MINT_COUNT | ||
.load(deps.storage, ð_address) | ||
.unwrap_or(0); | ||
ADDRS_TO_MINT_COUNT.save(deps.storage, ð_address, &(mint_count_for_address + 1))?; | ||
|
||
Ok(Response::new()) | ||
} | ||
|
||
mod build_messages { | ||
use super::*; | ||
use sg_std::NATIVE_DENOM; | ||
|
||
pub fn claim_and_whitelist_add( | ||
deps: &DepsMut, | ||
info: MessageInfo, | ||
airdrop_amount: u128, | ||
) -> Result<Response, ContractError> { | ||
let mut res = Response::new(); | ||
let bank_msg = SubMsg::new(BankMsg::Send { | ||
to_address: info.sender.to_string(), | ||
amount: coins(airdrop_amount, NATIVE_DENOM), | ||
}); | ||
res = res.add_submessage(bank_msg); | ||
let collection_whitelist = query_collection_whitelist(deps)?; | ||
let res = res.add_message(add_member_to_collection_whitelist( | ||
deps, | ||
info.sender, | ||
collection_whitelist, | ||
)?); | ||
Ok(res) | ||
} | ||
|
||
fn add_member_to_collection_whitelist( | ||
deps: &DepsMut, | ||
wallet_address: Addr, | ||
collection_whitelist: String, | ||
) -> StdResult<CosmosMsg> { | ||
let inner_msg = AddMembersMsg { | ||
to_add: vec![wallet_address.to_string()], | ||
}; | ||
let execute_msg = CollectionWhitelistExecuteMsg::AddMembers(inner_msg); | ||
CollectionWhitelistContract(deps.api.addr_validate(&collection_whitelist)?) | ||
.call(execute_msg) | ||
} | ||
} | ||
|
||
mod validation { | ||
use super::*; | ||
use cosmwasm_std::StdError; | ||
use ethereum_verify::verify_ethereum_text; | ||
|
||
use crate::{ | ||
query::{query_airdrop_is_eligible, query_per_address_limit}, | ||
state::Config, | ||
}; | ||
|
||
pub fn compute_plaintext_msg(config: &Config, info: MessageInfo) -> String { | ||
str::replace( | ||
&config.claim_msg_plaintext, | ||
"{wallet}", | ||
info.sender.as_ref(), | ||
) | ||
} | ||
|
||
pub fn validate_claim( | ||
deps: &DepsMut, | ||
info: MessageInfo, | ||
eth_address: String, | ||
eth_sig: String, | ||
config: Config, | ||
) -> Result<(), ContractError> { | ||
validate_is_eligible(deps, eth_address.clone())?; | ||
validate_eth_sig(deps, info, eth_address.clone(), eth_sig, config)?; | ||
validate_mints_remaining(deps, ð_address)?; | ||
Ok(()) | ||
} | ||
|
||
fn validate_is_eligible(deps: &DepsMut, eth_address: String) -> Result<(), ContractError> { | ||
let eligible = query_airdrop_is_eligible(deps.as_ref(), eth_address.clone())?; | ||
match eligible { | ||
true => Ok(()), | ||
false => Err(ContractError::AddressNotEligible { | ||
address: eth_address, | ||
}), | ||
} | ||
} | ||
|
||
fn validate_eth_sig( | ||
deps: &DepsMut, | ||
info: MessageInfo, | ||
eth_address: String, | ||
eth_sig: String, | ||
config: Config, | ||
) -> Result<(), ContractError> { | ||
let valid_eth_sig = | ||
validate_ethereum_text(deps, info, &config, eth_sig, eth_address.clone())?; | ||
match valid_eth_sig { | ||
true => Ok(()), | ||
false => Err(ContractError::AddressNotEligible { | ||
address: eth_address, | ||
}), | ||
} | ||
} | ||
|
||
pub fn validate_mints_remaining( | ||
deps: &DepsMut, | ||
eth_address: &str, | ||
) -> Result<(), ContractError> { | ||
let mint_count = ADDRS_TO_MINT_COUNT.load(deps.storage, eth_address); | ||
let mint_count = mint_count.unwrap_or(0); | ||
let per_address_limit = query_per_address_limit(&deps.as_ref())?; | ||
if mint_count < per_address_limit { | ||
Ok(()) | ||
} else { | ||
Err(ContractError::MintCountReached { | ||
address: eth_address.to_string(), | ||
}) | ||
} | ||
} | ||
|
||
pub fn validate_ethereum_text( | ||
deps: &DepsMut, | ||
info: MessageInfo, | ||
config: &Config, | ||
eth_sig: String, | ||
eth_address: String, | ||
) -> StdResult<bool> { | ||
let plaintext_msg = compute_plaintext_msg(config, info); | ||
match hex::decode(eth_sig.clone()) { | ||
Ok(eth_sig_hex) => { | ||
verify_ethereum_text(deps.as_ref(), &plaintext_msg, ð_sig_hex, ð_address) | ||
} | ||
Err(_) => Err(StdError::InvalidHex { | ||
msg: format!("Could not decode {eth_sig}"), | ||
}), | ||
} | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can just be whitelist_add and call the dust( ) function from the calling function