Coins: 13,980
Exchanges: 1,057
Market Cap: $2.497T 0.6%
24h Vol: $69.396B
Gas: 9 GWEI
Go Ad-free
Guides
TABLE OF CONTENTS

Understanding Risk of Rebase Tokens Through Smart Contract Analysis

5.0 | by Johnson Lai

In this article, I will dig into the smart contracts of a few projects with such functionalities in order to understand how the rebase function in Solidity smart contract works, as well as some of the potential risks of these projects. 4 tokens - Ampleforth (AMPL), Antiample (XAMP), Tokens of Babel (TOB) and RMPL (RMPL) will be the subject of interest for this research.

Ampleforth (AMPL)

Ampleforth is first token that started it all and made rebase popular enough that new tokens are now copying and innovating on top of it.

Let's take a look in the Smart Contract of Ampleforth.

AMPL Contract: https://etherscan.io/address/0xd46ba6d942050d489dbd938a2c909a5d5039a161#code

Since the contract is a proxy, the real contract is here: https://etherscan.io/address/0xf9e6a96229140195777a1c3ab47c9bf16f055406#code

/**
 * @dev Notifies Fragments contract about a new rebase cycle.
 * @param supplyDelta The number of new fragment tokens to add into circulation via expansion.
 * @return The total number of fragments after the supply adjustment.
 */
function rebase(uint256 epoch, int256 supplyDelta)
    external
    onlyMonetaryPolicy
    returns (uint256)
{
    if (supplyDelta == 0) {
        emit LogRebase(epoch, _totalSupply);
        return _totalSupply;
    }

    if (supplyDelta < 0) {
        _totalSupply = _totalSupply.sub(uint256(supplyDelta.abs()));
    } else {
        _totalSupply = _totalSupply.add(uint256(supplyDelta));
    }

    if (_totalSupply > MAX_SUPPLY) {
        _totalSupply = MAX_SUPPLY;
    }

    _gonsPerFragment = TOTAL_GONS.div(_totalSupply);

    // From this point forward, _gonsPerFragment is taken as the source of truth.
    // We recalculate a new _totalSupply to be in agreement with the _gonsPerFragment
    // conversion rate.
    // This means our applied supplyDelta can deviate from the requested supplyDelta,
    // but this deviation is guaranteed to be < (_totalSupply^2)/(TOTAL_GONS - _totalSupply).
    //
    // In the case of _totalSupply <= MAX_UINT128 (our current supply cap), this
    // deviation is guaranteed to be < 1, so we can omit this step. If the supply cap is
    // ever increased, it must be re-included.
    // _totalSupply = TOTAL_GONS.div(_gonsPerFragment)

    emit LogRebase(epoch, _totalSupply);
    return _totalSupply;
}

How rebase works?

Basically, Ampleforth's smart contract changes the code of balanceOf method. They just need to make a contract call to rebase in order to change the total ownership that you have in the token. In this case, to call the rebase method, all you need is just epoch which is date time for logging and supplyDelta which is to add or remove supply of the token.

As you can see onlyMonetaryPolicy role can call this rebase function.

// Used for authentication
address public monetaryPolicy;
/**
 * @param monetaryPolicy_ The address of the monetary policy contract to use for authentication.
 */
modifier onlyMonetaryPolicy() {
    require(msg.sender == monetaryPolicy);
    _;
}

In the contract data, it seems like the address is set to 0x0 which is not the case when you use readAsProxy feature on Etherscan on the main proxy contract.

https://etherscan.io/address/0xd46ba6d942050d489dbd938a2c909a5d5039a161#readProxyContract


So the monetoryPolicy address is set to https://etherscan.io/address/0x1b228a749077b8e307c5856ce62ef35d96dca2ea where in this case, it is an oracle smart contract called Rebaser.

By using an oracle like Chainlink, Ampleforth can create a trustless manner of rebasing. This article does not cover the part of oracle code.

AntiAmple (XAMP)

The AntiAmple token also rebases, but it only allow burning of the supply.

XAMP contract: https://etherscan.io/address/0xf911a7ec46a2c6fa49193212fe4a2a9b95851c27#code

function rebase(uint256 epoch, uint256 supplyDelta)
    external
    onlyOwner
    returns (uint256)
{
    if (supplyDelta == 0) {
        emit LogRebase(epoch, _totalSupply);
        return _totalSupply;
    }

     _totalSupply = _totalSupply.sub(supplyDelta);

    
    if (_totalSupply > MAX_SUPPLY) {
        _totalSupply = MAX_SUPPLY;
    }

    _gonsPerFragment = TOTAL_GONS.div(_totalSupply);

    emit LogRebase(epoch, _totalSupply);
    return _totalSupply;
}

For AntiAmple, the rebase part of the code is almost similar as Ampleforth's rebase.

How it works is that, it only has negative rebase. The line _totalSupply = _totalSupply.sub(supplyDelta); shows that the supplyDelta is an unsigned integer, the total supply can only be reduce, never increase.

This rebase method is accessible via a modifier called onlyOwner.

address public _owner;

modifier onlyOwner() {
    require(_owner == msg.sender, "Ownable: caller is not the owner");
    _;
}

If you read the contract https://etherscan.io/address/0xf911a7ec46a2c6fa49193212fe4a2a9b95851c27#readContract

The contract owner is actually a Rebaser Oracle also https://etherscan.io/address/0x8ceb211a7567cf399e1ee01e6974bf4a13b64c04

Tokens of Babel (TOB)

Tokens of Babel was also created by the Antiample team.

Contract Code: https://etherscan.io/address/0x7777770f8a6632ff043c8833310e245eba9209e6#code

function rebase(uint256 epoch, uint256 supplyDelta)
    external
    onlyOwner
    returns (uint256)
{
    if (supplyDelta == 0) {
        emit LogRebase(epoch, _totalSupply);
        return _totalSupply;
    }

     _totalSupply = _totalSupply.sub(supplyDelta);

    
    if (_totalSupply > MAX_SUPPLY) {
        _totalSupply = MAX_SUPPLY;
    }

    _gonsPerFragment = TOTAL_GONS.div(_totalSupply);

    emit LogRebase(epoch, _totalSupply);
    return _totalSupply;
}

The code is similar to AntiAmple, similar onlyOwner modifier, but here's a small difference.

At the point of writing, when you check the owner of the contract, it is actually still owned by the owner. https://etherscan.io/address/0xe41e5fa65d197afa059edce5225c1da2a01a361c

I asked in TOB telegram group about this issue.

Well, it make sense that building the oracle with logic require a lot of testing and development time, so in order to ship it first, it used an offchain mechanism (maybe a script) to do a rebase.

Refer to end of the article, where I share the possible vulnerability of off-chain Owner key.

RMPL

RMPL is a random rebase version of Ampleforth.

Contract address: https://etherscan.io/address/0xe17f017475a709de58e976081eb916081ff4c9d5#code

struct Transaction {
        bool enabled;
        address destination;
        bytes data;
    }

/**
 * @dev Notifies Fragments contract about a new rebase cycle.
 * @param supplyDelta The number of new fragment tokens to add into circulation via expansion.
 * @return The total number of fragments after the supply adjustment.
 */
function rebase(int256 supplyDelta)
    external
    onlyOwner
    returns (uint256)
{

	_epoch = _epoch.add(1);

  if (supplyDelta == 0) {
      emit LogRebase(_epoch, _totalSupply);
      return _totalSupply;
  }

  if (supplyDelta < 0) {
      _totalSupply = _totalSupply.sub(uint256(supplyDelta.abs()));
  } else {
      _totalSupply = _totalSupply.add(uint256(supplyDelta));
  }

  if (_totalSupply > MAX_SUPPLY) {
      _totalSupply = MAX_SUPPLY;
  }

  _gonsPerFragment = TOTAL_GONS.div(_totalSupply);

	// From this point forward, _gonsPerFragment is taken as the source of truth.
  // We recalculate a new _totalSupply to be in agreement with the _gonsPerFragment
  // conversion rate.
  // This means our applied supplyDelta can deviate from the requested supplyDelta,
  // but this deviation is guaranteed to be < (_totalSupply^2)/(TOTAL_GONS - _totalSupply).
  //
  // In the case of _totalSupply <= MAX_UINT128 (our current supply cap), this
  // deviation is guaranteed to be < 1, so we can omit this step. If the supply cap is
  // ever increased, it must be re-included.
  // _totalSupply = TOTAL_GONS.div(_gonsPerFragment)

	emit LogRebase(_epoch, _totalSupply);

	for (uint i = 0; i < transactions.length; i++) {
      Transaction storage t = transactions[i];
      if (t.enabled) {
          bool result = externalCall(t.destination, t.data);
          if (!result) {
              emit TransactionFailed(t.destination, i, t.data);
              revert("Transaction Failed");
          }
      }
    }

    return _totalSupply;
}

The code is similar to Ampleforth, and they implemented onlyOwner modifier

address private _owner;

modifier onlyOwner() {
  require(isOwner());
  _;
}

function isOwner() public view returns(bool) {
  return msg.sender == _owner;
}

According to their RMPL roadmap

Once onchain random rebasing solution has been finalized, contract owner will be locked to ensure no party has control and the implementation is completely self governed.

Similar to TOB, Currently the rebase function are still being triggered off chain.

Owner key address: https://etherscan.io/address/0xd91cf98fdfc0f38c5b7c87510a414636fd3890b0

 

Final Thoughts

AntiAmple and Ampleforth had a rebase mechanism using an Oracle. Since the analysis of Oracle is out of scope of today's article, we will be focusing on the rebase function

At the moment of writing, Holding TOB and RMPL will exposed risk to the Owner key, where the owner key can call rebase with any amount of supplyDelta. So instead of using an on-chain oracle to get the price, they use offchain method and update the contract via owner key.

Why is this important?

If this part of the owner address is not executed by a smart contract oracle (which can be verified), the owner address have the power to provide supplyDelta value in whatever parameters that owner wants.

What would happen?

The owner can hold a certain amount of TOB, and then provide an arbitrary high value of supplyDelta to the rebase function. And then, with that the owner can dump the token in the next block.

So until the Owner key is changed to Oracle based, this rebase method are exposed to the risk.

At CoinGecko, we wanted inform all our users regarding on this kind of risk when investing to the coin. That is why we added a notice for these coin that are exposed to the risk of offchain rebase.

CoinGecko's Content Editorial Guidelines
CoinGecko’s content aims to demystify the crypto industry. While certain posts you see may be sponsored, we strive to uphold the highest standards of editorial quality and integrity, and do not publish any content that has not been vetted by our editors.
Learn more
Tell us how much you like this article!
Vote count: 3
Johnson Lai
Johnson Lai

Software Engineer at CoinGecko. In his free time, Johnson works on side projects around blockchain, mobile app, web and electronics. Follow the author on Twitter @jlwhoo7

More Articles


Explore Polkadot's Ecosystem
Discover trending dApps, wallets, DeFi & more

What is Zeebu?
Learn more about the Web3 neobank


coingecko
Continue in app
Track prices in real-time
Open App
Select Currency
Suggested Currencies
USD
US Dollar
IDR
Indonesian Rupiah
TWD
New Taiwan Dollar
EUR
Euro
KRW
South Korean Won
JPY
Japanese Yen
RUB
Russian Ruble
CNY
Chinese Yuan
Fiat Currencies
AED
United Arab Emirates Dirham
ARS
Argentine Peso
AUD
Australian Dollar
BDT
Bangladeshi Taka
BHD
Bahraini Dinar
BMD
Bermudian Dollar
BRL
Brazil Real
CAD
Canadian Dollar
CHF
Swiss Franc
CLP
Chilean Peso
CZK
Czech Koruna
DKK
Danish Krone
GBP
British Pound Sterling
GEL
Georgian Lari
HKD
Hong Kong Dollar
HUF
Hungarian Forint
ILS
Israeli New Shekel
INR
Indian Rupee
KWD
Kuwaiti Dinar
LKR
Sri Lankan Rupee
MMK
Burmese Kyat
MXN
Mexican Peso
MYR
Malaysian Ringgit
NGN
Nigerian Naira
NOK
Norwegian Krone
NZD
New Zealand Dollar
PHP
Philippine Peso
PKR
Pakistani Rupee
PLN
Polish Zloty
SAR
Saudi Riyal
SEK
Swedish Krona
SGD
Singapore Dollar
THB
Thai Baht
TRY
Turkish Lira
UAH
Ukrainian hryvnia
VEF
Venezuelan bolívar fuerte
VND
Vietnamese đồng
ZAR
South African Rand
XDR
IMF Special Drawing Rights
Cryptocurrencies
BTC
Bitcoin
ETH
Ether
LTC
Litecoin
BCH
Bitcoin Cash
BNB
Binance Coin
EOS
EOS
XRP
XRP
XLM
Lumens
LINK
Chainlink
DOT
Polkadot
YFI
Yearn.finance
Bitcoin Units
BITS
Bits
SATS
Satoshi
Commodities
XAG
Silver - Troy Ounce
XAU
Gold - Troy Ounce
Select Language
Popular Languages
EN
English
RU
Русский
DE
Deutsch
PL
język polski
ES
Español
VI
Tiếng việt
FR
Français
PT
Português
All Languages
AR
العربية
BG
български
CS
čeština
DA
dansk
EL
Ελληνικά
FI
suomen kieli
HE
עִבְרִית
HI
हिंदी
HR
hrvatski
HU
Magyar nyelv
ID
Bahasa Indonesia
IT
Italiano
JA
日本語
KO
한국어
LT
lietuvių kalba
NL
Nederlands
NO
norsk
RO
Limba română
SK
slovenský jazyk
SL
slovenski jezik
SV
Svenska
TH
ภาษาไทย
TR
Türkçe
UK
украї́нська мо́ва
ZH
简体中文
ZH-TW
繁體中文
Login to track your favorite coin easily 🚀
By continuing, you agree to CoinGecko Terms of Service and acknowledge you’ve read our Privacy Policy
or
Forgot your password?
Didn't receive confirmation instructions?
Resend confirmation instructions
IT'S FREE! Track your favorite coin easily with CoinGecko 🚀
By continuing, you agree to CoinGecko Terms of Service and acknowledge you’ve read our Privacy Policy
or
Password must contain at least 8 characters including 1 uppercase letter, 1 lowercase letter, 1 number, and 1 special character
Didn't receive confirmation instructions?
Resend confirmation instructions
Forgot your password?
You will receive an email with instructions on how to reset your password in a few minutes.
Resend confirmation instructions
You will receive an email with instructions for how to confirm your email address in a few minutes.
Get the CoinGecko app.
Scan this QR code to download the app now App QR Code Or check it out in the app stores