-
Notifications
You must be signed in to change notification settings - Fork 11
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
feat: add campaign manager to token vesting contract #122
Conversation
WalkthroughThe update introduces a comprehensive overhaul to the token vesting system, adding functionality for campaign management, user rewards, and enhanced control over vesting accounts. It streamlines operations for rewarding users and managing funds, incorporating a system that allows for more dynamic and efficient token distribution. Changes
Related issues
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (invoked as PR comments)
Additionally, you can add CodeRabbit Configration File (
|
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.
Review Status
Actionable comments generated: 0
Configuration used: CodeRabbit UI
Files selected for processing (4)
- contracts/core-token-vesting/src/contract.rs (6 hunks)
- contracts/core-token-vesting/src/errors.rs (1 hunks)
- contracts/core-token-vesting/src/msg.rs (1 hunks)
- contracts/core-token-vesting/src/state.rs (2 hunks)
Files skipped from review due to trivial changes (1)
- contracts/core-token-vesting/src/errors.rs
Additional comments: 16
contracts/core-token-vesting/src/state.rs (4)
- 8-9: The introduction of
CAMPAIGN
andUSER_REWARDS
constants is a good practice for managing state in smart contracts. It ensures that data access is consistent and reduces the likelihood of typos in storage keys.- 24-34: The
Campaign
struct is well-defined, covering essential aspects of a campaign such as ID, name, description, allocation, ownership, and management. Includingis_active
as a boolean to manage the campaign's state is a practical approach for enabling or disabling campaigns without removing them from storage.- 36-39: The
DeregisterResult
struct is designed to hold the result of a deregistration operation, including messages to be dispatched and attributes for logging. This struct facilitates a clean way to return multiple values from a function, enhancing code readability and maintainability.- 40-40: The
denom_to_key
function remains unchanged. Assuming it was correctly implemented before, no action is required here. However, it's crucial to ensure that this function is covered by unit tests to prevent regressions in future updates.Verification successful
The verification process aimed to confirm the presence of unit tests for the
denom_to_key
function within thecontracts/core-token-vesting/src/state.rs
file. The output from the executed shell script indicates that there is indeed a test namedtest_denom_to_key
within the same file, suggesting that the function is covered by at least one unit test.Given this information, it can be concluded that the original review comment's concern about ensuring the
denom_to_key
function is covered by unit tests to prevent regressions in future updates has been addressed. The presence of thetest_denom_to_key
function serves as evidence that there is an attempt to verify the correctness of thedenom_to_key
function through testing.Therefore, the verification process supports the original comment's implication that no further action is required regarding the
denom_to_key
function, assuming it was correctly implemented before, as long as the test is adequately designed to cover the function's expected behavior.Scripts Executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Search for tests related to denom_to_key function rg --type rust "denom_to_key" --files-with-matches | xargs rg "fn test"Length of output: 138
contracts/core-token-vesting/src/msg.rs (7)
- 50-64: The
CreateCampaign
variant in theExecuteMsg
enum is well-structured, providing a clear interface for creating campaigns with necessary details such as vesting schedule, ID, name, description, and managers. This addition aligns with the PR's objective to enhance campaign management.- 66-73: The
RewardUsers
variant introduces a mechanism to reward users within a specific campaign, taking a campaign ID and a list of reward requests. This approach is efficient for batch processing rewards and aligns with the system's goal to streamline reward distribution.- 75-86: The
DeregisterVestingAccounts
variant allows for batch deregistration of vesting accounts, which is a significant improvement in terms of flexibility and efficiency when managing user accounts. However, ensure that the batch processing logic properly handles partial failures to avoid inconsistent states.- 88-94: The
ClaimCampaign
variant provides users with the ability to claim vested tokens from a campaign. This functionality is crucial for user engagement and liquidity, ensuring users can access their rewards under predefined conditions.- 96-102: The
DeactivateCampaign
variant allows for the deactivation of campaigns, enabling campaign managers to halt operations and return unallocated tokens. This feature is essential for managing the lifecycle of campaigns and ensuring flexibility in campaign management.- 104-110: The
Withdraw
variant enables campaign owners to withdraw unallocated tokens, which is a critical feature for managing campaign finances and ensuring liquidity. It's important to ensure that withdrawal operations are secure and only accessible by authorized users.- 114-124: The addition of
RewardUserRequest
andRewardUserResponse
structs provides a structured way to handle user rewards, facilitating clear communication between contract functions and external callers. This structured approach enhances the contract's usability and maintainability.contracts/core-token-vesting/src/contract.rs (5)
- 74-93: The refactoring of
deregister_vesting_account
to handle multiple addresses is a significant improvement, enhancing the contract's flexibility in managing user accounts. Ensure that error handling is robust, especially in scenarios where some deregistrations may fail while others succeed, to maintain consistent state.Verification successful
Given the lack of output from the previous script, it seems that searching for the explicit phrase "error handling" in the context of
deregister_vesting_account
did not yield results. This approach might have been too narrow, as error handling in Rust often involves pattern matching onResult
orOption
types rather than comments or explicit mentions of "error handling."To better understand how
deregister_vesting_account
handles errors, especially in batch scenarios, a more targeted approach towards examining the function's implementation and its usage might be necessary. Specifically, looking at how the function's return typeResult
is handled could provide insights into the error handling mechanism.Given the context, a more effective strategy would be to directly inspect the implementation of
deregister_vesting_account
and its callers to see how errors are managed. This would involve looking for the function definition and instances where it is called, focusing on error propagation and handling.
The provided script output reveals the implementation details of
deregister_vesting_account
and its batch versionderegister_vesting_accounts
within thecontracts/core-token-vesting/src/contract.rs
file. From the output, we can observe the following:
Batch Deregistration (
deregister_vesting_accounts
): This function accepts multiple addresses for deregistration. It iterates over each address, callingderegister_vesting_account
for each one. If an error occurs during the deregistration of any account, it captures the error and continues processing the remaining addresses. This approach ensures that the function attempts to deregister each account, collecting errors rather than halting at the first encounter.Error Handling: The error handling within
deregister_vesting_accounts
involves capturing errors for each deregistration attempt and adding an attribute with the error message. This allows the function to report back on which deregistrations failed and why, without stopping the entire batch process due to a single failure.Single Account Deregistration (
deregister_vesting_account
): This function is designed to deregister a single vesting account. It performs checks such as the existence of the vesting account and authorization before proceeding with the deregistration. If any of these checks fail, it returns an error.The error handling mechanism in
deregister_vesting_accounts
aligns with the initial review comment's concern about robust error handling, especially in scenarios where some deregistrations may fail while others succeed. The implementation ensures that errors are handled gracefully, allowing the process to continue for other accounts while reporting back on any issues encountered.Given this analysis, the review comment regarding the need for robust error handling in batch deregistration scenarios is verified as addressed in the implementation. The code demonstrates a thoughtful approach to managing potential errors, ensuring that the contract can handle multiple deregistrations effectively, even if some fail.
* 97-112: The `create_campaign` function implementation aligns with the PR's objectives to enhance campaign management capabilities. It's crucial to validate input parameters thoroughly to prevent the creation of campaigns with invalid or malicious data. * 114-116: The `reward_users` function is a key addition, enabling the rewarding of users within campaigns. This function must ensure that rewards do not exceed the campaign's unallocated amount to maintain financial integrity.Scripts Executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Check for error handling in batch deregistration scenarios rg --type rust "deregister_vesting_account" --files-with-matches | xargs rg "error handling"Length of output: 92
Script:
#!/bin/bash # Find the implementation of `deregister_vesting_account` and its usage to inspect error handling rg --type rust "fn deregister_vesting_account" -A 30 rg --type rust "deregister_vesting_account" --files-with-matchesLength of output: 4931
Verification successful
Given the information from the script output, it's necessary to examine the implementation of the
reward_users
function to verify if it indeed checks that rewards do not exceed the campaign's unallocated amount. To do this, I will generate a new script to view the contents of thereward_users
function within thecontracts/core-token-vesting/src/contract.rs
file.
To fully assess whether the
reward_users
function checks that rewards do not exceed the campaign's unallocated amount, we need to view more of the function's implementation. I will generate a new script to retrieve additional lines of the function to hopefully capture the logic related to managing the campaign's unallocated amount.
The extended script output provides a clearer view of the
reward_users
function's implementation, revealing that it indeed checks if the campaign's unallocated amount is sufficient for the requested rewards. Specifically, the function iterates over the requests and checks if the campaign's unallocated amount is less than the requested amount for each reward. If the unallocated amount is insufficient, it returns an error indicating "Not enough funds in the campaign." This mechanism ensures that rewards do not exceed the campaign's unallocated amount, aligning with the financial integrity concern mentioned in the original review comment.Based on this information, the
reward_users
function's implementation correctly addresses the concern of ensuring rewards do not exceed the campaign's unallocated amount.* 144-166: The `deactivate_campaign` function provides a mechanism for halting campaign operations and returning unallocated tokens. This function must authenticate the caller to prevent unauthorized deactivations, which could disrupt campaign operations.Scripts Executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Ensure reward_users function checks for campaign's unallocated amount rg --type rust "reward_users" --files-with-matches | xargs rg "unallocated amount"Length of output: 169
Script:
#!/bin/bash # Examine the implementation of the reward_users function rg --type rust "fn reward_users" -A 20 contracts/core-token-vesting/src/contract.rsLength of output: 735
Script:
#!/bin/bash # Extend the examination of the reward_users function to include more of its implementation rg --type rust "fn reward_users" -A 50 contracts/core-token-vesting/src/contract.rsLength of output: 1648
Verification successful
The initial verification script aimed to find instances of the phrase "authenticate caller" within the context of the
deactivate_campaign
function in Rust files. However, this approach was flawed for several reasons:
- The file in question is not a Rust file but appears to be a CosmWasm contract, which is typically written in Rust. The command used
--type rust
correctly, but the context provided is from a CosmWasm contract, which might not use the exact phrase "authenticate caller" to describe authentication logic.- The authentication logic in the provided code snippet is implicit in the comparison of
campaign.owner
andcampaign.managers
withinfo.sender
, rather than an explicit call to a function or method that could be labeled as "authenticate caller".Given these observations, a more appropriate verification approach would involve directly examining the authentication logic within the
deactivate_campaign
function, rather than searching for a specific phrase. Since the initial script did not yield useful results, a new strategy is required.To accurately verify the authentication logic within the
deactivate_campaign
function, we should:
- Confirm the presence of the
deactivate_campaign
function in the codebase.- Examine the logic within this function to ensure it checks the caller's authorization against the campaign owner or managers.
Given the limitations of the script execution environment, we cannot directly inspect the logic within the function. However, we can refine our search to confirm the presence of the function and look for patterns that suggest authentication checks, such as comparisons involving
info.sender
.This script aims to confirm the presence of the
deactivate_campaign
function. If found, the provided code snippet already demonstrates the authentication logic, which we can then discuss based on the output of this script.
The script confirmed the presence of the
deactivate_campaign
function within thecontracts/core-token-vesting/src/contract.rs
file. This aligns with the initial context provided, indicating that the function indeed exists in the codebase and is part of the contract's logic.Given this confirmation and the initial code snippet provided, we can infer that the authentication logic within the
deactivate_campaign
function is implemented through the conditional checks againstcampaign.owner
andcampaign.managers
withinfo.sender
. This mechanism ensures that only the campaign owner or designated managers can deactivate the campaign, thereby preventing unauthorized deactivations.Since the script output aligns with the provided context and demonstrates the presence of the function in question, we can conclude that the review comment regarding the need for authentication within the
deactivate_campaign
function is accurate. The function does authenticate the caller by verifying if they are the campaign owner or one of the managers before allowing the campaign to be deactivated.Therefore, the verification process confirms that the initial review comment is consistent with the codebase, and the authentication logic is indeed implemented as described.
* 655-739: The `withdraw` function is critical for managing campaign finances. It's essential to ensure that the withdrawal amount does not exceed the campaign's unallocated funds and that only authorized users can perform withdrawals. Additionally, the function should handle errors gracefully to prevent state inconsistencies.Scripts Executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Verify authentication in deactivate_campaign function rg --type rust "deactivate_campaign" --files-with-matches | xargs rg "authenticate caller"Length of output: 90
Script:
#!/bin/bash # Confirm the presence of the deactivate_campaign function and examine authentication logic rg "fn deactivate_campaign" --type rustLength of output: 110
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.
Review Status
Actionable comments generated: 5
Configuration used: CodeRabbit UI
Files ignored due to path filters (1)
Cargo.lock
is excluded by:!**/*.lock
Files selected for processing (2)
- contracts/core-token-vesting/src/contract.rs (3 hunks)
- contracts/core-token-vesting/src/msg.rs (1 hunks)
Files skipped from review as they are similar to previous changes (1)
- contracts/core-token-vesting/src/msg.rs
Additional comments: 2
contracts/core-token-vesting/src/contract.rs (2)
- 622-630: In the
withdraw
function, the response construction is correct and follows best practices for creating a Cosmos SDK message. However, ensure that the documentation or comments clearly explain the conditions under which the withdrawal is allowed, especially regarding the campaign's unallocated amount and the contract's balance checks.The implementation correctly handles the withdrawal logic, including balance checks and message construction.
- 163-224: Security consideration: Ensure that the
reward_users
function properly validates therequests
input to prevent potential overflow issues when updating theunallocated_amount
of a campaign. While Rust's type system provides some safety against overflow, explicit checks and error handling for arithmetic operations can prevent logical errors and potential exploits.Consider adding explicit checks for arithmetic operations to ensure they do not overflow or underflow.
Codecov ReportAttention:
Additional details and impacted files
|
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.
Review Status
Actionable comments generated: 17
Configuration used: CodeRabbit UI
Files ignored due to path filters (1)
contracts/core-token-vesting/Cargo.toml
is excluded by:!**/*.toml
Files selected for processing (10)
- contracts/core-token-vesting/src/contract.rs (3 hunks)
- contracts/core-token-vesting/src/lib.rs (1 hunks)
- contracts/core-token-vesting/src/msg.rs (2 hunks)
- contracts/core-token-vesting/tests/all_test.rs (1 hunks)
- contracts/core-token-vesting/tests/tests/helpers/helpers.rs (1 hunks)
- contracts/core-token-vesting/tests/tests/helpers/mod.rs (1 hunks)
- contracts/core-token-vesting/tests/tests/mod.rs (1 hunks)
- contracts/core-token-vesting/tests/tests/test_airdrop.rs (1 hunks)
- contracts/core-token-vesting/tests/tests/test_manager.rs (1 hunks)
- contracts/core-token-vesting/tests/tests/test_vesting.rs (2 hunks)
Files skipped from review due to trivial changes (3)
- contracts/core-token-vesting/src/lib.rs
- contracts/core-token-vesting/tests/all_test.rs
- contracts/core-token-vesting/tests/tests/helpers/helpers.rs
Additional comments: 5
contracts/core-token-vesting/tests/tests/helpers/mod.rs (1)
- 1-2: Changes look good.
contracts/core-token-vesting/tests/tests/mod.rs (1)
- 1-5: Changes look good.
contracts/core-token-vesting/tests/tests/test_manager.rs (1)
- 1-149: Changes look good.
contracts/core-token-vesting/src/msg.rs (1)
- 49-111: Changes look good.
contracts/core-token-vesting/src/contract.rs (1)
- 83-277: > 📝 NOTE
This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [102-675]
Changes look good.
#[test] | ||
fn execute_register_vesting_account_invalid_deposit() -> TestResult { | ||
let (mut deps, env) = setup_with_block_time(100)?; | ||
|
||
// Attempt registration with invalid deposit details | ||
let res = execute( | ||
deps.as_mut(), | ||
env, | ||
mock_info("addr_sender", &[coin(500, "invalid_token")]), // Incorrect token denomination | ||
ExecuteMsg::RegisterVestingAccount { | ||
master_address: Some("addr_master".to_string()), | ||
address: "addr_vesting".to_string(), | ||
vesting_schedule: VestingSchedule::LinearVesting { | ||
start_time: Uint64::new(100), | ||
end_time: Uint64::new(200), | ||
vesting_amount: Uint128::new(1000u128), | ||
}, | ||
}, | ||
); | ||
|
||
assert!( | ||
matches!(res, Err(ContractError::Std(StdError::GenericErr { msg, .. })) if msg.contains("Only native tokens are allowed")) | ||
); | ||
|
||
Ok(()) | ||
} |
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.
For execute_register_vesting_account_invalid_deposit
, enhance the test by asserting the specific error message related to the invalid token denomination to ensure the contract correctly identifies and rejects non-native tokens.
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.
Review Status
Actionable comments generated: 5
Configuration used: CodeRabbit UI
Files selected for processing (4)
- contracts/core-token-vesting/src/contract.rs (3 hunks)
- contracts/core-token-vesting/src/state.rs (2 hunks)
- contracts/core-token-vesting/tests/tests/test_airdrop.rs (1 hunks)
- contracts/core-token-vesting/tests/tests/test_vesting.rs (3 hunks)
Files skipped from review as they are similar to previous changes (3)
- contracts/core-token-vesting/src/state.rs
- contracts/core-token-vesting/tests/tests/test_airdrop.rs
- contracts/core-token-vesting/tests/tests/test_vesting.rs
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.
Review Status
Actionable comments generated: 5
Configuration used: CodeRabbit UI
Files selected for processing (2)
- contracts/core-token-vesting/src/contract.rs (3 hunks)
- contracts/core-token-vesting/tests/tests/test_airdrop.rs (1 hunks)
Files skipped from review as they are similar to previous changes (1)
- contracts/core-token-vesting/tests/tests/test_airdrop.rs
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.
Review Status
Actionable comments generated: 4
Configuration used: CodeRabbit UI
Files selected for processing (3)
- contracts/core-token-vesting/src/contract.rs (5 hunks)
- contracts/core-token-vesting/tests/tests/test_manager.rs (1 hunks)
- contracts/core-token-vesting/tests/tests/test_vesting.rs (4 hunks)
Files skipped from review as they are similar to previous changes (2)
- contracts/core-token-vesting/tests/tests/test_manager.rs
- contracts/core-token-vesting/tests/tests/test_vesting.rs
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.
Review Status
Actionable comments generated: 6
Configuration used: CodeRabbit UI
Files selected for processing (2)
- contracts/core-token-vesting/src/contract.rs (7 hunks)
- contracts/core-token-vesting/src/state.rs (2 hunks)
Files skipped from review as they are similar to previous changes (1)
- contracts/core-token-vesting/src/state.rs
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.
Review Status
Actionable comments generated: 0
Configuration used: CodeRabbit UI
Files selected for processing (4)
- contracts/core-token-vesting/src/contract.rs (7 hunks)
- contracts/core-token-vesting/src/msg.rs (2 hunks)
- contracts/core-token-vesting/src/state.rs (2 hunks)
- contracts/core-token-vesting/tests/tests/test_airdrop.rs (1 hunks)
Files skipped from review as they are similar to previous changes (2)
- contracts/core-token-vesting/src/state.rs
- contracts/core-token-vesting/tests/tests/test_airdrop.rs
Additional comments: 8
contracts/core-token-vesting/src/msg.rs (3)
- 49-82: The new
ExecuteMsg
enum variants introduce significant functionality for campaign management and user rewards. Ensure that the associated logic in handling these messages is securely implemented, especially regarding authorization checks and state mutations.- 84-94: The
RewardUserRequest
struct is straightforward, but ensure that theuser_address
is validated where it's used, to prevent any misuse or security vulnerabilities.- 90-94: The
RewardUserResponse
struct includes asuccess
flag and anerror_msg
. Ensure that error messages do not leak sensitive information or internal system details that could be exploited.contracts/core-token-vesting/src/contract.rs (5)
- 87-107: The implementation of new campaign management functions (
CreateCampaign
,RewardUsers
,DeactivateCampaign
,Withdraw
) introduces complex logic. Ensure that each function properly handles errors, validates inputs, and correctly manages state changes to prevent inconsistencies or vulnerabilities.- 111-139: The
deactivate_campaign
function must ensure that only authorized users can deactivate a campaign. The current implementation checks for ownership or manager status, which is good. However, ensure that theinfo.sender
is properly validated and that the withdrawal logic securely handles the transfer of unallocated funds.- 141-220: In
reward_users
, ensure that the logic for rewarding multiple users is efficient and secure. Pay attention to the loop that processes eachRewardUserRequest
, ensuring that it correctly updates the campaign's unallocated amount and handles any potential errors or exceptions gracefully.- 222-259: The
create_campaign
function should validate theinfo.funds
to ensure that the campaign is funded with the correct token type and amount. Additionally, check that the campaign's initial state is correctly set and that all inputs (e.g.,campaign_name
,managers
) are validated for correctness and security.- 578-617: The
withdraw
function must securely handle the withdrawal of unallocated funds from a campaign. Ensure that it correctly checks for campaign ownership, validates the withdrawal amount, and securely transfers the funds to the campaign owner.
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.
Review Status
Actionable comments generated: 3
Configuration used: CodeRabbit UI
Files selected for processing (2)
- .gitignore (1 hunks)
- contracts/core-token-vesting/src/contract.rs (7 hunks)
Files skipped from review due to trivial changes (1)
- .gitignore
Additional comments: 4
contracts/core-token-vesting/src/contract.rs (4)
- 1-1: The import of
min
fromstd::cmp
is correctly added to support the new logic in thewithdraw
function. This is a good use of standard library functions to simplify code.- 87-99: The
create_campaign
function correctly implements the logic for creating a new campaign. However, it's important to ensure that thecampaign_name
andcampaign_description
are sanitized to prevent injection attacks or unintended behavior when these strings are used elsewhere in the contract or displayed in UIs.- 221-257: In the
create_campaign
function, there's a check to ensure only one type of denomination is sent during campaign creation (if info.funds.len() != 1
). This is a good practice for ensuring the contract's state remains consistent. However, it's also important to validate themanagers
list to ensure it contains valid addresses and does not introduce any security risks, such as unauthorized access to campaign management functions.- 576-615: The
withdraw
function correctly calculates the maximum amount that can be withdrawn (amount_max
) and updates the campaign'sunallocated_amount
accordingly. It's important to ensure that the transaction to transfer the withdrawn amount (build_send_msg
) is secure and correctly implemented. Additionally, consider adding a check to ensure that the campaign is active before allowing withdrawals, as this could be a business logic requirement.
])) | ||
} | ||
|
||
/// Claim funds from the vesting accounts | ||
fn claim( | ||
deps: DepsMut, | ||
env: Env, |
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.
📝 NOTE
This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [382-456]
The claim
function allows users to claim funds from their vesting accounts. It's crucial to ensure that the logic for calculating claimable_amount
and updating the claimed_amount
is correct to prevent issues such as double spending or incorrect fund allocation. Additionally, the removal of vesting accounts once fully claimed (VESTING_ACCOUNTS.remove
) should be carefully tested to ensure it behaves as expected without unintended side effects.
Would you like assistance in creating additional tests for the claim
function to cover these scenarios?
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.
Review Status
Actionable comments generated: 3
Configuration used: CodeRabbit UI
Files selected for processing (1)
- contracts/core-token-vesting/src/contract.rs (8 hunks)
Additional comments: 5
contracts/core-token-vesting/src/contract.rs (5)
- 1-1: The import of
min
fromstd::cmp
is correctly added to support the new logic in thewithdraw
function. This is a good use of standard library functions to simplify code.- 100-102: Given the previous comment regarding the
reward_users
function, it's crucial to ensure that the logic for summing up the total requested amount and comparing it against thecampaign.unallocated_amount
is correct to prevent over-allocation of rewards. This logic appears sound, but adding tests specifically targeting edge cases around this calculation is advisable.
The past comment is still valid and addresses the same concern.- 110-138: The
deactivate_campaign
function correctly checks for authorization and campaign status before proceeding with deactivation. However, the return statement at the end directly callswithdraw
, which might not be clear at first glance. It's important to document this behavior clearly in the function's comments to ensure maintainability.
The past comment is still valid and addresses the same concern.- 379-385: > 📝 NOTE
This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [382-456]
The
claim
function allows users to claim funds from their vesting accounts. It's crucial to ensure that the logic for calculatingclaimable_amount
and updating theclaimed_amount
is correct to prevent issues such as double spending or incorrect fund allocation. Additionally, the removal of vesting accounts once fully claimed should be carefully tested to ensure it behaves as expected without unintended side effects.
The past comment is still valid and addresses the same concern.
- 575-614: The
withdraw
function correctly implements logic to allow the campaign owner to withdraw unallocated funds, ensuring the amount is available and does not exceed the unallocated amount. The use ofmin
to determine the maximum allowable withdrawal is a good practice. However, it's important to ensure that the transaction is secure and that edge cases are handled appropriately.
return Err(StdError::generic_err("one denom sent required").into()); | ||
} | ||
|
||
let coin = info.funds.get(0).unwrap(); |
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 doing
let coin = info.funds.get(0)?;
is a little bit more controlled. If something fails in the other it panics and I wonder what the error is in those cases.
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.
Review Status
Actionable comments generated: 6
Configuration used: CodeRabbit UI
Files selected for processing (1)
- contracts/core-token-vesting/src/contract.rs (8 hunks)
Additional comments: 1
contracts/core-token-vesting/src/contract.rs (1)
- 1-1: The import of
min
fromstd::cmp
is correctly added to support the new logic in thewithdraw
function, ensuring that withdrawals do not exceed the unallocated amount in a campaign.
…-nibiru into mat/manager-token-vesting
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.
Review Status
Actionable comments generated: 3
Configuration used: CodeRabbit UI
Files selected for processing (1)
- contracts/core-token-vesting/src/contract.rs (8 hunks)
Additional comments: 4
contracts/core-token-vesting/src/contract.rs (4)
- 1-1: The import of the
min
function fromstd::cmp
is correctly added to support the new logic in thewithdraw
function. This is a good use of standard library functions to ensure code simplicity and readability.- 18-20: Renaming
VestingSchedule
toRewardUserRequest
andVestingAccountResponse
toRewardUserResponse
aligns the naming with the new functionality related to campaign management and user rewards. This improves the clarity of the codebase.- 100-102: The
reward_users
function is added to handle rewarding users within a campaign. It's crucial to ensure that the logic for summing up the total requested amount (total_requested
) and comparing it against thecampaign.unallocated_amount
is correct to prevent over-allocation of rewards. This logic appears sound, but it's advisable to add tests specifically targeting edge cases around this calculation.- 381-381: The
claim
function allows users to claim funds from their vesting accounts. It's crucial to ensure that the logic for calculatingclaimable_amount
and updating theclaimed_amount
is correct to prevent issues such as double spending or incorrect fund allocation. Additionally, the removal of vesting accounts once fully claimed (VESTING_ACCOUNTS.remove
) should be carefully tested to ensure it behaves as expected without unintended side effects.
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.
Review Status
Actionable comments generated: 5
Configuration used: CodeRabbit UI
Files selected for processing (1)
- contracts/core-token-vesting/src/contract.rs (8 hunks)
Additional comments: 2
contracts/core-token-vesting/src/contract.rs (2)
- 1-1: The addition of the
min
function import fromstd::cmp
is appropriate for the use cases within this file, particularly in thewithdraw
function where it's used to ensure the withdrawal amount does not exceed the available funds.- 18-19: Renaming
VestingSchedule
toRewardUserRequest
andVestingAccountResponse
toRewardUserResponse
aligns with the new functionality related to campaign management and user rewards. This change improves clarity and better reflects the purpose of these entities.
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.
Review Status
Actionable comments generated: 5
Configuration used: CodeRabbit UI
Files selected for processing (2)
- contracts/core-token-vesting/src/contract.rs (11 hunks)
- contracts/core-token-vesting/src/state.rs (2 hunks)
Additional comments: 5
contracts/core-token-vesting/src/state.rs (3)
- 8-8: The addition of the
CAMPAIGN
constant usingItem::new("campaign")
is correctly implemented for storing campaign data in the contract's state. This approach follows best practices for defining storage items in CosmWasm contracts.- 38-41: The
DeregisterResult
struct is correctly defined for representing the result of a deregistration operation. It's good practice to use descriptive names for fields, as done here withmsgs
andattributes
, which clearly indicate their purpose.- 43-43: The modification to the
denom_to_key
function to take a reference toDenom
is a good practice as it avoids unnecessary cloning of theDenom
value, which can improve performance, especially in cases where the function is called frequently.contracts/core-token-vesting/src/contract.rs (2)
- 1-1: The import of the
min
function fromstd::cmp
is correctly done and is necessary for the logic implemented in thewithdraw
function to determine the maximum allowable withdrawal amount.- 87-99: Given the previous comment regarding the need for validation on
campaign_name
andcampaign_description
, ensure that such validation is implemented to prevent potential abuse or errors. This is crucial for maintaining the integrity of the campaign data.// Ensure campaign_name and campaign_description meet specific criteria if campaign_name.is_empty() || campaign_description.is_empty() { return Err(StdError::generic_err("Campaign name and description cannot be empty").into()); }
pub struct Campaign { | ||
pub campaign_name: String, | ||
pub campaign_description: String, | ||
|
||
pub unallocated_amount: Uint128, | ||
pub denom: Denom, | ||
|
||
pub owner: String, | ||
pub managers: Vec<String>, | ||
|
||
pub vesting_schedule: VestingSchedule, | ||
|
||
pub is_active: bool, | ||
} |
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.
The Campaign
struct is well-defined with appropriate fields for managing campaign details. However, consider adding documentation comments to each field to improve code readability and maintainability, especially for complex structures like vesting_schedule
.
#[cw_serde]
pub struct Campaign {
/// Name of the campaign.
pub campaign_name: String,
/// Description of the campaign.
pub campaign_description: String,
...
}
ExecuteMsg::RewardUsers { requests } => { | ||
reward_users(deps, env, info, requests) | ||
} |
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.
Considering the previous suggestion to add tests for edge cases in the reward_users
function, ensure that these tests are implemented to cover scenarios such as over-allocation of rewards and handling of insufficient funds.
Would you like me to help generate tests for edge cases in the reward_users
function?
/// Deactivate a campaign and withdraw all unallocated funds | ||
/// This will also withdraw all unallocated funds from the contract | ||
/// and send them to the campaign owner. | ||
fn deactivate_campaign( | ||
deps: DepsMut, | ||
env: Env, | ||
info: MessageInfo, | ||
) -> Result<Response, ContractError> { | ||
let mut campaign = CAMPAIGN | ||
.load(deps.storage) | ||
.map_err(|_| StdError::generic_err("Failed to load campaign data"))?; | ||
|
||
if campaign.owner != info.sender | ||
&& !campaign.managers.contains(&info.sender.to_string()) | ||
{ | ||
return Err(StdError::generic_err("Unauthorized. Only the campaign owner or managers can deactivate the campaign").into()); | ||
} | ||
|
||
if !campaign.is_active { | ||
return Ok(Response::new() | ||
.add_attribute("method", "deactivate") | ||
.add_attribute("message", "Campaign is already deactivated")); | ||
} | ||
|
||
campaign.is_active = false; | ||
CAMPAIGN.save(deps.storage, &campaign)?; | ||
|
||
return withdraw(deps, env, info, campaign.unallocated_amount); | ||
} |
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.
The direct call to withdraw
within deactivate_campaign
is a critical operation that should be documented clearly in the function's comments for maintainability. Ensure that detailed comments are added to explain this behavior.
// Note: This function deactivates the campaign and directly calls `withdraw` to return all unallocated funds to the campaign owner.
campaign_name, | ||
campaign_description, | ||
owner: info.sender.into_string(), | ||
managers, |
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 would validate that the list of managers is valid nibi addresses here.
@@ -80,9 +84,179 @@ pub fn execute( | |||
ExecuteMsg::Claim { denoms, recipient } => { | |||
claim(deps, env, info, denoms, recipient) | |||
} | |||
ExecuteMsg::CreateCampaign { |
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.
Since we only create a campaign once, and the contract is pretty much useless without a campaign being created, I would create the campaign in the instantiate function and move all the parameters into InstantiateMsg
.
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.
We can still register vesting contracts directly without needing to create a campaign
.map_err(|_| StdError::generic_err("Failed to load campaign data"))?; | ||
|
||
if campaign.owner != info.sender | ||
&& !campaign.managers.contains(&info.sender.to_string()) |
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 would restrict this ability to only the campaign owner (i.e. the treasury multisig). The risk is too great if an individual is able to call this and have the tokens transfered to them.
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.
Review Status
Actionable comments generated: 8
Configuration used: CodeRabbit UI
Files selected for processing (3)
- contracts/core-token-vesting/src/contract.rs (8 hunks)
- contracts/core-token-vesting/src/state.rs (2 hunks)
- contracts/core-token-vesting/tests/tests/test_airdrop.rs (1 hunks)
Files skipped from review as they are similar to previous changes (1)
- contracts/core-token-vesting/src/state.rs
Additional comments: 15
contracts/core-token-vesting/src/contract.rs (4)
- 1-1: The addition of the
min
function import fromstd::cmp
is appropriate for the use case of comparing and determining the minimum of two values, as seen in thewithdraw
function. This is a good use of Rust's standard library to ensure code efficiency and readability.- 18-20: Renaming
VestingSchedule
toRewardUserRequest
andVestingAccountResponse
toRewardUserResponse
aligns the entity names more closely with their usage within the context of rewarding users and managing campaigns. This improves code readability and maintainability by making the purpose of these entities clearer.- 87-99: The addition of
CreateCampaign
,DeactivateCampaign
,RewardUsers
, andWithdraw
execution messages, along with their corresponding functions, significantly expands the contract's functionality to support campaign management and user rewards. This aligns with the PR objectives to enhance the token vesting contract with campaign management features. It's important to ensure that these new functionalities are thoroughly tested, especially in terms of security and correctness, given their impact on financial transactions and contract state.Also applies to: 100-102, 103-105, 106-106
Verification successful
The verification process has confirmed the presence of test cases for the new functionalities
CreateCampaign
,DeactivateCampaign
,RewardUsers
, andWithdraw
within the contract's codebase, specifically incontracts/core-token-vesting/tests/tests/test_airdrop.rs
. This indicates that the necessary steps have been taken to ensure these functionalities are tested for security and correctness, aligning with the objectives mentioned in the PR to enhance the token vesting contract with campaign management features.* 459-459: The `build_send_msg` function provides a utility for creating Cosmos messages for token transfers. This function is well-implemented, supporting both native and CW20 tokens. Ensure that this function is used consistently throughout the contract for all token transfer operations to maintain code consistency and reduce the likelihood of errors.Scripts Executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Placeholder for potential verification script. Actual verification would involve reviewing test cases and manual testing. echo "Review test cases for new functionalities."Length of output: 94
Script:
#!/bin/bash # Search for mentions of the new functionalities in test files rg "CreateCampaign|DeactivateCampaign|RewardUsers|Withdraw" --glob '*test*.rs'Length of output: 2289
contracts/core-token-vesting/tests/tests/test_airdrop.rs (11)
- 137-168: The test
execute_create_campaign_invalid_coin_count
correctly tests the scenario where no coins are sent with the campaign creation request, expecting an error about a required denomination. This test effectively covers the validation of coin count during campaign creation.- 172-203: The test
execute_create_campaign_2_coins
is similar to the previous test but checks the scenario where more than one denomination is sent. It correctly expects an error stating that only one denomination is required. This test ensures that the contract enforces the rule of a single denomination for campaign creation.- 207-262: The test
execute_reward_users_unactive_campaign
checks the behavior when trying to reward users in an inactive campaign. It correctly sets up a campaign, deactivates it, and then attempts to reward users, expecting an error about the campaign not being active. This test effectively covers the scenario and follows good practices.- 266-313: The test
execute_reward_users_unauthorized
validates the contract's handling of unauthorized attempts to reward users. It sets up a campaign and then attempts to reward users as an unauthorized user, expecting an "Unauthorized" error. This test effectively ensures that only authorized users can perform certain actions.- 317-373: The test
execute_reward_users_valid
correctly sets up a campaign and rewards users, then asserts the creation of vesting accounts with the correct amounts. This test effectively covers the successful scenario of rewarding users and follows good practices by separating the setup, action, and assertion phases.- 376-419: The test
execute_reward_users_insufficient_funds
aims to validate the contract's handling of reward attempts that exceed the available funds. It correctly sets up a campaign with limited funds and then attempts to reward a user with an amount greater than available, expecting an error about insufficient funds. This test effectively covers the scenario and follows good practices.- 423-447: Given the existing comment on lines 423-447 about ensuring the specific error message related to the missing vesting account is asserted, this test
execute_claim_no_vesting_account
correctly follows the advice by asserting a specific error message related to the missing vesting entry for a denom. This ensures the contract's error handling is correctly implemented for this scenario.- 450-488: The test
execute_withdraw_valid
correctly sets up a campaign, manually funds the contract, and then attempts a valid withdrawal. It asserts that the campaign's unallocated amount is updated correctly. This test effectively covers the successful withdrawal scenario and follows good practices by clearly defining the setup, action, and assertion phases.- 492-512: The test
execute_withdraw_unauthorized
checks the contract's handling of unauthorized withdrawal attempts. It sets up a campaign and then attempts to withdraw funds as an unauthorized user, expecting an error about the campaign owner's exclusive withdrawal rights. This test effectively ensures that only authorized users can perform withdrawals.- 516-531: The test
execute_deactivate_campaign_authorized
validates the contract's handling of campaign deactivation by an authorized user. It sets up a campaign and then deactivates it, checking if the campaign's active status is correctly updated. This test effectively covers the scenario of authorized campaign deactivation.- 535-555: The test
execute_deactivate_campaign_unauthorized
checks the contract's handling of unauthorized attempts to deactivate a campaign. It sets up a campaign and then attempts deactivation as an unauthorized user, expecting an "Unauthorized" error. This test effectively ensures that only authorized users can deactivate campaigns.
fn execute_create_campaign_valid() -> TestResult { | ||
let (mut deps, env) = setup_with_block_time(0)?; | ||
|
||
// Create a campaign with valid parameters | ||
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_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")]), | ||
create_campaign_msg, | ||
)?; | ||
|
||
// Assertions to verify the campaign is created correctly | ||
assert!( | ||
res.attributes | ||
.iter() | ||
.any(|attr| attr.key == "method" && attr.value == "create_campaign"), | ||
"Expected 'create_campaign' method in response attributes" | ||
); | ||
assert!( | ||
CAMPAIGN.may_load(deps.as_ref().storage)?.is_some(), | ||
"Campaign should be saved in state" | ||
); |
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.
The test execute_create_campaign_valid
correctly sets up a campaign with valid parameters and asserts the successful creation by checking the response attributes and the campaign's presence in the state. This test follows good practices by clearly defining the setup, action, and assertion phases. However, it might be beneficial to also assert the specific details of the created campaign (e.g., name, description, managers) to ensure they match the input parameters.
Consider adding assertions to verify the details of the created campaign in the state match the input parameters.
fn execute_create_campaign_invalid_manager() -> TestResult { | ||
let (mut deps, env) = setup_with_block_time(0)?; | ||
|
||
// Create a campaign with valid parameters | ||
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_name: "Test Campaign".to_string(), | ||
campaign_description: "A test campaign".to_string(), | ||
managers: vec!["".to_string(), "manager2".to_string()], | ||
}; | ||
let res = execute( | ||
deps.as_mut(), | ||
env, | ||
mock_info("creator", &[coin(5000, "token")]), | ||
create_campaign_msg, | ||
); | ||
|
||
// Assertions that res has error with "human address too short for this mock implementation" | ||
match res { | ||
Err(ContractError::Std(StdError::GenericErr { msg, .. })) | ||
if msg.contains("human address too short for this mock implementation") => | ||
{ | ||
Ok(()) | ||
} | ||
_ => Err(anyhow!( | ||
"Expected 'human address too short for this mock implementation' error, found {:?}", | ||
res | ||
)), | ||
} |
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.
The test execute_create_campaign_invalid_manager
aims to validate the handling of invalid manager addresses during campaign creation. It correctly triggers an error by providing an empty string as a manager address. The assertion checks for a specific error message related to the mock implementation's address validation. This test effectively covers the scenario of invalid manager addresses but relies on the mock implementation's specific error message, which might not be ideal for testing the contract's logic.
To make the test more focused on the contract's validation logic, consider adding a validation for manager addresses in the contract itself and assert against a contract-specific error message.
#[test] | ||
fn execute_create_campaign_duplicate_id() -> TestResult { | ||
let (mut deps, _env) = setup_with_block_time(0)?; | ||
|
||
// Create a campaign with a unique ID | ||
let create_campaign_msg = ExecuteMsg::CreateCampaign { | ||
campaign_name: "Test Campaign".to_string(), | ||
campaign_description: "This is a test campaign".to_string(), | ||
managers: vec![], | ||
vesting_schedule: VestingSchedule::LinearVesting { | ||
start_time: Uint64::new(100), | ||
end_time: Uint64::new(200), | ||
vesting_amount: Uint128::new(1000), | ||
}, | ||
}; | ||
|
||
execute( | ||
deps.as_mut(), | ||
mock_env(), | ||
mock_info("creator", &[coin(5000, "token")]), | ||
create_campaign_msg.clone(), | ||
)?; | ||
|
||
// Attempt to create another campaign with the same ID | ||
let res = execute( | ||
deps.as_mut(), | ||
mock_env(), | ||
mock_info("creator", &[coin(5000, "token")]), | ||
create_campaign_msg, | ||
); | ||
|
||
match res { | ||
Err(ContractError::Std(StdError::GenericErr { msg, .. })) | ||
if msg.contains("Campaign already exists") => | ||
{ | ||
Ok(()) | ||
} | ||
_ => Err(anyhow!( | ||
"Expected 'Campaign already exists' error, found {:?}", | ||
res | ||
)), | ||
} |
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.
The test execute_create_campaign_duplicate_id
checks for the handling of attempts to create a campaign with a duplicate name. However, the test setup does not explicitly set a unique identifier for the campaign, and the assertion relies on a generic error message. This might not accurately test the duplicate campaign scenario if the contract does not implement specific logic for handling duplicate names or IDs.
Ensure the contract includes logic to uniquely identify campaigns and update the test to assert against a specific error message related to duplicate campaigns.
fn create_campaign( | ||
deps: DepsMut, | ||
info: MessageInfo, | ||
vesting_schedule: VestingSchedule, | ||
campaign_name: String, | ||
campaign_description: String, | ||
managers: Vec<String>, | ||
) -> Result<Response, ContractError> { | ||
if CAMPAIGN.may_load(deps.storage)?.is_some() { | ||
return Err(StdError::generic_err("Campaign already exists").into()); | ||
} | ||
|
||
if info.funds.len() != 1 { | ||
return Err(StdError::generic_err("one denom sent required").into()); | ||
} | ||
|
||
let coin = info.funds.get(0).ok_or(StdError::generic_err( | ||
"one denom sent required, unexpected error", | ||
))?; | ||
|
||
for manager in managers.iter() { | ||
let _ = deps.api.addr_validate(manager)?; | ||
} | ||
|
||
let campaign = Campaign { | ||
campaign_name, | ||
campaign_description, | ||
owner: info.sender.into_string(), | ||
managers, | ||
unallocated_amount: coin.amount, | ||
denom: Denom::Native(coin.denom.clone()), | ||
vesting_schedule: vesting_schedule.clone(), | ||
is_active: true, | ||
}; | ||
CAMPAIGN.save(deps.storage, &campaign)?; | ||
|
||
Ok(Response::new() | ||
.add_attribute("method", "create_campaign") | ||
.add_attribute("campaign_name", &campaign.campaign_name) | ||
.add_attribute("campaign_description", &campaign.campaign_description) | ||
.add_attribute("initial_unallocated_amount", &coin.amount.to_string()) | ||
.add_attribute("schedule", &to_string(&vesting_schedule).unwrap())) |
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.
The create_campaign
function correctly implements the logic for creating a new campaign, including validation for the campaign's existence and the deposit denomination. However, the validation of manager addresses (lines 238-239) should ensure that the addresses are not only valid but also unique to prevent potential issues with duplicate manager entries. Consider adding a check to enforce uniqueness.
@@ -205,6 +382,7 @@ | |||
])) | |||
} | |||
|
|||
/// Claim funds from the vesting accounts |
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.
Considering the previous suggestions to add tests for edge cases in the claim
function, ensure that these tests are implemented to cover scenarios such as double spending or incorrect fund allocation. Additionally, validate the removal of vesting accounts once fully claimed to ensure it behaves as expected without unintended side effects.
Would you like assistance in creating additional tests for the claim
function to cover these scenarios?
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.
Review Status
Actionable comments generated: 4
Configuration used: CodeRabbit UI
Files selected for processing (1)
- contracts/core-token-vesting/src/contract.rs (8 hunks)
Additional comments: 1
contracts/core-token-vesting/src/contract.rs (1)
- 1-1: The addition of
use std::cmp::min;
is appropriate for the new logic introduced in thewithdraw
function, where it's used to determine the maximum allowable withdrawal amount. This is a good use of standard library functions to ensure code simplicity and reliability.
ExecuteMsg::CreateCampaign { | ||
vesting_schedule, | ||
campaign_name, | ||
campaign_description, | ||
managers, | ||
} => create_campaign( | ||
deps, | ||
info, | ||
vesting_schedule, | ||
campaign_name, | ||
campaign_description, | ||
managers, | ||
), |
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.
The create_campaign
function introduces the capability to create campaigns within the token vesting contract. It's crucial to validate the campaign_name
and campaign_description
for length and content to prevent potential abuse or errors. Additionally, ensure that the list of managers consists of valid addresses. This aligns with the previous suggestion to validate manager addresses, enhancing the security and integrity of the campaign creation process.
// Inside create_campaign function, before saving the campaign
if campaign_name.is_empty() || campaign_name.len() > MAX_NAME_LENGTH {
return Err(StdError::generic_err("Invalid campaign name length").into());
}
if campaign_description.len() > MAX_DESCRIPTION_LENGTH {
return Err(StdError::generic_err("Invalid campaign description length").into());
}
// Assuming MAX_NAME_LENGTH and MAX_DESCRIPTION_LENGTH are defined appropriately
/// Deactivate a campaign and withdraw all unallocated funds | ||
/// This will also withdraw all unallocated funds from the contract | ||
/// and send them to the campaign owner. | ||
fn deactivate_campaign( | ||
deps: DepsMut, | ||
env: Env, | ||
info: MessageInfo, | ||
) -> Result<Response, ContractError> { | ||
let mut campaign = CAMPAIGN | ||
.load(deps.storage) | ||
.map_err(|_| StdError::generic_err("Failed to load campaign data"))?; | ||
|
||
if campaign.owner != info.sender { | ||
return Err(StdError::generic_err("Unauthorized. Only the campaign owner or managers can deactivate the campaign").into()); | ||
} | ||
|
||
if !campaign.is_active { | ||
return Ok(Response::new() | ||
.add_attribute("method", "deactivate") | ||
.add_attribute("message", "Campaign is already deactivated")); | ||
} | ||
|
||
campaign.is_active = false; | ||
CAMPAIGN.save(deps.storage, &campaign)?; | ||
|
||
return withdraw(deps, env, info, campaign.unallocated_amount); |
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.
The deactivate_campaign
function correctly implements the logic for deactivating a campaign and withdrawing unallocated funds. However, it's crucial to ensure that the campaign's state change (from active to inactive) and the withdrawal logic are atomic operations to prevent any inconsistencies in the contract's state. Consider wrapping these operations in a transactional context if the underlying platform supports it, to enhance the robustness of the contract.
fn reward_users( | ||
deps: DepsMut, | ||
env: Env, | ||
info: MessageInfo, | ||
requests: Vec<RewardUserRequest>, | ||
) -> Result<Response, ContractError> { | ||
let mut res = vec![]; | ||
|
||
let mut campaign = CAMPAIGN | ||
.load(deps.storage) | ||
.map_err(|_| StdError::generic_err("Failed to load campaign data"))?; | ||
|
||
if campaign.owner != info.sender | ||
&& !campaign.managers.contains(&info.sender.into()) | ||
{ | ||
return Err(StdError::generic_err("Unauthorized").into()); | ||
} | ||
|
||
if !campaign.is_active { | ||
return Err(StdError::generic_err("Campaign is not active").into()); | ||
} | ||
|
||
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() | ||
); | ||
} | ||
|
||
let mut attrs: Vec<Attribute> = vec![]; | ||
|
||
for req in requests { | ||
// update the vesting amount inside the vesting schedule | ||
let mut vesting_schedule = campaign.vesting_schedule.clone(); | ||
|
||
if let VestingSchedule::LinearVesting { | ||
ref mut vesting_amount, | ||
.. | ||
} = vesting_schedule | ||
{ | ||
*vesting_amount = req.amount; | ||
} | ||
|
||
let result = register_vesting_account( | ||
deps.storage, | ||
env.block.time, | ||
Some(campaign.owner.clone()), | ||
req.user_address.clone(), | ||
campaign.denom.clone(), | ||
req.amount, | ||
vesting_schedule, | ||
); | ||
|
||
if let Ok(response) = result { | ||
attrs.extend(response.attributes); | ||
res.push(RewardUserResponse { | ||
user_address: req.user_address.clone(), | ||
success: true, | ||
error_msg: "".to_string(), | ||
}); | ||
} else { | ||
let error = result.err().unwrap(); | ||
res.push(RewardUserResponse { | ||
user_address: req.user_address.clone(), | ||
success: false, | ||
error_msg: "Failed to register vesting account: ".to_string() | ||
+ &error.to_string(), | ||
}); | ||
} | ||
} | ||
|
||
campaign.unallocated_amount = campaign.unallocated_amount - total_requested; | ||
CAMPAIGN.save(deps.storage, &campaign)?; | ||
|
||
Ok(Response::new() | ||
.add_attributes(attrs) | ||
.add_attribute("method", "reward_users") | ||
.set_data(to_json_binary(&res).unwrap())) |
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.
The reward_users
function introduces complex logic for rewarding multiple users based on a campaign's vesting schedule. It's important to ensure that the logic for updating the campaign's unallocated amount and registering vesting accounts for each user is correct and secure. Specifically, the subtraction of the total requested amount from the campaign's unallocated amount (line 209) should be carefully tested for underflow scenarios. Additionally, consider optimizing the loop to reduce storage access and improve performance.
Summary by CodeRabbit
deregister_vesting_account
function and associated tests to fix issues related to account deregistration.