The Coinfix team asked us to review and audit their MerchantSubscription
contract. We looked at the code and now publish our results.
The audited code is located in the ChainXcom/coinfix.io-smart-contracts repository. The version used for this report is commit 75edd659ce96c88fe2784f3e767d6617787e8b7c
.
Here is our assessment and recommendations, in order of importance.
Update: The Coinfix team has followed most of our recommendations and updated the contracts. The new version is at commit c02c083173fee08fb6e8e20ff854e5fbbbe9ed55
.
Critical Severity
No issues of critical severity.
High Severity
No issues of high severity.
Medium Severity
Merchant address can be null
A MerchantSubscription
contract can be instantiated with the null address as the merchant
parameter. Such an instance will never be able to be activated or function at all. Consider adding a sanity check in the constructor to require that the merchant
parameter is different from 0x0
. This will also be in line with the principle of failing as early and loudly as possible.
Update: Fixed in this commit by checking merchant != 0x0
.
Low Severity
Solidity version
The contracts can be compiled with versions of the compiler as low as 0.4.11
. We recommend changing the Solidity version pragma to a more recent version (for example, pragma solidity ^0.4.17
) to enforce the use of an up to date compiler.
Update: Fixed in this commit.
Reuse open source contracts
The contract implements similar functionality to code found in OpenZeppelin’s SafeMath
,Ownable
(or
Claimable
) and Pausable
. Reimplementing functionality instead of reusing public and already audited code can bring regression problems and difficult to find bugs. Consider removing the duplicate code from your repo and using the installed versions from OpenZeppelin.
Update: Fixed in this commit by using OpenZeppelin’s contracts.
Redundant amount state variable
The contract has an amount
state variable, which intends to track the amount of ether received. However, it is redundant because such a value is already accessible via this.balance
.
Additionally, bear in mind that the contract can receive ether bypassing the fallback function (see the second warning here. This would leave the amount
variable out of sync with the actual balance, and the ether received in such a way unrecoverable. Moreover, the SubscriptionPaymentMade
event will not be emitted for these cases.
Consider removing this variable from the contract, and using this.balance
instead. After this removal SafeMath
will be unnecessary.
Update: Fixed in this commit by using this.balance
.
Notes & Additional Information
- Neither the
constructor
, fallback function nor theclaimOwnership
method have explicit visibility. Solidity defaults topublic
. Consider making this explicit. This will also avoid some compiler warnings introduced in the latest versions, motivated by the first Parity wallet hack.
(Update: Fixed in this commit.) - The contract’s
version
state variable could be declaredconstant
.
(Update: Fixed in this commit.) - The
SafeMath
methods could be markedpure
. Consider using Solidity’susing for
feature for enhanced readability.
(Update: Fixed in this commit by reusing OpenZeppelin’sSafeMath
.) - Consider indexing event parameters such as
SubscriptionPaymentMade
’scustomer
as it enables faster lookups for consuming apps.
(Update: Fixed in this commit.) - Only the owner can trigger a withdrawal of funds from the subscription. This requires trust in the owner by the merchant. Unless this limitation is by design, consider also allowing the merchant to trigger it.
- The
withdrawal
function transfers ether to themerchant
address (by using Solidity’stransfer
). Make sure that merchant addresses can receive ether.
Conclusion
No critical or high severity issues were found. Some changes were proposed to follow best practices and reduce potential attack surface.
Note that as of the date of publishing, the above review reflects the current understanding of known security patterns as they relate to Coinfix’s contract. We have not reviewed the related Coinfix project. The above should not be construed as investment advice. For general information about smart contract security, check out our thoughts here.