POC Borrow and lend callbacks#552
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f224c90130
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| IERC4626(vault).withdraw(buyerAssets, buyer, buyer); | ||
| } else if (withdrawType == WithdrawType.Midnight) { | ||
| address obligationDataAddress = address(uint160(uint256(withdrawData))); | ||
| Obligation memory otherObligation = abi.decode(obligationDataAddress.code, (Obligation)); | ||
| Midnight(midnight).withdraw(otherObligation, buyerAssets, buyer, buyer); |
There was a problem hiding this comment.
Reject callback sources that use a different loan token
onBuy never checks that the selected source actually matches obligation.loanToken. If callbackData points to a vault or another Midnight obligation for a different asset and the buyer already has the traded loan token approved to Midnight, the callback will withdraw the wrong asset first and Midnight.take will still settle using the buyer's wallet balance. That turns a bad source configuration into an unintended extra withdrawal instead of a clean revert.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
not sure it should be required, could be a comment
| function withdraw(uint256 assets, address receiver, address) external returns (uint256) { | ||
| ERC20(asset).transfer(receiver, assets); | ||
| return assets; |
There was a problem hiding this comment.
Make the vault mock enforce ERC4626 ownership rules
MockVault.withdraw ignores the owner argument and has no share or allowance accounting, so the new testOnBuyVaultV2* cases can pass even when LenderCallback.onBuy would revert against a compliant ERC4626. In particular, the callback currently calls withdraw(buyerAssets, buyer, buyer) as a third party, and this mock never exercises the approval check that a real vault would perform.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
will update the test with arbitrary vault v2 when the adapter is live
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0b9f0c7a2b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| { | ||
| require(msg.sender == MIDNIGHT, "unauthorized"); | ||
| address vault = abi.decode(data, (address)); | ||
| IERC4626(vault).withdraw(buyerAssets, buyer, buyer); |
There was a problem hiding this comment.
Validate vault asset before withdrawing
onBuy withdraws from any vault address in data but never checks that IERC4626(vault).asset() matches the offer’s obligation.loanToken. When the source vault holds a different asset and the buyer already has/approved the obligation loan token, take still succeeds by pulling the loan token from the wallet while also draining the unrelated vault asset, turning a bad callback config into unintended extra withdrawal. Fresh evidence after the callback split: this new VaultLenderCallback path ignores the Obligation token fields entirely.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
same as before, it could be a comment
| require(msg.sender == MIDNIGHT, "unauthorized"); | ||
| bytes32 otherObligationId = abi.decode(data, (bytes32)); | ||
| Obligation memory otherObligation = abi.decode(address(uint160(uint256(otherObligationId))).code, (Obligation)); | ||
| Midnight(MIDNIGHT).withdraw(otherObligation, buyerAssets, buyer, buyer); |
There was a problem hiding this comment.
Validate source obligation token before withdrawing
onBuy decodes an arbitrary source obligation from data and immediately calls Midnight.withdraw without verifying that otherObligation.loanToken equals the traded obligation.loanToken. If data points to a different-token obligation and the buyer has approved the traded token, settlement can still complete from wallet balance while withdrawing unrelated funds from the source obligation, so a misconfigured callback does not fail closed. Fresh evidence after the split: the new ObligationLenderCallback still ignores the destination obligation’s token in this path.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
same as before, it could be a comment
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ee5c8fdad9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Co-authored-by: prd-carapulse[bot] <264278285+prd-carapulse[bot]@users.noreply.github.com> Co-authored-by: Quentin Garchery <garchery.quentin@gmail.com>
Co-authored-by: MathisGD <74971347+MathisGD@users.noreply.github.com> Co-authored-by: prd-carapulse[bot] <264278285+prd-carapulse[bot]@users.noreply.github.com> Co-authored-by: MathisGD <mathis@morpho.xyz> Co-authored-by: Quentin Garchery <garchery.quentin@gmail.com>
Signed-off-by: MathisGD <74971347+MathisGD@users.noreply.github.com> Co-authored-by: Quentin Garchery <garchery.quentin@gmail.com>
Signed-off-by: MathisGD <74971347+MathisGD@users.noreply.github.com> Co-authored-by: MathisGD <74971347+MathisGD@users.noreply.github.com> Co-authored-by: MathisGD <mathis@morpho.xyz>
Signed-off-by: MathisGD <74971347+MathisGD@users.noreply.github.com> Co-authored-by: MathisGD <74971347+MathisGD@users.noreply.github.com> Co-authored-by: MathisGD <mathis@morpho.xyz>
Co-authored-by: MathisGD <74971347+MathisGD@users.noreply.github.com>
Co-authored-by: Adrien Husson <adhusson@gmail.com>
Co-authored-by: peyha <peyha.nicole@outlook.fr>
Signed-off-by: MathisGD <74971347+MathisGD@users.noreply.github.com>
Co-authored-by: prd-carapulse[bot] <264278285+prd-carapulse[bot]@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 864df15f18
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| require(msg.sender == MIDNIGHT, "unauthorized"); | ||
| CollateralData[] memory collateralData = abi.decode(data, (CollateralData[])); | ||
| for (uint256 i = 0; i < collateralData.length; i++) { | ||
| Midnight(MIDNIGHT) |
There was a problem hiding this comment.
Add allowance setup for collateral transfers
BorrowerCallback.onSell calls Midnight.supplyCollateral from the callback address, but this contract never grants MIDNIGHT an allowance for collateral tokens and exposes no function to do so. On-chain, a regular ERC20 collateral therefore reverts on first use when supplyCollateral reaches safeTransferFrom with allowance(callback, MIDNIGHT) == 0. The new tests pass only because they impersonate the callback address with vm.prank(...) to call approve, which is not possible in production.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: adb8a02744
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bdf8858f0f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| require(msg.sender == MIDNIGHT, "unauthorized"); | ||
| bytes32 otherMarketId = abi.decode(data, (bytes32)); | ||
| Market memory otherMarket = abi.decode(address(uint160(uint256(otherMarketId))).code, (Market)); | ||
| Midnight(MIDNIGHT).withdraw(otherMarket, buyerAssets, buyer, address(this)); |
There was a problem hiding this comment.
Reject withdrawing from the market being filled
When data points to the same market as the active take, this withdraw can burn the buyer's just-booked credit before the callback payment is collected, because Midnight.take updates credit/debt and then invokes the buy callback before the loan-token transfers. If the market already has withdrawable liquidity, a lender can fund a new borrow from existing repaid funds without bringing external assets, leaving the new debt unmatched by lender credit. Keep the id callback parameter and reject a source market whose decoded/recomputed id equals it, e.g. require(Midnight(MIDNIGHT).toId(otherMarket) != id, "same market");.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 486aebc53e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The borrow callback supply collaterals on behalf of the user (maker or taker) while the lend callback withdraws the liquidity (either from another obligation or from a morpho vault) on behalf of the user.
Additional questions