-
Notifications
You must be signed in to change notification settings - Fork 0
[Certora] Blue Bundles: no residue #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
88a6e3a
tuned
bhargavbh d6b6823
added conf
bhargavbh 383d4ae
certora internal ignored
bhargavbh e4aa3a7
nit
MathisGD e5e7076
Apply suggestion from @MathisGD
MathisGD 8d185f7
nit
MathisGD 02c3269
Merge remote-tracking branch 'origin/certora/no-residue' into certora…
MathisGD 1b8c425
Merge remote-tracking branch 'origin/main' into certora/no-residue
MathisGD 8cb1893
refactor no residue
QGarchery 0ceea93
another round of cleaning
QGarchery c18cea3
improve assumptions
QGarchery 83d7695
exclude migrate borrow position
QGarchery 9aca2a4
more general summaries
QGarchery 09aba3c
remove useless require
QGarchery a56a3a2
Apply suggestions from code review
QGarchery File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,3 +5,6 @@ broadcast/ | |
| *.swp | ||
| .DS_Store | ||
| node_modules/ | ||
|
|
||
| # Certora local run cache | ||
| .certora_internal/ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| { | ||
| "files": [ | ||
| "src/blue/BlueBundlesV1.sol" | ||
| ], | ||
| "verify": "BlueBundlesV1:certora/specs/NoResidue.spec", | ||
| "solc": "solc-0.8.34", | ||
| "solc_via_ir": true, | ||
| "solc_evm_version": "osaka", | ||
| "optimistic_loop": true, | ||
| "loop_iter": 2, | ||
| "msg": "BlueBundles: no token residue" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||
|
|
||
| // No token residue: every entry point preserves the bundler's balance of every token (delta 0). | ||
| // Scope: all entry points, excluding migrate borrow position. | ||
| // Two assumptions shared with that suite: | ||
| // - no bundler donations: the receiver and the recipient are different from the bundler. | ||
| // - well-behaved ERC20 (no fee-on-transfer/rebasing): matching the token restriction in BlueBundles' header. | ||
|
|
||
| definition WAD() returns mathint = 10 ^ 18; | ||
|
|
||
| // The bundler's balance of every token, updated on every transfer that touches it. | ||
| persistent ghost mapping(address => mathint) bundlerBalance; | ||
|
|
||
| methods { | ||
| // ERC20: the bundler's own transfers move bundlerBalance. | ||
|
|
||
| function _.transferFrom(address from, address to, uint256 amt) external => cvlTransferFrom(calledContract, from, to, amt) expect(bool); | ||
| function _.transfer(address to, uint256 amt) external with(env e) => cvlTransferFrom(calledContract, e.msg.sender, to, amt) expect(bool); | ||
|
|
||
| // Morpho: pull on supply/repay/supplyCollateral, send on borrow/withdraw/withdrawCollateral. | ||
| // Also assumes that the Morpho Blue address is different from the bundler's. | ||
|
|
||
| function _.supply(BlueBundlesV1.MarketParams marketParams, uint256 assets, uint256 shares, address onBehalf, bytes data) external => summarySupply(marketParams.loanToken, assets, shares) expect(uint256, uint256); | ||
| function _.repay(BlueBundlesV1.MarketParams marketParams, uint256 assets, uint256 shares, address onBehalf, bytes data) external => summaryRepay(marketParams.loanToken) expect(uint256, uint256); | ||
| function _.supplyCollateral(BlueBundlesV1.MarketParams marketParams, uint256 assets, address onBehalf, bytes data) external => summarySupplyCollateral(marketParams.collateralToken, assets) expect void; | ||
| function _.borrow(BlueBundlesV1.MarketParams marketParams, uint256 assets, uint256 shares, address onBehalf, address receiver) external => summaryBorrow(marketParams.loanToken, assets, shares, receiver) expect(uint256, uint256); | ||
| function _.withdraw(BlueBundlesV1.MarketParams marketParams, uint256 assets, uint256 shares, address onBehalf, address receiver) external => summaryWithdraw(marketParams.loanToken, receiver) expect(uint256, uint256); | ||
| function _.withdrawCollateral(BlueBundlesV1.MarketParams marketParams, uint256 assets, address onBehalf, address receiver) external => summaryWithdrawCollateral(marketParams.collateralToken, assets, receiver) expect void; | ||
|
|
||
| // Since calls are not summarized as havoc all by default, it is assumed that other calls don't change the bundler's balance of any token. | ||
| } | ||
|
|
||
| // well-behaved ERC20: transfers move balances by the amount. | ||
| function cvlTransferFrom(address token, address from, address to, uint256 amount) returns bool { | ||
| if (from == currentContract) bundlerBalance[token] = bundlerBalance[token] - amount; | ||
| if (to == currentContract) bundlerBalance[token] = bundlerBalance[token] + amount; | ||
| return true; | ||
| } | ||
|
|
||
| function summarySupply(address token, uint256 assets, uint256 shares) returns (uint256, uint256) { | ||
| assert shares == 0; | ||
| bundlerBalance[token] = bundlerBalance[token] - assets; | ||
| uint256 returnedShares; | ||
| return (assets, returnedShares); | ||
| } | ||
|
|
||
| function summaryRepay(address token) returns (uint256, uint256) { | ||
| uint256 assets; | ||
| uint256 shares; | ||
| bundlerBalance[token] = bundlerBalance[token] - assets; | ||
| return (assets, shares); | ||
| } | ||
|
|
||
| function summarySupplyCollateral(address token, uint256 assets) { | ||
| bundlerBalance[token] = bundlerBalance[token] - assets; | ||
| } | ||
|
|
||
| function summaryBorrow(address token, uint256 assets, uint256 shares, address receiver) returns (uint256, uint256) { | ||
| assert shares == 0; | ||
| if (receiver == currentContract) bundlerBalance[token] = bundlerBalance[token] + assets; | ||
| uint256 returnedShares; | ||
| return (assets, returnedShares); | ||
| } | ||
|
|
||
| function summaryWithdraw(address token, address receiver) returns (uint256, uint256) { | ||
| uint256 assets; | ||
| uint256 shares; | ||
| if (receiver == currentContract) bundlerBalance[token] = bundlerBalance[token] + assets; | ||
| return (assets, shares); | ||
| } | ||
|
|
||
| function summaryWithdrawCollateral(address token, uint256 assets, address receiver) { | ||
| if (receiver == currentContract) bundlerBalance[token] = bundlerBalance[token] + assets; | ||
| } | ||
|
|
||
| rule supplyPreservesBalance(env e, BlueBundlesV1.MarketParams marketParams, uint256 assets, address onBehalf, TokenLib.TokenPermit permit, uint256 feePct, address recipient, address token, uint256 deadline) { | ||
| require permit.kind == TokenLib.PermitKind.None, "simplification for prover performance"; | ||
| require e.msg.sender != currentContract, "bundler is never its own caller"; | ||
| require recipient != currentContract, "no bundler donations of the fee"; | ||
|
|
||
| mathint before = bundlerBalance[token]; | ||
| blueBundlesV1Supply(e, marketParams, assets, onBehalf, permit, feePct, recipient, deadline); | ||
| assert bundlerBalance[token] == before; | ||
| } | ||
|
|
||
| rule withdrawPreservesBalance(env e, BlueBundlesV1.MarketParams marketParams, uint256 withdrawAssets, address onBehalf, address receiver, uint256 feePct, address recipient, address token, uint256 deadline) { | ||
| require e.msg.sender != currentContract, "bundler is never its own caller"; | ||
| require receiver != currentContract, "no bundler donations of proceeds"; | ||
| require recipient != currentContract, "no bundler donations of the fee"; | ||
|
|
||
| mathint before = bundlerBalance[token]; | ||
| blueBundlesV1Withdraw(e, marketParams, withdrawAssets, onBehalf, receiver, feePct, recipient, deadline); | ||
| assert bundlerBalance[token] == before; | ||
| } | ||
|
|
||
| rule supplyCollateralAndBorrowPreservesBalance(env e, BlueBundlesV1.MarketParams marketParams, uint256 collateralAmount, uint256 borrowAssets, uint256 maxLtv, address onBehalf, address receiver, TokenLib.TokenPermit permit, uint256 feePct, address recipient, address token, uint256 deadline) { | ||
| require permit.kind == TokenLib.PermitKind.None, "simplification for prover performance"; | ||
| require e.msg.sender != currentContract, "bundler is never its own caller"; | ||
| require receiver != currentContract, "no bundler donations of proceeds"; | ||
| require recipient != currentContract, "no bundler donations of the fee"; | ||
|
|
||
| mathint before = bundlerBalance[token]; | ||
| blueBundlesV1SupplyCollateralAndBorrow(e, marketParams, collateralAmount, borrowAssets, maxLtv, onBehalf, receiver, permit, feePct, recipient, deadline); | ||
| assert bundlerBalance[token] == before; | ||
| } | ||
|
|
||
| rule repayAndWithdrawCollateralPreservesBalance(env e, BlueBundlesV1.MarketParams marketParams, uint256 assets, uint256 maxRepayAssets, uint256 withdrawCollateralAssets, uint256 maxLtv, address onBehalf, address receiver, TokenLib.TokenPermit permit, uint256 feePct, address recipient, address token, uint256 deadline) { | ||
| require permit.kind == TokenLib.PermitKind.None, "simplification for prover performance"; | ||
| require e.msg.sender != currentContract, "bundler is never its own caller"; | ||
| require receiver != currentContract, "no bundler donations of proceeds"; | ||
| require recipient != currentContract, "no bundler donations of the fee"; | ||
|
|
||
| mathint before = bundlerBalance[token]; | ||
| blueBundlesV1RepayAndWithdrawCollateral(e, marketParams, assets, maxRepayAssets, withdrawCollateralAssets, maxLtv, onBehalf, receiver, permit, feePct, recipient, deadline); | ||
| assert bundlerBalance[token] == before; | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why excluding this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. I think it's because requires another setup, because of the callback: the current model of
repayis too simplistic. Adding this to the wish list