Skip to content

Commit

Permalink
fix: fix comments
Browse files Browse the repository at this point in the history
  • Loading branch information
matthiasmatt committed Feb 7, 2024
1 parent 0418973 commit 5543049
Show file tree
Hide file tree
Showing 2 changed files with 238 additions and 25 deletions.
40 changes: 19 additions & 21 deletions contracts/core-token-vesting/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,19 +186,13 @@ fn reward_users(
return Err(StdError::generic_err("Campaign is not active").into());
}

let mut unallocated_amount = campaign.unallocated_amount;

let total_requested: Uint128 = requests.iter().map(|req| req.amount).sum();
if total_requested > campaign.unallocated_amount {
return Err(
StdError::generic_err("Insufficient funds for all rewards").into()
);
}
for req in requests {
if unallocated_amount < req.amount {
// We fail on the first request that cannot be fulfilled
// This is to ensure that we do not partially fulfill requests
// and leave the campaign in an inconsistent state.
return Err(StdError::generic_err(
"Not enough funds in the campaign",
)
.into());
}

match USER_REWARDS.may_load(deps.storage, req.user_address.clone())? {
Some(mut user_reward) => {
user_reward += req.amount;
Expand All @@ -216,16 +210,14 @@ fn reward_users(
)?;
}
};
unallocated_amount -= req.amount;

res.push(RewardUserResponse {
user_address: req.user_address.clone(),
success: true,
error_msg: "".to_string(),
});
}

campaign.unallocated_amount = unallocated_amount;
campaign.unallocated_amount = campaign.unallocated_amount - total_requested;
CAMPAIGN.save(deps.storage, campaign_id.clone(), &campaign)?;

Ok(Response::new()
Expand All @@ -251,7 +243,7 @@ fn create_campaign(
}

if info.funds.len() != 1 {
return Err(StdError::generic_err("Only one coin is allowed").into());
return Err(StdError::generic_err("one denom sent required").into());
}

let coin = info.funds.get(0).unwrap();
Expand Down Expand Up @@ -645,9 +637,15 @@ pub fn withdraw(
}
}

Ok(Response::new().add_messages(vec![build_send_msg(
campaign.denom,
amount,
info.sender.to_string(),
)?]))
Ok(Response::new()
.add_messages(vec![build_send_msg(
campaign.denom,
amount,
info.sender.to_string(),
)?])
.add_attribute("withdraw", &amount.to_string())
.add_attribute(
"campaign_unallocated_amount",
&campaign.unallocated_amount.to_string(),
))
}
223 changes: 219 additions & 4 deletions contracts/core-token-vesting/tests/tests/test_airdrop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,79 @@ fn execute_create_campaign_duplicate_id() -> TestResult {
}

#[test]
fn execute_reward_users_valid() -> TestResult {
fn execute_create_campaign_invalid_coin_count() -> TestResult {
let (mut deps, env) = setup_with_block_time(0)?;

// Create a campaign with invalid coin count
let create_campaign_msg = ExecuteMsg::CreateCampaign {
vesting_schedule: VestingSchedule::LinearVesting {
start_time: Uint64::new(100),
end_time: Uint64::new(200),
vesting_amount: Uint128::new(5000),
},
campaign_id: "campaign1".to_string(),
campaign_name: "Test Campaign".to_string(),
campaign_description: "A test campaign".to_string(),
managers: vec!["manager1".to_string(), "manager2".to_string()],
};
let res = execute(
deps.as_mut(),
env,
mock_info("creator", &[]),
create_campaign_msg,
);

match res {
Err(ContractError::Std(StdError::GenericErr { msg, .. }))
if msg.contains("one denom sent required") =>
{
Ok(())
}
_ => Err(anyhow!(
"Expected 'one denom sent required' error, found {:?}",
res
)),
}
}

#[test]
fn execute_create_campaign_2_coins() -> TestResult {
let (mut deps, env) = setup_with_block_time(0)?;

// Create a campaign with 2 coins
let create_campaign_msg = ExecuteMsg::CreateCampaign {
vesting_schedule: VestingSchedule::LinearVesting {
start_time: Uint64::new(100),
end_time: Uint64::new(200),
vesting_amount: Uint128::new(5000),
},
campaign_id: "campaign2".to_string(),
campaign_name: "Test Campaign".to_string(),
campaign_description: "A test campaign".to_string(),
managers: vec!["manager1".to_string(), "manager2".to_string()],
};
let res = execute(
deps.as_mut(),
env,
mock_info("creator", &[coin(5000, "token"), coin(5000, "token")]),
create_campaign_msg,
);

match res {
Err(ContractError::Std(StdError::GenericErr { msg, .. }))
if msg.contains("one denom sent required") =>
{
Ok(())
}
_ => Err(anyhow!(
"Expected 'one denom sent required' error, found {:?}",
res
)),
}
}

#[test]
fn execute_reward_users_unactive_campaign() -> TestResult {
let (mut deps, env) = setup_with_block_time(0)?;

// Create a campaign
Expand All @@ -121,6 +193,13 @@ fn execute_reward_users_valid() -> TestResult {
},
)?;

// Deactivate the campaign
let msg = ExecuteMsg::DeactivateCampaign {
campaign_id: campaign_id.clone(),
};
let info = mock_info("creator", &[]);
execute(deps.as_mut(), env.clone(), info, msg)?;

// Reward users
let reward_users_msg = ExecuteMsg::RewardUsers {
campaign_id: campaign_id.clone(),
Expand All @@ -135,9 +214,120 @@ fn execute_reward_users_valid() -> TestResult {
},
],
};
let res = execute(
deps.as_mut(),
env,
mock_info("creator", &[]),
reward_users_msg,
);

match res {
Err(ContractError::Std(StdError::GenericErr { msg, .. }))
if msg.contains("Campaign is not active") =>
{
Ok(())
}
_ => Err(anyhow!(
"Expected 'Campaign is not active' error, found {:?}",
res
)),
}
}

#[test]
fn execute_reward_users_unauthorized() -> TestResult {
let (mut deps, env) = setup_with_block_time(0)?;

// Create a campaign
let campaign_id = "campaign1".to_string();
execute(
deps.as_mut(),
env.clone(),
mock_info("creator", &[coin(10000, "token")]),
ExecuteMsg::CreateCampaign {
campaign_id: campaign_id.clone(),
campaign_name: "Campaign One".to_string(),
campaign_description: "The first campaign".to_string(),
managers: vec!["manager1".to_string()],
vesting_schedule: VestingSchedule::LinearVesting {
start_time: Uint64::new(100),
end_time: Uint64::new(200),
vesting_amount: Uint128::new(10000),
},
},
)?;

// Reward users
let reward_users_msg = ExecuteMsg::RewardUsers {
campaign_id: campaign_id.clone(),
requests: vec![
RewardUserRequest {
user_address: "user1".to_string(),
amount: Uint128::new(500),
},
RewardUserRequest {
user_address: "user2".to_string(),
amount: Uint128::new(1500),
},
],
};
let res = execute(
deps.as_mut(),
env,
mock_info("unauthorized_user", &[]),
reward_users_msg,
);

match res {
Err(ContractError::Std(StdError::GenericErr { msg, .. }))
if msg.contains("Unauthorized") =>
{
Ok(())
}
_ => Err(anyhow!("Expected 'Unauthorized' error, found {:?}", res)),
}
}

#[test]
fn execute_reward_users_valid() -> TestResult {
let (mut deps, env) = setup_with_block_time(0)?;

// Create a campaign
let campaign_id = "campaign1".to_string();
execute(
deps.as_mut(),
env.clone(),
mock_info("creator", &[coin(10000, "token")]),
ExecuteMsg::CreateCampaign {
campaign_id: campaign_id.clone(),
campaign_name: "Campaign One".to_string(),
campaign_description: "The first campaign".to_string(),
managers: vec!["manager1".to_string()],
vesting_schedule: VestingSchedule::LinearVesting {
start_time: Uint64::new(100),
end_time: Uint64::new(200),
vesting_amount: Uint128::new(10000),
},
},
)?;

// Reward users
let reward_users_msg = ExecuteMsg::RewardUsers {
campaign_id: campaign_id.clone(),
requests: vec![
RewardUserRequest {
user_address: "user1".to_string(),
amount: Uint128::new(500),
},
RewardUserRequest {
user_address: "user2".to_string(),
amount: Uint128::new(1500),
},
],
};
execute(
deps.as_mut(),
env.clone(),
mock_info("creator", &[]),
reward_users_msg,
)?;
Expand All @@ -159,13 +349,38 @@ fn execute_reward_users_valid() -> TestResult {
"User2 rewards do not match."
);

let updated_campaign = CAMPAIGN.load(deps.as_ref().storage, campaign_id)?;
let updated_campaign =
CAMPAIGN.load(deps.as_ref().storage, campaign_id.clone())?;
assert_eq!(
updated_campaign.unallocated_amount,
Uint128::new(8000),
"Campaign unallocated amount does not match expected."
);

// Additional reward
let reward_users_msg = ExecuteMsg::RewardUsers {
campaign_id: campaign_id.clone(),
requests: vec![RewardUserRequest {
user_address: "user1".to_string(),
amount: Uint128::new(1000),
}],
};
execute(
deps.as_mut(),
env,
mock_info("creator", &[]),
reward_users_msg,
)?;

// Verify user rewards and campaign state
let user1_rewards =
USER_REWARDS.load(deps.as_ref().storage, "user1".to_string())?;
assert_eq!(
user1_rewards,
Uint128::new(1500),
"User1 rewards do not match."
);

Ok(())
}

Expand Down Expand Up @@ -208,12 +423,12 @@ fn execute_reward_users_insufficient_funds() -> TestResult {

match res {
Err(ContractError::Std(StdError::GenericErr { msg, .. }))
if msg.contains("Not enough funds in the campaign") =>
if msg.contains("Insufficient funds for all rewards") =>
{
Ok(())
}
_ => Err(anyhow!(
"Expected 'Not enough funds in the campaign' error, found {:?}",
"Expected 'Insufficient funds for all rewards' error, found {:?}",
res
)),
}
Expand Down

0 comments on commit 5543049

Please sign in to comment.