From 5c6455aa1ee743543b4769b427b179a1fbea0013 Mon Sep 17 00:00:00 2001 From: ashirleyshe Date: Fri, 19 Dec 2025 18:13:49 +0800 Subject: [PATCH] feat(periphery): add supra --- src/core/helpers/SatoshiPeriphery.sol | 212 +++++++++++++++++++++++++- 1 file changed, 210 insertions(+), 2 deletions(-) diff --git a/src/core/helpers/SatoshiPeriphery.sol b/src/core/helpers/SatoshiPeriphery.sol index e04dac7..70b7061 100644 --- a/src/core/helpers/SatoshiPeriphery.sol +++ b/src/core/helpers/SatoshiPeriphery.sol @@ -11,7 +11,9 @@ import { ICoreFacet } from "../interfaces/ICoreFacet.sol"; import { ILiquidationFacet } from "../interfaces/ILiquidationFacet.sol"; import { ITroveManager } from "../interfaces/ITroveManager.sol"; +import { ISupraOraclePull } from "../../priceFeed/interfaces/ISupraOraclePull.sol"; import { IDebtToken } from "../interfaces/IDebtToken.sol"; +import { IPriceFeedAggregatorFacet } from "../interfaces/IPriceFeedAggregatorFacet.sol"; import { ISatoshiPeriphery, LzSendParam } from "./interfaces/ISatoshiPeriphery.sol"; import { IWETH } from "./interfaces/IWETH.sol"; import { @@ -92,21 +94,63 @@ contract SatoshiPeriphery is ISatoshiPeriphery, UUPSUpgradeable, OwnableUpgradea _afterWithdrawDebt(userDebtAmount, _lzSendParam); } + function openTroveWithSupraPriceUpdate( + ITroveManager troveManager, + uint256 _maxFeePercentage, + uint256 _collAmount, + uint256 _debtAmount, + address _upperHint, + address _lowerHint, + LzSendParam calldata _lzSendParam, + bytes calldata _bytesProof + ) + external + payable + { + IERC20 collateralToken = troveManager.collateralToken(); + + _updateSupraPriceFeed(troveManager, _bytesProof); + + _beforeAddColl(collateralToken, _collAmount); + + uint256 debtTokenBalanceBefore = debtToken.balanceOf(address(this)); + + IBorrowerOperationsFacet(xApp) + .openTrove(troveManager, msg.sender, _maxFeePercentage, _collAmount, _debtAmount, _upperHint, _lowerHint); + + uint256 debtTokenBalanceAfter = debtToken.balanceOf(address(this)); + uint256 userDebtAmount = debtTokenBalanceAfter - debtTokenBalanceBefore; + require(userDebtAmount == _debtAmount, "SatoshiPeriphery: Debt amount mismatch"); + + _afterWithdrawDebt(userDebtAmount, _lzSendParam); + } + /// @notice Add collateral to a active trove /// @param troveManager The TroveManager contract /// @param _collAmount The amount of additional collateral /// @param _upperHint The upper hint (for querying the position of the sorted trove) /// @param _lowerHint The lower hint (for querying the position of the sorted trove) - function addColl( + function addColl(ITroveManager troveManager, uint256 _collAmount, address _upperHint, address _lowerHint) external { + IERC20 collateralToken = troveManager.collateralToken(); + + _beforeAddColl(collateralToken, _collAmount); + + IBorrowerOperationsFacet(xApp).addColl(troveManager, msg.sender, _collAmount, _upperHint, _lowerHint); + } + + function addCollWithSupraPriceUpdate( ITroveManager troveManager, uint256 _collAmount, address _upperHint, - address _lowerHint + address _lowerHint, + bytes calldata _bytesProof ) external { IERC20 collateralToken = troveManager.collateralToken(); + _updateSupraPriceFeed(troveManager, _bytesProof); + _beforeAddColl(collateralToken, _collAmount); IBorrowerOperationsFacet(xApp).addColl(troveManager, msg.sender, _collAmount, _upperHint, _lowerHint); @@ -138,6 +182,28 @@ contract SatoshiPeriphery is ISatoshiPeriphery, UUPSUpgradeable, OwnableUpgradea _afterWithdrawColl(collateralToken, userCollAmount); } + function withdrawCollWithSupraPriceUpdate( + ITroveManager troveManager, + uint256 _collWithdrawal, + address _upperHint, + address _lowerHint, + bytes calldata _bytesProof + ) + external + { + IERC20 collateralToken = troveManager.collateralToken(); + uint256 collTokenBalanceBefore = collateralToken.balanceOf(address(this)); + + _updateSupraPriceFeed(troveManager, _bytesProof); + + IBorrowerOperationsFacet(xApp).withdrawColl(troveManager, msg.sender, _collWithdrawal, _upperHint, _lowerHint); + + uint256 collTokenBalanceAfter = collateralToken.balanceOf(address(this)); + uint256 userCollAmount = collTokenBalanceAfter - collTokenBalanceBefore; + require(userCollAmount == _collWithdrawal, "SatoshiPeriphery: Collateral amount mismatch"); + _afterWithdrawColl(collateralToken, userCollAmount); + } + /// @notice Issues _debtAmount of Debt token from the caller’s Trove to the caller. /// @dev Executes only if the Trove's collateralization ratio would remain above the minimum /// @param troveManager The TroveManager contract @@ -166,6 +232,29 @@ contract SatoshiPeriphery is ISatoshiPeriphery, UUPSUpgradeable, OwnableUpgradea _afterWithdrawDebt(userDebtAmount, _lzSendParam); } + function withdrawDebtWithSupraPriceUpdate( + ITroveManager troveManager, + uint256 _maxFeePercentage, + uint256 _debtAmount, + address _upperHint, + address _lowerHint, + LzSendParam calldata _lzSendParam, + bytes calldata _bytesProof + ) + external + payable + { + uint256 debtTokenBalanceBefore = debtToken.balanceOf(address(this)); + _updateSupraPriceFeed(troveManager, _bytesProof); + IBorrowerOperationsFacet(xApp) + .withdrawDebt(troveManager, msg.sender, _maxFeePercentage, _debtAmount, _upperHint, _lowerHint); + uint256 debtTokenBalanceAfter = debtToken.balanceOf(address(this)); + uint256 userDebtAmount = debtTokenBalanceAfter - debtTokenBalanceBefore; + require(userDebtAmount == _debtAmount, "SatoshiPeriphery: Debt amount mismatch"); + + _afterWithdrawDebt(userDebtAmount, _lzSendParam); + } + /// @notice Repays _debtAmount of Debt token to the caller’s Trove /// @param troveManager The TroveManager contract /// @param _debtAmount The amount of debt to repay @@ -184,6 +273,21 @@ contract SatoshiPeriphery is ISatoshiPeriphery, UUPSUpgradeable, OwnableUpgradea IBorrowerOperationsFacet(xApp).repayDebt(troveManager, msg.sender, _debtAmount, _upperHint, _lowerHint); } + function repayDebtWithSupraPriceUpdate( + ITroveManager troveManager, + uint256 _debtAmount, + address _upperHint, + address _lowerHint, + bytes calldata _bytesProof + ) + external + { + _updateSupraPriceFeed(troveManager, _bytesProof); + _beforeRepayDebt(_debtAmount); + + IBorrowerOperationsFacet(xApp).repayDebt(troveManager, msg.sender, _debtAmount, _upperHint, _lowerHint); + } + /// @notice Enables a borrower to simultaneously change (decrease/increase) both their collateral and debt, function adjustTrove( ITroveManager troveManager, @@ -238,6 +342,61 @@ contract SatoshiPeriphery is ISatoshiPeriphery, UUPSUpgradeable, OwnableUpgradea } } + function adjustTroveWithSupraPriceUpdate( + ITroveManager troveManager, + uint256 _maxFeePercentage, + uint256 _collDeposit, + uint256 _collWithdrawal, + uint256 _debtChange, + bool _isDebtIncrease, + address _upperHint, + address _lowerHint, + LzSendParam calldata _lzSendParam, + bytes calldata _bytesProof + ) + external + payable + { + if (_collDeposit != 0 && _collWithdrawal != 0) revert CannotWithdrawAndAddColl(); + + IERC20 collateralToken = troveManager.collateralToken(); + _updateSupraPriceFeed(troveManager, _bytesProof); + _beforeAddColl(collateralToken, _collDeposit); + + uint256 debtTokenBalanceBefore = debtToken.balanceOf(address(this)); + + // repay debt + if (!_isDebtIncrease) { + _beforeRepayDebt(_debtChange); + } + + IBorrowerOperationsFacet(xApp) + .adjustTrove( + troveManager, + msg.sender, + _maxFeePercentage, + _collDeposit, + _collWithdrawal, + _debtChange, + _isDebtIncrease, + _upperHint, + _lowerHint + ); + + uint256 debtTokenBalanceAfter = debtToken.balanceOf(address(this)); + // withdraw collateral + _afterWithdrawColl(collateralToken, _collWithdrawal); + + // withdraw debt + if (_isDebtIncrease) { + require( + debtTokenBalanceAfter - debtTokenBalanceBefore == _debtChange, "SatoshiPeriphery: Debt amount mismatch" + ); + + _afterWithdrawDebt(_debtChange, _lzSendParam); + } + } + /// @notice Close the trove from the caller /// @param troveManager The TroveManager contract function closeTrove(ITroveManager troveManager) external { @@ -256,6 +415,23 @@ contract SatoshiPeriphery is ISatoshiPeriphery, UUPSUpgradeable, OwnableUpgradea _afterWithdrawColl(collateralToken, userCollAmount); } + function closeTroveWithSupraPriceUpdate(ITroveManager troveManager, bytes calldata _bytesProof) external { + (uint256 collAmount, uint256 debtAmount) = troveManager.getTroveCollAndDebt(msg.sender); + uint256 netDebtAmount = debtAmount - ICoreFacet(xApp).gasCompensation(); + _updateSupraPriceFeed(troveManager, _bytesProof); + _beforeRepayDebt(netDebtAmount); + + IERC20 collateralToken = troveManager.collateralToken(); + uint256 collTokenBalanceBefore = collateralToken.balanceOf(address(this)); + + IBorrowerOperationsFacet(xApp).closeTrove(troveManager, msg.sender); + + uint256 collTokenBalanceAfter = collateralToken.balanceOf(address(this)); + uint256 userCollAmount = collTokenBalanceAfter - collTokenBalanceBefore; + require(userCollAmount == collAmount, "SatoshiPeriphery: Collateral amount mismatch"); + _afterWithdrawColl(collateralToken, userCollAmount); + } + function liquidateTroves( ITroveManager troveManager, uint256 maxTrovesToLiquidate, @@ -280,6 +456,32 @@ contract SatoshiPeriphery is ISatoshiPeriphery, UUPSUpgradeable, OwnableUpgradea _afterWithdrawColl(troveManager.collateralToken(), userCollAmount); } + function liquidateTrovesWithSupraPriceUpdate( + ITroveManager troveManager, + uint256 maxTrovesToLiquidate, + uint256 maxICR, + LzSendParam calldata _lzSendParam, + bytes calldata _bytesProof + ) + external + payable + { + uint256 debtTokenBalanceBefore = debtToken.balanceOf(address(this)); + uint256 collTokenBalanceBefore = troveManager.collateralToken().balanceOf(address(this)); + _updateSupraPriceFeed(troveManager, _bytesProof); + + ILiquidationFacet(xApp).liquidateTroves(troveManager, maxTrovesToLiquidate, maxICR); + + uint256 debtTokenBalanceAfter = debtToken.balanceOf(address(this)); + uint256 collTokenBalanceAfter = troveManager.collateralToken().balanceOf(address(this)); + + uint256 userDebtAmount = debtTokenBalanceAfter - debtTokenBalanceBefore; + uint256 userCollAmount = collTokenBalanceAfter - collTokenBalanceBefore; + + _afterWithdrawDebt(userDebtAmount, _lzSendParam); + _afterWithdrawColl(troveManager.collateralToken(), userCollAmount); + } + // INTERNAL FUNCTIONS // /// @dev Only support ERC20 token, not support native token @@ -346,4 +548,10 @@ contract SatoshiPeriphery is ISatoshiPeriphery, UUPSUpgradeable, OwnableUpgradea function _authorizeUpgrade(address newImplementation) internal view override onlyOwner { // No additional authorization logic is needed for this contract } + + function _updateSupraPriceFeed(ITroveManager troveManager, bytes calldata _bytesProof) internal { + (IPriceFeed priceFeed,) = IPriceFeedAggregatorFacet(xApp).oracleRecords(troveManager.collateralToken()); + ISupraOraclePull supra_pull = ISupraOraclePull(priceFeed.source()); + supra_pull.verifyOracleProof(_bytesProof); + } }