Skip to content

Instantly share code, notes, and snippets.

@Amxx

Amxx/offset.md Secret

Last active February 26, 2024 10:11
Show Gist options
  • Save Amxx/ec7992a21499b6587979754206a48632 to your computer and use it in GitHub Desktop.
Save Amxx/ec7992a21499b6587979754206a48632 to your computer and use it in GitHub Desktop.
ERC4626 offset explainer

Visualizing the vault

In exchange for the assets deposited into an ERC4626 vault, a user receives shares. These shares can later be burned to redeem the corresponding underlying assets. The number of shares a user get depend on the amount of assets they put in and on the exchange rate of the vault. This exchange rate is defined by the current liquidity held by the vault.

  • If a vault has 100 tokens to back 200 shares, than each share is worth 0.5 asset.
  • If a vault has 200 tokens to back 100 shares, than each share is worth 2.0 asset.

In other words, the exchange rate can be defined as the slope of the line that passes through the origin and the current number of assets and shares in the vault. Deposits and withdrawals move the vault in this line.

FIGURE1

When ploted in log-log scale, the rate is defined similarly, but appears differently (because the point (0,0) is infinitelly far away). Rates are represented by "diagonals" lines with different offsets.

FIGURE2

In such a reprentation, widelly different rates can be clearly visible in the same graph. This wouldn't be the case in linear scale.

FIGURE3

The attack

When depositing tokens, the number of shares a user gets is rounded down. This rounding takes away value from the user in favor or the vault (i.e. in favor of all the current share holders). This rounding is often negligeable because of the amount at stake. If you deposit 1e9 shares worth of tokens, the rounding will have you lose at most 0.0000001% of your deposit. However if you deposit 10 shares worth of tokens, you could lose 10% of your deposit. Even worst, if you deposit <1 share worth of tokens, then you get 0 shares, and you basically made a donation.

For a given amount of assets, the more shares you receive the safer you are. If you want to limit your loses to at most 1%, you need to receive at least 100 shares.

FIGURE3b

In the figure we can see that for a given deposit of 500 asset, the number of share we get, and the corresponding rounding loses depend on the exchange rate. If the exchange rate is that of the orange curve, we are getting less than a share, so we lose 100% of our deposit. However, if the exchange rate is that of the green curve, we get 5000 shares, with limits our rounding loses to at most 0.02%.

FIGURE3c

Simetrically, if we focus on limiting our loses to a maximum of 0.5%, we need to get at least 200 shares. With the green exchange rate that requires just 20 tokens, but with the orange rate that requires 200000 tokens.

We can clearly see that that the blue and green curves correspond to vaults that are safer than the yellow and orange curves.

The idea of an inflation attack is that an attacker can donate assets to the vault to move the rate curve to the right, and make the vault unsafe.

Figure4

Figure 6 shows how an attacker can manipulate the rate of an empty vault. First the attacker must deposit a small amout of tokens (1 token) and follow up with a donation of 1e5 tokens directly to the vault to move the exchange rate "right". This puts the vault in a state where any deposit smaller than 1e5 would be completelly lost to the vault. Given that the attacker is the only share holders (from its donation), the attacker would steal all the tokens deposited.

An attacker would tipically wait for a user to do the first deposit into the vault, and would frontrun that operation with the attack described above. The risk is low, and the size of the "donation" required to manipulate the vault is equivalent to the size of the deposit that is being attacked.

In math that gives:

  • $de$ the attacker deposit
  • $do$ the attacker donation
  • $du$ the user deposit
Assets in vault Shares in vault Rate (share per asset)
initial $0$ $0$ -
after attacker's deposit $de$ $de$ $1$
after attacker's donation $de+do$ $de$ $\frac{de}{de+do}$

This means a deposit of $du$ will give $\frac{du*de}{de+do}$ shares.

For the attacker to dilute that deposit to 0 shares, causing the user to lose all its deposit, it must ensure that $$\frac{du*de}{de+do} &lt; 1 \iff du &lt; 1 + \frac{do}{de}$$

Using $de = 1$ and $do = du$ is enough. So the attacker only needs $du+1$ assets to perform a sucessfull attack.

Defending with a virtual offset

The defence we propose consists in two part:

  • Use an offset between the "precision" of the representation of shares and assets. Said otherwize, we use more decimals places to represent the shares then the underlying token does to represent the assets.
  • Include virtual shares and virtual assets in the exchange rate computation. These virtuals assets enforce the conversion rate when the vault is empty.

These two part work together in enforcing the security of the vault. First, the increase precision correspond to a high rate, which we saw is safer as it reduces the rounding error when computing the amount of shares. Second, the virtual assets and shares (in addition to simplifying a lot of the computations) capture part of the donation, making it unprofitable for a developper to perform an attack.

Following the previous math definition, we have:

  • $off$ the vault offset
  • $de$ the attacker deposit
  • $do$ the attacker donation
  • $du$ the user deposit
Assets in vault Shares in vault Rate (share per asset)
initial $1$ $10^{off}$ $10^{off}$
after attacker's deposit $1+de$ $10^{off} \times (1+de)$ $10^{off}$
after attacker's donation $1+de+do$ $10^{off} \times (1+de)$ $10^{off} \times \frac{1+de}{1+de+do}$

One important thing to note is that the attacker only owns a fraction $\frac{de}{1+de}$ of the shares, so when doing the donation, he will only be able to recover that fraction $\frac{do*de}{1+de}$ of the donation. The remaining $\frac{do}{1+de}$ are captured by the vault.

$$loss = \frac{do}{1+de}$$

When the user deposits $du$, he receives

$$10^{off} \times du \times \frac{1+de}{1+de+do}$$

For the attacker to dilute that deposit to 0 shares, causing the user to lose all its deposit, it must ensure that

$$10^{off} \times du \times \frac{1+de}{1+de+do} < 1$$

$$\iff 10^{off} \times du < \frac{1+de+do}{1+de}$$

$$\iff 10^{off} \times du < 1 + \frac{do}{1+de}$$

$$\iff 10^{off} \times du \le loss$$

  • If the offset is 0, the attacker loss is at least equal to the users deposit.
  • If the offset is greater than 0, the attacker will have to suffer losses that are orders of magnitude bigger than the amount of value that can hypothetically be stolen from the user.

This shows that even with an offset of 0, the virtual shares and assets make this attack non profitable for the attacker. Bigger offsets increase the security even further by making any attack on the user extremelly wastefull.

The following figure show how the offset impacts the initial rate and limits the hability of an attacker with limited fund to inflate it effectivelly.

$off = 3$, $de = 1$, $do = 10^5$

Figure5

$off = 3$, $de = 100$, $do = 10^5$

Figure6

$off = 6$, $de = 1$, $do = 10^5$

Figure7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment