# Nebula Clusters: Attack Vectors and Basket Parameter Constraints
There are a variety of attack vectors that allow the attacker to do a series of unbalancing and balancing transactions and end up with more money than they started with, effectively draining assets out of the basket contract. The basket penalty parameters and the nebula fee need to be constrained to make such attacks always unprofitable.
The penalty parameters are:
penalty_params = {
“penalty_amt_lo”: “0.02”,
“penalty_cutoff_lo”: “0.01”,
“penalty_amt_hi”: “1”,
“penalty_cutoff_hi”: “0.1”,
“reward_amt”: “0.01”,
“reward_cutoff”: “0.02”,
}
There is also a transaction fee F on all mints and redeems that is paid to the Nebula ecosystem, and not does not go back into the basket
The following constraints might be conservative in some cases, ie there exists a looser constraint that would also close the attack vector. Some of these constraints may also be developed assuming other parameters take values that are already constrained by other constraints (F=0 for instance). We have chosen to err on the side of simplicity and safety.
First, obviously reward_amt < penalty_amt_lo.
Less obviously, sufficiently large imbalances (compared with the initial basket size) can result in an unbalance/rebalance being profitable.
With zero fees, and taking the current basket inventory notional value to be 1 without loss of generality, an attack that does an imbalance mint of notional size A followed by a rebalancing redeem of notional size A (returning the basket to its initial inventory), results in an attack PNL of at least:
PNL = A * (1 - P) - (1-reward_amt) * A * (1 - P) / (1 + A), where P is the effective penalty rate
For an attacker to be profitable requires PNL > 0, which yields:
A > (P - reward_amt) /(reward_amt * (1 - P))
This clearly requires a cap on A and/or P->1 for large A.
A>1 would mean the basket imbalance is as large as it’s notional value, which is not desirable from a tracking perspective, so putting limits on this is very reasonable. We require penalty_amt_hi=1 and also reject any transactions which would make the imbalance > penalty_cutoff_hi.
Another potential attack vector is the following, carried out on a basket with notional value 1:
1) Attacker pumps the notional value in the basket by minting C tokens (in a balanced mint)
2) Attacker makes a large unbalancing mint, paying a substantial penalty P
3) Attacker burns the C tokens minted in step 1, capturing C/(C+1) of the penalty paid in step 2
4) Attacker makes a large balancing redeem, receiving a reward R
Since the penalty paid out in step 2 is paid into the basket when the attacker is holding C tokens and the reward paid out in step 4 after the attacker has redeemed C tokens, this sequence potentially lets the attacker syphon assets out of the basket. Furthermore, since these transactions could potentially be done in a single block, the possibility of a “flash loan” style attack makes this attack vector particularly dangerous as the assets needed to pump the basket in step 1 could be in the form of a flash loan.
With:
- Initial basket notional value of 1
- Attack pump basket with notional value C
- Attack unbalancing mint of notional value A
- Effective penalty rate of P for unbalanacing mint
- Effective reward rate of R for balancing redeem
- Nebula Fee rate of F (that does NOT go into the basket, but gets paid to the Nebula protocol) IMPORTANT
Then the profit from such an attack can be found to be:
PNL = (1-F)*(C+A*(1-P)) - (1+F) * (C+(1-R)*A) * (1+C+A*(1-P)) / (1+C+A)
Now we find constraints on F, R, P so that PNL<0 for all C and A
An upper limit for the PNL for the attack is R*A, which is how much the attacker could get if there was no penalty and no fees.
In the case of F=0, setting PNL=0 and solving for C shows the attack first becomes profitable for C=C_0 with
C_0 = (P/R - 1) - A * (1 - P)
If the fees paid at this minimum pump size C_0 are greater than the upper limit of possible PNL, then there are no possible profitable attacks, since the fees paid can only go up with larger C
So we require:
Fees paid = 2F * (C_0 + A) > R*A
F > R*A / (2 * ( (P/R - 1) + P*A) )
The above argument fails in the case where C_0 <=0, so we handle that case explicitly:
Setting C=0 in the PNL formula above then requiring PNL<0 and solving for F yields:
F >= {(1 - P) * (A + 1) - (1 - R) * (1 + A * (1 - P))} / {(1 - P) * (A + 1) + (1 - R) * (1 + A * (1 - P))}
Taking these two constraints together, and applying them to the penalty function parameters above we get:
Taking P >= penalty_amt_lo
A <= penalty_cutoff_hi - reward_cutoff
R <= reward_amt
F > ((1-penalty_amt_lo)*((penalty_cutoff_hi - reward_cutoff)+1) - (1-reward_amt)*(1+(penalty_cutoff_hi - reward_cutoff)*(1-penalty_amt_lo))) / ((1-penalty_amt_lo)*((penalty_cutoff_hi - reward_cutoff)+1) + (1-reward_amt)*(1+(penalty_cutoff_hi - reward_cutoff)*(1-penalty_amt_lo)))
And
F > 0.5*reward_amt*(penalty_cutoff_hi - reward_cutoff)/((penalty_amt_lo/reward_amt-1) + penalty_amt_lo*(penalty_cutoff_hi - reward_cutoff))
It is critically important that these constraints are enforced, otherwise an attacker could profitably drain all of the assets out of the basket.