
Safe Farm - Smart Contract Audit Report
Summary
Safe Farm is a new yield farm platform allowing users to create ERC20 and ERC721 based farms.
Notes on the ERC20Farm and ERC721Farm Contracts::Notes on the FarmFactory Contract:
- These contracts allow users to stake a single asset determined by the project team in exchange for rewards in a second asset determined by the team.
- In order to stake users must have a minimum amount of a tertiary "utility" asset. Both the asset and the minimum amount needed are determined by the team.
- The team must exercise caution when deciding the staking token to avoid ERC777-compliant tokens (this is uncommon).
- Users will receive a reward amount for every 15 minute period based on the amount staked and the reward rate set by the owner on deployment; staking rewards can be calculated and transferred to the user at any time.
- A cooldown period must pass before users are able to unstake their token. There is no max value for the cooldown period.
- Fees are taken on deposit and withdrawal in the ERC20 Farm contract; they are taken from rewards payouts in the ERC721 Farm contract. There is no limit on fees taken and can be up to 100%.
- On withdrawals, the user will receive the entire amount of the staking tokens they deposited minus fees; pending rewards are calculated and transferred.
- Users also have the option to collect their rewards without unstaking.
- Fees are initially collected in the contract for the owner to withdraw. The owner may elect to stop receiving fees and instead begin permanently distributing them as rewards amongst stakers.
- Reward tokens must be supplied to the contract to be distributed. Users will lose their rewards if they withdraw while there are no reward tokens in the contract.
- The owner is able to put the contract into an emergency state at anytime. This allows the owner to withdraw all of the rewards tokens in the contract. Users can also trigger an emergency withdraw, which will transfer all the user's deposited tokens to their wallet address, without calculating rewards.
Audit Findings Summary
- Any user who pays the fee can use the FarmFactory contract to create a new ERC20Farm or ERC721Farm; the user is set as the owner in the newly created Farm.
- The implementation code for the ERC20Farm or ERC721Farm is set by the project team.
- The owner is able to withdraw the collected fees from this contract at anytime.
- The owner is able to set the fee to any amount at anytime.
- The owner is able to set the cooldown period before users can unstake in any of the farms at anytime.
- The contract is ERC721 compliant; all standard functionality is present.
- As the project is implemented with solidity version ^0.8.0, it is protected from overflows.
- No external threats were identified.
- Ensure trust in the team as they have considerable control within the ecosystem.
- Date: November 1st, 2021.
Audit Results
| Vulnerability Category | Notes | Result |
|---|---|---|
| Arbitrary Storage Write | N/A | PASS |
| Arbitrary Jump | N/A | PASS |
| Delegate Call to Untrusted Contract | N/A | PASS |
| Dependence on Predictable Variables | N/A | PASS |
| Deprecated Opcodes | N/A | PASS |
| Ether Thief | N/A | PASS |
| Exceptions | N/A | PASS |
| External Calls | N/A | PASS |
| Flash Loans | N/A | PASS |
| Integer Over/Underflow | N/A | PASS |
| Multiple Sends | N/A | PASS |
| Oracles | N/A | PASS |
| Suicide | N/A | PASS |
| State Change External Calls | N/A | PASS |
| Unchecked Retval | N/A | PASS |
| User Supplied Assertion | N/A | PASS |
| Critical Solidity Compiler | N/A | PASS |
| Overall Contract Safety | PASS |


($) = payable function
# = non-constant function
+ [Int] IERC20
- [Ext] totalSupply
- [Ext] balanceOf
- [Ext] transfer #
- [Ext] allowance
- [Ext] approve #
- [Ext] transferFrom #
+ [Int] IERC165
- [Ext] supportsInterface
+ [Int] IERC721 (IERC165)
- [Ext] balanceOf
- [Ext] ownerOf
- [Ext] safeTransferFrom #
- [Ext] transferFrom #
- [Ext] approve #
- [Ext] getApproved
- [Ext] setApprovalForAll #
- [Ext] isApprovedForAll
- [Ext] safeTransferFrom #
+ [Int] IERC721Receiver
- [Ext] onERC721Received #
+ Context
- [Int] _msgSender
- [Int] _msgData
+ Ownable (Context)
- [Pub] #
- [Pub] owner
- [Pub] renounceOwnership #
- modifiers: onlyOwner
- [Pub] transferOwnership #
- modifiers: onlyOwner
+ ERC20Farm (Context)
- [Pub] #
- [Ext] stake #
- [Ext] unstake #
- [Ext] seed ($)
- [Ext] withdraw #
- [Ext] emergencySwitch #
- [Ext] emergencyWithdraw #
- [Ext] emergencyUnstake #
- [Ext] routeFeesBackToFarm #
- [Ext] setCooldown #
- [Ext] getFees
- [Ext] getUtilityToken
- [Ext] getUtilityRequirement
- [Ext] getStakedToken
- [Ext] getRewardToken
- [Ext] getFee
- [Ext] getCooldown
- [Ext] getRewardRate
- [Pub] getRewardRateTokens
- [Ext] getRewardAPY
- [Ext] getRewardsTotal
- [Pub] payout #
- [Pub] payoutFlex #
- [Pub] getStakedTotal
- [Pub] getUserStartedStaking
- [Pub] getUserStaked
- [Pub] getUserFarmed
- [Pub] getUserFeeOfAmount
- [Pub] getUserRewardsAvailable
- [Pub] getUserEstimatedRewardDaily
+ ERC721Farm (IERC721Receiver, Context)
- [Pub] #
- [Ext] stake #
- [Ext] unstake #
- [Ext] seed ($)
- [Ext] withdraw #
- [Ext] emergencySwitch #
- [Ext] emergencyWithdraw #
- [Ext] emergencyUnstake #
- [Ext] routeFeesBackToFarm #
- [Ext] setCooldown #
- [Ext] getFees
- [Ext] getUtilityToken
- [Ext] getUtilityRequirement
- [Ext] getStakedToken
- [Ext] getRewardToken
- [Ext] getFee
- [Ext] getCooldown
- [Ext] getPlatform
- [Pub] getRewardRate
- [Ext] getRewardAPY
- [Ext] getRewardsTotal
- [Pub] payout #
- [Pub] payoutFlex #
- [Pub] getStakedTotal
- [Pub] getUserStartedStaking
- [Pub] getUserStaked
- [Pub] getUserStakedIDs
- [Pub] getUserRewards
- [Pub] getUserFeeOfAmount
- [Pub] getUserRewardsAvailable
- [Pub] getUserEstimatedRewardDaily
- [Pub] onERC721Received #
+ FarmFactory (Ownable)
- [Pub] #
- [Ext] ($)
- [Ext] createERC20Farm ($)
- [Ext] createERC721Farm ($)
- [Ext] withdraw #
- modifiers: onlyOwner
- [Ext] setFee #
- modifiers: onlyOwner
- [Ext] setCooldownFarm #
- modifiers: onlyOwner
- [Ext] getFee
- [Ext] getERC20Farms
- [Ext] getERC721Farms
- [Ext] getERC20FarmsLength
- [Ext] getERC721StakingPoolsLength