Skip to content

Commit

Permalink
fix(airdrop-token-vesting): improve cliff validation logic (#132)
Browse files Browse the repository at this point in the history
  • Loading branch information
k-yang authored Mar 6, 2024
1 parent 55404f2 commit 939f68c
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 137 deletions.
67 changes: 0 additions & 67 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 2 additions & 4 deletions contracts/airdrop-token-vesting/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ fn reward_users(
StdError::generic_err("Insufficient funds for all rewards").into()
);
}
vesting_schedule.validate(env.block.time)?;
vesting_schedule.validate()?;

let mut attrs: Vec<Attribute> = vec![];
for req in rewards {
Expand All @@ -169,7 +169,6 @@ fn reward_users(

let result = register_vesting_account(
deps.storage,
env.block.time,
req.user_address.clone(),
req.vesting_amount,
req.cliff_amount,
Expand Down Expand Up @@ -205,7 +204,6 @@ fn reward_users(

fn register_vesting_account(
storage: &mut dyn Storage,
block_time: Timestamp,
address: String,
vesting_amount: Uint128,
cliff_amount: Uint128,
Expand All @@ -215,7 +213,7 @@ fn register_vesting_account(
if VESTING_ACCOUNTS.has(storage, address.as_str()) {
return Err(StdError::generic_err("already exists").into());
}
vesting_schedule.validate(block_time)?;
vesting_schedule.validate()?;

VESTING_ACCOUNTS.save(
storage,
Expand Down
28 changes: 10 additions & 18 deletions contracts/airdrop-token-vesting/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,10 @@ pub enum ContractError {
#[error(transparent)]
Vesting(#[from] VestingError),

#[error(transparent)]
Cliff(#[from] CliffError),

#[error(transparent)]
Overflow(#[from] cosmwasm_std::OverflowError),
}

#[derive(thiserror::Error, Debug, PartialEq)]
pub enum CliffError {
#[error("cliff_time ({cliff_time}) should be greater than block_time ({block_time})")]
InvalidTime { cliff_time: u64, block_time: u64 },

#[error("cliff_amount ({cliff_amount}) should be less than or equal to vesting_amount ({vesting_amount})")]
ExcessiveAmount {
cliff_amount: u128,
vesting_amount: u128,
},
}

#[derive(thiserror::Error, Debug, PartialEq)]
pub enum VestingError {
#[error("vesting_amount is zero but should be greater than 0")]
Expand All @@ -35,10 +20,17 @@ pub enum VestingError {
#[error(
"end_time ({end_time}) should be greater than start_time ({start_time})"
)]
InvalidTimeRange { start_time: u64, end_time: u64 },
InvalidTimeRange {
start_time: u64,
cliff_time: u64,
end_time: u64,
},

#[error(transparent)]
Cliff(#[from] CliffError),
#[error("cliff_amount ({cliff_amount}) should be less than or equal to vesting_amount ({vesting_amount})")]
ExcessiveAmount {
cliff_amount: u128,
vesting_amount: u128,
},

#[error("vesting_amount ({vesting_amount}) should be equal to deposit_amount ({deposit_amount})")]
MismatchedVestingAndDepositAmount {
Expand Down
66 changes: 23 additions & 43 deletions contracts/airdrop-token-vesting/src/msg.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Timestamp, Uint128, Uint64};
use cosmwasm_std::{Uint128, Uint64};
use cw20::Denom;

use crate::errors::{CliffError, ContractError, VestingError};
use crate::errors::{ContractError, VestingError};

/// Structure for the message that instantiates the smart contract.
#[cw_serde]
Expand Down Expand Up @@ -64,12 +64,10 @@ impl RewardUserRequest {
}

if self.cliff_amount > self.vesting_amount {
return Err(ContractError::Vesting(VestingError::Cliff(
CliffError::ExcessiveAmount {
cliff_amount: self.cliff_amount.into(),
vesting_amount: self.vesting_amount.into(),
},
)));
return Err(ContractError::Vesting(VestingError::ExcessiveAmount {
cliff_amount: self.cliff_amount.into(),
vesting_amount: self.vesting_amount.into(),
}));
}

Ok(())
Expand Down Expand Up @@ -151,35 +149,6 @@ pub fn from_vesting_to_query_output(
}
}

pub struct Cliff {
pub amount: Uint128,
pub time: Uint64,
}

impl Cliff {
pub fn ok_time(&self, block_time: Timestamp) -> Result<(), CliffError> {
let cliff_time_seconds = self.time.u64();
if cliff_time_seconds < block_time.seconds() {
return Err(CliffError::InvalidTime {
cliff_time: cliff_time_seconds,
block_time: block_time.seconds(),
});
}
Ok(())
}

pub fn ok_amount(&self, vesting_amount: Uint128) -> Result<(), CliffError> {
let cliff_amount = self.amount.u128();
if cliff_amount > vesting_amount.u128() {
return Err(CliffError::ExcessiveAmount {
cliff_amount,
vesting_amount: vesting_amount.u128(),
});
}
Ok(())
}
}

impl VestingSchedule {
///
/// validate_time checks that the start_time is less than the end_time.
Expand All @@ -189,7 +158,7 @@ impl VestingSchedule {
/// Additionally, it the vesting schedule is LinearVestingWithCliff, it checks that the cliff_time
/// is bigger or equal to the block_time.
///
pub fn validate(&self, block_time: Timestamp) -> Result<(), VestingError> {
pub fn validate(&self) -> Result<(), VestingError> {
match self {
VestingSchedule::LinearVestingWithCliff {
start_time,
Expand All @@ -200,14 +169,25 @@ impl VestingSchedule {
if end_time <= start_time {
return Err(VestingError::InvalidTimeRange {
start_time: start_time.u64(),
cliff_time: cliff_time.u64(),
end_time: end_time.u64(),
});
}
if cliff_time < start_time {
return Err(VestingError::InvalidTimeRange {
start_time: start_time.u64(),
cliff_time: cliff_time.u64(),
end_time: end_time.u64(),
});
}

if cliff_time > end_time {
return Err(VestingError::InvalidTimeRange {
start_time: start_time.u64(),
cliff_time: cliff_time.u64(),
end_time: end_time.u64(),
});
}
let cliff = Cliff {
amount: Uint128::zero(),
time: *cliff_time,
};
cliff.ok_time(block_time)?;
Ok(())
}
}
Expand Down
12 changes: 7 additions & 5 deletions contracts/airdrop-token-vesting/src/testing.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::contract::tests::TestResult;
use crate::contract::{execute, instantiate, query};
use crate::errors::{CliffError, ContractError, VestingError};
use crate::errors::{ContractError, VestingError};
use crate::msg::{
ExecuteMsg, InstantiateMsg, QueryMsg, RewardUserRequest,
VestingAccountResponse, VestingData, VestingSchedule,
Expand Down Expand Up @@ -291,10 +291,11 @@ fn register_cliff_vesting_account_with_native_token() -> TestResult {
&env,
mock_info("addr0000", &[Coin::new(1000u128, "uusd")]),
msg,
ContractError::Vesting(VestingError::Cliff(CliffError::InvalidTime {
ContractError::Vesting(VestingError::InvalidTimeRange {
start_time: 100,
cliff_time: 99,
block_time: 100,
})),
end_time: 110,
}),
);

// end time less than start time
Expand All @@ -306,6 +307,7 @@ fn register_cliff_vesting_account_with_native_token() -> TestResult {
msg,
ContractError::Vesting(VestingError::InvalidTimeRange {
start_time: 110,
cliff_time: 105,
end_time: 100,
}),
);
Expand All @@ -319,7 +321,7 @@ fn register_cliff_vesting_account_with_native_token() -> TestResult {
mock_info("addr0000", &[Coin::new(1000u128, "uusd")]),
msg,
ContractError::Vesting(
CliffError::ExcessiveAmount {
VestingError::ExcessiveAmount {
cliff_amount,
vesting_amount,
}
Expand Down

0 comments on commit 939f68c

Please sign in to comment.