You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/3.5/Aave-v3.5-features.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -80,7 +80,8 @@ Aave historically has never accurately tracked allowance. The reason for this is
80
80
For allowance / approval, this means that the consumed allowance is not always equal to the amount transferred. While this problem is not perfectly solvable without breaking changes, in v3.5 the protocol ensures that the exact consumed allowance is burned if available.
81
81
82
82
Example: When a user calls `transferFrom(sender, recipient, 100)` in most cases the transfer will transfer slightly more than `100` tokens (e.g `101`). This is due to precision loss between assets/shares conversion.
83
-
In Aave versions `< 3.5` this action would always result in burning `100` allowance. On Aave v3.5, the transfer will either burn `101` allowance or burn `100` allowance dependent on the users available allowance. This prevents undesired double spending of allowance, while maintaining backwards compatibility.
83
+
In Aave versions `< 3.5` this action would always result in burning `100` allowance. On Aave v3.5, the transfer will check the balance difference on the sender and discount up to the difference from the allowance.
84
+
Example: The user transfers `100`, but due to rounding he loses `102` balance. The allowance is reduced by up to `102`. If the original allowance was only `100`, the transaction will still pass for backwards compatibility.
// According to the ERC20 specification, the spent allowance should reflect the amount transferred.
199
-
// Following the spec exactly is impossible though, as the allowance references the "scaled up" amount while the transfer operates with "scaled down" amount.
200
-
// Because of this different handling of amounts, there are amounts that are impossible to accurately reflect on the balance.
201
-
// As an example: transferFrom(..., 1) at a liquidity index of 2e27, can never transfer exactly `1` as the smallest unit that can be accounted for would be 2.
202
-
// In addition to that the existing balance has an effect on the final "scaled up" balance after transfer.
203
-
// As an example: transferFrom(..., 1) at a liquidity index of 1.1 where the recipient has a "scaled up" balance of `9 * 1.1 = 9.9 = 9` before the transfer, will have a balance of `10 * 1.1. = 11` after the Transfer.
204
-
// While this problem is not solvable without introducing breaking changes, on Aave v3.5 the situation is improved in the following way:
205
-
// - The `correct` amount to be deducted is considered to be `scaledUpFloor(scaledDownCeil(input.amount))`. This replicates the behavior on transfer, followed by a balanceOf.
206
-
// - To avoid breaking existing integrations, the amount deducted from the allowance is the minimum of the available allowance and the actual up-scaled asset amount.
// This comment explains the logic behind the allowance spent calculation.
200
+
//
201
+
// Problem:
202
+
// Simply decreasing the allowance by the input `amount` is not ideal for scaled-balance tokens.
203
+
// Due to rounding, the actual decrease in the sender's balance (`amount_out`) can be slightly
204
+
// larger than the input `amount`.
205
+
//
206
+
// Definitions:
207
+
// - `amount`: The unscaled amount to be transferred, passed as an argument.
208
+
// - `amount_out`: The actual unscaled amount deducted from the sender's balance.
209
+
// - `amount_in`: The actual unscaled amount added to the recipient's balance.
210
+
// - `allowance_spent`: The unscaled amount deducted from the spender's allowance.
211
+
// - `amount_logged`: The amount logged in the `Transfer` event.
212
+
//
213
+
// Solution:
214
+
// To fix this, `allowance_spent` must be exactly equal to `amount_out`.
215
+
// We calculate `amount_out` precisely by simulating the effect of the transfer on the sender's balance.
216
+
// `actualBalanceDecrease` in the code corresponds to `amount_out`.
217
+
// By passing `actualBalanceDecrease` to `_spendAllowance`, we ensure `allowance_spent` is as close as possible to `amount_out`.
218
+
// `amount_logged` is equal to `amount`. `amount_in` is the actual balance increase for the recipient, which is >= `amount` due to rounding.
219
+
//
220
+
// Backward Compatibility & Guarantees:
221
+
// This implementation is backward-compatible and secure. The `_spendAllowance` function has a critical feature:
222
+
// 1. It REQUIRES the allowance to be >= `amount` (the user's requested transfer amount).
223
+
// 2. The amount consumed from the allowance is `actualBalanceDecrease`, but it is capped at the `currentAllowance`.
224
+
// This means if a user has an allowance of 100 wei and calls `transferFrom` with an `amount` of 100, the call will succeed
225
+
// even if the calculated `actualBalanceDecrease` is 101 wei. In that specific scenario, the allowance consumed will be 100 wei (since that is the `currentAllowance`),
226
+
// and the transaction will not revert. But if the allowance is 101 wei, then the allowance consumed will be 101 wei.
0 commit comments