MStrategy
M-strategy is a strategy for tokens pair, for example (WBTC/WETH, USDC/WETH).
The strategy assumes that we have 2 parts of the portfolio:
  1. 1.
    Token X
  2. 2.
    Token Y

Strategy

The strategy manages Token X and Token Y pair.
One portion of the portfolio (e.g. 20%) is stored inside ERC20 vault, while the remaining portion is put into the money market protocols such as AAVE or Compound.
The ratio of portfolio which is allocated in ERC20 vault is defined by erc20MoneyRatio parameter. The remaining part 1 - erc20MoneyRatioD goes to the money market protocols.
The strategy uses the price taken from the oracle with a delay, i.e oracleObservationDelta parameter.

Portfolio rebalancing mechanics

Let's assume that tick - is current price expressed in ticks, while tickMin,tickMax - bounds of emulated Uniswap V3 interval. Then the portions of Token X and Token Y in portfolio are determined by following formulas:
$w_x = \frac{tick - tickMax}{tickMin - tickMax}$ - the portion of portfolio allocated in X Token
$w_y = \frac{tick - tickMin}{tickMax - tickMin}$ - the portion of portfolio allocated in Y Token
There will be no case when the price goes beyond the boundaries of the interval, since rebalancing of the emulated interval is provided (see the next section).
The rebalance is activated by a trigger — whether the price has deviated from the previous rebalance price by a certain number of ticks, i.e. minTickRebalanceThreshold parameter.
Rebalance steps:
  • The strategy checks whether the current price triggers rebalancing of the portfolio or not.
  • If rebalance is triggered, strategy computes new weights for the portfolio and value of tokens to be swapped (for more details go to the Appendix 1.).
  • Then strategy swaps one of the assets for another one on Uniswap V3.

Emulated Uniswap V3 interval rebalancing mechanics

In order for the weights of tokens $\omega_x, \omega_y$ in the portfolio to be calculated correctly, the base interval needs to be rebalanced.
As soon as the current price — tick is greater than tickMax - tickNeiborhood or less than tickMin + tickNeiborhood the boundaries of the interval is expanded by tickIncrease amount.
Rebalance steps:
  • tick is greater than tickMax - tickNeiborhood then new boundaries are
    [tickMin, max(tick, tickMax) + tickIncrease]
  • tick is less than tickMin + tickNeiborhood then new boundaries are
    [min(tick, tickMin) - tickIncrease, tickMax]

ERC20 ratio rebalance

As well strategy checks erc20MoneyRatio. If current ratio greater than erc20MoneyRatio, then put capital difference into money market protocols, otherwise pull from money market protocols.

Appendix

  1. 1.
    Let's assume that 1-targetTokenRatioD, targetTokenRatioD - is new weights and token0, token1 is current amounts for Token X and Y, then compute following:
token1InToken0 = token1 / price
targetToken0 = (token1InToken0 + token0) * targetTokenRatioD
If (targetToken0 < token0) then swap token0 - targetToken0 amount of Token X for some Token Y.
Else swap (targetToken0 - token0)*priceX96 amount of Token Y for some Token X.

Parameters

RatioParams:
Name
Description
tickMin
Lower bound of emulated Uniswap V3 interval
tickMax
Upper bound of emulated Uniswap V3 interval
erc20MoneyRatioD
The ratio of portfolio which is allocated in ERC20 vault
minTickRebalanceThreshold
How many ticks should the price deviate from the previous rebalancing to perform the next rebalancing
tickNeiborhood
The offset from the interval boundary.
tickIncrease
The amount of ticks by which we extend the interval boundary
OraclesParams:
oracleObservationDelta
How many blocks back are we referring to the price (skipping blocks with no trades)
maxTickDeviation
Acceptable deviation between oracle price and Uniswap V3 spot price (if the deviation is higher we don’t do rebalance)
maxSlippageD
Maximum acceptable price slippage in a tokens swap on rebalance
WBTC / ETH 0.3%:
  • price_min = 10 Eth for 1 Btc
  • price_max = 20 Eth for 1 Btc
  • minTickRebalanceThreshold = 800 ticks
USDC / ETH 0.05%:
  • price_min = 1/6000 Eth for 1 USDC
  • price_max = 1/1000 Eth for 1 USDC
  • minTickRebalanceThreshold = 1200 ticks