- All findings
- 3
- Critical
- 0
- High
- 0
- Medium
- 0
- Low
- 3
- Informational
- 0
Date of engagement: 22nd April 2024 - 26th April 2024
About Us
Guvenkaya is a security research firm specializing in Rust security, Web3 security of Rust-based protocols, and Web2 security. With our expertise, we provide both security auditing services and custom security solutions
About The Sweat
Foundation The Sweat Foundation is an organization behind Sweat Economy, an innovative project at the intersection of fitness and crypto. It motivates users to stay active by converting their steps into SWEAT Token. This approach promotes health and fitness and works as an entry point to crypto for many users.
Audit Results
Guvenkaya conducted a security assessment of the Sweat Economy new burn model from 22nd April 2024 to 26th April 2024. During this engagement, a total of 3 findings were reported. All of the findings are low severity. All issues are fixed by the Sweat Foundation team.
Project Scope
Commit Hash:
8fcaa54079dfa69cc6f57ae8d2644de4001ed427
| Files | Link |
|---|---|
| Migration | src/migration/migration.rs |
| Record API | src/record/api.rs |
| Claim API | claim/api.rs |
| Account Record | https://github.com/sweatco/sweat-claim/blob/8fcaa54079dfa69cc6f57ae8d2644de4001ed427/model/src/account_record.rs#L159-L170 |
Out of Scope
The audit will include, but is not limited to, reviewing the code for security vulnerabilities, coding practices, and architecture. The audit does not include a review of the dependencies. Only the changes to the burn model are in scope.
Timeline
- Start of the audit
22nd April 2024
- Final report
28th April 2024
Methodology
- RESEARCH INTO PROJECT ARCHITECTURE
- PREPARING ATTACK VECTORS
- SETTING UP AN ENVIRONMENT
- MANUAL CODE REVIEW OF THE CODE
- ASSESSMENT OF RUST SECURITY ISSUES
- ASSESSMENT OF NEAR SECURITY ISSUES
- ASSESSMENT OF ARITHMETIC ISSUES
- BUSINESS LOGIC VULNERABILITY ASSESSMENT
- ONCHAIN TESTING USING NEAR WORKSPACES
- BEST PRACTICES AND CODE QUALITY
- CHECKING FOR CODE REFACTORING/SIMPLIFICATION POSSIBILITIES
- ARCHITECTURE IMPROVEMENT SUGGESTIONS
- PREPARING POCS AND/OR TESTS FOR EACH CRITICAL/HIGH/MEDIUM ISSUES
Severity Breakdown
Findings Summary
| Finding | Impact | Likelihood | Severity | Remediation complexity | Remediation status |
|---|---|---|---|---|---|
| GUV-1: Error Prone Burn Rate Calculation | Moderate | Rare | Low | Simple | Fixed |
| GUV-2: Error Prone Getting Account API | Moderate | Rare | Low | Simple | Fixed |
| GUV-3: Lack of Prepaid Gas Checking Before Cross Contract Calls | Moderate | Rare | Low | Simple | Fixed |
Findings Details
GUV-1: Error Prone Burn Rate Calculation
LowWe observed that get_burn_rate uses floating point arithmetic in smart contracts, and then casts the result from a floating point number to a fixed point one. This approach is prone to errors as it could potentially cause truncation errors.
model:get_burn_rate:model/src/lib.rs
#[allow(
clippy::cast_possible_truncation,
clippy::cast_precision_loss,
clippy::cast_sign_loss
)]
pub fn get_burn_rate(balance: TokensAmount, burn_period: Duration) ->
TokensAmount {
(balance as f64 / f64::from(burn_period)).ceil() as u128
}PROPOSED SOLUTION
We propose using div_ceil which handles the division and the ceiling of the result, without utilizing floating point arithmetic.
REMEDIATION - FIXED
The Sweat Foundation team has fixed the issue by replacing the calculation with div_ceil in this commit: 18a8f9d7c064f6fe89960eb7e07e1b0333faabff
GUV-2: Error Prone Getting Account API
LowWe noticed that the get_account_mut method not only gets the mutable reference to the account, but also inserts the account if it does not exist. This could lead to unexpected behavior and potential security vulnerabilities if this method is used without checking the implementation.
common:get_account_mut:contract/src/common/mod.rs
fn get_account_mut(&mut self, account_id: &AccountId) -> &mut AccountRecord {
if !self.contains_key(account_id) {
self.insert(account_id.clone(),
AccountRecordVersioned::new(now_seconds()));
} let AccountRecordVersioned::V1(account) =
self.get_mut(account_id).expect("Account not found");
account
}PROPOSED SOLUTION
We propose removing an account creation functionality from get_account_mut and creating a separate function called get_or_insert_account_mut which will use get_account_mut.
REMEDIATION - FIXED
The Sweat Foundation team has fixed the issue by implementing suggested fix in these commits: 417d42ea895aaf9193501b3b33ccc8b8a91e35b1 a0a9e4057a833b2d60c12ee7038a556dc9e8edde
GUV-3: Lack of Prepaid Gas Checking Before Cross Contract Calls
LowWe noticed that in both claim and burn methods, the contract does not check whether there is enough prepaid gas for cross-contract calls and callbacks. This could lead to the "Exceeded the prepaid gas" errors if not enough gas was attached
PROPOSED SOLUTION
We propose checking whether env::prepaid_gas() is enough for the cross-contract call and callback before making a call.
REMEDIATION - FIXED
The Sweat Foundation team has fixed the issue by taking a difference between env::prepaid_gas and env::used_gas and asserting it in both claim and burn methods before cross-contract calls in this commit: 06c59cdb1476d173de96a68ff82c00d4bf17e8bf
Source: published GitHub report · 13 pages. The original PDF includes the source formatting, figures, and linked references.
