Skip to content

Commit

Permalink
Merge pull request #55 from neutron-org/feat/airdrop-update-reserve
Browse files Browse the repository at this point in the history
added update_reserve method. withdraw_all is permissioned #NTRN-95
  • Loading branch information
pr0n00gler authored Aug 19, 2023
2 parents e306308 + 1cb9ba0 commit 54592b0
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 4 deletions.
20 changes: 20 additions & 0 deletions contracts/cw20-merkle-airdrop/schema/cw20-merkle-airdrop.json
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,26 @@
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"update_reserve"
],
"properties": {
"update_reserve": {
"type": "object",
"required": [
"address"
],
"properties": {
"address": {
"type": "string"
}
}
}
},
"additionalProperties": false
}
],
"definitions": {
Expand Down
20 changes: 20 additions & 0 deletions contracts/cw20-merkle-airdrop/schema/raw/execute.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,26 @@
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"update_reserve"
],
"properties": {
"update_reserve": {
"type": "object",
"required": [
"address"
],
"properties": {
"address": {
"type": "string"
}
}
}
},
"additionalProperties": false
}
],
"definitions": {
Expand Down
25 changes: 23 additions & 2 deletions contracts/cw20-merkle-airdrop/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ pub fn execute(
ExecuteMsg::WithdrawAll {} => execute_withdraw_all(deps, env, info),
ExecuteMsg::Pause {} => execute_pause(deps, env, info),
ExecuteMsg::Resume {} => execute_resume(deps, env, info),
ExecuteMsg::UpdateReserve { address } => execute_update_reserve(deps, env, info, address),
}
}

Expand Down Expand Up @@ -197,6 +198,10 @@ pub fn execute_withdraw_all(
env: Env,
info: MessageInfo,
) -> Result<Response, ContractError> {
let cfg = CONFIG.load(deps.storage)?;
if info.sender != cfg.reserve_address {
return Err(ContractError::Unauthorized {});
}
let vesting_start = VESTING_START.load(deps.storage)?;
let vesting_duration = VESTING_DURATION.load(deps.storage)?;
let expiration = vesting_start + vesting_duration;
Expand All @@ -218,7 +223,6 @@ pub fn execute_withdraw_all(

// Get the current total balance for the contract and burn it all.
// By burning, we exchange them for NTRN tokens
let cfg = CONFIG.load(deps.storage)?;
let amount_to_withdraw = deps
.querier
.query_wasm_smart::<BalanceResponse>(
Expand All @@ -245,13 +249,30 @@ pub fn execute_withdraw_all(
.add_messages([burn_message, send_message])
.add_attributes(vec![
attr("action", "withdraw_all"),
attr("address", info.sender),
attr("amount", amount_to_withdraw),
attr("recipient", cfg.reserve_address),
]);
Ok(res)
}

fn execute_update_reserve(
deps: DepsMut,
_: Env,
info: MessageInfo,
address: String,
) -> Result<Response, ContractError> {
let mut cfg = CONFIG.load(deps.storage)?;
if cfg.owner != info.sender && cfg.reserve_address != info.sender {
return Err(ContractError::Unauthorized {});
}
cfg.reserve_address = deps.api.addr_validate(&address)?;
CONFIG.save(deps.storage, &cfg)?;
Ok(Response::new().add_attributes(vec![
attr("action", "update_reserve"),
attr("address", address),
]))
}

pub fn execute_pause(
deps: DepsMut,
env: Env,
Expand Down
3 changes: 3 additions & 0 deletions contracts/cw20-merkle-airdrop/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ pub enum ExecuteMsg {
WithdrawAll {},
Pause {},
Resume {},
UpdateReserve {
address: String,
},
}

#[cw_serde]
Expand Down
102 changes: 100 additions & 2 deletions contracts/cw20-merkle-airdrop/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,91 @@ fn expiration() {
)
}

#[test]
fn update_reserve_address() {
let mut deps = mock_dependencies();
let env = mock_env();
let airdrop_start = env.block.time.minus_seconds(5_000).seconds();
let vesting_start = env.block.time.plus_seconds(10_000).seconds();
let vesting_duration_seconds = 20_000;
let info = mock_info("owner0000", &[]);

let msg = InstantiateMsg {
credits_address: "credits0000".to_string(),
reserve_address: "reserve0000".to_string(),
merkle_root: "5d4f48f147cb6cb742b376dce5626b2a036f69faec10cd73631c791780e150fc".to_string(),
airdrop_start,
vesting_start,
vesting_duration_seconds,
total_amount: None,
hrp: None,
};
let _res = instantiate(deps.as_mut(), env.clone(), info, msg).unwrap();

// can't claim expired
let msg = ExecuteMsg::UpdateReserve {
address: "reserve0001".to_string(),
};

let res = execute(
deps.as_mut(),
env.clone(),
mock_info("regularaddress", &[]),
msg.clone(),
)
.unwrap_err();
assert_eq!(res, ContractError::Unauthorized {});

let res = execute(
deps.as_mut(),
env.clone(),
mock_info("owner0000", &[]),
msg.clone(),
)
.unwrap();
assert_eq!(
res.attributes,
vec![
attr("action", "update_reserve"),
attr("address", "reserve0001"),
]
);

// old reserve is unauthorized now
let res = execute(
deps.as_mut(),
env.clone(),
mock_info("reserve0000", &[]),
msg,
)
.unwrap_err();
assert_eq!(res, ContractError::Unauthorized {});

let res = execute(
deps.as_mut(),
env.clone(),
mock_info("reserve0001", &[]),
ExecuteMsg::UpdateReserve {
address: "reserve0002".to_string(),
},
)
.unwrap();
assert_eq!(
res.attributes,
vec![
attr("action", "update_reserve"),
attr("address", "reserve0002"),
]
);

assert_eq!(
from_binary::<ConfigResponse>(&query(deps.as_ref(), env, QueryMsg::Config {}).unwrap())
.unwrap()
.reserve_address,
"reserve0002"
);
}

#[test]
fn withdraw_all() {
let test_data: Encoded = from_slice(TEST_DATA_1).unwrap();
Expand Down Expand Up @@ -449,8 +534,9 @@ fn withdraw_all() {
)
.unwrap();
assert_eq!(Uint128::new(10000), response.balance);
//withdraw before expiration

let withdraw_msg = ExecuteMsg::WithdrawAll {};
//unauthorized
let err = router
.execute_contract(
Addr::unchecked("owner0000".to_string()),
Expand All @@ -461,6 +547,18 @@ fn withdraw_all() {
.unwrap_err()
.downcast::<ContractError>()
.unwrap();
assert_eq!(err, ContractError::Unauthorized {});
//withdraw before expiration
let err = router
.execute_contract(
Addr::unchecked("reserve0000".to_string()),
merkle_airdrop_addr.clone(),
&withdraw_msg,
&[],
)
.unwrap_err()
.downcast::<ContractError>()
.unwrap();
assert_eq!(
err,
ContractError::WithdrawAllUnavailable {
Expand All @@ -480,7 +578,7 @@ fn withdraw_all() {
let withdraw_all_msg = ExecuteMsg::WithdrawAll {};
router
.execute_contract(
Addr::unchecked("owner0000".to_string()),
Addr::unchecked("reserve0000".to_string()),
merkle_airdrop_addr.clone(),
&withdraw_all_msg,
&[],
Expand Down

0 comments on commit 54592b0

Please sign in to comment.