Smart Contracts Audit
This is an audit of SocialX smart contracts: the crowdsale and the token.
The source code has been taken from the repository: https://bitbucket.org/nolimitdigital/socialx/src/sol/ico-improved.sol
The latest commit reviewed is: cf3363fb65dc6ce476c5505d646a36964bfbfa1b
Overview
The crowdsale process is regular. Contributors send their ETH to the crowdsale contract address and in response the crowdsale contract transfers SOCX tokens to every contributor right away. The crowdsale has a fixed price per SOCX and also adds a bonus to early contributors. The crowdsale has a minimum cap and will refund all contributions if the minimum cap is not reached. It also has a maximum cap and stops accepting contributions when the maximum cap is reached. It has a time limit and will stop accepting contributions when the time is over.
The token contract implements a standard ERC20 token.
Behaviour
The total amount of SOCX is 90,000,000.
The crowdsale offers 45,000,000 SOCX to contributors (50% of the total amount). 3,000,000 SOCX will be offered via ZenCash wallet. 42,000,000 SOCX are offered via the crowdsale contract that is being audited here. The rest is reserved for the team, the reward pool, the bounties, etc.
Minimal contribution accepted: 0.1 ETH.
Minimum cap: 495 ETH (min 3,300,000 SOCX to be sold)
Maximum cap: 6750 ETH (all 45,000,000 SOCX to be sold, 3,000,000 of them via ZEN)
Initial token price: 0.00015 ETH per 1 SOCX
Only whitelisted contributors are allowed to contribute. If anyone who is not on the white list sends ETH to the contract the transaction will fail. You can whitelist here.
Early contributors bonuses:
First hour: +50%
First day: +25%
Second day: +10%
Third day: +5%
The crowdsale also reserves the tokens that will be distributed to the presale contributors.
Total amount contributed on presale: 187.68 ETH
Presale tokens: 2,502,400 SOCX
The crowdsale ends when a maximum cap is reached or when the time is over.
Contributed ETH are sent to a multisig wallet and the SOCX reserved for the reward pool, bounties, management and team salaries (45,000,000 SOCX, 50% of the total supply) are sent to the team address.
If the minimum cap is not reached (less than 3,300,000 SOCX are sold via the contract) then the crowdsale is considered failed and will refund all contributions.
If any tokens are left unsold, they are frozen on the crowdsale contract balance for 180 days. The team can start a second crowdsale with the same contract any time to sell the remaining SOCX, or transfer the unsold SOCX to another crowdsale contract 180 days after the end of the crowdsale.
SOCX token transfers are locked until the crowdsale is finished.
Contributors will receive their tokens right away, but they won’t be able to transfer them until the end of the crowdsale.
SOCX tokens can be migrated to a newer version of the contract whenever it’s released. The migration can only be done by the owner of the contract (the team).
Critical Issues
No critical issues found.
Moderate Issues
[Fixed] Inconsistent choice of the comparison operator used to check if the minimum cap is reached.
One part of the code used SOCXSentToETH > minCap
(greater than operator) while other parts relied on the >=
(greater than or equals) operator.
It would become an issue only if the funds raised during the crowdsale were exactly equal to the minimum cap.
Probability: very low
Severity: high
Minor Issues
[Fixed] After the crowdsale is finished the token contract would be unlocked for token transfers even if the minimum cap is not reached.
Potential consequences: users would be able to transfer and trade their tokens while they’d be supposed only to get a refund from the crowdsale.
Probability: moderate
Severity: low
[Fixed] Redundant modifier usage: onlyBy(owner)
. There is already onlyOwner()
for the same purpose.
Severity: very low
[Fixed] Redundant condition check in the fallback function: if (block.number > endBlock)
. There is already a modifier respectTimeFrame()
that performs the same check.
Severity: very low
[Fixed] Redundant condition check in the token transferFrom()
function:
if (safeAdd(balances[_to], _value) < balances[_to]) revert(); // Check for overflows
Function safeAdd()
already checks for overflows, no need to duplicate it.
Severity: very low
Security practices used
- All
send()
calls are checked for a failure properly. - Arithmetical operations are performed safely.
- Not vulnerable to reentrancy attacks.
- Pull payments are used for payouts in case of a refund process.
- Proper workflow is used in every function: conditions, actions, interactions.
- No loops used.
- Emergency mode for unexpected situations.
tx.origin
is not used.
Conclusion
These smart contracts are well designed. The code is short, well commented and easy to read. It follows common security practices. The logic is simple and reliable. No critical or severe issues were found. All found issues have been fixed.
The contracts have been tested in a private Ethereum network. They performed exactly as expected and showed no issues.