Xion Global Subscriptions

October 5, 2021

1. Preface

The team of Xion Global contracted byterocket to conduct a smart contract audit of their smart contracts handling subscriptions and single-billing purchases for their eCommerce platform. Xion Global is building a ​​decentralized payment gateway that allows online businesses to accept multiple payment options like cryptocurrencies.

The team of byterocket reviewed and audited the above smart contracts in the course of this audit. We started on the 27th of September and finished on the 5th of October, 2021.

The audit included the following services:

  • Manual Multi-Pass Code Review
  • Automated Code Review
  • In-Depth Protocol Analysis
  • Formal Report

byterocket gained access to the code via their public GitHub repository. We based the audit on the master branch’s state on October 5th, 2021 (commit hash fd59cd8a85ec3c501208e1883a5a71580e98d906).

2. Manual Code Review

We conducted a manual multi-pass code review of the smart contracts mentioned in section (1). Three different auditors went through the smart contract independently and compared their results in multiple concluding discussions.

These contracts are written according to the latest standards used within the Ethereum community and the Solidity community’s best practices. The naming of variables is very logical and understandable, which results in the contract being easy to understand. The code is very well documented and up to the latest standards.

On the code level, we found no bugs or flaws. Two low severity ones have been found and fixed prior to the completion of the audit, listed below. A further check with multiple automated reviewing tools (MythX, Slither, Manticore, and different fuzzing tools) did not find any additional bugs besides some common false positives.

Prior findings that we forwarded to the developers throughout the audit have been fixed accordingly and have been verified by us to be correct.

2.1. Bugs & Vulnerabilities

2.1.A - XGHub.sol - Line 82 - 88 [LOW SEVERITY] [FIXED]
function pause() external onlyOwner whenNotPaused {
 _pause();
 wallet.pause();
 features.pause();
}

The function aims to pause all sub-contracts when being invoked to simplify the pausing and unpausing process. However, it does not include the calls to pause the subscription and single-billing contracts. This would need to be changed if the developers want it like that.

Update

The developers have implemented our suggested change and have included two additional calls to the pause and unpause function to complete it.

function pause() external onlyOwner whenNotPaused {
 _pause();
 wallet.pause();
 features.pause();
 subscriptions.pause();
 purchases.pause();
}
2.1.B - XGWallet.sol [LOW SEVERITY] [FIXED]
(success, ) = payable(_receiver).call{value: _amount, gas: 2300}("");
uint256 balanceAfter = address(this).balance;
if (!success && balanceBefore.sub(balanceAfter) == 0) {
 (success, ) = payable(_receiver).call{value: _amount, gas: 2900}("");
 balanceAfter = address(this).balance;
}

If the first ETH/xDai transfer fails, it is being retried with a higher gas amount. We suggest increasing the 2850 gas amount in the retry to an even higher value since there are still a lot of smart contract wallets or multi-sigs which need more than 2850 gas for a transfer. In that case, the retry would still fail.

Update

The developers have implemented our suggested change and have increased the gas limit to 20.000 gas, which should be plenty.

2.2. Other Findings

2.2.A - General [NO SEVERITY] [FIXED]

Contracts like the XGHub are slightly over the contract size limit already, which would not allow them to be deployed on Ethereum Mainnet and some other networks. They might work on xDai but won’t allow any more changes to be included in the future.

We would suggest splitting the contracts even further, so the subscriptions and the single-billing functionalities are separated into their own contracts. Main functionalities should then be routed through the XGHub.sol still.

Update

The developers have implemented our suggested change and have separated the functionalities into separate contracts. The contracts are now several kb below the contract size limit, which should give enough room for further upgrades and features.

3. Protocol/Logic Review

Part of our audits are also analyses of the protocol and its logic. A team of three auditors went through the implementation and documentation of the implemented protocol.

In our discussion, we were not able to find any weaknesses within the implementation of the protocol. None of our function calls (even when we did randomized fuzzing tests) were able to produce any unforeseen outcomes and skew the results in any way. The overall process flow was valid at all times.

Thus, We were not able to discover any problems in the protocol implemented in the smart contract.

4. Testnet Deployment

As per our testing strategy, we deploy audited smart contracts (if requested by the client) onto a testnet to verify the implementation’s functionality. We usually deploy simple smart contracts to a local Ganache instance, which is sufficient for most cases. In this case. we wanted to ensure no Ganache-related coverups of the contracts’ misbehavior. We created two testnets: a geth-based one and a parity/openethereum-based one. All of our tests have been executed on both testnets without any difference in the results. We were able to use the contracts as intended and could not maliciously game the protocol in practice.


We used fuzzing tools that generate random and semi-random inputs and interact with the contracts, trying to produce any unforeseen states within the contracts, especially the treasury contract. Throughout our tests, we were not able to create or observe any issues or problems. The contract behaved as expected and reverted correctly, given wrong inputs. No unforeseen states occurred during our fuzz-tests.

5. Summary

During our code review (which was done manually and automated), we found no bugs or flaws. Two low severity ones have been found and fixed prior to the completion of the audit, which are listed in section (2.1.). Additionally, our automated systems and review tools also did not find any additional ones.

The protocol review and analysis did neither uncover any game-theoretical nature problems nor any other functions prone to abuse.

During our multiple deployments to various local testnets, we haven’t been able to find any additional problems or unforeseen issues. The provided unit tests worked flawlessly and we were also not able to find any issues here.

In general, we are delighted with the overall quality of the code, its tests, and its documentation.

Stored on IPFS

We store our public audit reports on IPFS; a peer-to-peer network called the "Inter Planetary File System". This allows us to store our reports in a distributed network instead of just a single server, so even if our website is down, every report is still available.

Learn more about IPFS
Signed On-Chain

The IPFS Hash, a unique identifier of the report, is signed on-chain by both the client and us to prove that both sides have approved this audit report. This signing mechanism allows users to verify that neither side has faked or tampered with the audit.

Check the Signatures