-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix auction edge case and add WLWrappedERC20 (#343)
- Loading branch information
Showing
4 changed files
with
163 additions
and
1 deletion.
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,86 @@ | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
pragma solidity ^0.8.18; | ||
|
||
import {SafeERC20} from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; | ||
import {SafeCast} from "openzeppelin/utils/math/SafeCast.sol"; | ||
import {ConvertDecimals} from "lyra-utils/decimals/ConvertDecimals.sol"; | ||
|
||
import {IERC20Metadata} from "openzeppelin/token/ERC20/extensions/IERC20Metadata.sol"; | ||
import {ISubAccounts} from "../interfaces/ISubAccounts.sol"; | ||
import {IAsset} from "../interfaces/IAsset.sol"; | ||
import {WrappedERC20Asset} from "./WrappedERC20Asset.sol"; | ||
|
||
/** | ||
* @title Whitelisted Wrapped ERC20 Asset | ||
* @dev Select users (subaccounts) can deposit the given ERC20, and can only have positive balances. | ||
* @dev Fee-on-transfer and rebasing tokens are not supported | ||
* @author Lyra | ||
*/ | ||
contract WLWrappedERC20Asset is WrappedERC20Asset { | ||
using SafeERC20 for IERC20Metadata; | ||
using ConvertDecimals for uint; | ||
using SafeCast for uint; | ||
using SafeCast for int; | ||
|
||
/// @dev Subaccounts which have been whitelisted to be able to deposit | ||
mapping(uint accountId => bool) public wlAccounts; | ||
bool public wlEnabled = true; | ||
|
||
constructor(ISubAccounts _subAccounts, IERC20Metadata _wrappedAsset) WrappedERC20Asset(_subAccounts, _wrappedAsset) {} | ||
|
||
/////////// | ||
// Admin // | ||
/////////// | ||
|
||
/** | ||
* @dev Whitelist a subaccount to be able to deposit the ERC20 | ||
* @param accountId The subaccount to whitelist | ||
*/ | ||
function setSubAccountWL(uint accountId, bool isWhitelisted) external onlyOwner { | ||
wlAccounts[accountId] = isWhitelisted; | ||
emit SubAccountWhitelisted(accountId, isWhitelisted); | ||
} | ||
|
||
function setWhitelistEnabled(bool enabled) external onlyOwner { | ||
wlEnabled = enabled; | ||
} | ||
|
||
//////////////////////////// | ||
// External Functions // | ||
//////////////////////////// | ||
|
||
/** | ||
* @dev Deposit ERC20 asset and increase account balance | ||
* @param recipientAccount account id to receive the cash asset | ||
* @param assetAmount amount of the wrapped asset to deposit | ||
*/ | ||
function deposit(uint recipientAccount, uint assetAmount) external override { | ||
if (wlEnabled && !wlAccounts[recipientAccount]) { | ||
revert WLWERC_NotWhitelisted(); | ||
} | ||
|
||
wrappedAsset.safeTransferFrom(msg.sender, address(this), assetAmount); | ||
uint adjustmentAmount = assetAmount.to18Decimals(assetDecimals); | ||
|
||
subAccounts.assetAdjustment( | ||
ISubAccounts.AssetAdjustment({ | ||
acc: recipientAccount, | ||
asset: IAsset(address(this)), | ||
subId: 0, | ||
amount: int(adjustmentAmount), | ||
assetData: bytes32(0) | ||
}), | ||
true, | ||
"" | ||
); | ||
|
||
emit Deposit(recipientAccount, msg.sender, adjustmentAmount, assetAmount); | ||
} | ||
|
||
/////////////////// | ||
// Events/Errors // | ||
/////////////////// | ||
event SubAccountWhitelisted(uint indexed subaccount, bool isWhitelisted); | ||
|
||
error WLWERC_NotWhitelisted(); | ||
} |
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
76 changes: 76 additions & 0 deletions
76
test/assets/wrapped-erc20/unit-tests/WLWrappedERC20Hook.t.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,76 @@ | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
pragma solidity ^0.8.18; | ||
|
||
import "forge-std/Test.sol"; | ||
import "forge-std/console2.sol"; | ||
|
||
import "test/shared/mocks/MockERC20.sol"; | ||
import "test/shared/mocks/MockManager.sol"; | ||
import {IPositionTracking} from "../../../../src/interfaces/IPositionTracking.sol"; | ||
import {IAllowances} from "../../../../src/interfaces/IAllowances.sol"; | ||
import "../../../../src/assets/WLWrappedERC20Asset.sol"; | ||
import "../../../../src/SubAccounts.sol"; | ||
|
||
contract UNIT_WLWrappedBaseAssetHook is Test { | ||
WLWrappedERC20Asset asset; | ||
MockERC20 wbtc; | ||
MockManager manager; | ||
|
||
SubAccounts subAccounts; | ||
|
||
uint accId1; | ||
uint accId2; | ||
|
||
function setUp() public { | ||
subAccounts = new SubAccounts("Lyra Margin Accounts", "LyraMarginNFTs"); | ||
|
||
manager = new MockManager(address(subAccounts)); | ||
wbtc = new MockERC20("WBTC", "WBTC"); | ||
wbtc.setDecimals(8); | ||
|
||
asset = new WLWrappedERC20Asset(subAccounts, wbtc); | ||
accId1 = subAccounts.createAccount(address(this), manager); | ||
accId2 = subAccounts.createAccount(address(this), manager); | ||
asset.setWhitelistManager(address(manager), true); | ||
|
||
wbtc.mint(address(this), 1000e8); | ||
wbtc.approve(address(asset), 1000e8); | ||
} | ||
|
||
function testDeposit() public { | ||
vm.expectRevert(WLWrappedERC20Asset.WLWERC_NotWhitelisted.selector); | ||
asset.deposit(accId1, 100e8); | ||
|
||
asset.setSubAccountWL(accId1, true); | ||
|
||
// only acc1 can deposit now | ||
asset.deposit(accId1, 100e8); | ||
|
||
assertEq(wbtc.balanceOf(address(asset)), 100e8); | ||
assertEq(subAccounts.getBalance(accId1, asset, 0), 100e18); // 18 decimals | ||
|
||
vm.expectRevert(WLWrappedERC20Asset.WLWERC_NotWhitelisted.selector); | ||
asset.deposit(accId2, 100e8); | ||
|
||
// even though not WL can still be transferred to | ||
ISubAccounts.AssetTransfer memory transfer = ISubAccounts.AssetTransfer({ | ||
fromAcc: accId1, toAcc: accId2, asset: asset, subId: 0, amount: 20e18, assetData: "" | ||
}); | ||
subAccounts.submitTransfer(transfer, ""); | ||
|
||
assertEq(subAccounts.getBalance(accId1, asset, 0), 80e18); // 18 decimals | ||
assertEq(subAccounts.getBalance(accId2, asset, 0), 20e18); // 18 decimals | ||
|
||
// acc 2 can also still withdraw | ||
asset.withdraw(accId2, 10e8, address(this)); | ||
assertEq(subAccounts.getBalance(accId2, asset, 0), 10e18); // 18 decimals | ||
assertEq(wbtc.balanceOf(address(asset)), 90e8); // 100 deposited and 10 withdrawn | ||
|
||
// now enable it for anyone | ||
asset.setWhitelistEnabled(false); | ||
asset.deposit(accId2, 100e8); | ||
|
||
assertEq(wbtc.balanceOf(address(asset)), 190e8); // 200 deposited and 10 withdrawn | ||
assertEq(subAccounts.getBalance(accId2, asset, 0), 110e18); // 18 decimals | ||
} | ||
} |
File renamed without changes.