-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
584 additions
and
26 deletions.
There are no files selected for viewing
This file contains 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,140 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.25; | ||
|
||
import {SelfDestruct} from "src/contracts/SelfDestruct.sol"; | ||
|
||
import {IDC_ETHx_Burner} from "src/interfaces/burners/DC_ETHx/IDC_ETHx_Burner.sol"; | ||
import {IStaderStakePoolsManager} from "src/interfaces/burners/DC_ETHx/IStaderStakePoolsManager.sol"; | ||
import {IUserWithdrawalManager} from "src/interfaces/burners/DC_ETHx/IUserWithdrawalManager.sol"; | ||
import {IStaderConfig} from "src/interfaces/burners/DC_ETHx/IStaderConfig.sol"; | ||
|
||
import {IDefaultCollateral} from "@symbiotic/collateral/interfaces/defaultCollateral/IDefaultCollateral.sol"; | ||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; | ||
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; | ||
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; | ||
|
||
contract DC_ETHx_Burner is IDC_ETHx_Burner { | ||
using Math for uint256; | ||
using EnumerableSet for EnumerableSet.UintSet; | ||
|
||
/** | ||
* @inheritdoc IDC_ETHx_Burner | ||
*/ | ||
address public immutable COLLATERAL; | ||
|
||
/** | ||
* @inheritdoc IDC_ETHx_Burner | ||
*/ | ||
address public immutable ASSET; | ||
|
||
/** | ||
* @inheritdoc IDC_ETHx_Burner | ||
*/ | ||
address public immutable STADER_CONFIG; | ||
|
||
/** | ||
* @inheritdoc IDC_ETHx_Burner | ||
*/ | ||
address public immutable USER_WITHDRAW_MANAGER; | ||
|
||
/** | ||
* @inheritdoc IDC_ETHx_Burner | ||
*/ | ||
address public immutable STAKE_POOLS_MANAGER; | ||
|
||
EnumerableSet.UintSet private _requestIds; | ||
|
||
constructor(address collateral, address staderConfig) { | ||
COLLATERAL = collateral; | ||
|
||
ASSET = IDefaultCollateral(collateral).asset(); | ||
|
||
STADER_CONFIG = staderConfig; | ||
USER_WITHDRAW_MANAGER = IStaderConfig(STADER_CONFIG).getUserWithdrawManager(); | ||
STAKE_POOLS_MANAGER = IStaderConfig(STADER_CONFIG).getStakePoolManager(); | ||
|
||
IERC20(ASSET).approve(USER_WITHDRAW_MANAGER, type(uint256).max); | ||
} | ||
|
||
/** | ||
* @inheritdoc IDC_ETHx_Burner | ||
*/ | ||
function requestIdsLength() external view returns (uint256) { | ||
return _requestIds.length(); | ||
} | ||
|
||
/** | ||
* @inheritdoc IDC_ETHx_Burner | ||
*/ | ||
function requestIds(uint256 index, uint256 maxRequestIds) external view returns (uint256[] memory requestIds_) { | ||
uint256 length = Math.min(index + maxRequestIds, _requestIds.length()) - index; | ||
|
||
requestIds_ = new uint256[](length); | ||
for (uint256 i; i < length;) { | ||
requestIds_[i] = _requestIds.at(index); | ||
unchecked { | ||
++i; | ||
++index; | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* @inheritdoc IDC_ETHx_Burner | ||
*/ | ||
function triggerWithdrawal(uint256 maxRequests) external returns (uint256 firstRequestId, uint256 lastRequestId) { | ||
IDefaultCollateral(COLLATERAL).withdraw(address(this), IERC20(COLLATERAL).balanceOf(address(this))); | ||
uint256 amount = IERC20(ASSET).balanceOf(address(this)); | ||
|
||
uint256 maxWithdrawalAmount = IStaderStakePoolsManager(STAKE_POOLS_MANAGER).previewDeposit( | ||
IStaderConfig(STADER_CONFIG).getMaxWithdrawAmount() | ||
); | ||
uint256 minWithdrawalAmount = IStaderStakePoolsManager(STAKE_POOLS_MANAGER).previewDeposit( | ||
IStaderConfig(STADER_CONFIG).getMinWithdrawAmount() | ||
) + 1; | ||
|
||
uint256 requests = amount / maxWithdrawalAmount; | ||
if (amount % maxWithdrawalAmount >= minWithdrawalAmount) { | ||
requests += 1; | ||
} | ||
requests = Math.min(requests, maxRequests); | ||
|
||
if (requests == 0) { | ||
revert InsufficientWithdrawal(); | ||
} | ||
|
||
uint256 requestsMinusOne = requests - 1; | ||
firstRequestId = IUserWithdrawalManager(USER_WITHDRAW_MANAGER).nextRequestId(); | ||
lastRequestId = firstRequestId + requestsMinusOne; | ||
uint256 requestId = firstRequestId; | ||
for (; requestId < lastRequestId; ++requestId) { | ||
_requestIds.add(requestId); | ||
IUserWithdrawalManager(USER_WITHDRAW_MANAGER).requestWithdraw(maxWithdrawalAmount, address(this)); | ||
} | ||
_requestIds.add(requestId); | ||
IUserWithdrawalManager(USER_WITHDRAW_MANAGER).requestWithdraw( | ||
Math.min(amount - requestsMinusOne * maxWithdrawalAmount, maxWithdrawalAmount), address(this) | ||
); | ||
|
||
emit TriggerWithdrawal(msg.sender, firstRequestId, lastRequestId); | ||
|
||
return (firstRequestId, lastRequestId); | ||
} | ||
|
||
/** | ||
* @inheritdoc IDC_ETHx_Burner | ||
*/ | ||
function triggerBurn(uint256 requestId) external { | ||
if (!_requestIds.remove(requestId)) { | ||
revert InvalidRequestId(); | ||
} | ||
|
||
IUserWithdrawalManager(USER_WITHDRAW_MANAGER).claim(requestId); | ||
|
||
new SelfDestruct{value: address(this).balance}(); | ||
|
||
emit TriggerBurn(msg.sender, requestId); | ||
} | ||
|
||
receive() external payable {} | ||
} |
This file contains 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
This file contains 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,74 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.25; | ||
|
||
interface IDC_ETHx_Burner { | ||
error InsufficientWithdrawal(); | ||
error InvalidRequestId(); | ||
|
||
/** | ||
* @notice Emitted when a withdrawal is triggered. | ||
* @param caller caller of the function | ||
* @param firstRequestId first request ID that was created | ||
* @param lastRequestId last request ID that was created | ||
*/ | ||
event TriggerWithdrawal(address indexed caller, uint256 firstRequestId, uint256 lastRequestId); | ||
|
||
/** | ||
* @notice Emitted when a burn is triggered. | ||
* @param caller caller of the function | ||
* @param requestId request ID of the withdrawal that was claimed and burned | ||
*/ | ||
event TriggerBurn(address indexed caller, uint256 requestId); | ||
|
||
/** | ||
* @notice Get an address of the Default Collateral contract. | ||
*/ | ||
function COLLATERAL() external view returns (address); | ||
|
||
/** | ||
* @notice Get an address of the collateral's asset. | ||
*/ | ||
function ASSET() external view returns (address); | ||
|
||
/** | ||
* @notice Get an address of the Stader Config contract. | ||
*/ | ||
function STADER_CONFIG() external view returns (address); | ||
|
||
/** | ||
* @notice Get an address of the User Withdraw Manager contract. | ||
*/ | ||
function USER_WITHDRAW_MANAGER() external view returns (address); | ||
|
||
/** | ||
* @notice Get an address of the Stake Pools Manager contract. | ||
*/ | ||
function STAKE_POOLS_MANAGER() external view returns (address); | ||
|
||
/** | ||
* @notice Get the number of unprocessed request IDs. | ||
*/ | ||
function requestIdsLength() external view returns (uint256); | ||
|
||
/** | ||
* @notice Get a list of unprocessed request IDs. | ||
* @param index index of the first request ID | ||
* @param maxRequestIds maximum number of request IDs to return | ||
* @return requestIds request IDs | ||
*/ | ||
function requestIds(uint256 index, uint256 maxRequestIds) external view returns (uint256[] memory requestIds); | ||
|
||
/** | ||
* @notice Trigger a withdrawal of ETH from the collateral's underlying asset. | ||
* @param maxRequests maximum number of withdrawal requests to create | ||
* @return firstRequestId first request ID that was created | ||
* @return lastRequestId last request ID that was created | ||
*/ | ||
function triggerWithdrawal(uint256 maxRequests) external returns (uint256 firstRequestId, uint256 lastRequestId); | ||
|
||
/** | ||
* @notice Trigger a claim and a burn of ETH. | ||
* @param requestId request ID of the withdrawal to process | ||
*/ | ||
function triggerBurn(uint256 requestId) external; | ||
} |
This file contains 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,14 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.25; | ||
|
||
interface IStaderConfig { | ||
function getUserWithdrawManager() external view returns (address); | ||
|
||
function getStakePoolManager() external view returns (address); | ||
|
||
function getMinWithdrawAmount() external view returns (uint256); | ||
|
||
function getMaxWithdrawAmount() external view returns (uint256); | ||
|
||
function getMinBlockDelayToFinalizeWithdrawRequest() external view returns (uint256); | ||
} |
10 changes: 10 additions & 0 deletions
10
src/interfaces/burners/DC_ETHx/IStaderStakePoolsManager.sol
This file contains 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,10 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.25; | ||
|
||
interface IStaderStakePoolsManager { | ||
// returns the amount of share corresponding to `_assets` assets | ||
function previewDeposit(uint256 _assets) external view returns (uint256); | ||
|
||
// return the amount of assets corresponding to `_shares` shares | ||
function previewWithdraw(uint256 _shares) external view returns (uint256); | ||
} |
This file contains 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,28 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.25; | ||
|
||
interface IUserWithdrawalManager { | ||
function nextRequestId() external view returns (uint256); | ||
|
||
function nextRequestIdToFinalize() external view returns (uint256); | ||
|
||
/** | ||
* @notice put a withdrawal request | ||
* @param _ethXAmount amount of ethX shares to withdraw | ||
* @param _owner owner of withdraw request to redeem | ||
* @return requestId | ||
*/ | ||
function requestWithdraw(uint256 _ethXAmount, address _owner) external returns (uint256); | ||
|
||
/** | ||
* @notice finalize user requests | ||
* @dev check for safeMode to finalizeRequest | ||
*/ | ||
function finalizeUserWithdrawalRequest() external; | ||
|
||
/** | ||
* @notice transfer the eth of finalized request to recipient and delete the request | ||
* @param _requestId request id to redeem | ||
*/ | ||
function claim(uint256 _requestId) external; | ||
} |
Oops, something went wrong.