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
Historically transferFrom etc have consumed ther users input as allowance.
That has never really been accurate, as the users input might not actually be transferrable due to rounding, to account for that we improved the logic to consumer "up to the raw scaled up transfer amount".
Copy file name to clipboardExpand all lines: docs/3.5/Aave-v3.5-features.md
+8Lines changed: 8 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -74,6 +74,14 @@ In v3.5 we decided to double down on these robustness improvements:
74
74
75
75
- on `repayWithAToken` and `withdraw`, the collateral flag is now properly set to `false` when burning all aTokens in the process. In previous versions of the protocol, there were edge cases in which the collateral flag was not properly updated.
76
76
77
+
### Improved allowance
78
+
79
+
Aave historically has never accurately tracked allowance. The reason for this is that in practice most operations are performed with the desired amount of `assets`, but the a/v token converting these amounts to `shares`.
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
+
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.
84
+
77
85
### Misc changes
78
86
79
87
- smaller refactoring in `LiquidationLogic` making the code more consistent
"full amount; sender: with delegations, ->disableCollateral; receiver: without delegations, ->enableCollateral": "158388",
3
-
"full amount; sender: with delegations, delegatee, ->disableCollateral; receiver: with delegations, delegatee, ->enableCollateral": "154326",
4
-
"full amount; sender: with delegations, not delegatee, ->disableCollateral; receiver: with delegations, not delegatee, ->enableCollateral": "154326",
5
-
"full amount; sender: without delegations, ->disableCollateral; receiver: with delegations, ->enableCollateral": "141288",
6
-
"full amount; sender: without delegations, delegatee, ->disableCollateral; receiver: without delegations, delegatee, ->enableCollateral": "145351",
7
-
"full amount; sender: without delegations, not delegatee, ->disableCollateral; receiver: without delegations, not delegatee, ->enableCollateral": "145351"
2
+
"full amount; sender: with delegations, ->disableCollateral; receiver: without delegations, ->enableCollateral": "158387",
3
+
"full amount; sender: with delegations, delegatee, ->disableCollateral; receiver: with delegations, delegatee, ->enableCollateral": "154325",
4
+
"full amount; sender: with delegations, not delegatee, ->disableCollateral; receiver: with delegations, not delegatee, ->enableCollateral": "154325",
5
+
"full amount; sender: without delegations, ->disableCollateral; receiver: with delegations, ->enableCollateral": "141287",
6
+
"full amount; sender: without delegations, delegatee, ->disableCollateral; receiver: without delegations, delegatee, ->enableCollateral": "145350",
7
+
"full amount; sender: without delegations, not delegatee, ->disableCollateral; receiver: without delegations, not delegatee, ->enableCollateral": "145350"
uint256 index = POOL.getReserveNormalizedIncome(_underlyingAsset);
200
+
_spendAllowance(
201
+
sender,
202
+
_msgSender(),
203
+
amount,
204
+
// According to the ERC20 specification, the spent allowance should reflect the amount transferred.
205
+
// Following the spec exactly is impossible though, as the allowance references the "scaled up" amount while the transfer operates with "scaled down" amount.
206
+
// Because of this different handling of amounts, there are amounts that are impossible to accurately reflect on the balance.
207
+
// 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.
208
+
// In addition to that the existing balance has an effect on the final "scaled up" balance after transfer.
209
+
// 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.
210
+
// While this problem is not solvable without introducing breaking changes, on Aave v3.5 the situation is improved in the following way:
211
+
// - The `correct` amount to be deducted is considered to be `scaledUpFloor(scaledDownCeil(input.amount))`. This replicates the behavior on transfer, followed by a balanceOf.
212
+
// - In order to not introduce a breaking change for existing integrations, the deducted allowance is based on the available allowance as `Max(availableAllowance, (amount, correctAmount))`
// When borrowing on behalf of a user, the borrower specified an "amount", which is measured in the underlying the user wants to receive.
92
+
// The protocol internally works, with a "scaled down" representation of the amount, which in most cases loses precision.
93
+
// In practice this means that when borrowing `n`, the user might receive `n+m` debt.
94
+
// Similar to the aToken `transferFrom` function, handling this scenario exactly is impossible.
95
+
// While this problem is not solvable without introducing breaking changes, on Aave v3.5 the situation is improved in the following way:
96
+
// - The `correct` amount to be deducted is considered to be `scaledUpCeil(scaledAmount)`. This replicates the behavior on borrow followed by a balanceOf.
97
+
// - In order to not introduce a breaking change for existing integrations, the deducted allowance is based on the available allowance as `Max(availableAllowance, (amount, correctAmount))`
0 commit comments