Technical: Implementation of the Rebase Operation

This post aims to explain how Ampleforth’s rebase operation is implemented. While the whitepaper provides an overview of the different components involved, it misses some implementation details.

I hope the post helps community members to gain a better understanding of the underlying details. Please comment if things are unclear, missing, or faulty.

The Rebase Operation

The rebase operation is an atomically executed adjustment to AMPL’s supply and user balances according to a discretional rule set.

Overview

1. A User initiates the Rebase Operation

To initiate the rebase a user needs to call the rebase function in the Orchestrator contract. The intention behind the Orchestrator is to coordinate AMPL’s supply change with external contracts. This becomes important later in step 7.

It is also worth mentioning that the Orchestrator’s rebase function fails if its called by a contract, meaning only EOAs (Externally Owned Contracts) can initiate a rebase. This makes it harder to atomically sandwich-trade AMPL’s supply adjustment.

2. The Orchestrator calls the MonetaryPolicy’s rebase function

Ampleforth’s monetary policy is rules-based, i.e. supply adjustments are done algorithmically. These rules are implemented inside the MonetaryPolicy contract.

The first rule enforced is that the rebase is only allowed to happen once during a reoccurring time window. Currently, the time window is set to 20 minutes and opens every 24 hours.

3. The MonetaryPolicy fetches the Target and Market Rate from the Oracles

In order to compute AMPL’s supply delta, the policy needs to know AMPL’s current target and market rate. These values are fetched from two different instances of the same MedianOracle contract.

A MedianOracle is a contract in which a set of authorized providers are allowed to push reports. Each report becomes only valid after some time passed (the reportDelaySec) and invalid again after some more time (the reportExpirationTimeSec).

Upon request, the MedianOracle returns the median of the averages of valid reports for each provider.

Currently, the value pushed to the MedianOracle the MonetaryPolicy queries as the target rate is the 2019 CPI value. For the market rate MedianOracle, AMPL’s VWAP (Volume Weighted Average Price) of the last 24 hours is pushed by the providers.

For more info about the oracle’s providers, see for example this discussion.

4. The MonetaryPolicy computes AMPL’s supplyDelta

Having AMPL’s target and market rate, the MonetaryPolicy computes how much AMPL’s supply has to change. This supplyDelta can be either positive (expansion) or negative (contraction).

For more info about the mathematical details, see the AIP-5 discussion.

5. The MonetaryPolicy calls AMPL’s rebase function

The AMPL ERC20’s rebase function receives the computed supplyDelta as an argument. The function must be only callable by the MonetaryPolicy contract.

6. AMPL’s rebase scalar is updated

To update all user balances at once, the AMPL token uses an internal, fixed (i.e. non-rebasing) user balance and “simulates” an external user balance (the AMPL balance in your wallet) by multiplying the fixed balance with some number called rebase scalar.

Changing AMPL’s supply, that is the sum of all external user balances (isn’t it? :stuck_out_tongue_winking_eye:), only involves updating the rebase scalar with which the external balances are calculated.

This implementation ensures the supply adjustment is always independent of the number of user balances!

Furthermore, it is guaranteed that a supply adjustment is always non-dilutive. (This is an interesting property, meaning even the MonetaryPolicy can not introduce any Cantillon effect)

7. The Orchestrator calls external Contracts to help Coordinate the Supply Adjustment

Now comes the job of the Orchestrator contract.

The Orchestrator manages a set of transactions that get executed directly after AMPL’s supply adjustment.

Two of the transactions currently included are:

  • Adjusting Balancer’s AMPL-USDC smart pool ratio. For more info see this post.
  • Call UniswapV2’s sync function for AMPL pools to force the Uniswap pools to update its cached balance of AMPL tokens inside the pool. Without calling this function, Uniswap’s x * y = k property would operate on an outdated AMPL balance.

If any of the function calls fail, the whole rebase operation is reverted. Furthermore, every transaction added to the Orchestrator increases the gas costs to execute a rebase operation. It should also be noted that the transactions must not depend on each other because the order in which they are executed is random.

One policy of the ForthDAO should therefore be to not blow the Orchestrator with transactions but rather integrate external contracts by other methods, e.g. wrapped AMPL.

5 Likes

Great write up @pascal-merkleplant! That’s all very accurate.

If there’s any more color I could add, it would be around the orchestrator callbacks. There are currently four post-rebase transactions:

  1. The Balancer Smart Pool
  2. Uniswap V2 AMPL/ETH
  3. Sushiswap AMPL/ETH
  4. Balancer Trinity (AMPL/ETH/WBTC)

With Elastic Swap live, there’s a good chance that the Smart Pool will be sunset and removed eventually.

2 Likes