Skip to content

Commit 2ac5c2f

Browse files
doc: Add security review reports (#22)
* doc: Add Certora reports * feat: logo files (#20) (#21) * chore: Add codeowners * fix: Fix lint * test: Fix test * test: fix test * doc: add stermi audit report * fix: update readme; stermi report rename * fix: fix date --------- Co-authored-by: YBM <31329384+yan-man@users.noreply.github.com>
1 parent 4b94ca7 commit 2ac5c2f

File tree

10 files changed

+60
-26
lines changed

10 files changed

+60
-26
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* @The-3D @yan-man @miguelmtzinf @avniculae @DhairyaSethi @CheyenneAtapour @CanonicalJP

.github/workflows/certora-basic.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,6 @@ jobs:
6565
install-java: true
6666
env:
6767
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
68-
69-
7068
# Put back the following rule after ticket 8889 is closed
71-
# certora/basic/conf/NEW-pool-no-summarizations.conf ##### waiting for
69+
# certora/basic/conf/NEW-pool-no-summarizations.conf ##### waiting for
7270

.github/workflows/certora-stata.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
cd certora/stata
3636
touch applyHarness.patch
3737
make munged
38-
38+
3939
- uses: Certora/certora-run-action@v1
4040
with:
4141
cli-version: 7.29.1

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,13 @@ In addition, Enigma Dark has adapted the Foundry-based fuzzing [invariant suite]
9595

9696
<br>
9797

98+
**-> Horizon Aave v3.3 - July 2025**
99+
100+
- [Certora](./audits/2025-05-30_Certora_Horizon-v3.3.0.pdf)
101+
- [StErMi](./audits/2025-06-25_StErMi_Horizon-v3.3.0.pdf)
102+
103+
<br>
104+
98105
### Bug bounty
99106

100107
This repository will be subjected to [this bug bounty](https://immunefi.com/bounty/aave/) once the Aave Governance upgrades the smart contracts in the applicable production instances.
414 KB
Binary file not shown.
313 KB
Binary file not shown.

docs/Horizon/Horizon-overview.md

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ RWA assets can be listed by utilizing a newly developed aToken contract, `RwaATo
2626

2727
- RwaAToken transfers
2828
- users cannot transfer their own RwaATokens (transfer, allowance, and permit related methods will revert).
29-
- new `ATOKEN_ADMIN` role, which can forcibly transfer any RwaAToken without needing approval (but can still only transfer an RwaAToken amount up to a healthy collateralization/health factor). This role is expected to be given to the `RwaATokenManager` contract, which will granularly delegate authorization to individual accounts on a per-RwaAToken basis.
29+
- new `ATOKEN_ADMIN` role, which can forcibly transfer any RwaAToken without needing approval (but can still only transfer an RwaAToken amount up to a healthy collateralization/health factor). This role is expected to be given to the `RwaATokenManager` contract, which will granularly delegate authorization to individual accounts on a per-RwaAToken basis.
3030
- note that `ATOKEN_ADMIN` can also forcibly transfer RwaATokens away from the treasury address. While the treasury address currently does not receive RwaATokens of any sort through Reserve Factor or Liquidation Bonus, if this changes in the future there must be restrictions in place to protect RwaATokens earned by treasury.
3131
- `RwaATokenManager` contract
3232
- external RwaAToken manager smart contract which encodes granular authorized RwaAToken transfer permissions (by granting `AUTHORIZED_TRANSFER_ROLE` for specific RwaATokens).
3333
- it is expected that only trusted parties (such as token Issuers) will be granted `AUTHORIZED_TRANSFER_ROLE`, and that RwaAToken authorized transfers will only occur in emergency situations (such as resolving [specific edge cases](#edge-cases-of-note)), rather than within the typical flow of operations.
34-
- it is left to Authorized Transfer Admin to execute authorized transfers that ensure compliance (for example, ensuring that Authorized Transfer RwaAToken recipients are allowlisted to hold the corresponding RWA Token). This scenario is described [here](#non-allowlisted-account-can-receive-rwaatokens).
34+
- it is left to Authorized Transfer Admin to execute authorized transfers that ensure compliance (for example, ensuring that Authorized Transfer RwaAToken recipients are allowlisted to hold the corresponding RWA Token). This scenario is described [here](#non-allowlisted-account-can-receive-rwaatokens).
3535
- Supply
3636
- can only be supplied by permissioned users allowlisted to hold RWA Token (will rely on underlying RWA asset-level permissioning).
3737
- can be supplied as collateral, through proper risk configuration (non-zero LTV and Liquidation Threshold).
@@ -55,7 +55,7 @@ RWA assets can be listed by utilizing a newly developed aToken contract, `RwaATo
5555
- RwaATokenManager contract address granted the RwaAToken admin role in the ACL Manager.
5656
- further granular RwaAToken admin permissions will be configured in the RwaATokenManager contract itself.
5757
- Token Issuers or relevant admin can be granted admin permissions on the RwaAToken corresponding to their specific RWA asset.
58-
- No bridges/portals will be configured, hence no unbacked RwaATokens can be minted.
58+
- No bridges/portals will be configured, hence no unbacked RwaATokens can be minted.
5959

6060
#### Reserve Configuration
6161

@@ -76,15 +76,15 @@ RWA assets can be listed by utilizing a newly developed aToken contract, `RwaATo
7676

7777
### Stablecoins / Permissionless Non-RWA Assets (Borrowable Asset)
7878

79-
Stablecoins, or other non-RWA assets, can be supplied permissionlessly to earn yield. However, they will only be able to be borrowed, but disabled as collateral assets (via asset configuration, by setting Liquidation Threshold to 0). Borrowing will be implicitly permissioned because only users that have supplied RWA assets can borrow stablecoins or other permissionless non-RWA assets (except in a potential edge case described [here](#non-allowlisted-account-can-receive-rwaatokens)).
79+
Stablecoins, or other non-RWA assets, can be supplied permissionlessly to earn yield. However, they will only be able to be borrowed, but disabled as collateral assets (via asset configuration, by setting Liquidation Threshold to 0). Borrowing will be implicitly permissioned because only users that have supplied RWA assets can borrow stablecoins or other permissionless non-RWA assets (except in a potential edge case described [here](#non-allowlisted-account-can-receive-rwaatokens)).
8080

8181
All other existing functionality remains unchanged from v3.3. Stablecoins, or other non-RWA assets, will be listed and operate as usual, following the standard process.
8282

8383
#### Reserve Configuration
8484

8585
- priceFeed: different per asset, Chainlink-compatible
86-
- rateStrategyParams: different per asset
87-
- borrowingEnabled: true
86+
- rateStrategyParams: different per asset
87+
- borrowingEnabled: true
8888
- borrowableInIsolation: true
8989
- withSiloedBorrowing: false
9090
- flashloanable: true (authorized flashborrowers can be configured)
@@ -121,13 +121,13 @@ If a user has a borrow position but loses private keys to their wallet, this pos
121121

122122
#### Resolution
123123

124-
1. `ALICE` creates a new wallet, `ALICE2`.
124+
1. `ALICE` creates a new wallet, `ALICE2`.
125125
2. `RWA_1_ISSUER` creates a new multisig wallet controlled by `RWA_1_ISSUER` and `ALICE2` with 1 of 2 signers (`NEW_ALICE_WALLET`) which will eventually be fully transferred to `ALICE2`.
126126
3. `RWA_1_ISSUER` executes a "complex" flashloan for `50 USDC` by calling `Pool.flashLoan(...)`. In the flashloan callback, `RWA_1_ISSUER`:
127-
- repays the `50 USDC` debt `onBehalfOf` `ALICE`.
128-
- executes `RwaATokenManager.transferRwaAToken` to transfer `100 aRWA_1` to `NEW_ALICE_WALLET`.
129-
- `RWA_1_ISSUER` opens a new borrow position from `NEW_ALICE_WALLET` for `50 USDC`.
130-
- `RWA_1_ISSUER` repays flashloan using newly borrowed `50 USDC`.
127+
- repays the `50 USDC` debt `onBehalfOf` `ALICE`.
128+
- executes `RwaATokenManager.transferRwaAToken` to transfer `100 aRWA_1` to `NEW_ALICE_WALLET`.
129+
- `RWA_1_ISSUER` opens a new borrow position from `NEW_ALICE_WALLET` for `50 USDC`.
130+
- `RWA_1_ISSUER` repays flashloan using newly borrowed `50 USDC`.
131131
4. `RWA_1_ISSUER` revokes its signing role from `NEW_ALICE_WALLET`, fully transferring ownership to `ALICE2`.
132132

133133
At the conclusion, `RWA_1_ISSUER` will have migrated both `ALICE`'s initial debt and collateral positions to `NEW_ALICE_WALLET`, which will be fully controlled by `ALICE2`. It is not strictly necessary for `RWA_1_ISSUER` to be granted the `FLASH_BORROWER_ROLE`, but this will be helpful in cases where the position to migrate is large, ensuring that `RWA_1_ISSUER` will not be required to consistently maintain a liquidity buffer on hand to resolve this situation. This also allows for the position to be migrated without paying a premium for the flashloaned amount.
@@ -156,7 +156,7 @@ If a user creates a debt position but then becomes sanctioned, their actions may
156156
- `RWA_1_ISSUER` calls `RwaAToken.authorizedTransfer` to move all `1000 aRWA_1` collateral to a separate trusted address (`RWA_1_TRUSTED`) to be custodied until the sanction case is resolved.
157157
- `RWA_1_ISSUER` retains off-chain agreement with `ALICE` to recoup `100 USDC` repaid debt.
158158

159-
At the conclusion, `aRWA_1` custodied by `RWA_1_TRUSTED` can be returned or moved elsewhere to ensure legal compliance. It is left to `RWA_1_ISSUER` to adjudicate as required.
159+
At the conclusion, `aRWA_1` custodied by `RWA_1_TRUSTED` can be returned or moved elsewhere to ensure legal compliance. It is left to `RWA_1_ISSUER` to adjudicate as required.
160160

161161
#### Limitations
162162

@@ -169,11 +169,12 @@ Consider the following scenarios involving the example permissioned `RWA_1` toke
169169

170170
### Non Allowlisted Account Can Receive RwaATokens
171171

172-
`authorizedTransfer` of RwaATokens do not validate that recipient addresses belong to the allowlist of the underlying RWA Token. It is left to Authorized Transfer Admin to execute authorized transfers that adhere to the proper underlying RWA Token mechanics and ensure legal compliance.
172+
`authorizedTransfer` of RwaATokens do not validate that recipient addresses belong to the allowlist of the underlying RWA Token. It is left to Authorized Transfer Admin to execute authorized transfers that adhere to the proper underlying RWA Token mechanics and ensure legal compliance.
173173

174-
This theoretically allows recipients to open stablecoin debt positions without owning underlying RWA Tokens. Consider the following scenario.
174+
This theoretically allows recipients to open stablecoin debt positions without owning underlying RWA Tokens. Consider the following scenario.
175175

176176
Assumptions:
177+
177178
- `RWA_1_ISSUER` has been granted `AUTHORIZED_TRANSFER_ROLE` in the RwaATokenManager contract for `aRWA_1`..
178179
- `ALICE` is allowlisted to hold `RWA_1` and has supplied `100 RWA_1` to Horizon, receiving `100 aRWA_1`.
179180
- `BOB` is not allowlisted to hold `RWA_1`.
@@ -186,9 +187,10 @@ Assumptions:
186187

187188
### `Withdraw` as a Transfer of Underlying RWA Token
188189

189-
By specifying an arbitrary `to` address argument in the `withdraw` function, users who have supplied RWA Tokens can withdraw them to any other allowlisted account. This should be considered a standard ERC20 transfer and will adhere to the same restrictions imposed by the underlying RWA Token.
190+
By specifying an arbitrary `to` address argument in the `withdraw` function, users who have supplied RWA Tokens can withdraw them to any other allowlisted account. This should be considered a standard ERC20 transfer and will adhere to the same restrictions imposed by the underlying RWA Token.
190191

191192
Assumptions:
193+
192194
- `ALICE` has been allowlisted.
193195
- `RWA_1` and `aRWA_1` have decimals of 6.
194196

@@ -210,6 +212,7 @@ event Transfer(address indexed from, address indexed to, uint256 value);
210212
```
211213

212214
From `ScaledBalanceTokenBase.sol`, where:
215+
213216
- `from` is the user account whose tokens are withdrawn, `BOB`.
214217
- `to` is the zero address to signify a `burn` action.
215218
- `value` is the amount of `aRWA_1` being burned when collateral is withdrawn, including `aToken` decimals (ie `50_000_000`).
@@ -221,8 +224,9 @@ event Transfer(address indexed from, address indexed to, uint256 value);
221224
```
222225

223226
From the RWA `ERC20` Token contract itself, where:
227+
224228
- `from` is the `RWA_1` **RwaAToken** address.
225-
- Note that the emitted `from` address is the **RwaAToken** smart contract rather than `BOB`'s account.
229+
- Note that the emitted `from` address is the **RwaAToken** smart contract rather than `BOB`'s account.
226230
- `to` is `ALICE`'s account.
227231
- `value` is the amount of `RWA_1` withdrawn, including decimals (ie `50_000_000`).
228232

@@ -231,6 +235,7 @@ event Withdraw(address indexed reserve, address indexed user, address indexed to
231235
```
232236

233237
From `Pool.sol`, where:
238+
234239
- `reserve` is the `RWA_1` token address.
235240
- `user` is `BOB`'s account.
236241
- `to` is `ALICE`'s account.
@@ -240,17 +245,19 @@ The `RWA_1` Transfer Agent must properly record this action officially as a tran
240245

241246
### `Liquidation` as a Transfer of Underlying RWA Token
242247

243-
During a liquidation, collateral seized from the user being liquidated will be transferred to the liquidator. This should also be considered a standard ERC20 transfer.
248+
During a liquidation, collateral seized from the user being liquidated will be transferred to the liquidator. This should also be considered a standard ERC20 transfer.
244249

245250
Assumptions:
251+
246252
- `BOB` and `ALICE` are allowlisted to hold `RWA_1`.
247253
- `ALICE` has an off-chain legal agreement with `RWA_1_ISSUER` to be able to be a liquidator.
248254
- `LTV` of `RWA_1` is `>80%` in Horizon.
249255
- `RWA_1` and `aRWA_1` have decimals of 8.
250256

251257
Consider the following scenario:
258+
252259
- `BOB` supplies `100 RWA_1`, and borrows `80 USDC`.
253-
- time flies and `Bob`'s `USDC` debt grows to `120 USDC` through accumulation of interest. His position is no longer healthy and it becomes eligible for liquidation.
260+
- time flies and `Bob`'s `USDC` debt grows to `120 USDC` through accumulation of interest. His position is no longer healthy and it becomes eligible for liquidation.
254261
- `ALICE` executes a `liquidationCall` on `BOB`'s position, and receives all of `BOB`'s `100 RWA_1` collateral (which includes the liquidation bonus) by repaying `BOB`'s `120 USDC` debt.
255262
- `ALICE` receives `100 RWA_1`.
256263

@@ -265,6 +272,7 @@ event Transfer(address indexed from, address indexed to, uint256 value);
265272
```
266273

267274
From `ScaledBalanceTokenBase.sol`, where:
275+
268276
- `from` is the user account being liquidated, `BOB`.
269277
- `to` is the zero address to signify a `burn` action.
270278
- `value` is the amount of `aRWA_1` being burned when collateral is liquidated, including decimals (ie `10_000_000_000 aRWA_1`).
@@ -276,8 +284,9 @@ event Transfer(address indexed from, address indexed to, uint256 value);
276284
```
277285

278286
From the RWA `ERC20` Token contract itself, where:
287+
279288
- `from` is the `RWA_1` **RwaAToken** address.
280-
- Note that the emitted `from` address is the **RwaAToken** smart contract rather than `BOB`'s account.
289+
- Note that the emitted `from` address is the **RwaAToken** smart contract rather than `BOB`'s account.
281290
- `to` is `ALICE`'s account.
282291
- `value` will be the liquidated `RWA_1` collateral amount, including decimals (ie `10_000_000_000 RWA_1`).
283292

@@ -294,6 +303,7 @@ event LiquidationCall(
294303
```
295304

296305
From `Pool.sol`, where:
306+
297307
- `collateralAsset` is the `RWA_1` collateral token address.
298308
- `debtAsset` is the `USDC` debt token address.
299309
- `user` is the liquidated user account, `BOB`.
@@ -311,4 +321,4 @@ Exact configuration details for eMode, isolated mode, flashloan fees, and liquid
311321
## References
312322

313323
- https://governance.aave.com/t/arfc-horizon-s-rwa-instance/21898
314-
- https://avara.xyz/blog/horizon
324+
- https://avara.xyz/blog/horizon
27.1 KB
Loading

0 commit comments

Comments
 (0)