AlexGo Audit ::: Launchpad, Vault, and Reserve Pool

Introduction

CoinFabrik was asked to audit the contracts for the AlexGo project. First we will provide a summary of our discoveries and then we will show the details of our findings.

Scope

The contracts audited are from the alex-v1 git repository. The audit is based on the commit 44c44846bfbcce6096be04bd1380728c98f09ec8. The fixes were added to the commit 31a5d660c83d41c10cd1b34498f02bc3a407721e.

The audited contracts are:

clarity/contracts/alex-vault.clar: Contract that stores system tokens and allows flash loans.
clarity/contracts/pool/alex-launchpad.clar: IDO token launchpad.
clarity/contracts/pool/alex-reserve-pool.clar: Contract for token staking.

The scope of the audit is limited to those files. No other files in this repository were audited. Its dependencies are assumed to work according to their documentation. Also, no tests were reviewed for this audit.

Analyses

Without being limited to them, the audit process included the following analyses:

● Arithmetic errors
● Race conditions
● Reentrancy attacks
● Misuse of block timestamps
● Denial of service attacks
● Excessive gas usage
● Missing or misused function qualifiers
● Needlessly complex code and contract interactions
● Poor or nonexistent error handling
● Insufficient validation of the input parameters
● Incorrect handling of cryptographic signatures
● Centralization and upgradeability

Summary of Findings

We found a critical issue, two medium issues and a minor issue. Also, two
enhancements were proposed.
The critical severity issue and the two medium issues were acknowledged. Two minor severity issues were fixed. An enhancement was implemented.

Security Issues

Privileged Roles

These are the privileged roles that we identified on each of the audited contracts.

Alex-vault.clar

Owner

In the beginning, the owner is the address of the deployer. Then, the owner can set an address as a new owner. Also, this role can set a new flash loan fee rate and add new approved contracts, flash loan users and flash loan tokens. Finally, the owner can transfer fungible and semi-fungible tokens stored in the vault.

Approved Contracts

The approved contracts are addresses which can execute the transfer functions to move fungible and semi-fungible tokens from the vault contract. This address set is initialized including alex-reserve-pool, collateral-rebalancing-pool, fixed-weight-pool, liquidity-bootstrapping-pool, yield-token-pool, and yield-collateral-rebalancing-pool.

Approved Flash Loan Users

Flash loan users are addresses allowed to be used when flash-loan() is called. This contract should implement the specific trait in order for the vault contract to call the execute() function.

Alex-launchpad.clar

Owner

In the beginning, the owner is the address of the deployer. Then, the owner can set an address as a new owner. Also, this role can create new token-ticket pools.

Liquidity Provider

This is an address set by the owner for each pool created. This address is the only one allowed to provide tokens to the pool. Also, this address receives the amount of stacks paid to validate the winner ticket.

Alex-reserve-pool.clar

Owner

In the beginning, the owner is the address of the deployer. Then, the owner can set an address as a new owner. Also, this role can add new approved contracts and approved tokens, set a new activation delay, activation threshold, a new value for the halving cycle and coinbase amount of a token and a new reward cycle length. Finally, the owner can increase and decrease the balance of a token.

Approved Contracts

The approved contracts are addresses which can increase and decrease the balance of a token. Initially, the contracts included in this set are:
collateral-rebalancing-pool, fixed-weight-pool, yield-token-pool, yield-collateral-rebalancing-pool and the reserve pool itself.

Security Issues Found

Severity Classification

Security risks are classified as follows:

Critical: These are issues that we manage to exploit. They compromise the
system seriously. They must be fixed immediately.
●Medium: These are potentially exploitable issues. Even though we did not
manage to exploit them or their impact is not clear, they might represent a
security risk in the near future. We suggest fixing them as soon as possible.
Minor: These issues represent problems that are relatively small or difficult to take advantage of but can be exploited in combination with other issues. These kinds of issues do not block deployments in production environments. They should be taken into account and be fixed when possible

Issues Status

An issue detected by this audit can have four distinct statuses:

●Unresolved: The issue has not been resolved.
●Acknowledged: The issue remains in the code but is a result of an intentional decision.
●Resolved: Adjusted program implementation to eliminate the risk.
●Mitigated: Implemented actions to minimize the impact or likelihood of the risk.

Critical Severity Issues

CR-01 Unfair Lotteries through Weak Randomness

Location:

●clarity/contracts/pool/alex-launchpad.clar

Users can validate their tickets during the registration process, delimited by the variables registration-start and registration-end. A counter is increased for each ticket validated, and each user has a range of positions related to when they joined the lottery and the amount of tickets validated. When the registration ends and the minimum amount of participants is reached, users can call claim() one time for each ticket validated.

This function determines if the ticket is a winner based on a pseudo-random number modulo the counter of tickets. If the resulting value is in the range of positions of tickets validated by the user, then it is a winner ticket.

However, the first pseudo-random number is generated based on the vrf-seed of registration-start block in the first call to claim(). For the subsequent calls, the function calculates a new pseudo-random based on the latest random.
Therefore, since the contract is public and the process transparent, anyone can calculate the sequence of values to be generated. Users can speculate with which position is the most convenient to register themselves and when to claim based on the following number in the sequence.

Recommendation

The speculation in the registration can be solved using the VRF seed of the block next to the end of the registration (registration-end + 1) as randomness source.
Finally, the speculation in the claiming order can be solved computing the
pseudo-random number with the mentioned VRF seed and a value unique for each ticket (e.g., the ticket’s position). Then, using two constant values, the claiming order will not have an impact because the random number is already determined.

Status

Acknowledged. claim() now uses registration-end instead of
registration-start for the VRF seed. The speculation was reduced, but it still uses a seed that can be known if register() is called at registration-end. Using the block next to registration-end can solve the problem.
The new changes also made the entire random sequence unpredictable. However, the next random still can be predicted and the user might check if this random is beneficial and wait for the next random if not. In order to avoid the speculation in the claiming order, the number should be generated with either an input unknown for the user or constant values. The first solution makes the next random unpredictable for the user, while the second one makes it constant.

Medium Severity Issues

ME-01 Insecure Authentication through tx-sender

Location:

●clarity/contracts/alex-vault.clar,
●clarity/contracts/pool/alex-launchpad.clar,
●clarity/contracts/pool/alex-reserve-pool.clar

Global variable tx-sender returns the original sender of the current transaction, or if as-contract was called to modify the sending context, it returns that contract principal. Using this variable for authentication is not secure. Actors in the system could be targets of phishing. This is analogous to what happens to tx.origin and msg.sender in Solidity. There, the convention is to use msg.sender, which works like the contract-caller.
For instance, the vault’s owner can be tricked into calling a malicious contract which executes vault.set-contract-owner() against his will.

Recommendation

Prefer contract-caller to tx-sender for authentication. contract-caller
returns the caller of the current contract context.

Status

Acknowledged. A new development would address this issue.

ME-02 Independent Winning Probability in Lottery

Location:

●clarity/contracts/pool/alex-launchpad.clar

As it was described in CR-01, each claim() execution generates a new random number. Therefore, while there are tokens to transfer, the winning probability is independent and the amount of winners is unknown. In order to solve it, the function checks if all the tickets provided were won before executing the rest of the function. When all the winner tickets are determined, the listing is completed and new claims are not accepted. This mechanism may result in two issues.

Firstly, some tokens might not be claimed if there are not enough winner tickets. Furthermore, there is no use given to this remainder tokens.

Secondly, it generates a race condition between the users to claim before the listing is completed. Otherwise, a user will not be able to claim
even when he has tickets.

Recommendation

A solution would be to generate only n random numbers, where n is the number of winning tickets. Then, claim() would check if one of the random numbers were in the user’s range of tickets. However, due to Clarity limitations, this solution cannot be implemented.

Status

Acknowledged.

Minor Severity Issues

MI-01 Arithmetic Underflow Calculating Staking Reward

Location:

●clarity/contracts/pool/alex-reserve-pool.clar:[379]

In get-entitled-staking-reward(), the rewards are calculated with the quotient between the amount staked by the user and the total amount staked, multiplied by the token’s coinbase amount.

Quotient’s result may have a higher imprecision than the result obtained by
multiplying first and then dividing it by the total staked.

Recommendation:

For a more precise result, get the product between the coinbase amount and the amount staked by the user, and divide it by the total amount staked:

Status

Resolved.

MI-02 Ended Pool can be Created

Location:

●clarity/contracts/pool/alex-launchpad.clar

Pool creation function (create-pool()) does not validate the block numbers provided for the registration-start and registration-end variables. Therefore, a pool can be created without time for registration.

Recommendation

The input registration-start should be checked to be equal or greater than the current block number.

Status

Resolved.

Enhancements

These items do not represent a security risk. They are best practices that we
suggest implementing.

Table

Details

EN-01 Missing Source Code Comments

Location:

●clarity/contracts/pool/alex-launchpad.clar

The launchpad contract lacks of function documentation in the source code.
Comments documenting a function helps the contract reader to understand better the usage of that piece of code.

Status

Not implemented. The development team committed to add the documentation.

EN-02 Unnecessary Computation to Check if the Listing Is Activated

Location:

●clarity/contracts/pool/alex-launchpad.clar

The listing mapping contains a variable named activated that is initially set to false when the pool is created and then increased for each new register. The register() function updates the value to true if the amount of tickets validated (total-subscribed) reached the activation-threshold.

There is no other function that updates the total-subscribed value nor the activated value. However, the getter function is-listing-activated() computes again the comparison between the two variables instead of reading from the activated variable.

Recommendation:

Read from the activated variable instead of performing the comparison again.

Status

Implemented.

Changelog

●2022-01-07 – Initial report based on commit
44c44846bfbcce6096be04bd1380728c98f09ec8.
●2022-01-11 – Reaudit report based on the fixes in commit
31a5d660c83d41c10cd1b34498f02bc3a407721e.
●2022-01-13 – CR-01 state changed to “acknowledged”.

Disclaimer: This audit report is not a security warranty, investment advice, or an approval of the AlexGo project since CoinFabrik has not reviewed its platform. Moreover, it does not provide a smart contract code faultlessness guarantee.

Avalaunch Audit <> Allocation Staking and Cooldown feature

Introduction

CoinFabrik was asked to audit the contracts for the Avalaunch AllocationStaking project. First we will provide a summary of our discoveries and then we will show the details of our findings.

Summary

The contracts audited are from the GitHub repository at
https://github.com/avalaunch-app/xava-protocol.

The audit is based on the commit fc32d84a67233ebba6f980182a951076858d30c0.

Contracts

The audited contracts are:

● contracts/AllocationStaking.sol
● contracts/sales/AvalaunchSale.sol
● contracts/sales/SalesFactory.sol

Analyses

The following analyses were performed:

● Misuse of the different call methods
● Integer overflow errors
● Division by zero errors
● Outdated version of Solidity compiler
● Front running attacks
● Reentrancy attacks
● Misuse of block timestamps
● Softlock denial of service attacks
● Functions with excessive gas cost
● Missing or misused function qualifiers
● Needlessly complex code and contract interactions
● Poor or nonexistent error handling
● Failure to use a withdrawal pattern
● Insufficient validation of the input parameters
● Incorrect handling of cryptographic signatures

Findings and Fixes

Severity Classification

Security risks are classified as follows:

Critical: These are issues that we manage to exploit. They compromise the system seriously. They must be fixed immediately.
Medium: These are potentially exploitable issues. Even though we did not
manage to exploit them or their impact is not clear, they might represent a
security risk in the near future. We suggest fixing them as soon as possible.
Minor: These issues represent problems that are relatively small or difficult to take advantage of but can be exploited in combination with other issues. These kinds of issues do not block deployments in production environments. They should be taken into account and be fixed when possible.
Enhancement: These kinds of findings do not represent a security risk. They are best practices that we suggest to implement.

This classification is summarized in the following table:

Issues Found by Severity

Critical Severity Issues

No issues found.

Medium Severity Issues

No issues found.

Minor Severity Issues

MI-01 Failure to Use safeMath Library

The functions fund() (line 120), totalPending() (line 196) and erc20Transfer() (line 412) make use of standard arithmetic which are susceptible to overflows and underflows.

Recommendation

Replace + by add() and – by sub().

Enhancements

EN-01 Unvalidated Input in Function and Constructor

The following are functions and constructors that fail to validate the input. In most cases, they are used to set parameters which may be changed later and the impact of setting a bad parameter is small.

  • The parameter _token in setSaleParams() is not checked to be non-null.
  • The input addresses _erc20 and _salesFactory in the AllocationStaking constructor are not checked to be non-null.

Conclusion

We found the contracts to be simple and straightforward and have an adequate amount of documentation. A minor vulnerability pointing to unsafe use of math was found in some functions with little security impact.

Disclaimer: This audit report is not a security warranty, investment advice, or an approval of the Avalaunch project since CoinFabrik has not reviewed its platform. Moreover, it does not provide a smart contract code faultlessness guarantee.

Alex Logo

AlexGo Audit

Introduction

CoinFabrik was asked to audit the contracts for the AlexGo project. First we will provide a summary of our discoveries and then we will show the details of our findings.

Summary

The contracts audited are from the alex-v1 repository at
https://github.com/alexgo-io/alex-v1. The audit is based on the commit
0913c9eb0c8f79b3cd0b843641075ce27d437c96. Fixes were made and rechecked based on the commit feb43898de520ca1c55a6d8bc5bcf2d6f7df8ffa.

Contracts

The audited contracts are:

● clarity/contracts/equations/weighted-equation.clar: Library for
weighted math functions.
● clarity/contracts/equations/yield-token-equation.clar: Library for
yield token math functions.
● clarity/contracts/pool/alex-reserve-pool.clar: Staking contract.
● clarity/contracts/pool/collateral-rebalancing-pool.clar: Lending
and borrowing pool contract with pools of variable weights.
● clarity/contracts/pool/fixed-weight-pool.clar: Contract with
fixed-weight liquidity pools.
● clarity/contracts/pool/liquidity-bootstrapping-pool.clar:
Contract with liquidity pools that increase bootstrapped token weight over
the time.
● clarity/contracts/pool/yield-token-pool.clar: Liquidity pools for
token and correspondent yield token pairs.

Analyses

The following analyses were performed:

● Misuse of the different call methods
● Integer overflow errors
● Division by zero errors
● Front running attacks
● Reentrancy attacks
● Misuse of block timestamps
● Softlock denial of service attacks
● Functions with excessive gas cost
● Missing or misused function qualifiers
● Needlessly complex code and contract interactions
● Poor or nonexistent error handling
● Failure to use a withdrawal pattern
● Insufficient validation of the input parameters
● Incorrect handling of cryptographic signatures

Findings and Fixes

Severity Classification

Security risks are classified as follows:

Critical: These are issues that we manage to exploit. They compromise the system seriously. They must be fixed immediately.
Medium: These are potentially exploitable issues. Even though we did not
manage to exploit them or their impact is not clear, they might represent a
security risk in the near future. We suggest fixing them as soon as possible.
Minor: These issues represent problems that are relatively small or difficult to take advantage of but can be exploited in combination with other issues. These kinds of issues do not block deployments in production environments. They should be taken into account and be fixed when possible.
Enhancement: These kinds of findings do not represent a security risk. They are best practices that we suggest to implement.

This classification is summarized in the following table:

Issues Found by Severity

Critical Severity Issues

CR-01 Pools Transfer More Tokens than Expected

The function add-to-position() in the contracts
liquidity-bootstrapping-pool.clar and fixed-weight-pool.clar receives as a parameter how many tokens the user would like to provide to the pool. In order to conform the pool balance, the function calculates the amount of tokens y to be provided based on the amount of token x. As a consequence, the actual value provided to the pool could be greater than the one specified by the user. The result would be the contract moving more tokens than the ones consented by the user.

Recommendation

The actual amount of token y to be provided to the pool should never be greater than the value defined by the user (dy). This could be done by adding an asserts! that compares those values.

Solution

Fixed according to the recommendation

CR-02 Lost Funds when Burning Yield Tokens

In a collateral rebalancing pool (collateral-rebalancing-pool.clar), liquidity providers get an amount of yield and key tokens equal to the provided liquidity multiplied by ltv (Loan-to-Value). When yield tokens are burnt calling reduce-position-yield(), the pool is completely rebalanced, swapping all the collateral. Then, for instance, if a user owns 100% of the pool value and burns all his yield tokens, the balance stored in the blockchain will be reduced to zero.
However, the user gets transferred only the exact amount of yield token burnt (balance * ltv). Since this does not represent the actual value provided, users will realize they lost funds when they try to burn their key tokens and receive zero tokens because the pool is empty.

Recommendation

Subtract from the pool balance the same amount transferred to the user.

Solution

Fixed according to the recommendation.

CR-03 Denial of Service when Burning Yield Tokens

In a collateral rebalancing pool (collateral-rebalancing-pool.clar), when yield tokens are burnt calling reduce-position-yield(), the pool is completely rebalanced, swapping all the collateral (i.e., it becomes a 0-100 pool). As a consequence, it becomes unusable for token swaps since either the input or output value will be greater than the zero-balance, causing the transaction to revert because of the assertions made in weighted-equation.clar. These assertions verify the value deposited to a pool in an A token is lower than that token’s balance multiplied by a ratio, and also the amount of B tokens given in exchange is lower than that token’s balance multiplied by a ratio.
Moreover, this Denial of Service would be most of the time unintentionally executed by the users and would persist until someone provides liquidity to the pool again, incrementing the zero-balance.

Solution

Swap functions can only be called before the expiration block.

Medium Severity Issues

ME-01 Denial of Service when Burning Key Tokens

In a collateral rebalancing pool (collateral-rebalancing-pool.clar), if all the key tokens were burnt and the reserve pool (alex-reserve-pool.clar) does not have tokens in its balance, users might not burn any amount of their yield tokens.
Since reduce-position-yield() swaps all the collateral, a new balance of the token is calculated based on the previous balance and the amount of tokens received after the swap. Then, the function calculates a variable
shares-to-yield which is equal to the amount of yield tokens the user wants to burn (shares) divided by its total supply (yield-supply). Afterwards, it calculates dy, the product of new-bal-y and shares-to-yield, and compares dy to shares.
Since the pool only has a value equal to the yield supply, it is swapped and fees are taken out, dy will be lower than shares. Therefore, in line 496, it calls alex-reserve-pool.remove-from-balance() to transfer the shortfall, but if alex-reserve-pool does not have tokens, it will revert.

Solution

Changes made to fix CR-02 solved this issue.

Minor Severity Issues

MI-01 Low Decimal Precision

Clarity integer types are stored in 128-bit storage slots. In order to represent the fractional part, a fixed point precision is used with 8 decimal for the fractional part and 30 for the whole part. However, this precision is low and can result in significant decimal errors in the long term.

Recommendation

Since the whole part is more than long enough, the precision could be increased to, for instance, 18 decimal places.

Solution

The development team is studying the implementation of a higher decimal
precision.

MI-02 Funds Taken because of Liquidity Pool Token Repetition

Whenever users provide liquidity to a pool, they receive liquidity pool tokens (LP tokens). If two pools were created with the same LP token, users could provide liquidity in one of those pools and withdraw funds from the other. Currently, only the contract owners can create pools and it is at their discretion.

Recommendation

Restrict LP token repetition, not only in each contract, but also across pool
contracts: fixed-weight-pool.clar, liquidity-bootstrapping-pool.clar, yield-token-pool.clar. These are the pools that share the same trait for the LP tokens.

Solution

The development team is considering maintaining a registry contract that is
updated every time a pool is created and checks if the principal address of the pool token passed is already in use.

MI-03 Swap Limit Setter not Restricted

Amounts swapped are limited in order not to be larger than a certain percentage of total balance (MAX-IN-RATIO and MAX-OUT-RATIO). These values are set initially to 30% in weighted-equation.clar and yield-token-equation.clar, but they can be modified without restriction. It can result in a denial of service if the value is too small.

Recommendation

Setters should check the new value is, at least, greater than zero with an asserts!.

Solution

Fixed according to the recommendation.

MI-04 Front-running after Pool Creation

Liquidity bootstrapping pools (liquidity-bootstrapping-pool.clar) are created with a default value for maximum and minimum prices for bootstrapped token (maximum is set to 10^8 and minimum to zero). They can be changed, but only calling the setter in another transaction. Since the pool creator must provide liquidity in the same transaction they created the pool, under certain market conditions, an attacker might find it profitable to execute a swap immediately after the pool creation and before the maximum and minimum are modified.

Recommendation

Add two parameters to create-pool() to assign initial values for price-x-min and price-x-max.

Solution

Fixed according to the recommendation.

MI-05 New Max Expiry in the Past

In yield-token-pool.clar, max-expiry is a variable essential to calculate the time to maturity. If this variable is lower or equal to the current block, most of the transactions will revert, causing a denial of service in that contract. Currently, its setter, set-max-expiry(), does not check if the new value is valid.

Recommendation

Add an asserts! to check new-max-expiry is greater than block-height before assigning it to max-expiry.

Solution

Fixed according to the recommendation.

Enhancements

EN-01 Unused Math Constants and Functions

Useful math functions and constants are copied in the contracts. However, they are not always used by the rest of the contract functions and make the deployment more expensive. For instance, in collateral-rebalancing-pool.clar, pow-up(), ONE_10, log-fixed() and ln-fixed() are not used.

Recommendation

Remove the functions that are not necessary for the contracts.

Other Considerations

  1. collateral-rebalancing-pool.clar uses an approximation for the error function (Abramowitz and Stegun) which has a high maximum error. The recommendation is to extensively test it to assure it does not have unexpected implications.
  2. In yield-token-pool contract, max-expiry value is based on a 15-second block time. AlexGo team explained it is set for the mocknet environment. It should be changed to 10 minutes when it is deployed to Stacks mainnet.

Conclusion

We found the contracts to be simple and straightforward and have an adequate amount of documentation, but not always up-to-date. Three critical, one medium and five minor severity issues were found. Additionally, an enhancement was proposed. The development team fixed seven issues and acknowledged two minor issues.

Disclaimer: This audit report is not a security warranty, investment advice, or an approval of the AlexGo project since CoinFabrik has not reviewed its platform. Moreover, it does not provide a smart contract code faultlessness guarantee.

AlexGo Audit ::: Launchpad, Vault, and Reserve Pool

Introduction

CoinFabrik was asked to audit the contracts for the AlexGo project. First we will provide a summary of our discoveries and then we will show the details of our findings.

Scope

The contracts audited are from the alex-v1 git repository. The audit is based on the commit 44c44846bfbcce6096be04bd1380728c98f09ec8. The fixes were added to the commit 31a5d660c83d41c10cd1b34498f02bc3a407721e.

The audited contracts are:

clarity/contracts/alex-vault.clar: Contract that stores system tokens and allows flash loans.
clarity/contracts/pool/alex-launchpad.clar: IDO token launchpad.
clarity/contracts/pool/alex-reserve-pool.clar: Contract for token staking.

The scope of the audit is limited to those files. No other files in this repository were audited. Its dependencies are assumed to work according to their documentation. Also, no tests were reviewed for this audit.

Analyses

Without being limited to them, the audit process included the following analyses:

● Arithmetic errors
● Race conditions
● Reentrancy attacks
● Misuse of block timestamps
● Denial of service attacks
● Excessive gas usage
● Missing or misused function qualifiers
● Needlessly complex code and contract interactions
● Poor or nonexistent error handling
● Insufficient validation of the input parameters
● Incorrect handling of cryptographic signatures
● Centralization and upgradeability

Summary of Findings

We found a critical issue, two medium issues and a minor issue. Also, two
enhancements were proposed.
The critical severity issue and the two medium issues were acknowledged. Two minor severity issues were fixed. An enhancement was implemented.

Security Issues

Privileged Roles

These are the privileged roles that we identified on each of the audited contracts.

Alex-vault.clar

Owner

In the beginning, the owner is the address of the deployer. Then, the owner can set an address as a new owner. Also, this role can set a new flash loan fee rate and add new approved contracts, flash loan users and flash loan tokens. Finally, the owner can transfer fungible and semi-fungible tokens stored in the vault.

Approved Contracts

The approved contracts are addresses which can execute the transfer functions to move fungible and semi-fungible tokens from the vault contract. This address set is initialized including alex-reserve-pool, collateral-rebalancing-pool, fixed-weight-pool, liquidity-bootstrapping-pool, yield-token-pool, and yield-collateral-rebalancing-pool.

Approved Flash Loan Users

Flash loan users are addresses allowed to be used when flash-loan() is called. This contract should implement the specific trait in order for the vault contract to call the execute() function.

Alex-launchpad.clar

Owner

In the beginning, the owner is the address of the deployer. Then, the owner can set an address as a new owner. Also, this role can create new token-ticket pools.

Liquidity Provider

This is an address set by the owner for each pool created. This address is the only one allowed to provide tokens to the pool. Also, this address receives the amount of stacks paid to validate the winner ticket.

Alex-reserve-pool.clar

Owner

In the beginning, the owner is the address of the deployer. Then, the owner can set an address as a new owner. Also, this role can add new approved contracts and approved tokens, set a new activation delay, activation threshold, a new value for the halving cycle and coinbase amount of a token and a new reward cycle length. Finally, the owner can increase and decrease the balance of a token.

Approved Contracts

The approved contracts are addresses which can increase and decrease the balance of a token. Initially, the contracts included in this set are:
collateral-rebalancing-pool, fixed-weight-pool, yield-token-pool, yield-collateral-rebalancing-pool and the reserve pool itself.

Security Issues Found

Severity Classification

Security risks are classified as follows:

Critical: These are issues that we manage to exploit. They compromise the
system seriously. They must be fixed immediately.
●Medium: These are potentially exploitable issues. Even though we did not
manage to exploit them or their impact is not clear, they might represent a
security risk in the near future. We suggest fixing them as soon as possible.
Minor: These issues represent problems that are relatively small or difficult to take advantage of but can be exploited in combination with other issues. These kinds of issues do not block deployments in production environments. They should be taken into account and be fixed when possible

Issues Status

An issue detected by this audit can have four distinct statuses:

●Unresolved: The issue has not been resolved.
●Acknowledged: The issue remains in the code but is a result of an intentional decision.
●Resolved: Adjusted program implementation to eliminate the risk.
●Mitigated: Implemented actions to minimize the impact or likelihood of the risk.

Critical Severity Issues

CR-01 Unfair Lotteries through Weak Randomness

Location:

●clarity/contracts/pool/alex-launchpad.clar

Users can validate their tickets during the registration process, delimited by the variables registration-start and registration-end. A counter is increased for each ticket validated, and each user has a range of positions related to when they joined the lottery and the amount of tickets validated. When the registration ends and the minimum amount of participants is reached, users can call claim() one time for each ticket validated.

This function determines if the ticket is a winner based on a pseudo-random number modulo the counter of tickets. If the resulting value is in the range of positions of tickets validated by the user, then it is a winner ticket.

However, the first pseudo-random number is generated based on the vrf-seed of registration-start block in the first call to claim(). For the subsequent calls, the function calculates a new pseudo-random based on the latest random.
Therefore, since the contract is public and the process transparent, anyone can calculate the sequence of values to be generated. Users can speculate with which position is the most convenient to register themselves and when to claim based on the following number in the sequence.

Recommendation

The speculation in the registration can be solved using the VRF seed of the block next to the end of the registration (registration-end + 1) as randomness source.
Finally, the speculation in the claiming order can be solved computing the
pseudo-random number with the mentioned VRF seed and a value unique for each ticket (e.g., the ticket’s position). Then, using two constant values, the claiming order will not have an impact because the random number is already determined.

Status

Acknowledged. claim() now uses registration-end instead of
registration-start for the VRF seed. The speculation was reduced, but it still uses a seed that can be known if register() is called at registration-end. Using the block next to registration-end can solve the problem.
The new changes also made the entire random sequence unpredictable. However, the next random still can be predicted and the user might check if this random is beneficial and wait for the next random if not. In order to avoid the speculation in the claiming order, the number should be generated with either an input unknown for the user or constant values. The first solution makes the next random unpredictable for the user, while the second one makes it constant.

Medium Severity Issues

ME-01 Insecure Authentication through tx-sender

Location:

●clarity/contracts/alex-vault.clar,
●clarity/contracts/pool/alex-launchpad.clar,
●clarity/contracts/pool/alex-reserve-pool.clar

Global variable tx-sender returns the original sender of the current transaction, or if as-contract was called to modify the sending context, it returns that contract principal. Using this variable for authentication is not secure. Actors in the system could be targets of phishing. This is analogous to what happens to tx.origin and msg.sender in Solidity. There, the convention is to use msg.sender, which works like the contract-caller.
For instance, the vault’s owner can be tricked into calling a malicious contract which executes vault.set-contract-owner() against his will.

Recommendation

Prefer contract-caller to tx-sender for authentication. contract-caller
returns the caller of the current contract context.

Status

Acknowledged. A new development would address this issue.

ME-02 Independent Winning Probability in Lottery

Location:

●clarity/contracts/pool/alex-launchpad.clar

As it was described in CR-01, each claim() execution generates a new random number. Therefore, while there are tokens to transfer, the winning probability is independent and the amount of winners is unknown. In order to solve it, the function checks if all the tickets provided were won before executing the rest of the function. When all the winner tickets are determined, the listing is completed and new claims are not accepted. This mechanism may result in two issues.

Firstly, some tokens might not be claimed if there are not enough winner tickets. Furthermore, there is no use given to this remainder tokens.

Secondly, it generates a race condition between the users to claim before the listing is completed. Otherwise, a user will not be able to claim
even when he has tickets.

Recommendation

A solution would be to generate only n random numbers, where n is the number of winning tickets. Then, claim() would check if one of the random numbers were in the user’s range of tickets. However, due to Clarity limitations, this solution cannot be implemented.

Status

Acknowledged.

Minor Severity Issues

MI-01 Arithmetic Underflow Calculating Staking Reward

Location:

●clarity/contracts/pool/alex-reserve-pool.clar:[379]

In get-entitled-staking-reward(), the rewards are calculated with the quotient between the amount staked by the user and the total amount staked, multiplied by the token’s coinbase amount.

Quotient’s result may have a higher imprecision than the result obtained by
multiplying first and then dividing it by the total staked.

Recommendation:

For a more precise result, get the product between the coinbase amount and the amount staked by the user, and divide it by the total amount staked:

Status

Resolved.

MI-02 Ended Pool can be Created

Location:

●clarity/contracts/pool/alex-launchpad.clar

Pool creation function (create-pool()) does not validate the block numbers provided for the registration-start and registration-end variables. Therefore, a pool can be created without time for registration.

Recommendation

The input registration-start should be checked to be equal or greater than the current block number.

Status

Resolved.

Enhancements

These items do not represent a security risk. They are best practices that we
suggest implementing.

Table

Details

EN-01 Missing Source Code Comments

Location:

●clarity/contracts/pool/alex-launchpad.clar

The launchpad contract lacks of function documentation in the source code.
Comments documenting a function helps the contract reader to understand better the usage of that piece of code.

Status

Not implemented. The development team committed to add the documentation.

EN-02 Unnecessary Computation to Check if the Listing Is Activated

Location:

●clarity/contracts/pool/alex-launchpad.clar

The listing mapping contains a variable named activated that is initially set to false when the pool is created and then increased for each new register. The register() function updates the value to true if the amount of tickets validated (total-subscribed) reached the activation-threshold.

There is no other function that updates the total-subscribed value nor the activated value. However, the getter function is-listing-activated() computes again the comparison between the two variables instead of reading from the activated variable.

Recommendation:

Read from the activated variable instead of performing the comparison again.

Status

Implemented.

Changelog

●2022-01-07 – Initial report based on commit
44c44846bfbcce6096be04bd1380728c98f09ec8.
●2022-01-11 – Reaudit report based on the fixes in commit
31a5d660c83d41c10cd1b34498f02bc3a407721e.
●2022-01-13 – CR-01 state changed to “acknowledged”.

Disclaimer: This audit report is not a security warranty, investment advice, or an approval of the AlexGo project since CoinFabrik has not reviewed its platform. Moreover, it does not provide a smart contract code faultlessness guarantee.

EMDX – Protocol Audit

Reading Time: 4 minutes

Introduction CoinFabrik was asked to audit the contracts for the EMDX project. First, we will provide a summary of our discoveries and then we will show the details of our findings. Summary The contracts audited are from the EMDX repository at https://github.com/emdx-dex/perpetual-protocol/. The audit is based on the commit ca34a5e9e254caca5056ab5002a3fdb0b4f3b004.Fixes were made and rechecked based […]

Avalaunch Audit <> Allocation Staking and Cooldown feature

Introduction

CoinFabrik was asked to audit the contracts for the Avalaunch AllocationStaking project. First we will provide a summary of our discoveries and then we will show the details of our findings.

Summary

The contracts audited are from the GitHub repository at
https://github.com/avalaunch-app/xava-protocol.

The audit is based on the commit fc32d84a67233ebba6f980182a951076858d30c0.

Contracts

The audited contracts are:

● contracts/AllocationStaking.sol
● contracts/sales/AvalaunchSale.sol
● contracts/sales/SalesFactory.sol

Analyses

The following analyses were performed:

● Misuse of the different call methods
● Integer overflow errors
● Division by zero errors
● Outdated version of Solidity compiler
● Front running attacks
● Reentrancy attacks
● Misuse of block timestamps
● Softlock denial of service attacks
● Functions with excessive gas cost
● Missing or misused function qualifiers
● Needlessly complex code and contract interactions
● Poor or nonexistent error handling
● Failure to use a withdrawal pattern
● Insufficient validation of the input parameters
● Incorrect handling of cryptographic signatures

Findings and Fixes

Severity Classification

Security risks are classified as follows:

Critical: These are issues that we manage to exploit. They compromise the system seriously. They must be fixed immediately.
Medium: These are potentially exploitable issues. Even though we did not
manage to exploit them or their impact is not clear, they might represent a
security risk in the near future. We suggest fixing them as soon as possible.
Minor: These issues represent problems that are relatively small or difficult to take advantage of but can be exploited in combination with other issues. These kinds of issues do not block deployments in production environments. They should be taken into account and be fixed when possible.
Enhancement: These kinds of findings do not represent a security risk. They are best practices that we suggest to implement.

This classification is summarized in the following table:

Issues Found by Severity

Critical Severity Issues

No issues found.

Medium Severity Issues

No issues found.

Minor Severity Issues

MI-01 Failure to Use safeMath Library

The functions fund() (line 120), totalPending() (line 196) and erc20Transfer() (line 412) make use of standard arithmetic which are susceptible to overflows and underflows.

Recommendation

Replace + by add() and – by sub().

Enhancements

EN-01 Unvalidated Input in Function and Constructor

The following are functions and constructors that fail to validate the input. In most cases, they are used to set parameters which may be changed later and the impact of setting a bad parameter is small.

  • The parameter _token in setSaleParams() is not checked to be non-null.
  • The input addresses _erc20 and _salesFactory in the AllocationStaking constructor are not checked to be non-null.

Conclusion

We found the contracts to be simple and straightforward and have an adequate amount of documentation. A minor vulnerability pointing to unsafe use of math was found in some functions with little security impact.

Disclaimer: This audit report is not a security warranty, investment advice, or an approval of the Avalaunch project since CoinFabrik has not reviewed its platform. Moreover, it does not provide a smart contract code faultlessness guarantee.

Alex Logo

AlexGo Audit

Introduction

CoinFabrik was asked to audit the contracts for the AlexGo project. First we will provide a summary of our discoveries and then we will show the details of our findings.

Summary

The contracts audited are from the alex-v1 repository at
https://github.com/alexgo-io/alex-v1. The audit is based on the commit
0913c9eb0c8f79b3cd0b843641075ce27d437c96. Fixes were made and rechecked based on the commit feb43898de520ca1c55a6d8bc5bcf2d6f7df8ffa.

Contracts

The audited contracts are:

● clarity/contracts/equations/weighted-equation.clar: Library for
weighted math functions.
● clarity/contracts/equations/yield-token-equation.clar: Library for
yield token math functions.
● clarity/contracts/pool/alex-reserve-pool.clar: Staking contract.
● clarity/contracts/pool/collateral-rebalancing-pool.clar: Lending
and borrowing pool contract with pools of variable weights.
● clarity/contracts/pool/fixed-weight-pool.clar: Contract with
fixed-weight liquidity pools.
● clarity/contracts/pool/liquidity-bootstrapping-pool.clar:
Contract with liquidity pools that increase bootstrapped token weight over
the time.
● clarity/contracts/pool/yield-token-pool.clar: Liquidity pools for
token and correspondent yield token pairs.

Analyses

The following analyses were performed:

● Misuse of the different call methods
● Integer overflow errors
● Division by zero errors
● Front running attacks
● Reentrancy attacks
● Misuse of block timestamps
● Softlock denial of service attacks
● Functions with excessive gas cost
● Missing or misused function qualifiers
● Needlessly complex code and contract interactions
● Poor or nonexistent error handling
● Failure to use a withdrawal pattern
● Insufficient validation of the input parameters
● Incorrect handling of cryptographic signatures

Findings and Fixes

Severity Classification

Security risks are classified as follows:

Critical: These are issues that we manage to exploit. They compromise the system seriously. They must be fixed immediately.
Medium: These are potentially exploitable issues. Even though we did not
manage to exploit them or their impact is not clear, they might represent a
security risk in the near future. We suggest fixing them as soon as possible.
Minor: These issues represent problems that are relatively small or difficult to take advantage of but can be exploited in combination with other issues. These kinds of issues do not block deployments in production environments. They should be taken into account and be fixed when possible.
Enhancement: These kinds of findings do not represent a security risk. They are best practices that we suggest to implement.

This classification is summarized in the following table:

Issues Found by Severity

Critical Severity Issues

CR-01 Pools Transfer More Tokens than Expected

The function add-to-position() in the contracts
liquidity-bootstrapping-pool.clar and fixed-weight-pool.clar receives as a parameter how many tokens the user would like to provide to the pool. In order to conform the pool balance, the function calculates the amount of tokens y to be provided based on the amount of token x. As a consequence, the actual value provided to the pool could be greater than the one specified by the user. The result would be the contract moving more tokens than the ones consented by the user.

Recommendation

The actual amount of token y to be provided to the pool should never be greater than the value defined by the user (dy). This could be done by adding an asserts! that compares those values.

Solution

Fixed according to the recommendation

CR-02 Lost Funds when Burning Yield Tokens

In a collateral rebalancing pool (collateral-rebalancing-pool.clar), liquidity providers get an amount of yield and key tokens equal to the provided liquidity multiplied by ltv (Loan-to-Value). When yield tokens are burnt calling reduce-position-yield(), the pool is completely rebalanced, swapping all the collateral. Then, for instance, if a user owns 100% of the pool value and burns all his yield tokens, the balance stored in the blockchain will be reduced to zero.
However, the user gets transferred only the exact amount of yield token burnt (balance * ltv). Since this does not represent the actual value provided, users will realize they lost funds when they try to burn their key tokens and receive zero tokens because the pool is empty.

Recommendation

Subtract from the pool balance the same amount transferred to the user.

Solution

Fixed according to the recommendation.

CR-03 Denial of Service when Burning Yield Tokens

In a collateral rebalancing pool (collateral-rebalancing-pool.clar), when yield tokens are burnt calling reduce-position-yield(), the pool is completely rebalanced, swapping all the collateral (i.e., it becomes a 0-100 pool). As a consequence, it becomes unusable for token swaps since either the input or output value will be greater than the zero-balance, causing the transaction to revert because of the assertions made in weighted-equation.clar. These assertions verify the value deposited to a pool in an A token is lower than that token’s balance multiplied by a ratio, and also the amount of B tokens given in exchange is lower than that token’s balance multiplied by a ratio.
Moreover, this Denial of Service would be most of the time unintentionally executed by the users and would persist until someone provides liquidity to the pool again, incrementing the zero-balance.

Solution

Swap functions can only be called before the expiration block.

Medium Severity Issues

ME-01 Denial of Service when Burning Key Tokens

In a collateral rebalancing pool (collateral-rebalancing-pool.clar), if all the key tokens were burnt and the reserve pool (alex-reserve-pool.clar) does not have tokens in its balance, users might not burn any amount of their yield tokens.
Since reduce-position-yield() swaps all the collateral, a new balance of the token is calculated based on the previous balance and the amount of tokens received after the swap. Then, the function calculates a variable
shares-to-yield which is equal to the amount of yield tokens the user wants to burn (shares) divided by its total supply (yield-supply). Afterwards, it calculates dy, the product of new-bal-y and shares-to-yield, and compares dy to shares.
Since the pool only has a value equal to the yield supply, it is swapped and fees are taken out, dy will be lower than shares. Therefore, in line 496, it calls alex-reserve-pool.remove-from-balance() to transfer the shortfall, but if alex-reserve-pool does not have tokens, it will revert.

Solution

Changes made to fix CR-02 solved this issue.

Minor Severity Issues

MI-01 Low Decimal Precision

Clarity integer types are stored in 128-bit storage slots. In order to represent the fractional part, a fixed point precision is used with 8 decimal for the fractional part and 30 for the whole part. However, this precision is low and can result in significant decimal errors in the long term.

Recommendation

Since the whole part is more than long enough, the precision could be increased to, for instance, 18 decimal places.

Solution

The development team is studying the implementation of a higher decimal
precision.

MI-02 Funds Taken because of Liquidity Pool Token Repetition

Whenever users provide liquidity to a pool, they receive liquidity pool tokens (LP tokens). If two pools were created with the same LP token, users could provide liquidity in one of those pools and withdraw funds from the other. Currently, only the contract owners can create pools and it is at their discretion.

Recommendation

Restrict LP token repetition, not only in each contract, but also across pool
contracts: fixed-weight-pool.clar, liquidity-bootstrapping-pool.clar, yield-token-pool.clar. These are the pools that share the same trait for the LP tokens.

Solution

The development team is considering maintaining a registry contract that is
updated every time a pool is created and checks if the principal address of the pool token passed is already in use.

MI-03 Swap Limit Setter not Restricted

Amounts swapped are limited in order not to be larger than a certain percentage of total balance (MAX-IN-RATIO and MAX-OUT-RATIO). These values are set initially to 30% in weighted-equation.clar and yield-token-equation.clar, but they can be modified without restriction. It can result in a denial of service if the value is too small.

Recommendation

Setters should check the new value is, at least, greater than zero with an asserts!.

Solution

Fixed according to the recommendation.

MI-04 Front-running after Pool Creation

Liquidity bootstrapping pools (liquidity-bootstrapping-pool.clar) are created with a default value for maximum and minimum prices for bootstrapped token (maximum is set to 10^8 and minimum to zero). They can be changed, but only calling the setter in another transaction. Since the pool creator must provide liquidity in the same transaction they created the pool, under certain market conditions, an attacker might find it profitable to execute a swap immediately after the pool creation and before the maximum and minimum are modified.

Recommendation

Add two parameters to create-pool() to assign initial values for price-x-min and price-x-max.

Solution

Fixed according to the recommendation.

MI-05 New Max Expiry in the Past

In yield-token-pool.clar, max-expiry is a variable essential to calculate the time to maturity. If this variable is lower or equal to the current block, most of the transactions will revert, causing a denial of service in that contract. Currently, its setter, set-max-expiry(), does not check if the new value is valid.

Recommendation

Add an asserts! to check new-max-expiry is greater than block-height before assigning it to max-expiry.

Solution

Fixed according to the recommendation.

Enhancements

EN-01 Unused Math Constants and Functions

Useful math functions and constants are copied in the contracts. However, they are not always used by the rest of the contract functions and make the deployment more expensive. For instance, in collateral-rebalancing-pool.clar, pow-up(), ONE_10, log-fixed() and ln-fixed() are not used.

Recommendation

Remove the functions that are not necessary for the contracts.

Other Considerations

  1. collateral-rebalancing-pool.clar uses an approximation for the error function (Abramowitz and Stegun) which has a high maximum error. The recommendation is to extensively test it to assure it does not have unexpected implications.
  2. In yield-token-pool contract, max-expiry value is based on a 15-second block time. AlexGo team explained it is set for the mocknet environment. It should be changed to 10 minutes when it is deployed to Stacks mainnet.

Conclusion

We found the contracts to be simple and straightforward and have an adequate amount of documentation, but not always up-to-date. Three critical, one medium and five minor severity issues were found. Additionally, an enhancement was proposed. The development team fixed seven issues and acknowledged two minor issues.

Disclaimer: This audit report is not a security warranty, investment advice, or an approval of the AlexGo project since CoinFabrik has not reviewed its platform. Moreover, it does not provide a smart contract code faultlessness guarantee.

EMDX – Token Contracts Audit

Reading Time: 3 minutes

Introduction CoinFabrik was asked to audit the contracts for the EMDX project. First, we will provide a summary of our discoveries and then we will show the details of our findings. Summary The contracts audited are from the EMDX repository at https://github.com/emdx-dex/token-contracts.git. The audit is based on the commit 2a376848d3d0a3604f8c6ca702fe4718019d1b3d. Fixes were made and rechecked […]

Bit2Me Token – Security Audit

Reading Time: 2 minutes

Introduction CoinFabrik was asked to audit the contracts for the Bit2Me project. First, we will provide a summary of our discoveries and then we will show the details of our findings. Summary The contracts audited are from the files delivered to us. We transcribe their hashes for later integrity checks: SHA-18255b832c12202390efbca9627abb5ac47060f03 Token.sol 8bb18db88c1c70bf7b20a83ef75ee99b04782e5f TokenManager.sol SHA-2563c9780e71238ca6233311cf382f006d18780c97841497dc2dc42ec180446de7a […]

Avalaunch Audit <>Allocation Staking and Sales

Reading Time: 4 minutes

Introduction CoinFabrik was asked to audit the contracts for the Avalaunch project. First we will provide a summary of our discoveries and then we will show the details of our findings. Summary The contracts audited are from the Github repository athttps://github.com/avalaunch-app/xava-protocol/. The audit is based on the commit fd252f8b9b0283d245d9d561130fe789ff08dfe9. Next, developers fixed issues and we […]

Known Origin Digital Asset Audit

Reading Time: 7 minutes

Introduction CoinFabrik was asked to audit the contracts for the Known Origin Digital Asset v3 project. First we will provide a summary of our discoveries and then we will show the details of our findings. Summary The contracts audited are from the Known Origin Next Generation Project repository at this link(https://github.com/knownorigin/known-origin-contracts-next-gen). The audit started based […]

BLOX STAKING Audit: Vesting and DEX Contracts

Reading Time: 2 minutes

Introduction CoinFabrik was asked to audit the contracts for the Vesting for Blox Staking. First we will provide a summary of our discoveries and then we will show the details of our findings. Summary The contracts audited are from the Github repository athttps://github.com/bloxapp/ssv-network. The audit is based on the commit95a79e44bbeb35b8c6a2bbd20e47762a4bb0dd11, fixes were applied and thecommit […]

Woonkly Security Audit (DEX & STAKE)

Reading Time: 6 minutes

Introduction CoinFabrik was asked to audit the contracts for the Woonkly project. First we will provide a summary of our discoveries and then we will show the details of our findings. Summary The contracts audited are from the STAKESmartContractPreRelease repository and DEXsmartcontractsPreRelease repository at GitHub. The audit is based on the commit 779522de8afcf9285d660abdcc0fb10a62f6f659, and 49777cd67d0227c21437236ab9f42b501a864895 […]