BPAY Presale
Smart Contract Audit Report
Audit Summary
BPAY is building a new presale platform where users can initiate purchases with ETH and USDT.
For this audit, we reviewed the project team's BPAYPresale contract at 0x8b48f7388b075cbc50918d0802dee278b5ac2735 on the Ethereum Mainnet.
Audit Findings
All findings have been resolved, though some centralized aspects are present.
Date: December 11th, 2023.
Updated: December 13th, 2023 to reflect the contract's mainnet address.Finding #1 - BPAYPresale - Informational (Resolved)
Description: ThebaseDecimalsstate variable cannot be modified but is not declared constant.
Recommendation: The above state variable could be declared constant for additional gas savings on each reference.
Resolution: The team has implemented the above recommendation.
Contract Overview
- Any user can initiate a purchase while the sale is active by specifying a number of tokens to buy.
- The specified number of tokens must not exceed the maximum purchase limit per transaction.
- A USD amount is calculated for the number of tokens being purchased by multiplying the purchase amount by the price per token for the current stage of the presale.
- If the current time is beyond the current stage's time threshold, the next stage's price per token for the entire purchase amount is used.
- If a purchase extends over two stages due to exceeding the token limit of the current stage, the price is calculated for the portion of tokens that can be bought at the current stage’s price. Then, the price for the remaining tokens at the next stage's price is calculated to determine the total cost.
- If the purchase is with ETH, the USD price is converted to an equivalent amount in ETH using the latest price fetched through the Price Feed address set by the team.
- The provided amount of ETH must exceed the calculated ETH price of the transaction.
- The calculated USD price must exceed the minimum amount to buy value set by the owner.
- An amount of bonus tokens are added to the purchase amount if the purchase amount exceeds a bonus threshold set by the team. The number of bonus tokens is calculated by applying the corresponding percentage from the bonuses list to the amount of tokens being purchased.
- The stage value associated with the caller is set if they have not yet been assigned a stage and their purchase value exceeds the first USDT bonus threshold.
- If the sale has reached the token limit or the time limit for the current stage, the contract advances to the next stage.
- If the purchase is with ETH, the calculated ETH amount is transferred to the owner and any excess ETH is returned to the caller.
- If the purchase is with USDT, the calculated amount of USDT is transferred from the caller to the owner. The caller must grant this contract a sufficient allowance in order for the transaction to successfully occur.
- The owner can initiate the claiming period by specifying the claim start time, the address of the sale token, and a number of sale tokens to transfer to the contract.
- The claim start time must exceed the end time of the sale.
- The specified number of tokens must cover the total number of tokens sold.
- Any user that has purchased tokens can initiate a claim once the claim start time has been reached.
- The total number of tokens due to the user is transferred from the contract to their wallet address.
- The owner can initiate a purchase on behalf of any address without supplying ETH or USDT at any time.
- The owner can pause/unpause the contract at any time. When paused, all purchases and claims are unable to occur.
- The owner can set the maximum tokens to buy limit to any value at any time.
- The owner can set the minimum USDT purchase limit to any value at any time.
- The owner can set the stages and bonus values of the contract to any values at any time.
- The owner can set the USDT address referenced in the contract to any address at any time.
- The owner can set the Price Feed address to any address at any time.
- The owner can set the sale's sale start time and end time to any values at any time.
- The owner can update the claim start time after it has been initially set to any time in the future passed the sale end time.
- The owner can manually increment the current stage of the contract at any time.
- The contract utilizes ReentrancyGuard to prevent reentrancy attacks in applicable functions.
- As the contract is implemented with Solidity v0.8.x, it is safe from any possible overflows/underflows.
Audit Results
| Vulnerability Category | Notes | Result |
|---|---|---|
| Arbitrary Jump/Storage Write | N/A | PASS |
| Centralization of Control | N/A | PASS |
| Compiler Issues | N/A | PASS |
| Delegate Call to Untrusted Contract | N/A | PASS |
| Dependence on Predictable Variables | N/A | PASS |
| Ether/Token Theft | N/A | PASS |
| Flash Loans | N/A | PASS |
| Front Running | N/A | PASS |
| Improper Events | N/A | PASS |
| Improper Authorization Scheme | N/A | PASS |
| Integer Over/Underflow | N/A | PASS |
| Logical Issues | N/A | PASS |
| Oracle Issues | N/A | PASS |
| Outdated Compiler Version | N/A | PASS |
| Race Conditions | N/A | PASS |
| Reentrancy | N/A | PASS |
| Signature Issues | N/A | PASS |
| Sybil Attack | N/A | PASS |
| Unbounded Loops | N/A | PASS |
| Unused Code | N/A | PASS |
| Overall Contract Safety | PASS |
Inheritance Chart

Function Graph

Functions Overview
($) = payable function
# = non-constant function
Int = Internal
Ext = External
Pub = Public
+ [Int] IERC20
- [Ext] totalSupply
- [Ext] balanceOf
- [Ext] transfer #
- [Ext] allowance
- [Ext] approve #
- [Ext] transferFrom #
+ ReentrancyGuard
- [Pub] #
- [Prv] _nonReentrantBefore #
- [Prv] _nonReentrantAfter #
- [Int] _reentrancyGuardEntered
+ Context
- [Int] _msgSender
- [Int] _msgData
+ Pausable (Context)
- [Pub] #
- [Pub] paused
- [Int] _requireNotPaused
- [Int] _requirePaused
- [Int] _pause #
- modifiers: whenNotPaused
- [Int] _unpause #
- modifiers: whenPaused
+ Ownable (Context)
- [Pub] #
- [Pub] owner
- [Int] _checkOwner
- [Pub] renounceOwnership #
- modifiers: onlyOwner
- [Pub] transferOwnership #
- modifiers: onlyOwner
- [Int] _transferOwnership #
+ [Int] AggregatorV3Interface
- [Ext] decimals
- [Ext] description
- [Ext] version
- [Ext] getRoundData
- [Ext] latestRoundData
+ BPAYPresale (Ownable, Pausable, ReentrancyGuard)
- [Pub] #
- [Ext] pause #
- modifiers: onlyOwner
- [Ext] unpause #
- modifiers: onlyOwner
- [Ext] changeMaxTokensToBuy #
- modifiers: onlyOwner
- [Ext] changeMinUsdAmountToBuy #
- modifiers: onlyOwner
- [Ext] changeStages #
- modifiers: onlyOwner
- [Ext] changeBonuses #
- modifiers: onlyOwner
- [Ext] changeUSDTInterface #
- modifiers: onlyOwner
- [Ext] changeAggregatorInterface #
- modifiers: onlyOwner
- [Pub] calculatePrice
- [Pub] calculateBonus
- [Ext] changeSaleTimes #
- modifiers: onlyOwner
- [Pub] getLatestPrice
- [Ext] buyWithUSDT #
- modifiers: checkSaleState,whenNotPaused
- [Ext] buyWithEth ($)
- modifiers: checkSaleState,whenNotPaused,nonReentrant
- [Int] sendValue #
- [Ext] startClaim #
- modifiers: onlyOwner
- [Ext] changeClaimStartTime #
- modifiers: onlyOwner
- [Ext] claim #
- modifiers: whenNotPaused
- [Ext] incrementCurrentStage #
- modifiers: onlyOwner
- [Ext] getStages
- [Ext] getBonuses
- [Ext] manualBuy #
- modifiers: onlyOwner
About SourceHat
SourceHat has quickly grown to have one of the most experienced and well-equipped smart contract auditing teams in the industry. Our team has conducted 1800+ solidity smart contract audits covering all major project types and protocols, securing a total of over $50 billion U.S. dollars in on-chain value!
Our firm is well-reputed in the community and is trusted as a top smart contract auditing company for the review of solidity code, no matter how complex. Our team of experienced solidity smart contract auditors performs audits for tokens, NFTs, crowdsales, marketplaces, gambling games, financial protocols, and more!
Contact us today to get a free quote for a smart contract audit of your project!
What is a SourceHat Audit?
Typically, a smart contract audit is a comprehensive review process designed to discover logical errors, security vulnerabilities, and optimization opportunities within code. A SourceHat Audit takes this a step further by verifying economic logic to ensure the stability of smart contracts and highlighting privileged functionality to create a report that is easy to understand for developers and community members alike.
How Do I Interpret the Findings?
Each of our Findings will be labeled with a Severity level. We always recommend the team resolve High, Medium, and Low severity findings prior to deploying the code to the mainnet. Here is a breakdown on what each Severity level means for the project:
- High severity indicates that the issue puts a large number of users' funds at risk and has a high probability of exploitation, or the smart contract contains serious logical issues which can prevent the code from operating as intended.
- Medium severity issues are those which place at least some users' funds at risk and has a medium to high probability of exploitation.
- Low severity issues have a relatively minor risk association; these issues have a low probability of occurring or may have a minimal impact.
- Informational issues pose no immediate risk, but inform the project team of opportunities for gas optimizations and following smart contract security best practices.