Geist Protocol is a new decentralized liquidity markets protocol where users are in control of their funds while participating in the market.

We reviewed Geist Protocol’s Staking and Protocol folders at commit afa51f3018a4642f7d876996a4e6690cc22da7bf on the team’s private GitHub repository.

Audit Findings Summary

  • No external threats were identified.
  • Ensure trust in the team as they have substantial control in the ecosystem. The team can upgrade many of the platform’s contracts at any time.
  • Date: October 22nd, 2021

Notes on Individual Contracts:
AToken Contract:

  • aTokens are interest bearing tokens that correspond to an underlying asset. For example an aWETH aToken would correspond to WETH.
  • aTokens are minted to the user when they deposit the underlying asset into a Lending Pool.
  • When withdrawing from the Lending Pool, the tokens are burned and the corresponding asset is returned to the user.
  • When tokens are minted, burned, or transferred, rewards are minted as Staking Tokens in a MultiFeeDistribution contract. The amount of rewards earned is dependent on the amount of tokens and the time since rewards were last earned.
  • This contract complies with the ERC-20 standard.
  • Other than the ERC20 and EIP2612 functions, all functions that affect the state of the token can only be called by the Lending Pool.

StableDebtToken Contract:

  • StableDebtTokens are created when a user borrows from the Lending Pool.
  • As the name suggests, StableDebtTokens represent a borrowing position that has a stable interest rate.
  • Tokens are minted when the borrower takes the position, and burned when they repay their position.
  • When tokens are minted or burned, rewards are minted as Staking Tokens in a MultiFeeDistribution contract. The amount of rewards earned is dependent on the amount of tokens and the time since rewards were last earned.
  • These tokens are modeled after the ERC20 standard, but do not fully implement the standard. As debt is non-transferable, there are no transfer functions for StableDebtTokens.
  • Similar to the aToken, all non-ERC20 public functions that affect state are only able to be called by the Lending Pool.

VariableDebtToken Contract:

  • VariableDebtTokens are created when a user borrows from the Lending Pool.
  • As the name suggests, VariableDebtTokens represent a borrowing position that has a variable interest rate.
  • The variable interest rate is constantly changing based on the Utilization rate. The utilization rate is a measure of the liquidity of the corresponding asset existing in the Lending Pool.
  • Tokens are minted when the borrower takes the position, and burned when they repay their position.
  • When tokens are minted or burned, rewards are minted as Staking Tokens in a MultiFeeDistribution contract. The amount of rewards earned is dependent on the amount of tokens and the time since rewards were last earned.
  • These tokens are modeled after the ERC20 standard, but do not fully implement the standard.
  • As debt is non-transferable, there are no transfer functions for VariableDebtTokens.
  • Similar to the aToken, all non-ERC20 public functions that affect state are only able to be called by the Lending Pool.

ChefIncentivesController Contract:

  • This contract is used to provide rewards for IncentivizedERC20 token holders.
  • It is configured in the LendingPoolConfigurator contract.
  • Users are able to claim rewards which are minted in the MultiFeeDistribution contract and locked for a specified time; these earned rewards can be withdrawn before the lock time with a penalty.
  • Reward rates are variable and set by the owner on deployment. Each reward period may have a different rewards emission rate.
  • Rewards are determined based on the time elapsed, how many allocation points are given to the pool, and the user’s token balance.
  • The owner can start the rewards and set the start time only once after the contract is deployed.
  • The owner can change the allocation points for the token pools at any time.
  • The owner can change the receiver of rewards for any user at any time.

GeistToken Contract:

  • The GeistToken contract is deployed on FTMScan at 0xd8321aa83fb0a4ecd6348d4577431310a6e0814d
  • At the time of writing this report, 83.78% of the total $GEIST supply is held in the MultiFeeDistribution (Geist Staking) contract.
  • 14.39% of the total supply is stored in a UniswapV2Pair contract as liquidity.
  • Geist.Finance Protocol Token is a token which follows the ERC20 standard.
  • On deployment, a max total supply is defined and cannot be changed.
  • A minter address, which can be set only once, has the ability to mint tokens to any address as long as it does not result in the total supply exceeding the max total supply.
  • There are no burning functionalities present, however a user can send their tokens to any burn address to reduce circulating supply, if desired.

TokenVesting Contract:

  • This contract takes a list of recipients and amounts and unlocks these amounts in a MultiFeeDistribution contract over time.
  • User amounts vest linearly over the span of 1 year from deployment. For example, if 10% of a year has passed, 10% of funds will be available to claim.
  • When funds are claimed in this contract, they are minted as unlocked tokens for the user in the MultiFeeDistribution contract.

MultiFeeDistribution Contract:

  • This contract allows users to stake tokens to earn rewards in various tokens.
  • Users must deposit staking tokens with a lock in order to earn rewards in the same staking tokens. Tokens that are locked may not be withdrawn until the locked period is over. Unlocked tokens do not earn rewards in staking tokens, but will still accrue other rewards.
  • The lock duration is 13 weeks and cannot be changed.
  • Earned rewards are able to be withdrawn with a penalty before the lock duration is over.
  • Users are able to withdraw unlocked tokens and rewards at anytime.
  • The owner is able to set valid addresses for minters only once.
  • The owner is able to add a token as a reward at anytime.
  • The owner is able to withdraw any non-staking and non-rewards token in the contract at any time.
  • The team must exercise caution that the Staking Token used is not fee-on-transfer.

MasterChef Contract:

  • Users can stake designated tokens in the contract to earn rewards.
  • Rewards are determined based on the time elapsed, how many allocation points are given to the pool, and how much the user has staked.
  • Reward rates are variable and set by the owner on deployment. Each reward period may have a different rewards emission rate.
  • Users are able to designate where their rewards are sent.
  • Staking tokens are minted as rewards in an external MultiFeeDistribution contract as long as they do not exceed the max total amount that can be minted.
  • Minted rewards are locked at a time set in the MultiFeeDistribution contract. They can be withdrawn before the lock time at a penalty.
  • Rewards are claimed when both depositing and withdrawing. Users can also call the claim function to get rewards without a deposit or withdrawal.
  • There is also the option to emergency withdraw which will send the user all of their deposited tokens without claiming any rewards.
  • The owner can choose to start the rewards only once after the contract is deployed.
  • The owner can add a new pool to the contract at any time. The team must exercise caution when adding tokens to avoid fee-on-transfer and ERC777-compliant tokens.
  • The owner can change the allocation points for the token pools at any time.
  • The owner can change the receiver of rewards for any user at any time.

MerkleDistributor Contract:

  • The owner of this contract has the ability to create Claim Records with custom durations and amounts. A recipient is not specified.
  • The duration must be at least 1 week, and cannot be modified after the Claim Record is created.
  • Any user can redeem a Claim Record until its specified duration has passed.
  • When a user makes a claim, the amount claimed is minted and locked in the MultiFeeDistribution contract.
  • The total amount of claimable tokens cannot exceed the maximum claimable amount, which decreases over the course of a year to a base amount.
  • Claim Record data is secured and verified through the implementation of a Merkle Tree.

LendingPool Contract:

  • Users are able to deposit various supported tokens into this contract.
  • Upon depositing, aTokens corresponding to the token are minted to the user. When withdrawing, these aTokens are burned.
  • Users can also deposit and withdraw on behalf of another address, if desired. This means that aTokens can be minted to a different address upon deposit, and a different address can receive withdrawn funds.
  • A user can borrow an amount of an asset from its reserve, provided that the user has deposited enough funds to be used as collateral.
  • Users must manually set their funds to be used as collateral before borrowing. The collateralized loans are then locked and cannot be withdrawn.
  • When borrowing, users either choose to use a stable or variable interest rate model, where corresponding StableDebtTokens or VariableDebtTokens will be minted to the borrower to track debt.
  • Users can swap between interest rate models at any time.
  • Funds have no deadline to be paid back, however more interest will be accrued as time passes. This can lead to a decrease in the loan’s health factor, which is based on the liquidation threshold and the value of the borrowed assets.
  • If the health factor drops below a certain threshold, another user can pay a portion of the funds borrowed and receive a portion of the collateral plus an additional percentage of the collateral as a bonus.
  • The user performing the liquidation can select to receive the collateral aTokens or the actual underlying asset back.
  • The health factor can be increased by either repaying borrowed funds or by depositing futher collateral.
  • Users can specify a different address to receive debt, provided they have been given a credit delegation allowance. StableDebtTokens/VariableDebtTokens are then minted and burned to or from this different address.
  • The owner of the LendingPoolAddressProvider contract can update this contract’s LendingPoolCollateralManager address at any time.
  • This contract also implements flashloan functionality, where anyone can borrow the all of the assets in any liquidity pool, as long as they are returned within the transaction. A premium of up to .09% of each pool used in the flash loan is charged as a fee.
  • When depositing, borrowing, or taking out a flashloan, users are able to specify a referral address.
  • A Price Oracle contract is used to calculate price data, and can be changed at any time by the Pool Admin of the LendingPoolAddressProvider address.
  • The Lending Pool Configurator of the LendingPoolAddressesProvider contract has the ability to add new assets at any time, as long as the number of assets does not exceed 128.
  • The owner of the LendingPoolAddressProvider contract has the ability to update the LendingPool contract implementation at any time.

LendingPoolConfigurator Contract:

  • A Pool Admin, defined in the LendingPoolAddressesProvider contract, has power to make various configuration updates to the lending pools through this contract.
  • An Emergency Admin, also defined in the LendingPoolAddressesProvider contract, has the ability to pause all transactions through this contract.
  • The Pool Admin and Emergency Admin roles can be changed at any time by the owner of the LendingPoolAddressesProvider contract.
  • A Pool Admin has the ability to make any of the following changes at any time:
    • Update the implementation of any aToken.
    • Update the implementation of the StableDebtToken or VariableDebtToken.
    • Allow or disallow any kind of borrowing on any reserve.
    • Configure the loan to value ratio of an asset used as collateral.
    • Update the bonus percentage earned when liquidating an asset.
    • Update an asset’s health factor threshold to enable liquidations.
    • Activate or deactivate any reserve.
    • Freeze or unfreeze any reserve, disallowing/allowing deposits, borrows, and rate swaps.
    • Change a reserve’s strategy contract used to generate interest.
    • Update the reserve factor of an asset, which is the factor of how much of an asset is stored in a separate contract as reserve.

General notes across all contracts:

  • All contracts implements SafeMath to prevent overflows.
  • This platform implements ReentrancyGuard where applicable.
  • The platform’s core protocol contracts are based on Aave Protocol V2.

EXTERNAL THREATS – AUDIT RESULTS

Vulnerability Category Notes Result
Arbitrary Storage Write N/A PASS
Arbitrary Jump N/A PASS
Delegate Call to Untrusted Contract N/A PASS
Dependence on Predictable Variables N/A PASS
Deprecated Opcodes N/A PASS
Ether Thief N/A PASS
Exceptions N/A PASS
External Calls N/A PASS
Flash Loans N/A PASS
Integer Over/Underflow N/A PASS
Multiple Sends N/A PASS
Oracles N/A PASS
Suicide N/A PASS
State Change External Calls N/A PASS
Unchecked Retval N/A PASS
User Supplied Assertion N/A PASS
Critical Solidity Compiler N/A PASS
Overall Contract Safety PASS

CONTRACT SOURCE SUMMARY AND VISUALIZATIONS

 

Name




Address/Source Code


AToken









GitHub







StableDebtToken









GitHub







VariableDebtToken









GitHub







GeistToken









FTM Mainnet







ChefIncentives Controller









GitHub







TokenVesting>





MultiFeeDistribution>





MasterChef>





MerkleDistributor>





LendingPool









GitHub







LendingPoolCollateralManager









GitHub







LendingPoolConfigurator









GitHub







LendingPoolAddressesProvider









GitHub







LendingPoolAddressesProviderRegistry









FTM Mainnet