From b93db9e2dfc7046e6f3048613178760be9f12805 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Sun, 30 Jun 2024 19:35:01 +0800 Subject: [PATCH 01/39] feat: BlastYield contract --- contracts/BlastYield.sol | 62 ++++++++++++++++++++ contracts/interfaces/IBlast.sol | 77 +++++++++++++++++++++++++ contracts/interfaces/IBlastPoints.sol | 6 ++ contracts/interfaces/IERC20Rebasing.sol | 21 +++++++ package.json | 3 + yarn.lock | 5 ++ 6 files changed, 174 insertions(+) create mode 100644 contracts/BlastYield.sol create mode 100644 contracts/interfaces/IBlast.sol create mode 100644 contracts/interfaces/IBlastPoints.sol create mode 100644 contracts/interfaces/IERC20Rebasing.sol diff --git a/contracts/BlastYield.sol b/contracts/BlastYield.sol new file mode 100644 index 0000000..18e95e2 --- /dev/null +++ b/contracts/BlastYield.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; +import {IBlast, YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "./interfaces/IBlast.sol"; +import {IBlastPoints} from "./interfaces/IBlastPoints.sol"; +import {IERC20Rebasing, YieldMode as IERC20Rebasing__YieldMode} from "./interfaces/IERC20Rebasing.sol"; + +/** + * @title BlastYield + * @notice This contract is a base contract for future contracts that wish to claim Blast WETH or USDB yield to inherit from. + * @author LooksRare protocol team (πŸ‘€,πŸ’Ž) + */ +contract BlastYield is AccessControl { + address public immutable WETH; + address public immutable USDB; + + /** + * @param _blast Blast precompile + * @param _blastPoints Blast points + * @param _blastPointsOperator Blast points operator + * @param _owner Owner of the contract + * @param _usdb USDB address + * @param _weth WETH address + */ + constructor( + address _blast, + address _blastPoints, + address _blastPointsOperator, + address _owner, + address _usdb, + address _weth + ) { + _grantRole(DEFAULT_ADMIN_ROLE, _owner); + + WETH = _weth; + USDB = _usdb; + + IBlast(_blast).configure(IBlast__YieldMode.CLAIMABLE, IBlast__GasMode.CLAIMABLE, _owner); + IBlastPoints(_blastPoints).configurePointsOperator(_blastPointsOperator); + IERC20Rebasing(_weth).configure(IERC20Rebasing__YieldMode.CLAIMABLE); + IERC20Rebasing(_usdb).configure(IERC20Rebasing__YieldMode.CLAIMABLE); + } + + /** + * @notice Claim Blast yield. Only callable by contract owner. + * @param wethReceiver The receiver of WETH. + * @param usdbReceiver The receiver of USDB. + */ + function claim(address wethReceiver, address usdbReceiver) external virtual onlyRole(DEFAULT_ADMIN_ROLE) { + uint256 claimableWETH = IERC20Rebasing(WETH).getClaimableAmount(address(this)); + if (claimableWETH != 0) { + IERC20Rebasing(WETH).claim(wethReceiver, claimableWETH); + } + + uint256 claimableUSDB = IERC20Rebasing(USDB).getClaimableAmount(address(this)); + if (claimableUSDB != 0) { + IERC20Rebasing(USDB).claim(usdbReceiver, claimableUSDB); + } + } +} diff --git a/contracts/interfaces/IBlast.sol b/contracts/interfaces/IBlast.sol new file mode 100644 index 0000000..c0c88db --- /dev/null +++ b/contracts/interfaces/IBlast.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +enum YieldMode { + AUTOMATIC, + VOID, + CLAIMABLE +} + +enum GasMode { + VOID, + CLAIMABLE +} + +interface IBlast { + // configure + function configureContract(address contractAddress, YieldMode _yield, GasMode gasMode, address governor) external; + + function configure(YieldMode _yield, GasMode gasMode, address governor) external; + + // base configuration options + function configureClaimableYield() external; + + function configureClaimableYieldOnBehalf(address contractAddress) external; + + function configureAutomaticYield() external; + + function configureAutomaticYieldOnBehalf(address contractAddress) external; + + function configureVoidYield() external; + + function configureVoidYieldOnBehalf(address contractAddress) external; + + function configureClaimableGas() external; + + function configureClaimableGasOnBehalf(address contractAddress) external; + + function configureVoidGas() external; + + function configureVoidGasOnBehalf(address contractAddress) external; + + function configureGovernor(address _governor) external; + + function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external; + + // claim yield + function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256); + + function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256); + + // claim gas + function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256); + + function claimGasAtMinClaimRate( + address contractAddress, + address recipientOfGas, + uint256 minClaimRateBips + ) external returns (uint256); + + function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256); + + function claimGas( + address contractAddress, + address recipientOfGas, + uint256 gasToClaim, + uint256 gasSecondsToConsume + ) external returns (uint256); + + // read functions + function readClaimableYield(address contractAddress) external view returns (uint256); + + function readYieldConfiguration(address contractAddress) external view returns (uint8); + + function readGasParams( + address contractAddress + ) external view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode); +} diff --git a/contracts/interfaces/IBlastPoints.sol b/contracts/interfaces/IBlastPoints.sol new file mode 100644 index 0000000..14ba788 --- /dev/null +++ b/contracts/interfaces/IBlastPoints.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +interface IBlastPoints { + function configurePointsOperator(address operator) external; +} diff --git a/contracts/interfaces/IERC20Rebasing.sol b/contracts/interfaces/IERC20Rebasing.sol new file mode 100644 index 0000000..d8e1579 --- /dev/null +++ b/contracts/interfaces/IERC20Rebasing.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +enum YieldMode { + AUTOMATIC, + VOID, + CLAIMABLE +} + +interface IERC20Rebasing { + // changes the yield mode of the caller and update the balance + // to reflect the configuration + function configure(YieldMode) external returns (uint256); + + // "claimable" yield mode accounts can call this this claim their yield + // to another address + function claim(address recipient, uint256 amount) external returns (uint256); + + // read the claimable amount for an account + function getClaimableAmount(address account) external view returns (uint256); +} diff --git a/package.json b/package.json index 498dcd1..d064e0f 100644 --- a/package.json +++ b/package.json @@ -83,5 +83,8 @@ "ts-node": "^10.1.0", "typechain": "^5.1.2", "typescript": "^4.5.2" + }, + "dependencies": { + "@openzeppelin/contracts": "^5.0.2" } } diff --git a/yarn.lock b/yarn.lock index a033662..01f2722 100644 --- a/yarn.lock +++ b/yarn.lock @@ -962,6 +962,11 @@ dependencies: "@octokit/openapi-types" "^11.2.0" +"@openzeppelin/contracts@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.0.2.tgz#b1d03075e49290d06570b2fd42154d76c2a5d210" + integrity sha512-ytPc6eLGcHHnapAZ9S+5qsdomhjo6QBHTDRRBFfTxXIpsicMhVPouPgmUPebZZZGX7vt9USA+Z+0M0dSVtSUEA== + "@resolver-engine/core@^0.3.3": version "0.3.3" resolved "https://registry.yarnpkg.com/@resolver-engine/core/-/core-0.3.3.tgz#590f77d85d45bc7ecc4e06c654f41345db6ca967" From 84451901e1cf1c8b886e73511eb7ff2b8f6d971d Mon Sep 17 00:00:00 2001 From: stonehenge Date: Mon, 1 Jul 2024 10:14:21 +0800 Subject: [PATCH 02/39] fix: Compilier error --- hardhat.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hardhat.config.ts b/hardhat.config.ts index 7b19454..baacebf 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -33,7 +33,7 @@ const config: HardhatUserConfig = { solidity: { compilers: [ { - version: "0.8.17", + version: "0.8.20", settings: { optimizer: { enabled: true, runs: 888888 } }, }, { From f9fcf923dfe37319d9ba7e8b38d040fe84a584fd Mon Sep 17 00:00:00 2001 From: stonehenge Date: Mon, 1 Jul 2024 10:16:54 +0800 Subject: [PATCH 03/39] fix: Compilier error --- contracts/BlastYield.sol | 2 +- contracts/interfaces/IBlast.sol | 2 +- contracts/interfaces/IBlastPoints.sol | 2 +- contracts/interfaces/IERC20Rebasing.sol | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/BlastYield.sol b/contracts/BlastYield.sol index 18e95e2..4174d0f 100644 --- a/contracts/BlastYield.sol +++ b/contracts/BlastYield.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.24; +pragma solidity ^0.8.20; import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; import {IBlast, YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "./interfaces/IBlast.sol"; diff --git a/contracts/interfaces/IBlast.sol b/contracts/interfaces/IBlast.sol index c0c88db..ceb3367 100644 --- a/contracts/interfaces/IBlast.sol +++ b/contracts/interfaces/IBlast.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.24; +pragma solidity ^0.8.20; enum YieldMode { AUTOMATIC, diff --git a/contracts/interfaces/IBlastPoints.sol b/contracts/interfaces/IBlastPoints.sol index 14ba788..318b06f 100644 --- a/contracts/interfaces/IBlastPoints.sol +++ b/contracts/interfaces/IBlastPoints.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.24; +pragma solidity ^0.8.20; interface IBlastPoints { function configurePointsOperator(address operator) external; diff --git a/contracts/interfaces/IERC20Rebasing.sol b/contracts/interfaces/IERC20Rebasing.sol index d8e1579..da5e7db 100644 --- a/contracts/interfaces/IERC20Rebasing.sol +++ b/contracts/interfaces/IERC20Rebasing.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.24; +pragma solidity ^0.8.20; enum YieldMode { AUTOMATIC, From 2edb97e964a5fc4e50b0cac087a3f419d728e5bc Mon Sep 17 00:00:00 2001 From: stonehenge Date: Tue, 2 Jul 2024 18:17:07 +0800 Subject: [PATCH 04/39] test: BlastYield Tests --- contracts/BlastYield.sol | 3 ++ test/foundry/BlastYield.t.sol | 77 +++++++++++++++++++++++++++++++++ test/mock/MockBlastERC20.sol | 30 +++++++++++++ test/mock/MockBlastPoints.sol | 6 +++ test/mock/MockBlastWETH.sol | 80 +++++++++++++++++++++++++++++++++++ test/mock/MockBlastYield.sol | 18 ++++++++ 6 files changed, 214 insertions(+) create mode 100644 test/foundry/BlastYield.t.sol create mode 100644 test/mock/MockBlastERC20.sol create mode 100644 test/mock/MockBlastPoints.sol create mode 100644 test/mock/MockBlastWETH.sol create mode 100644 test/mock/MockBlastYield.sol diff --git a/contracts/BlastYield.sol b/contracts/BlastYield.sol index 4174d0f..6a44aac 100644 --- a/contracts/BlastYield.sol +++ b/contracts/BlastYield.sol @@ -15,6 +15,7 @@ import {IERC20Rebasing, YieldMode as IERC20Rebasing__YieldMode} from "./interfac contract BlastYield is AccessControl { address public immutable WETH; address public immutable USDB; + bytes32 private constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); /** * @param _blast Blast precompile @@ -33,6 +34,8 @@ contract BlastYield is AccessControl { address _weth ) { _grantRole(DEFAULT_ADMIN_ROLE, _owner); + _grantRole(OPERATOR_ROLE, _owner); + _grantRole(OPERATOR_ROLE, _blastPointsOperator); WETH = _weth; USDB = _usdb; diff --git a/test/foundry/BlastYield.t.sol b/test/foundry/BlastYield.t.sol new file mode 100644 index 0000000..6ea8414 --- /dev/null +++ b/test/foundry/BlastYield.t.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {BlastYield} from "../../contracts/BlastYield.sol"; +import {Test} from "../../lib/forge-std/src/Test.sol"; +import {YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "../../contracts/interfaces/IBlast.sol"; +import {YieldMode as IERC20Rebasing__YieldMode} from "../../contracts/interfaces/IERC20Rebasing.sol"; + +import {MockERC20} from "../mock/MockBlastERC20.sol"; +import {MockPoints} from "../mock/MockBlastPoints.sol"; +import {MockWETH} from "../mock/MockBlastWETH.sol"; +import {MockYield} from "../mock/MockBlastYield.sol"; + +contract BlastYield_Test is Test { + MockWETH private weth; + MockERC20 private usdb; + MockYield private mockYield; + MockPoints private mockPoints; + BlastYield private blastYield; + + address public owner = address(69); + address public operator = address(420); + address private constant TREASURY = address(69420); + address internal constant BLAST = 0x4300000000000000000000000000000000000002; + address internal constant BLAST_POINTS = 0x2536FE9ab3F511540F2f9e2eC2A805005C3Dd800; + + function setUp() public { + vm.etch(BLAST, address(new MockYield()).code); + vm.etch(BLAST_POINTS, address(new MockPoints()).code); + weth = new MockWETH(); + usdb = new MockERC20("USDB", "USDB"); + blastYield = new BlastYield(BLAST, BLAST_POINTS, operator, owner, address(usdb), address(weth)); + } + + function test_setUpState() public { + assertEq(blastYield.WETH(), address(weth)); + assertEq(blastYield.USDB(), address(usdb)); + assertTrue(blastYield.hasRole(bytes32(0), owner)); + assertTrue(blastYield.hasRole(keccak256("OPERATOR_ROLE"), owner)); + assertTrue(blastYield.hasRole(keccak256("OPERATOR_ROLE"), operator)); + + (IBlast__YieldMode yieldMode, IBlast__GasMode gasMode, address governor) = mockYield.config( + address(blastYield) + ); + assertEq(uint8(yieldMode), uint8(IBlast__YieldMode.CLAIMABLE)); + assertEq(uint8(gasMode), uint8(IBlast__GasMode.CLAIMABLE)); + assertEq(governor, owner); + + IERC20Rebasing__YieldMode wethYieldMode = weth.yieldMode(address(blastYield)); + assertEq(uint8(wethYieldMode), uint8(IERC20Rebasing__YieldMode.CLAIMABLE)); + + IERC20Rebasing__YieldMode usdbYieldMode = usdb.yieldMode(address(blastYield)); + assertEq(uint8(usdbYieldMode), uint8(IERC20Rebasing__YieldMode.CLAIMABLE)); + } + + function test_claim() public { + vm.startPrank(owner); + blastYield.claim(TREASURY, TREASURY); + + vm.stopPrank(); + + assertEq(weth.balanceOf(address(blastYield)), 0); + assertEq(usdb.balanceOf(address(blastYield)), 0); + assertEq(weth.balanceOf(TREASURY), 1 ether); + assertEq(usdb.balanceOf(TREASURY), 1 ether); + } + + function test_claim_RevertIf_NotOwner() public { + vm.expectRevert( + abi.encodePacked( + "AccessControl: account 0xb4c79dab8f259c7aee6e5b2aa729821864227e84 is missing role 0x0000000000000000000000000000000000000000000000000000000000000000" + ) + ); + blastYield.claim(TREASURY, TREASURY); + } +} diff --git a/test/mock/MockBlastERC20.sol b/test/mock/MockBlastERC20.sol new file mode 100644 index 0000000..a243811 --- /dev/null +++ b/test/mock/MockBlastERC20.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.23; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +import {YieldMode} from "../../../contracts/interfaces/IERC20Rebasing.sol"; + +contract MockERC20 is ERC20 { + mapping(address => YieldMode) public yieldMode; + + constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) {} + + function mint(address to, uint256 amount) public { + _mint(to, amount); + } + + function configure(YieldMode _yieldMode) external returns (uint256) { + yieldMode[msg.sender] = _yieldMode; + return uint256(_yieldMode); + } + + function getClaimableAmount(address) external pure returns (uint256) { + return 1 ether; + } + + function claim(address receiver, uint256 amount) external returns (uint256) { + _mint(receiver, amount); + return amount; + } +} diff --git a/test/mock/MockBlastPoints.sol b/test/mock/MockBlastPoints.sol new file mode 100644 index 0000000..a62fba6 --- /dev/null +++ b/test/mock/MockBlastPoints.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract MockPoints { + function configurePointsOperator(address operator) external {} +} diff --git a/test/mock/MockBlastWETH.sol b/test/mock/MockBlastWETH.sol new file mode 100644 index 0000000..65871bb --- /dev/null +++ b/test/mock/MockBlastWETH.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {YieldMode} from "../../../contracts/interfaces/IERC20Rebasing.sol"; + +contract MockWETH { + string public name = "Wrapped Ether"; + string public symbol = "WETH"; + uint8 public decimals = 18; + + event Approval(address indexed src, address indexed guy, uint256 wad); + event Transfer(address indexed src, address indexed dst, uint256 wad); + event Deposit(address indexed dst, uint256 wad); + event Withdrawal(address indexed src, uint256 wad); + + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + + mapping(address => YieldMode) public yieldMode; + + receive() external payable { + deposit(); + } + + function configure(YieldMode _yieldMode) external returns (uint256) { + yieldMode[msg.sender] = _yieldMode; + return uint256(_yieldMode); + } + + function getClaimableAmount(address) external pure returns (uint256) { + return 1 ether; + } + + function claim(address receiver, uint256 amount) external returns (uint256) { + balanceOf[receiver] += amount; + return amount; + } + + function deposit() public payable { + balanceOf[msg.sender] += msg.value; + emit Deposit(msg.sender, msg.value); + } + + function withdraw(uint256 wad) public { + require(balanceOf[msg.sender] >= wad); + balanceOf[msg.sender] -= wad; + payable(msg.sender).transfer(wad); + emit Withdrawal(msg.sender, wad); + } + + function totalSupply() public view returns (uint256) { + return address(this).balance; + } + + function approve(address guy, uint256 wad) public returns (bool) { + allowance[msg.sender][guy] = wad; + emit Approval(msg.sender, guy, wad); + return true; + } + + function transfer(address dst, uint256 wad) public returns (bool) { + return transferFrom(msg.sender, dst, wad); + } + + function transferFrom(address src, address dst, uint256 wad) public returns (bool) { + require(balanceOf[src] >= wad); + + if (src != msg.sender && allowance[src][msg.sender] != type(uint256).max) { + require(allowance[src][msg.sender] >= wad); + allowance[src][msg.sender] -= wad; + } + + balanceOf[src] -= wad; + balanceOf[dst] += wad; + + emit Transfer(src, dst, wad); + + return true; + } +} diff --git a/test/mock/MockBlastYield.sol b/test/mock/MockBlastYield.sol new file mode 100644 index 0000000..803af15 --- /dev/null +++ b/test/mock/MockBlastYield.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {YieldMode, GasMode} from "../../../contracts/interfaces/IBlast.sol"; + +contract MockYield { + struct Config { + YieldMode yieldMode; + GasMode gasMode; + address governor; + } + + mapping(address => Config) public config; + + function configure(YieldMode _yield, GasMode _gasMode, address _governor) external { + config[msg.sender] = Config(_yield, _gasMode, _governor); + } +} From edbe35f39041533cbc6428c403428841dbda3c8d Mon Sep 17 00:00:00 2001 From: stonehenge Date: Wed, 3 Jul 2024 12:20:07 +0800 Subject: [PATCH 05/39] test: BlastYield Test Fixes --- contracts/BlastYield.sol | 3 +-- test/foundry/BlastYield.t.sol | 30 ++++++++++++++++-------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/contracts/BlastYield.sol b/contracts/BlastYield.sol index 6a44aac..e2f6b3d 100644 --- a/contracts/BlastYield.sol +++ b/contracts/BlastYield.sol @@ -33,7 +33,6 @@ contract BlastYield is AccessControl { address _usdb, address _weth ) { - _grantRole(DEFAULT_ADMIN_ROLE, _owner); _grantRole(OPERATOR_ROLE, _owner); _grantRole(OPERATOR_ROLE, _blastPointsOperator); @@ -51,7 +50,7 @@ contract BlastYield is AccessControl { * @param wethReceiver The receiver of WETH. * @param usdbReceiver The receiver of USDB. */ - function claim(address wethReceiver, address usdbReceiver) external virtual onlyRole(DEFAULT_ADMIN_ROLE) { + function claim(address wethReceiver, address usdbReceiver) external virtual onlyRole(OPERATOR_ROLE) { uint256 claimableWETH = IERC20Rebasing(WETH).getClaimableAmount(address(this)); if (claimableWETH != 0) { IERC20Rebasing(WETH).claim(wethReceiver, claimableWETH); diff --git a/test/foundry/BlastYield.t.sol b/test/foundry/BlastYield.t.sol index 6ea8414..a6b24eb 100644 --- a/test/foundry/BlastYield.t.sol +++ b/test/foundry/BlastYield.t.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.20; +import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol"; import {BlastYield} from "../../contracts/BlastYield.sol"; import {Test} from "../../lib/forge-std/src/Test.sol"; import {YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "../../contracts/interfaces/IBlast.sol"; @@ -21,24 +22,24 @@ contract BlastYield_Test is Test { address public owner = address(69); address public operator = address(420); + address public user1 = address(1); address private constant TREASURY = address(69420); - address internal constant BLAST = 0x4300000000000000000000000000000000000002; address internal constant BLAST_POINTS = 0x2536FE9ab3F511540F2f9e2eC2A805005C3Dd800; + bytes32 private constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); function setUp() public { - vm.etch(BLAST, address(new MockYield()).code); vm.etch(BLAST_POINTS, address(new MockPoints()).code); weth = new MockWETH(); usdb = new MockERC20("USDB", "USDB"); - blastYield = new BlastYield(BLAST, BLAST_POINTS, operator, owner, address(usdb), address(weth)); + mockYield = new MockYield(); + blastYield = new BlastYield(address(mockYield), BLAST_POINTS, operator, owner, address(usdb), address(weth)); } function test_setUpState() public { assertEq(blastYield.WETH(), address(weth)); assertEq(blastYield.USDB(), address(usdb)); - assertTrue(blastYield.hasRole(bytes32(0), owner)); - assertTrue(blastYield.hasRole(keccak256("OPERATOR_ROLE"), owner)); - assertTrue(blastYield.hasRole(keccak256("OPERATOR_ROLE"), operator)); + assertTrue(blastYield.hasRole(OPERATOR_ROLE, owner)); + assertTrue(blastYield.hasRole(OPERATOR_ROLE, operator)); (IBlast__YieldMode yieldMode, IBlast__GasMode gasMode, address governor) = mockYield.config( address(blastYield) @@ -54,24 +55,25 @@ contract BlastYield_Test is Test { assertEq(uint8(usdbYieldMode), uint8(IERC20Rebasing__YieldMode.CLAIMABLE)); } - function test_claim() public { - vm.startPrank(owner); + function test_claim() public asPrankedUser(owner) { blastYield.claim(TREASURY, TREASURY); - vm.stopPrank(); - assertEq(weth.balanceOf(address(blastYield)), 0); assertEq(usdb.balanceOf(address(blastYield)), 0); assertEq(weth.balanceOf(TREASURY), 1 ether); assertEq(usdb.balanceOf(TREASURY), 1 ether); } - function test_claim_RevertIf_NotOwner() public { + function test_claim_RevertIf_NotOwner() public asPrankedUser(user1) { vm.expectRevert( - abi.encodePacked( - "AccessControl: account 0xb4c79dab8f259c7aee6e5b2aa729821864227e84 is missing role 0x0000000000000000000000000000000000000000000000000000000000000000" - ) + abi.encodeWithSelector(IAccessControl.AccessControlUnauthorizedAccount.selector, user1, OPERATOR_ROLE) ); blastYield.claim(TREASURY, TREASURY); } + + modifier asPrankedUser(address user) { + vm.startPrank(user); + _; + vm.stopPrank(); + } } From fe415c30b32489391e60f3d20f3725fd610611de Mon Sep 17 00:00:00 2001 From: stonehenge Date: Wed, 3 Jul 2024 12:38:21 +0800 Subject: [PATCH 06/39] fix: Prettier and Mocks --- package.json | 2 +- test/mock/MockBlastERC20.sol | 2 +- test/mock/MockBlastYield.sol | 2 +- yarn.lock | 42 ++++++++++++++++-------------------- 4 files changed, 22 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index d064e0f..41b791c 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "husky": "^7.0.4", "merkletreejs": "^0.2.31", "prettier": "^2.3.2", - "prettier-plugin-solidity": "^1.1.1", + "prettier-plugin-solidity": "^1.3.0", "release-it": "^15.0.0", "solhint": "^3.3.7", "solidity-coverage": "^0.7.21", diff --git a/test/mock/MockBlastERC20.sol b/test/mock/MockBlastERC20.sol index a243811..f87867e 100644 --- a/test/mock/MockBlastERC20.sol +++ b/test/mock/MockBlastERC20.sol @@ -6,7 +6,7 @@ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {YieldMode} from "../../../contracts/interfaces/IERC20Rebasing.sol"; contract MockERC20 is ERC20 { - mapping(address => YieldMode) public yieldMode; + mapping(address _contract => YieldMode) public yieldMode; constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) {} diff --git a/test/mock/MockBlastYield.sol b/test/mock/MockBlastYield.sol index 803af15..9991517 100644 --- a/test/mock/MockBlastYield.sol +++ b/test/mock/MockBlastYield.sol @@ -10,7 +10,7 @@ contract MockYield { address governor; } - mapping(address => Config) public config; + mapping(address _contract => Config) public config; function configure(YieldMode _yield, GasMode _gasMode, address _governor) external { config[msg.sender] = Config(_yield, _gasMode, _governor); diff --git a/yarn.lock b/yarn.lock index 01f2722..b21b315 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1089,12 +1089,10 @@ dependencies: antlr4ts "^0.5.0-alpha.4" -"@solidity-parser/parser@^0.14.5": - version "0.14.5" - resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.5.tgz#87bc3cc7b068e08195c219c91cd8ddff5ef1a804" - integrity sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg== - dependencies: - antlr4ts "^0.5.0-alpha.4" +"@solidity-parser/parser@^0.17.0": + version "0.17.0" + resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.17.0.tgz#52a2fcc97ff609f72011014e4c5b485ec52243ef" + integrity sha512-Nko8R0/kUo391jsEHHxrGM07QFdnPGvlmox4rmH0kNiNAashItAilhy4Mv4pK5gQmW5f4sXAF58fwJbmlkGcVw== "@szmarczak/http-timer@^1.1.2": version "1.1.2" @@ -9013,14 +9011,14 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier-plugin-solidity@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.1.1.tgz#4d3375b85f97812ffcbe48d5a8b3fe914d69c91f" - integrity sha512-uD24KO26tAHF+zMN2nt1OUzfknzza5AgxjogQQrMLZc7j8xiQrDoNWNeOlfFC0YLTwo12CLD10b9niLyP6AqXg== +prettier-plugin-solidity@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.3.1.tgz#59944d3155b249f7f234dee29f433524b9a4abcf" + integrity sha512-MN4OP5I2gHAzHZG1wcuJl0FsLS3c4Cc5494bbg+6oQWBPuEamjwDvmGfFMZ6NFzsh3Efd9UUxeT7ImgjNH4ozA== dependencies: - "@solidity-parser/parser" "^0.14.5" - semver "^7.3.8" - solidity-comments-extractor "^0.0.7" + "@solidity-parser/parser" "^0.17.0" + semver "^7.5.4" + solidity-comments-extractor "^0.0.8" prettier@^1.14.3: version "1.19.1" @@ -9983,12 +9981,10 @@ semver@^6.0.0, semver@^6.1.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.8: - version "7.3.8" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== - dependencies: - lru-cache "^6.0.0" +semver@^7.5.4: + version "7.6.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== semver@~5.4.1: version "5.4.1" @@ -10306,10 +10302,10 @@ solhint@^3.3.7: optionalDependencies: prettier "^1.14.3" -solidity-comments-extractor@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19" - integrity sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw== +solidity-comments-extractor@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.8.tgz#f6e148ab0c49f30c1abcbecb8b8df01ed8e879f8" + integrity sha512-htM7Vn6LhHreR+EglVMd2s+sZhcXAirB1Zlyrv5zBuTxieCvjfnRpd7iZk75m/u6NOlEyQ94C6TWbBn2cY7w8g== solidity-coverage@^0.7.21: version "0.7.21" From b7e2d0d8625e910cef4c250c9af21c8d637a3d41 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Wed, 3 Jul 2024 12:47:31 +0800 Subject: [PATCH 07/39] fix: Increase node version for github actions --- .github/workflows/checks.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 9d59e9c..63fe7ed 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -17,7 +17,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 14.x + node-version: 16.x - name: Get yarn cache directory path id: yarn-cache-dir-path run: echo "::set-output name=dir::$(yarn cache dir)" From d1c8d3fe7442317630156a7496963618056bf3a1 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Wed, 3 Jul 2024 12:49:12 +0800 Subject: [PATCH 08/39] fix: Increase node version for github actions --- .github/workflows/tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index dfa9724..776ee19 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -17,7 +17,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 14.x + node-version: 16.x - name: Get yarn cache directory path id: yarn-cache-dir-path run: echo "::set-output name=dir::$(yarn cache dir)" From 9ca51b78744cf4b4b3c25abf990884d9443787e5 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Thu, 4 Jul 2024 07:32:53 +0400 Subject: [PATCH 09/39] fix: Update Access Control to OwnableTwoSteps --- contracts/BlastYield.sol | 12 ++++-------- test/foundry/BlastYield.t.sol | 9 +++------ 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/contracts/BlastYield.sol b/contracts/BlastYield.sol index e2f6b3d..2018fc7 100644 --- a/contracts/BlastYield.sol +++ b/contracts/BlastYield.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.20; -import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; +import {OwnableTwoSteps} from "./OwnableTwoSteps.sol"; import {IBlast, YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "./interfaces/IBlast.sol"; import {IBlastPoints} from "./interfaces/IBlastPoints.sol"; import {IERC20Rebasing, YieldMode as IERC20Rebasing__YieldMode} from "./interfaces/IERC20Rebasing.sol"; @@ -12,10 +12,9 @@ import {IERC20Rebasing, YieldMode as IERC20Rebasing__YieldMode} from "./interfac * @notice This contract is a base contract for future contracts that wish to claim Blast WETH or USDB yield to inherit from. * @author LooksRare protocol team (πŸ‘€,πŸ’Ž) */ -contract BlastYield is AccessControl { +contract BlastYield is OwnableTwoSteps { address public immutable WETH; address public immutable USDB; - bytes32 private constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); /** * @param _blast Blast precompile @@ -32,10 +31,7 @@ contract BlastYield is AccessControl { address _owner, address _usdb, address _weth - ) { - _grantRole(OPERATOR_ROLE, _owner); - _grantRole(OPERATOR_ROLE, _blastPointsOperator); - + ) OwnableTwoSteps(_owner) { WETH = _weth; USDB = _usdb; @@ -50,7 +46,7 @@ contract BlastYield is AccessControl { * @param wethReceiver The receiver of WETH. * @param usdbReceiver The receiver of USDB. */ - function claim(address wethReceiver, address usdbReceiver) external virtual onlyRole(OPERATOR_ROLE) { + function claim(address wethReceiver, address usdbReceiver) external virtual onlyOwner { uint256 claimableWETH = IERC20Rebasing(WETH).getClaimableAmount(address(this)); if (claimableWETH != 0) { IERC20Rebasing(WETH).claim(wethReceiver, claimableWETH); diff --git a/test/foundry/BlastYield.t.sol b/test/foundry/BlastYield.t.sol index a6b24eb..352c15d 100644 --- a/test/foundry/BlastYield.t.sol +++ b/test/foundry/BlastYield.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.20; -import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol"; +import {IOwnableTwoSteps} from "../../contracts/interfaces/IOwnableTwoSteps.sol"; import {BlastYield} from "../../contracts/BlastYield.sol"; import {Test} from "../../lib/forge-std/src/Test.sol"; import {YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "../../contracts/interfaces/IBlast.sol"; @@ -38,8 +38,7 @@ contract BlastYield_Test is Test { function test_setUpState() public { assertEq(blastYield.WETH(), address(weth)); assertEq(blastYield.USDB(), address(usdb)); - assertTrue(blastYield.hasRole(OPERATOR_ROLE, owner)); - assertTrue(blastYield.hasRole(OPERATOR_ROLE, operator)); + assertEq(blastYield.owner(), owner); (IBlast__YieldMode yieldMode, IBlast__GasMode gasMode, address governor) = mockYield.config( address(blastYield) @@ -65,9 +64,7 @@ contract BlastYield_Test is Test { } function test_claim_RevertIf_NotOwner() public asPrankedUser(user1) { - vm.expectRevert( - abi.encodeWithSelector(IAccessControl.AccessControlUnauthorizedAccount.selector, user1, OPERATOR_ROLE) - ); + vm.expectRevert(IOwnableTwoSteps.NotOwner.selector); blastYield.claim(TREASURY, TREASURY); } From 6f67949c6a60d25eaf4f5102eaec324c8dba3a16 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Thu, 4 Jul 2024 16:17:33 +0400 Subject: [PATCH 10/39] feat: Private function to allow both access control and ownable two steps --- contracts/BlastYield.sol | 7 +++-- test/foundry/BlastYield.t.sol | 48 +++++++++++++++++++++++++---------- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/contracts/BlastYield.sol b/contracts/BlastYield.sol index 2018fc7..cd19a8b 100644 --- a/contracts/BlastYield.sol +++ b/contracts/BlastYield.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.20; -import {OwnableTwoSteps} from "./OwnableTwoSteps.sol"; import {IBlast, YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "./interfaces/IBlast.sol"; import {IBlastPoints} from "./interfaces/IBlastPoints.sol"; import {IERC20Rebasing, YieldMode as IERC20Rebasing__YieldMode} from "./interfaces/IERC20Rebasing.sol"; @@ -12,7 +11,7 @@ import {IERC20Rebasing, YieldMode as IERC20Rebasing__YieldMode} from "./interfac * @notice This contract is a base contract for future contracts that wish to claim Blast WETH or USDB yield to inherit from. * @author LooksRare protocol team (πŸ‘€,πŸ’Ž) */ -contract BlastYield is OwnableTwoSteps { +contract BlastYield { address public immutable WETH; address public immutable USDB; @@ -31,7 +30,7 @@ contract BlastYield is OwnableTwoSteps { address _owner, address _usdb, address _weth - ) OwnableTwoSteps(_owner) { + ) { WETH = _weth; USDB = _usdb; @@ -46,7 +45,7 @@ contract BlastYield is OwnableTwoSteps { * @param wethReceiver The receiver of WETH. * @param usdbReceiver The receiver of USDB. */ - function claim(address wethReceiver, address usdbReceiver) external virtual onlyOwner { + function _claim(address wethReceiver, address usdbReceiver) internal virtual { uint256 claimableWETH = IERC20Rebasing(WETH).getClaimableAmount(address(this)); if (claimableWETH != 0) { IERC20Rebasing(WETH).claim(wethReceiver, claimableWETH); diff --git a/test/foundry/BlastYield.t.sol b/test/foundry/BlastYield.t.sol index 352c15d..c4de21d 100644 --- a/test/foundry/BlastYield.t.sol +++ b/test/foundry/BlastYield.t.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.20; import {IOwnableTwoSteps} from "../../contracts/interfaces/IOwnableTwoSteps.sol"; +import {OwnableTwoSteps} from "../../contracts/OwnableTwoSteps.sol"; import {BlastYield} from "../../contracts/BlastYield.sol"; import {Test} from "../../lib/forge-std/src/Test.sol"; import {YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "../../contracts/interfaces/IBlast.sol"; @@ -13,12 +14,27 @@ import {MockPoints} from "../mock/MockBlastPoints.sol"; import {MockWETH} from "../mock/MockBlastWETH.sol"; import {MockYield} from "../mock/MockBlastYield.sol"; -contract BlastYield_Test is Test { +contract BlastYieldOwnableTwoSteps is BlastYield, OwnableTwoSteps { + constructor( + address _blast, + address _blastPoints, + address _blastPointsOperator, + address _owner, + address _usdb, + address _weth + ) BlastYield(_blast, _blastPoints, _blastPointsOperator, _owner, _usdb, _weth) OwnableTwoSteps(_owner) {} + + function claim(address wethReceiver, address usdbReceiver) public onlyOwner { + _claim(wethReceiver, usdbReceiver); + } +} + +contract BlastYieldOwnableTwoSteps_Test is Test { MockWETH private weth; MockERC20 private usdb; MockYield private mockYield; MockPoints private mockPoints; - BlastYield private blastYield; + BlastYieldOwnableTwoSteps private blastYieldOwnableTwoSteps; address public owner = address(69); address public operator = address(420); @@ -32,40 +48,46 @@ contract BlastYield_Test is Test { weth = new MockWETH(); usdb = new MockERC20("USDB", "USDB"); mockYield = new MockYield(); - blastYield = new BlastYield(address(mockYield), BLAST_POINTS, operator, owner, address(usdb), address(weth)); + blastYieldOwnableTwoSteps = new BlastYieldOwnableTwoSteps( + address(mockYield), + BLAST_POINTS, + operator, + owner, + address(usdb), + address(weth) + ); } function test_setUpState() public { - assertEq(blastYield.WETH(), address(weth)); - assertEq(blastYield.USDB(), address(usdb)); - assertEq(blastYield.owner(), owner); + assertEq(blastYieldOwnableTwoSteps.WETH(), address(weth)); + assertEq(blastYieldOwnableTwoSteps.USDB(), address(usdb)); (IBlast__YieldMode yieldMode, IBlast__GasMode gasMode, address governor) = mockYield.config( - address(blastYield) + address(blastYieldOwnableTwoSteps) ); assertEq(uint8(yieldMode), uint8(IBlast__YieldMode.CLAIMABLE)); assertEq(uint8(gasMode), uint8(IBlast__GasMode.CLAIMABLE)); assertEq(governor, owner); - IERC20Rebasing__YieldMode wethYieldMode = weth.yieldMode(address(blastYield)); + IERC20Rebasing__YieldMode wethYieldMode = weth.yieldMode(address(blastYieldOwnableTwoSteps)); assertEq(uint8(wethYieldMode), uint8(IERC20Rebasing__YieldMode.CLAIMABLE)); - IERC20Rebasing__YieldMode usdbYieldMode = usdb.yieldMode(address(blastYield)); + IERC20Rebasing__YieldMode usdbYieldMode = usdb.yieldMode(address(blastYieldOwnableTwoSteps)); assertEq(uint8(usdbYieldMode), uint8(IERC20Rebasing__YieldMode.CLAIMABLE)); } function test_claim() public asPrankedUser(owner) { - blastYield.claim(TREASURY, TREASURY); + blastYieldOwnableTwoSteps.claim(TREASURY, TREASURY); - assertEq(weth.balanceOf(address(blastYield)), 0); - assertEq(usdb.balanceOf(address(blastYield)), 0); + assertEq(weth.balanceOf(address(blastYieldOwnableTwoSteps)), 0); + assertEq(usdb.balanceOf(address(blastYieldOwnableTwoSteps)), 0); assertEq(weth.balanceOf(TREASURY), 1 ether); assertEq(usdb.balanceOf(TREASURY), 1 ether); } function test_claim_RevertIf_NotOwner() public asPrankedUser(user1) { vm.expectRevert(IOwnableTwoSteps.NotOwner.selector); - blastYield.claim(TREASURY, TREASURY); + blastYieldOwnableTwoSteps.claim(TREASURY, TREASURY); } modifier asPrankedUser(address user) { From e9cb33e1724f11ff061116c9d5cd6d8db4d1c452 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Thu, 4 Jul 2024 16:35:23 +0400 Subject: [PATCH 11/39] fix: Remove virtual from _claim --- contracts/BlastYield.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/BlastYield.sol b/contracts/BlastYield.sol index cd19a8b..532a532 100644 --- a/contracts/BlastYield.sol +++ b/contracts/BlastYield.sol @@ -45,7 +45,7 @@ contract BlastYield { * @param wethReceiver The receiver of WETH. * @param usdbReceiver The receiver of USDB. */ - function _claim(address wethReceiver, address usdbReceiver) internal virtual { + function _claim(address wethReceiver, address usdbReceiver) internal { uint256 claimableWETH = IERC20Rebasing(WETH).getClaimableAmount(address(this)); if (claimableWETH != 0) { IERC20Rebasing(WETH).claim(wethReceiver, claimableWETH); From cc8287718d05f286b5301a573fe6035425025c7b Mon Sep 17 00:00:00 2001 From: stonehenge Date: Thu, 4 Jul 2024 17:09:07 +0400 Subject: [PATCH 12/39] fix: Rename _owner to _governor --- contracts/BlastYield.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/BlastYield.sol b/contracts/BlastYield.sol index 532a532..8272965 100644 --- a/contracts/BlastYield.sol +++ b/contracts/BlastYield.sol @@ -19,7 +19,7 @@ contract BlastYield { * @param _blast Blast precompile * @param _blastPoints Blast points * @param _blastPointsOperator Blast points operator - * @param _owner Owner of the contract + * @param _governor Governor of the contract * @param _usdb USDB address * @param _weth WETH address */ @@ -27,14 +27,14 @@ contract BlastYield { address _blast, address _blastPoints, address _blastPointsOperator, - address _owner, + address _governor, address _usdb, address _weth ) { WETH = _weth; USDB = _usdb; - IBlast(_blast).configure(IBlast__YieldMode.CLAIMABLE, IBlast__GasMode.CLAIMABLE, _owner); + IBlast(_blast).configure(IBlast__YieldMode.CLAIMABLE, IBlast__GasMode.CLAIMABLE, _governor); IBlastPoints(_blastPoints).configurePointsOperator(_blastPointsOperator); IERC20Rebasing(_weth).configure(IERC20Rebasing__YieldMode.CLAIMABLE); IERC20Rebasing(_usdb).configure(IERC20Rebasing__YieldMode.CLAIMABLE); From e7dcbeb3b5c302ca7b2725b3cde6df60593d8056 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Thu, 4 Jul 2024 17:11:03 +0400 Subject: [PATCH 13/39] fix: Fix _claim notice --- contracts/BlastYield.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/BlastYield.sol b/contracts/BlastYield.sol index 8272965..14adac0 100644 --- a/contracts/BlastYield.sol +++ b/contracts/BlastYield.sol @@ -41,7 +41,7 @@ contract BlastYield { } /** - * @notice Claim Blast yield. Only callable by contract owner. + * @notice Claim Blast yield. Guarding of the function is dependent on the inherited contract. * @param wethReceiver The receiver of WETH. * @param usdbReceiver The receiver of USDB. */ From 25174449f39c8926683a1fed441d3ca3f9ed5424 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Thu, 4 Jul 2024 17:15:10 +0400 Subject: [PATCH 14/39] fix: Pass mockPoints --- test/foundry/BlastYield.t.sol | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/foundry/BlastYield.t.sol b/test/foundry/BlastYield.t.sol index c4de21d..afd18e6 100644 --- a/test/foundry/BlastYield.t.sol +++ b/test/foundry/BlastYield.t.sol @@ -40,17 +40,16 @@ contract BlastYieldOwnableTwoSteps_Test is Test { address public operator = address(420); address public user1 = address(1); address private constant TREASURY = address(69420); - address internal constant BLAST_POINTS = 0x2536FE9ab3F511540F2f9e2eC2A805005C3Dd800; bytes32 private constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); function setUp() public { - vm.etch(BLAST_POINTS, address(new MockPoints()).code); weth = new MockWETH(); usdb = new MockERC20("USDB", "USDB"); mockYield = new MockYield(); + mockPoints = new MockPoints(); blastYieldOwnableTwoSteps = new BlastYieldOwnableTwoSteps( address(mockYield), - BLAST_POINTS, + address(mockPoints), operator, owner, address(usdb), From 88ee19bcbaeed6c6850549581a34be03af5c4c8a Mon Sep 17 00:00:00 2001 From: stonehenge Date: Thu, 4 Jul 2024 17:21:25 +0400 Subject: [PATCH 15/39] fix: Remove operator role --- test/foundry/BlastYield.t.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/test/foundry/BlastYield.t.sol b/test/foundry/BlastYield.t.sol index afd18e6..a48a274 100644 --- a/test/foundry/BlastYield.t.sol +++ b/test/foundry/BlastYield.t.sol @@ -40,7 +40,6 @@ contract BlastYieldOwnableTwoSteps_Test is Test { address public operator = address(420); address public user1 = address(1); address private constant TREASURY = address(69420); - bytes32 private constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); function setUp() public { weth = new MockWETH(); From ce33daf9cf033280516e78d9ac601a8b5da5b6fb Mon Sep 17 00:00:00 2001 From: stonehenge Date: Thu, 4 Jul 2024 17:29:16 +0400 Subject: [PATCH 16/39] fix: Mock naming --- test/foundry/BlastYield.t.sol | 30 +++++++++++++++--------------- test/mock/MockBlastERC20.sol | 2 +- test/mock/MockBlastPoints.sol | 2 +- test/mock/MockBlastWETH.sol | 2 +- test/mock/MockBlastYield.sol | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/test/foundry/BlastYield.t.sol b/test/foundry/BlastYield.t.sol index a48a274..43d3cab 100644 --- a/test/foundry/BlastYield.t.sol +++ b/test/foundry/BlastYield.t.sol @@ -9,10 +9,10 @@ import {Test} from "../../lib/forge-std/src/Test.sol"; import {YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "../../contracts/interfaces/IBlast.sol"; import {YieldMode as IERC20Rebasing__YieldMode} from "../../contracts/interfaces/IERC20Rebasing.sol"; -import {MockERC20} from "../mock/MockBlastERC20.sol"; -import {MockPoints} from "../mock/MockBlastPoints.sol"; -import {MockWETH} from "../mock/MockBlastWETH.sol"; -import {MockYield} from "../mock/MockBlastYield.sol"; +import {MockBlastERC20} from "../mock/MockBlastERC20.sol"; +import {MockBlastPoints} from "../mock/MockBlastPoints.sol"; +import {MockBlastWETH} from "../mock/MockBlastWETH.sol"; +import {MockBlastYield} from "../mock/MockBlastYield.sol"; contract BlastYieldOwnableTwoSteps is BlastYield, OwnableTwoSteps { constructor( @@ -30,10 +30,10 @@ contract BlastYieldOwnableTwoSteps is BlastYield, OwnableTwoSteps { } contract BlastYieldOwnableTwoSteps_Test is Test { - MockWETH private weth; - MockERC20 private usdb; - MockYield private mockYield; - MockPoints private mockPoints; + MockBlastWETH private weth; + MockBlastERC20 private usdb; + MockBlastYield private mockBlastYield; + MockBlastPoints private mockBlastPoints; BlastYieldOwnableTwoSteps private blastYieldOwnableTwoSteps; address public owner = address(69); @@ -42,13 +42,13 @@ contract BlastYieldOwnableTwoSteps_Test is Test { address private constant TREASURY = address(69420); function setUp() public { - weth = new MockWETH(); - usdb = new MockERC20("USDB", "USDB"); - mockYield = new MockYield(); - mockPoints = new MockPoints(); + weth = new MockBlastWETH(); + usdb = new MockBlastERC20("USDB", "USDB"); + mockBlastYield = new MockBlastYield(); + mockBlastPoints = new MockBlastPoints(); blastYieldOwnableTwoSteps = new BlastYieldOwnableTwoSteps( - address(mockYield), - address(mockPoints), + address(mockBlastYield), + address(mockBlastPoints), operator, owner, address(usdb), @@ -60,7 +60,7 @@ contract BlastYieldOwnableTwoSteps_Test is Test { assertEq(blastYieldOwnableTwoSteps.WETH(), address(weth)); assertEq(blastYieldOwnableTwoSteps.USDB(), address(usdb)); - (IBlast__YieldMode yieldMode, IBlast__GasMode gasMode, address governor) = mockYield.config( + (IBlast__YieldMode yieldMode, IBlast__GasMode gasMode, address governor) = mockBlastYield.config( address(blastYieldOwnableTwoSteps) ); assertEq(uint8(yieldMode), uint8(IBlast__YieldMode.CLAIMABLE)); diff --git a/test/mock/MockBlastERC20.sol b/test/mock/MockBlastERC20.sol index f87867e..7cdd0aa 100644 --- a/test/mock/MockBlastERC20.sol +++ b/test/mock/MockBlastERC20.sol @@ -5,7 +5,7 @@ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {YieldMode} from "../../../contracts/interfaces/IERC20Rebasing.sol"; -contract MockERC20 is ERC20 { +contract MockBlastERC20 is ERC20 { mapping(address _contract => YieldMode) public yieldMode; constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) {} diff --git a/test/mock/MockBlastPoints.sol b/test/mock/MockBlastPoints.sol index a62fba6..e8db5f3 100644 --- a/test/mock/MockBlastPoints.sol +++ b/test/mock/MockBlastPoints.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -contract MockPoints { +contract MockBlastPoints { function configurePointsOperator(address operator) external {} } diff --git a/test/mock/MockBlastWETH.sol b/test/mock/MockBlastWETH.sol index 65871bb..821d48a 100644 --- a/test/mock/MockBlastWETH.sol +++ b/test/mock/MockBlastWETH.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.20; import {YieldMode} from "../../../contracts/interfaces/IERC20Rebasing.sol"; -contract MockWETH { +contract MockBlastWETH { string public name = "Wrapped Ether"; string public symbol = "WETH"; uint8 public decimals = 18; diff --git a/test/mock/MockBlastYield.sol b/test/mock/MockBlastYield.sol index 9991517..8824b6c 100644 --- a/test/mock/MockBlastYield.sol +++ b/test/mock/MockBlastYield.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.20; import {YieldMode, GasMode} from "../../../contracts/interfaces/IBlast.sol"; -contract MockYield { +contract MockBlastYield { struct Config { YieldMode yieldMode; GasMode gasMode; From 591cf53b7463bd1c9e1145a176b539f58f4b24c2 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Thu, 4 Jul 2024 18:29:46 +0400 Subject: [PATCH 17/39] fix: Get modifier from TestHelpers --- test/foundry/BlastYield.t.sol | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/test/foundry/BlastYield.t.sol b/test/foundry/BlastYield.t.sol index 43d3cab..4067bbf 100644 --- a/test/foundry/BlastYield.t.sol +++ b/test/foundry/BlastYield.t.sol @@ -6,6 +6,7 @@ import {IOwnableTwoSteps} from "../../contracts/interfaces/IOwnableTwoSteps.sol" import {OwnableTwoSteps} from "../../contracts/OwnableTwoSteps.sol"; import {BlastYield} from "../../contracts/BlastYield.sol"; import {Test} from "../../lib/forge-std/src/Test.sol"; +import {TestHelpers} from "./utils/TestHelpers.sol"; import {YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "../../contracts/interfaces/IBlast.sol"; import {YieldMode as IERC20Rebasing__YieldMode} from "../../contracts/interfaces/IERC20Rebasing.sol"; @@ -29,7 +30,7 @@ contract BlastYieldOwnableTwoSteps is BlastYield, OwnableTwoSteps { } } -contract BlastYieldOwnableTwoSteps_Test is Test { +contract BlastYieldOwnableTwoSteps_Test is Test, TestHelpers { MockBlastWETH private weth; MockBlastERC20 private usdb; MockBlastYield private mockBlastYield; @@ -87,10 +88,4 @@ contract BlastYieldOwnableTwoSteps_Test is Test { vm.expectRevert(IOwnableTwoSteps.NotOwner.selector); blastYieldOwnableTwoSteps.claim(TREASURY, TREASURY); } - - modifier asPrankedUser(address user) { - vm.startPrank(user); - _; - vm.stopPrank(); - } } From 0ba5d3ac227b9d0b200461e3cf70d5bfbe69cfa4 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Thu, 4 Jul 2024 21:30:14 +0400 Subject: [PATCH 18/39] chore: Update solmate to openzeppelin --- package.json | 5 +-- test/foundry/LowLevelWETH.t.sol | 10 +++--- test/mock/MockERC1155.sol | 4 +-- test/mock/MockERC20.sol | 4 +-- test/mock/MockERC721.sol | 2 +- test/mock/MockWETH.sol | 62 +++++++++++++++++++++++++++++++++ yarn.lock | 5 --- 7 files changed, 73 insertions(+), 19 deletions(-) create mode 100644 test/mock/MockWETH.sol diff --git a/package.json b/package.json index 41b791c..ff8d412 100644 --- a/package.json +++ b/package.json @@ -74,17 +74,14 @@ "hardhat-gas-reporter": "^1.0.8", "husky": "^7.0.4", "merkletreejs": "^0.2.31", + "@openzeppelin/contracts": "^5.0.2", "prettier": "^2.3.2", "prettier-plugin-solidity": "^1.3.0", "release-it": "^15.0.0", "solhint": "^3.3.7", "solidity-coverage": "^0.7.21", - "solmate": "^6.6.1", "ts-node": "^10.1.0", "typechain": "^5.1.2", "typescript": "^4.5.2" - }, - "dependencies": { - "@openzeppelin/contracts": "^5.0.2" } } diff --git a/test/foundry/LowLevelWETH.t.sol b/test/foundry/LowLevelWETH.t.sol index 7cf164c..a1ac50b 100644 --- a/test/foundry/LowLevelWETH.t.sol +++ b/test/foundry/LowLevelWETH.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import {WETH} from "solmate/src/tokens/WETH.sol"; +import {MockWETH} from "../mock/MockWETH.sol"; import {LowLevelWETH} from "../../contracts/lowLevelCallers/LowLevelWETH.sol"; import {TestHelpers} from "./utils/TestHelpers.sol"; @@ -30,18 +30,18 @@ contract RecipientFallback { contract LowLevelWETHTest is TestParameters, TestHelpers { ImplementedLowLevelWETH public lowLevelWETH; RecipientFallback public recipientFallback; - WETH public weth; + MockWETH public mockWeth; function setUp() external { lowLevelWETH = new ImplementedLowLevelWETH(); recipientFallback = new RecipientFallback(); - weth = new WETH(); + mockWeth = new MockWETH(); } function testTransferETHAndRevertsinWETH(uint256 amount) external payable asPrankedUser(_sender) { vm.deal(_sender, amount); - lowLevelWETH.transferETH{value: amount}(address(weth), address(recipientFallback), _GAS_LIMIT); + lowLevelWETH.transferETH{value: amount}(address(mockWeth), address(recipientFallback), _GAS_LIMIT); assertEq(address(recipientFallback).balance, 0); - assertEq(weth.balanceOf(address(recipientFallback)), amount); + assertEq(mockWeth.balanceOf(address(recipientFallback)), amount); } } diff --git a/test/mock/MockERC1155.sol b/test/mock/MockERC1155.sol index c0bab1b..d1e3eb1 100644 --- a/test/mock/MockERC1155.sol +++ b/test/mock/MockERC1155.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.8.7; -import {ERC1155} from "solmate/src/tokens/ERC1155.sol"; +import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; -contract MockERC1155 is ERC1155 { +contract MockERC1155 is ERC1155("MockURI") { function uri(uint256) public pure override returns (string memory) { return "uri"; } diff --git a/test/mock/MockERC20.sol b/test/mock/MockERC20.sol index 019bed0..e17788e 100644 --- a/test/mock/MockERC20.sol +++ b/test/mock/MockERC20.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.8.7; -import {ERC20} from "solmate/src/tokens/ERC20.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -contract MockERC20 is ERC20("MockERC20", "MockERC20", 18) { +contract MockERC20 is ERC20("MockERC20", "MockERC20") { function mint(address to, uint256 amount) public { _mint(to, amount); } diff --git a/test/mock/MockERC721.sol b/test/mock/MockERC721.sol index 079090e..24da4e5 100644 --- a/test/mock/MockERC721.sol +++ b/test/mock/MockERC721.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.8.7; -import {ERC721} from "solmate/src/tokens/ERC721.sol"; +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import {IERC165} from "../../contracts/interfaces/generic/IERC165.sol"; contract MockERC721 is ERC721("MockERC721", "MockERC721") { diff --git a/test/mock/MockWETH.sol b/test/mock/MockWETH.sol new file mode 100644 index 0000000..ec230b5 --- /dev/null +++ b/test/mock/MockWETH.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +contract MockWETH { + string public name = "Wrapped Ether"; + string public symbol = "WETH"; + uint8 public decimals = 18; + + event Approval(address indexed src, address indexed guy, uint256 wad); + event Transfer(address indexed src, address indexed dst, uint256 wad); + event Deposit(address indexed dst, uint256 wad); + event Withdrawal(address indexed src, uint256 wad); + + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + + receive() external payable { + deposit(); + } + + function deposit() public payable { + balanceOf[msg.sender] += msg.value; + emit Deposit(msg.sender, msg.value); + } + + function withdraw(uint256 wad) public { + require(balanceOf[msg.sender] >= wad); + balanceOf[msg.sender] -= wad; + payable(msg.sender).transfer(wad); + emit Withdrawal(msg.sender, wad); + } + + function totalSupply() public view returns (uint256) { + return address(this).balance; + } + + function approve(address guy, uint256 wad) public returns (bool) { + allowance[msg.sender][guy] = wad; + emit Approval(msg.sender, guy, wad); + return true; + } + + function transfer(address dst, uint256 wad) public returns (bool) { + return transferFrom(msg.sender, dst, wad); + } + + function transferFrom(address src, address dst, uint256 wad) public returns (bool) { + require(balanceOf[src] >= wad); + + if (src != msg.sender && allowance[src][msg.sender] != type(uint256).max) { + require(allowance[src][msg.sender] >= wad); + allowance[src][msg.sender] -= wad; + } + + balanceOf[src] -= wad; + balanceOf[dst] += wad; + + emit Transfer(src, dst, wad); + + return true; + } +} diff --git a/yarn.lock b/yarn.lock index b21b315..110aee2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10331,11 +10331,6 @@ solidity-coverage@^0.7.21: shelljs "^0.8.3" web3-utils "^1.3.0" -solmate@^6.6.1: - version "6.6.1" - resolved "https://registry.yarnpkg.com/solmate/-/solmate-6.6.1.tgz#f0907e1cdada6dd5fbfe11811ab545162b713197" - integrity sha512-WHvRXQvGtgR6R9nmkDTz/d+oULMqf/D33rlzQyadTX2SbuTmaW7ToEjGjGtWUVCQwZsZ/JP3vbOEVv7fB50btg== - source-map-resolve@^0.5.0: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" From acda72e724fa100ca8c6e01b7da6dd20e55b95b3 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Thu, 4 Jul 2024 22:12:37 +0400 Subject: [PATCH 19/39] fix: Governor comment --- contracts/BlastYield.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/BlastYield.sol b/contracts/BlastYield.sol index 14adac0..e78cbdd 100644 --- a/contracts/BlastYield.sol +++ b/contracts/BlastYield.sol @@ -19,7 +19,7 @@ contract BlastYield { * @param _blast Blast precompile * @param _blastPoints Blast points * @param _blastPointsOperator Blast points operator - * @param _governor Governor of the contract + * @param _governor The address that’s allowed to claim the contract’s yield and gas * @param _usdb USDB address * @param _weth WETH address */ From 4143be9f1ff96659683dc0fa9d02908d24d82379 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Thu, 4 Jul 2024 22:15:08 +0400 Subject: [PATCH 20/39] fix: TestHelpers inheritance --- test/foundry/BlastYield.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/foundry/BlastYield.t.sol b/test/foundry/BlastYield.t.sol index 4067bbf..1174124 100644 --- a/test/foundry/BlastYield.t.sol +++ b/test/foundry/BlastYield.t.sol @@ -30,7 +30,7 @@ contract BlastYieldOwnableTwoSteps is BlastYield, OwnableTwoSteps { } } -contract BlastYieldOwnableTwoSteps_Test is Test, TestHelpers { +contract BlastYieldOwnableTwoSteps_Test is TestHelpers { MockBlastWETH private weth; MockBlastERC20 private usdb; MockBlastYield private mockBlastYield; From 5946c5f46cbbc58d6022539617b300420268b006 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Fri, 5 Jul 2024 19:22:22 +0400 Subject: [PATCH 21/39] feat: Split BlastYield into multiple contracts --- ...tYield.sol => BlastERC20RebasingYield.sol} | 13 ++--- contracts/BlastNativeYield.sol | 27 ++++++++++ contracts/BlastPoints.sol | 20 ++++++++ ...ld.t.sol => BlastERC20RebasingYield.t.sol} | 39 +++++++------- test/foundry/BlastNativeYield.t.sol | 51 +++++++++++++++++++ test/foundry/BlastPoints.t.sol | 33 ++++++++++++ test/mock/MockBlastPoints.sol | 7 ++- 7 files changed, 159 insertions(+), 31 deletions(-) rename contracts/{BlastYield.sol => BlastERC20RebasingYield.sol} (79%) create mode 100644 contracts/BlastNativeYield.sol create mode 100644 contracts/BlastPoints.sol rename test/foundry/{BlastYield.t.sol => BlastERC20RebasingYield.t.sol} (65%) create mode 100644 test/foundry/BlastNativeYield.t.sol create mode 100644 test/foundry/BlastPoints.t.sol diff --git a/contracts/BlastYield.sol b/contracts/BlastERC20RebasingYield.sol similarity index 79% rename from contracts/BlastYield.sol rename to contracts/BlastERC20RebasingYield.sol index e78cbdd..1e22145 100644 --- a/contracts/BlastYield.sol +++ b/contracts/BlastERC20RebasingYield.sol @@ -2,16 +2,15 @@ pragma solidity ^0.8.20; -import {IBlast, YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "./interfaces/IBlast.sol"; -import {IBlastPoints} from "./interfaces/IBlastPoints.sol"; +import {BlastNativeYield} from "./BlastNativeYield.sol"; import {IERC20Rebasing, YieldMode as IERC20Rebasing__YieldMode} from "./interfaces/IERC20Rebasing.sol"; /** - * @title BlastYield - * @notice This contract is a base contract for future contracts that wish to claim Blast WETH or USDB yield to inherit from. + * @title BlastERC20RebasingYield + * @notice This contract is a base contract for future contracts that wish to claim Blast WETH or USDB yield to inherit from * @author LooksRare protocol team (πŸ‘€,πŸ’Ž) */ -contract BlastYield { +contract BlastERC20RebasingYield is BlastNativeYield { address public immutable WETH; address public immutable USDB; @@ -30,12 +29,10 @@ contract BlastYield { address _governor, address _usdb, address _weth - ) { + ) BlastNativeYield(_blast, _blastPoints, _blastPointsOperator, _governor) { WETH = _weth; USDB = _usdb; - IBlast(_blast).configure(IBlast__YieldMode.CLAIMABLE, IBlast__GasMode.CLAIMABLE, _governor); - IBlastPoints(_blastPoints).configurePointsOperator(_blastPointsOperator); IERC20Rebasing(_weth).configure(IERC20Rebasing__YieldMode.CLAIMABLE); IERC20Rebasing(_usdb).configure(IERC20Rebasing__YieldMode.CLAIMABLE); } diff --git a/contracts/BlastNativeYield.sol b/contracts/BlastNativeYield.sol new file mode 100644 index 0000000..18dd883 --- /dev/null +++ b/contracts/BlastNativeYield.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IBlast, YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "./interfaces/IBlast.sol"; +import {BlastPoints} from "./BlastPoints.sol"; +/** + * @title BlastNativeYield + * @notice This contract is a base contract for future contracts that wish to claim native yield and Blast points to inherit from + * @author LooksRare protocol team (πŸ‘€,πŸ’Ž) + */ +contract BlastNativeYield is BlastPoints { + /** + * @param _blast Blast precompile + * @param _blastPoints Blast points + * @param _blastPointsOperator Blast points operator + * @param _governor The address that’s allowed to claim the contract’s yield and gas + */ + constructor( + address _blast, + address _blastPoints, + address _blastPointsOperator, + address _governor + ) BlastPoints(_blastPoints, _blastPointsOperator) { + IBlast(_blast).configure(IBlast__YieldMode.CLAIMABLE, IBlast__GasMode.CLAIMABLE, _governor); + } +} diff --git a/contracts/BlastPoints.sol b/contracts/BlastPoints.sol new file mode 100644 index 0000000..c2d5f62 --- /dev/null +++ b/contracts/BlastPoints.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IBlastPoints} from "./interfaces/IBlastPoints.sol"; + +/** + * @title BlastPoints + * @notice This contract is a base contract for future contracts that wish to claim Blast points to inherit from + * @author LooksRare protocol team (πŸ‘€,πŸ’Ž) + */ +contract BlastPoints { + /** + * @param _blastPoints Blast points + * @param _blastPointsOperator Blast points operator + */ + constructor(address _blastPoints, address _blastPointsOperator) { + IBlastPoints(_blastPoints).configurePointsOperator(_blastPointsOperator); + } +} diff --git a/test/foundry/BlastYield.t.sol b/test/foundry/BlastERC20RebasingYield.t.sol similarity index 65% rename from test/foundry/BlastYield.t.sol rename to test/foundry/BlastERC20RebasingYield.t.sol index 1174124..6f69e59 100644 --- a/test/foundry/BlastYield.t.sol +++ b/test/foundry/BlastERC20RebasingYield.t.sol @@ -4,8 +4,7 @@ pragma solidity ^0.8.20; import {IOwnableTwoSteps} from "../../contracts/interfaces/IOwnableTwoSteps.sol"; import {OwnableTwoSteps} from "../../contracts/OwnableTwoSteps.sol"; -import {BlastYield} from "../../contracts/BlastYield.sol"; -import {Test} from "../../lib/forge-std/src/Test.sol"; +import {BlastERC20RebasingYield} from "../../contracts/BlastERC20RebasingYield.sol"; import {TestHelpers} from "./utils/TestHelpers.sol"; import {YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "../../contracts/interfaces/IBlast.sol"; import {YieldMode as IERC20Rebasing__YieldMode} from "../../contracts/interfaces/IERC20Rebasing.sol"; @@ -15,7 +14,7 @@ import {MockBlastPoints} from "../mock/MockBlastPoints.sol"; import {MockBlastWETH} from "../mock/MockBlastWETH.sol"; import {MockBlastYield} from "../mock/MockBlastYield.sol"; -contract BlastYieldOwnableTwoSteps is BlastYield, OwnableTwoSteps { +contract BlastERC20RebasingYieldOwnableTwoSteps is BlastERC20RebasingYield, OwnableTwoSteps { constructor( address _blast, address _blastPoints, @@ -23,19 +22,22 @@ contract BlastYieldOwnableTwoSteps is BlastYield, OwnableTwoSteps { address _owner, address _usdb, address _weth - ) BlastYield(_blast, _blastPoints, _blastPointsOperator, _owner, _usdb, _weth) OwnableTwoSteps(_owner) {} + ) + BlastERC20RebasingYield(_blast, _blastPoints, _blastPointsOperator, _owner, _usdb, _weth) + OwnableTwoSteps(_owner) + {} function claim(address wethReceiver, address usdbReceiver) public onlyOwner { _claim(wethReceiver, usdbReceiver); } } -contract BlastYieldOwnableTwoSteps_Test is TestHelpers { +contract BlastERC20RebasingYieldOwnableTwoStepsOwnableTwoSteps_Test is TestHelpers { MockBlastWETH private weth; MockBlastERC20 private usdb; MockBlastYield private mockBlastYield; MockBlastPoints private mockBlastPoints; - BlastYieldOwnableTwoSteps private blastYieldOwnableTwoSteps; + BlastERC20RebasingYieldOwnableTwoSteps private blastERC20RebasingYieldOwnableTwoSteps; address public owner = address(69); address public operator = address(420); @@ -47,7 +49,7 @@ contract BlastYieldOwnableTwoSteps_Test is TestHelpers { usdb = new MockBlastERC20("USDB", "USDB"); mockBlastYield = new MockBlastYield(); mockBlastPoints = new MockBlastPoints(); - blastYieldOwnableTwoSteps = new BlastYieldOwnableTwoSteps( + blastERC20RebasingYieldOwnableTwoSteps = new BlastERC20RebasingYieldOwnableTwoSteps( address(mockBlastYield), address(mockBlastPoints), operator, @@ -58,34 +60,27 @@ contract BlastYieldOwnableTwoSteps_Test is TestHelpers { } function test_setUpState() public { - assertEq(blastYieldOwnableTwoSteps.WETH(), address(weth)); - assertEq(blastYieldOwnableTwoSteps.USDB(), address(usdb)); + assertEq(blastERC20RebasingYieldOwnableTwoSteps.WETH(), address(weth)); + assertEq(blastERC20RebasingYieldOwnableTwoSteps.USDB(), address(usdb)); - (IBlast__YieldMode yieldMode, IBlast__GasMode gasMode, address governor) = mockBlastYield.config( - address(blastYieldOwnableTwoSteps) - ); - assertEq(uint8(yieldMode), uint8(IBlast__YieldMode.CLAIMABLE)); - assertEq(uint8(gasMode), uint8(IBlast__GasMode.CLAIMABLE)); - assertEq(governor, owner); - - IERC20Rebasing__YieldMode wethYieldMode = weth.yieldMode(address(blastYieldOwnableTwoSteps)); + IERC20Rebasing__YieldMode wethYieldMode = weth.yieldMode(address(blastERC20RebasingYieldOwnableTwoSteps)); assertEq(uint8(wethYieldMode), uint8(IERC20Rebasing__YieldMode.CLAIMABLE)); - IERC20Rebasing__YieldMode usdbYieldMode = usdb.yieldMode(address(blastYieldOwnableTwoSteps)); + IERC20Rebasing__YieldMode usdbYieldMode = usdb.yieldMode(address(blastERC20RebasingYieldOwnableTwoSteps)); assertEq(uint8(usdbYieldMode), uint8(IERC20Rebasing__YieldMode.CLAIMABLE)); } function test_claim() public asPrankedUser(owner) { - blastYieldOwnableTwoSteps.claim(TREASURY, TREASURY); + blastERC20RebasingYieldOwnableTwoSteps.claim(TREASURY, TREASURY); - assertEq(weth.balanceOf(address(blastYieldOwnableTwoSteps)), 0); - assertEq(usdb.balanceOf(address(blastYieldOwnableTwoSteps)), 0); + assertEq(weth.balanceOf(address(blastERC20RebasingYieldOwnableTwoSteps)), 0); + assertEq(usdb.balanceOf(address(blastERC20RebasingYieldOwnableTwoSteps)), 0); assertEq(weth.balanceOf(TREASURY), 1 ether); assertEq(usdb.balanceOf(TREASURY), 1 ether); } function test_claim_RevertIf_NotOwner() public asPrankedUser(user1) { vm.expectRevert(IOwnableTwoSteps.NotOwner.selector); - blastYieldOwnableTwoSteps.claim(TREASURY, TREASURY); + blastERC20RebasingYieldOwnableTwoSteps.claim(TREASURY, TREASURY); } } diff --git a/test/foundry/BlastNativeYield.t.sol b/test/foundry/BlastNativeYield.t.sol new file mode 100644 index 0000000..a3a65b3 --- /dev/null +++ b/test/foundry/BlastNativeYield.t.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IOwnableTwoSteps} from "../../contracts/interfaces/IOwnableTwoSteps.sol"; +import {OwnableTwoSteps} from "../../contracts/OwnableTwoSteps.sol"; +import {BlastNativeYield} from "../../contracts/BlastNativeYield.sol"; +import {TestHelpers} from "./utils/TestHelpers.sol"; +import {YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "../../contracts/interfaces/IBlast.sol"; + +import {MockBlastPoints} from "../mock/MockBlastPoints.sol"; +import {MockBlastYield} from "../mock/MockBlastYield.sol"; + +contract BlastNativeYieldOwnableTwoSteps is BlastNativeYield, OwnableTwoSteps { + constructor( + address _blast, + address _blastPoints, + address _blastPointsOperator, + address _owner + ) BlastNativeYield(_blast, _blastPoints, _blastPointsOperator, _owner) OwnableTwoSteps(_owner) {} +} + +contract BlastNativeYieldOwnableTwoSteps_Test is TestHelpers { + MockBlastYield private mockBlastYield; + MockBlastPoints private mockBlastPoints; + BlastNativeYieldOwnableTwoSteps private blastNativeYieldOwnableTwoSteps; + + address public owner = address(69); + address public operator = address(420); + address private constant TREASURY = address(69420); + + function setUp() public { + mockBlastPoints = new MockBlastPoints(); + mockBlastYield = new MockBlastYield(); + blastNativeYieldOwnableTwoSteps = new BlastNativeYieldOwnableTwoSteps( + address(mockBlastYield), + address(mockBlastPoints), + operator, + owner + ); + } + + function test_setUpState() public { + (IBlast__YieldMode yieldMode, IBlast__GasMode gasMode, address governor) = mockBlastYield.config( + address(blastNativeYieldOwnableTwoSteps) + ); + assertEq(uint8(yieldMode), uint8(IBlast__YieldMode.CLAIMABLE)); + assertEq(uint8(gasMode), uint8(IBlast__GasMode.CLAIMABLE)); + assertEq(governor, owner); + } +} diff --git a/test/foundry/BlastPoints.t.sol b/test/foundry/BlastPoints.t.sol new file mode 100644 index 0000000..eaa7756 --- /dev/null +++ b/test/foundry/BlastPoints.t.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {OwnableTwoSteps} from "../../contracts/OwnableTwoSteps.sol"; +import {BlastPoints} from "../../contracts/BlastPoints.sol"; +import {TestHelpers} from "./utils/TestHelpers.sol"; + +import {MockBlastPoints} from "../mock/MockBlastPoints.sol"; + +contract BlastPointsOwnableTwoSteps is BlastPoints, OwnableTwoSteps { + constructor( + address _blastPoints, + address _blastPointsOperator + ) BlastPoints(_blastPoints, _blastPointsOperator) OwnableTwoSteps(_blastPointsOperator) {} +} + +contract BlastPointsOwnableTwoSteps_Test is TestHelpers { + MockBlastPoints private mockBlastPoints; + BlastPointsOwnableTwoSteps private blastPointsOwnableTwoSteps; + + address public operator = address(420); + address private constant TREASURY = address(69420); + + function setUp() public { + mockBlastPoints = new MockBlastPoints(); + blastPointsOwnableTwoSteps = new BlastPointsOwnableTwoSteps(address(mockBlastPoints), operator); + } + + function test_setUpState() public { + assertEq(mockBlastPoints.contractOperators(address(blastPointsOwnableTwoSteps)), operator); + } +} diff --git a/test/mock/MockBlastPoints.sol b/test/mock/MockBlastPoints.sol index e8db5f3..3661f46 100644 --- a/test/mock/MockBlastPoints.sol +++ b/test/mock/MockBlastPoints.sol @@ -2,5 +2,10 @@ pragma solidity ^0.8.0; contract MockBlastPoints { - function configurePointsOperator(address operator) external {} + mapping(address _contract => address operator) public contractOperators; + event LogAddress(address); + + function configurePointsOperator(address operator) external { + contractOperators[msg.sender] = operator; + } } From 06cebd1c7dace679983cf18aca0ef8782fbbe985 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Fri, 5 Jul 2024 19:36:04 +0400 Subject: [PATCH 22/39] fix: Remove event --- test/mock/MockBlastPoints.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/test/mock/MockBlastPoints.sol b/test/mock/MockBlastPoints.sol index 3661f46..f83dd33 100644 --- a/test/mock/MockBlastPoints.sol +++ b/test/mock/MockBlastPoints.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.0; contract MockBlastPoints { mapping(address _contract => address operator) public contractOperators; - event LogAddress(address); function configurePointsOperator(address operator) external { contractOperators[msg.sender] = operator; From 70b57dd7748c908333ddbb65883f160ae2b66b89 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Fri, 5 Jul 2024 19:37:09 +0400 Subject: [PATCH 23/39] fix: Remove empty line --- contracts/BlastNativeYield.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/BlastNativeYield.sol b/contracts/BlastNativeYield.sol index 18dd883..3977bd4 100644 --- a/contracts/BlastNativeYield.sol +++ b/contracts/BlastNativeYield.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.20; import {IBlast, YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "./interfaces/IBlast.sol"; import {BlastPoints} from "./BlastPoints.sol"; + /** * @title BlastNativeYield * @notice This contract is a base contract for future contracts that wish to claim native yield and Blast points to inherit from From f80299b624bb29f3c05c21cf2ed9fbe11b714574 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Fri, 5 Jul 2024 19:41:24 +0400 Subject: [PATCH 24/39] fix: YieldMode GasMode fix --- contracts/BlastNativeYield.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/BlastNativeYield.sol b/contracts/BlastNativeYield.sol index 3977bd4..67f462f 100644 --- a/contracts/BlastNativeYield.sol +++ b/contracts/BlastNativeYield.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.20; -import {IBlast, YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "./interfaces/IBlast.sol"; +import {IBlast, IBlast__YieldMode, IBlast__GasMode} from "./interfaces/IBlast.sol"; import {BlastPoints} from "./BlastPoints.sol"; /** From 96c81ecce1ffb035e5749f47a16025cf66d7b328 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Fri, 5 Jul 2024 22:36:20 +0400 Subject: [PATCH 25/39] fix: Fix blast points notice --- contracts/BlastPoints.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/BlastPoints.sol b/contracts/BlastPoints.sol index c2d5f62..661369a 100644 --- a/contracts/BlastPoints.sol +++ b/contracts/BlastPoints.sol @@ -6,7 +6,7 @@ import {IBlastPoints} from "./interfaces/IBlastPoints.sol"; /** * @title BlastPoints - * @notice This contract is a base contract for future contracts that wish to claim Blast points to inherit from + * @notice This contract is a base for future contracts that wish to be recipients of Blast points to inherit from * @author LooksRare protocol team (πŸ‘€,πŸ’Ž) */ contract BlastPoints { From ed787620d83cc407b00b388163ef8713c86708d5 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Fri, 5 Jul 2024 22:44:30 +0400 Subject: [PATCH 26/39] fix: Refix YieldMode GasMode --- contracts/BlastNativeYield.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/BlastNativeYield.sol b/contracts/BlastNativeYield.sol index 67f462f..2aa743e 100644 --- a/contracts/BlastNativeYield.sol +++ b/contracts/BlastNativeYield.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.20; -import {IBlast, IBlast__YieldMode, IBlast__GasMode} from "./interfaces/IBlast.sol"; +import {IBlast, YieldMode, GasMode} from "./interfaces/IBlast.sol"; import {BlastPoints} from "./BlastPoints.sol"; /** @@ -23,6 +23,6 @@ contract BlastNativeYield is BlastPoints { address _blastPointsOperator, address _governor ) BlastPoints(_blastPoints, _blastPointsOperator) { - IBlast(_blast).configure(IBlast__YieldMode.CLAIMABLE, IBlast__GasMode.CLAIMABLE, _governor); + IBlast(_blast).configure(YieldMode.CLAIMABLE, GasMode.CLAIMABLE, _governor); } } From bc6d3e8172dbe58c7c8bbb4f91fff5b5de6f0aff Mon Sep 17 00:00:00 2001 From: stonehenge Date: Fri, 5 Jul 2024 22:49:22 +0400 Subject: [PATCH 27/39] fix: Test names --- test/foundry/BlastERC20RebasingYield.t.sol | 2 +- test/foundry/BlastNativeYield.t.sol | 2 +- test/foundry/BlastPoints.t.sol | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/foundry/BlastERC20RebasingYield.t.sol b/test/foundry/BlastERC20RebasingYield.t.sol index 6f69e59..81662b9 100644 --- a/test/foundry/BlastERC20RebasingYield.t.sol +++ b/test/foundry/BlastERC20RebasingYield.t.sol @@ -32,7 +32,7 @@ contract BlastERC20RebasingYieldOwnableTwoSteps is BlastERC20RebasingYield, Owna } } -contract BlastERC20RebasingYieldOwnableTwoStepsOwnableTwoSteps_Test is TestHelpers { +contract BlastERC20RebasingYield_Test is TestHelpers { MockBlastWETH private weth; MockBlastERC20 private usdb; MockBlastYield private mockBlastYield; diff --git a/test/foundry/BlastNativeYield.t.sol b/test/foundry/BlastNativeYield.t.sol index a3a65b3..1fd06fe 100644 --- a/test/foundry/BlastNativeYield.t.sol +++ b/test/foundry/BlastNativeYield.t.sol @@ -20,7 +20,7 @@ contract BlastNativeYieldOwnableTwoSteps is BlastNativeYield, OwnableTwoSteps { ) BlastNativeYield(_blast, _blastPoints, _blastPointsOperator, _owner) OwnableTwoSteps(_owner) {} } -contract BlastNativeYieldOwnableTwoSteps_Test is TestHelpers { +contract BlastNativeYield_Test is TestHelpers { MockBlastYield private mockBlastYield; MockBlastPoints private mockBlastPoints; BlastNativeYieldOwnableTwoSteps private blastNativeYieldOwnableTwoSteps; diff --git a/test/foundry/BlastPoints.t.sol b/test/foundry/BlastPoints.t.sol index eaa7756..b158ccd 100644 --- a/test/foundry/BlastPoints.t.sol +++ b/test/foundry/BlastPoints.t.sol @@ -15,7 +15,7 @@ contract BlastPointsOwnableTwoSteps is BlastPoints, OwnableTwoSteps { ) BlastPoints(_blastPoints, _blastPointsOperator) OwnableTwoSteps(_blastPointsOperator) {} } -contract BlastPointsOwnableTwoSteps_Test is TestHelpers { +contract BlastPoints_Test is TestHelpers { MockBlastPoints private mockBlastPoints; BlastPointsOwnableTwoSteps private blastPointsOwnableTwoSteps; From 3d7fac2d575cb34a0bf7edd4d102561a20ef8213 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Fri, 5 Jul 2024 23:07:35 +0400 Subject: [PATCH 28/39] fix: Improve notices --- contracts/BlastERC20RebasingYield.sol | 2 +- contracts/BlastNativeYield.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/BlastERC20RebasingYield.sol b/contracts/BlastERC20RebasingYield.sol index 1e22145..7851c04 100644 --- a/contracts/BlastERC20RebasingYield.sol +++ b/contracts/BlastERC20RebasingYield.sol @@ -7,7 +7,7 @@ import {IERC20Rebasing, YieldMode as IERC20Rebasing__YieldMode} from "./interfac /** * @title BlastERC20RebasingYield - * @notice This contract is a base contract for future contracts that wish to claim Blast WETH or USDB yield to inherit from + * @notice This contract is a base contract for inheriting functions to claim Blast WETH or USDB yield * @author LooksRare protocol team (πŸ‘€,πŸ’Ž) */ contract BlastERC20RebasingYield is BlastNativeYield { diff --git a/contracts/BlastNativeYield.sol b/contracts/BlastNativeYield.sol index 2aa743e..c4f827b 100644 --- a/contracts/BlastNativeYield.sol +++ b/contracts/BlastNativeYield.sol @@ -7,7 +7,7 @@ import {BlastPoints} from "./BlastPoints.sol"; /** * @title BlastNativeYield - * @notice This contract is a base contract for future contracts that wish to claim native yield and Blast points to inherit from + * @notice This contract is a base contract for inheriting functions to claim native yield and for those that wish to recieve Blast points * @author LooksRare protocol team (πŸ‘€,πŸ’Ž) */ contract BlastNativeYield is BlastPoints { From 666c866d0326865e1a1e8178aca6a9452a714be3 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Fri, 5 Jul 2024 23:17:43 +0400 Subject: [PATCH 29/39] fix: Fix native yield and points tests --- test/foundry/BlastNativeYield.t.sol | 20 +++----------------- test/foundry/BlastPoints.t.sol | 13 +++---------- 2 files changed, 6 insertions(+), 27 deletions(-) diff --git a/test/foundry/BlastNativeYield.t.sol b/test/foundry/BlastNativeYield.t.sol index 1fd06fe..74201e4 100644 --- a/test/foundry/BlastNativeYield.t.sol +++ b/test/foundry/BlastNativeYield.t.sol @@ -11,19 +11,10 @@ import {YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "../../ import {MockBlastPoints} from "../mock/MockBlastPoints.sol"; import {MockBlastYield} from "../mock/MockBlastYield.sol"; -contract BlastNativeYieldOwnableTwoSteps is BlastNativeYield, OwnableTwoSteps { - constructor( - address _blast, - address _blastPoints, - address _blastPointsOperator, - address _owner - ) BlastNativeYield(_blast, _blastPoints, _blastPointsOperator, _owner) OwnableTwoSteps(_owner) {} -} - contract BlastNativeYield_Test is TestHelpers { MockBlastYield private mockBlastYield; MockBlastPoints private mockBlastPoints; - BlastNativeYieldOwnableTwoSteps private blastNativeYieldOwnableTwoSteps; + BlastNativeYield private blastNativeYield; address public owner = address(69); address public operator = address(420); @@ -32,17 +23,12 @@ contract BlastNativeYield_Test is TestHelpers { function setUp() public { mockBlastPoints = new MockBlastPoints(); mockBlastYield = new MockBlastYield(); - blastNativeYieldOwnableTwoSteps = new BlastNativeYieldOwnableTwoSteps( - address(mockBlastYield), - address(mockBlastPoints), - operator, - owner - ); + blastNativeYield = new BlastNativeYield(address(mockBlastYield), address(mockBlastPoints), operator, owner); } function test_setUpState() public { (IBlast__YieldMode yieldMode, IBlast__GasMode gasMode, address governor) = mockBlastYield.config( - address(blastNativeYieldOwnableTwoSteps) + address(blastNativeYield) ); assertEq(uint8(yieldMode), uint8(IBlast__YieldMode.CLAIMABLE)); assertEq(uint8(gasMode), uint8(IBlast__GasMode.CLAIMABLE)); diff --git a/test/foundry/BlastPoints.t.sol b/test/foundry/BlastPoints.t.sol index b158ccd..ad6fc8c 100644 --- a/test/foundry/BlastPoints.t.sol +++ b/test/foundry/BlastPoints.t.sol @@ -8,26 +8,19 @@ import {TestHelpers} from "./utils/TestHelpers.sol"; import {MockBlastPoints} from "../mock/MockBlastPoints.sol"; -contract BlastPointsOwnableTwoSteps is BlastPoints, OwnableTwoSteps { - constructor( - address _blastPoints, - address _blastPointsOperator - ) BlastPoints(_blastPoints, _blastPointsOperator) OwnableTwoSteps(_blastPointsOperator) {} -} - contract BlastPoints_Test is TestHelpers { MockBlastPoints private mockBlastPoints; - BlastPointsOwnableTwoSteps private blastPointsOwnableTwoSteps; + BlastPoints private blastPoints; address public operator = address(420); address private constant TREASURY = address(69420); function setUp() public { mockBlastPoints = new MockBlastPoints(); - blastPointsOwnableTwoSteps = new BlastPointsOwnableTwoSteps(address(mockBlastPoints), operator); + blastPoints = new BlastPoints(address(mockBlastPoints), operator); } function test_setUpState() public { - assertEq(mockBlastPoints.contractOperators(address(blastPointsOwnableTwoSteps)), operator); + assertEq(mockBlastPoints.contractOperators(address(blastPoints)), operator); } } From c01c63d91178b262000dfd672c436d1c5da3b44c Mon Sep 17 00:00:00 2001 From: stonehenge Date: Fri, 5 Jul 2024 23:25:24 +0400 Subject: [PATCH 30/39] fix: YieldMode GasMode naming BlastNativeYield_Test --- test/foundry/BlastNativeYield.t.sol | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/test/foundry/BlastNativeYield.t.sol b/test/foundry/BlastNativeYield.t.sol index 74201e4..fc32580 100644 --- a/test/foundry/BlastNativeYield.t.sol +++ b/test/foundry/BlastNativeYield.t.sol @@ -6,7 +6,7 @@ import {IOwnableTwoSteps} from "../../contracts/interfaces/IOwnableTwoSteps.sol" import {OwnableTwoSteps} from "../../contracts/OwnableTwoSteps.sol"; import {BlastNativeYield} from "../../contracts/BlastNativeYield.sol"; import {TestHelpers} from "./utils/TestHelpers.sol"; -import {YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "../../contracts/interfaces/IBlast.sol"; +import {YieldMode, GasMode} from "../../contracts/interfaces/IBlast.sol"; import {MockBlastPoints} from "../mock/MockBlastPoints.sol"; import {MockBlastYield} from "../mock/MockBlastYield.sol"; @@ -27,11 +27,9 @@ contract BlastNativeYield_Test is TestHelpers { } function test_setUpState() public { - (IBlast__YieldMode yieldMode, IBlast__GasMode gasMode, address governor) = mockBlastYield.config( - address(blastNativeYield) - ); - assertEq(uint8(yieldMode), uint8(IBlast__YieldMode.CLAIMABLE)); - assertEq(uint8(gasMode), uint8(IBlast__GasMode.CLAIMABLE)); + (YieldMode yieldMode, GasMode gasMode, address governor) = mockBlastYield.config(address(blastNativeYield)); + assertEq(uint8(yieldMode), uint8(YieldMode.CLAIMABLE)); + assertEq(uint8(gasMode), uint8(GasMode.CLAIMABLE)); assertEq(governor, owner); } } From 68bb39c481845cf5d2ec1da288916bba66c0a300 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Sat, 6 Jul 2024 07:51:03 +0400 Subject: [PATCH 31/39] fix: Unused variables and imports --- test/foundry/BlastNativeYield.t.sol | 3 --- test/foundry/BlastPoints.t.sol | 2 -- 2 files changed, 5 deletions(-) diff --git a/test/foundry/BlastNativeYield.t.sol b/test/foundry/BlastNativeYield.t.sol index fc32580..ef8eed4 100644 --- a/test/foundry/BlastNativeYield.t.sol +++ b/test/foundry/BlastNativeYield.t.sol @@ -2,8 +2,6 @@ pragma solidity ^0.8.20; -import {IOwnableTwoSteps} from "../../contracts/interfaces/IOwnableTwoSteps.sol"; -import {OwnableTwoSteps} from "../../contracts/OwnableTwoSteps.sol"; import {BlastNativeYield} from "../../contracts/BlastNativeYield.sol"; import {TestHelpers} from "./utils/TestHelpers.sol"; import {YieldMode, GasMode} from "../../contracts/interfaces/IBlast.sol"; @@ -18,7 +16,6 @@ contract BlastNativeYield_Test is TestHelpers { address public owner = address(69); address public operator = address(420); - address private constant TREASURY = address(69420); function setUp() public { mockBlastPoints = new MockBlastPoints(); diff --git a/test/foundry/BlastPoints.t.sol b/test/foundry/BlastPoints.t.sol index ad6fc8c..1fdb61d 100644 --- a/test/foundry/BlastPoints.t.sol +++ b/test/foundry/BlastPoints.t.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.20; -import {OwnableTwoSteps} from "../../contracts/OwnableTwoSteps.sol"; import {BlastPoints} from "../../contracts/BlastPoints.sol"; import {TestHelpers} from "./utils/TestHelpers.sol"; @@ -13,7 +12,6 @@ contract BlastPoints_Test is TestHelpers { BlastPoints private blastPoints; address public operator = address(420); - address private constant TREASURY = address(69420); function setUp() public { mockBlastPoints = new MockBlastPoints(); From 1d6537f2335ff92cbbf7e4cf0557c46578c3b599 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Sat, 6 Jul 2024 07:52:42 +0400 Subject: [PATCH 32/39] fix: Remove variable alias --- contracts/BlastERC20RebasingYield.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/BlastERC20RebasingYield.sol b/contracts/BlastERC20RebasingYield.sol index 7851c04..bbb4a35 100644 --- a/contracts/BlastERC20RebasingYield.sol +++ b/contracts/BlastERC20RebasingYield.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.20; import {BlastNativeYield} from "./BlastNativeYield.sol"; -import {IERC20Rebasing, YieldMode as IERC20Rebasing__YieldMode} from "./interfaces/IERC20Rebasing.sol"; +import {IERC20Rebasing, YieldMode} from "./interfaces/IERC20Rebasing.sol"; /** * @title BlastERC20RebasingYield @@ -33,8 +33,8 @@ contract BlastERC20RebasingYield is BlastNativeYield { WETH = _weth; USDB = _usdb; - IERC20Rebasing(_weth).configure(IERC20Rebasing__YieldMode.CLAIMABLE); - IERC20Rebasing(_usdb).configure(IERC20Rebasing__YieldMode.CLAIMABLE); + IERC20Rebasing(_weth).configure(YieldMode.CLAIMABLE); + IERC20Rebasing(_usdb).configure(YieldMode.CLAIMABLE); } /** From 0729c1a091cc2839e6862215995ddd5b4fe8020f Mon Sep 17 00:00:00 2001 From: stonehenge Date: Sat, 6 Jul 2024 07:53:57 +0400 Subject: [PATCH 33/39] fix: Another unused import --- test/foundry/BlastERC20RebasingYield.t.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/test/foundry/BlastERC20RebasingYield.t.sol b/test/foundry/BlastERC20RebasingYield.t.sol index 81662b9..dd96855 100644 --- a/test/foundry/BlastERC20RebasingYield.t.sol +++ b/test/foundry/BlastERC20RebasingYield.t.sol @@ -6,7 +6,6 @@ import {IOwnableTwoSteps} from "../../contracts/interfaces/IOwnableTwoSteps.sol" import {OwnableTwoSteps} from "../../contracts/OwnableTwoSteps.sol"; import {BlastERC20RebasingYield} from "../../contracts/BlastERC20RebasingYield.sol"; import {TestHelpers} from "./utils/TestHelpers.sol"; -import {YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "../../contracts/interfaces/IBlast.sol"; import {YieldMode as IERC20Rebasing__YieldMode} from "../../contracts/interfaces/IERC20Rebasing.sol"; import {MockBlastERC20} from "../mock/MockBlastERC20.sol"; From 9183289f11b8b6e1d939af2533bc1d92a323da7b Mon Sep 17 00:00:00 2001 From: stonehenge Date: Sat, 6 Jul 2024 07:55:16 +0400 Subject: [PATCH 34/39] fix: Remove variable alias --- test/foundry/BlastERC20RebasingYield.t.sol | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/foundry/BlastERC20RebasingYield.t.sol b/test/foundry/BlastERC20RebasingYield.t.sol index dd96855..2b08b8c 100644 --- a/test/foundry/BlastERC20RebasingYield.t.sol +++ b/test/foundry/BlastERC20RebasingYield.t.sol @@ -6,7 +6,7 @@ import {IOwnableTwoSteps} from "../../contracts/interfaces/IOwnableTwoSteps.sol" import {OwnableTwoSteps} from "../../contracts/OwnableTwoSteps.sol"; import {BlastERC20RebasingYield} from "../../contracts/BlastERC20RebasingYield.sol"; import {TestHelpers} from "./utils/TestHelpers.sol"; -import {YieldMode as IERC20Rebasing__YieldMode} from "../../contracts/interfaces/IERC20Rebasing.sol"; +import {YieldMode} from "../../contracts/interfaces/IERC20Rebasing.sol"; import {MockBlastERC20} from "../mock/MockBlastERC20.sol"; import {MockBlastPoints} from "../mock/MockBlastPoints.sol"; @@ -62,11 +62,11 @@ contract BlastERC20RebasingYield_Test is TestHelpers { assertEq(blastERC20RebasingYieldOwnableTwoSteps.WETH(), address(weth)); assertEq(blastERC20RebasingYieldOwnableTwoSteps.USDB(), address(usdb)); - IERC20Rebasing__YieldMode wethYieldMode = weth.yieldMode(address(blastERC20RebasingYieldOwnableTwoSteps)); - assertEq(uint8(wethYieldMode), uint8(IERC20Rebasing__YieldMode.CLAIMABLE)); + YieldMode wethYieldMode = weth.yieldMode(address(blastERC20RebasingYieldOwnableTwoSteps)); + assertEq(uint8(wethYieldMode), uint8(YieldMode.CLAIMABLE)); - IERC20Rebasing__YieldMode usdbYieldMode = usdb.yieldMode(address(blastERC20RebasingYieldOwnableTwoSteps)); - assertEq(uint8(usdbYieldMode), uint8(IERC20Rebasing__YieldMode.CLAIMABLE)); + YieldMode usdbYieldMode = usdb.yieldMode(address(blastERC20RebasingYieldOwnableTwoSteps)); + assertEq(uint8(usdbYieldMode), uint8(YieldMode.CLAIMABLE)); } function test_claim() public asPrankedUser(owner) { From 602487ee6f545070007f6906a929068c28c42f88 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Sat, 6 Jul 2024 08:35:53 +0400 Subject: [PATCH 35/39] fix: Fix _claim notice --- contracts/BlastERC20RebasingYield.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/BlastERC20RebasingYield.sol b/contracts/BlastERC20RebasingYield.sol index bbb4a35..7891695 100644 --- a/contracts/BlastERC20RebasingYield.sol +++ b/contracts/BlastERC20RebasingYield.sol @@ -38,7 +38,7 @@ contract BlastERC20RebasingYield is BlastNativeYield { } /** - * @notice Claim Blast yield. Guarding of the function is dependent on the inherited contract. + * @notice Claim Blast yield. Guarding of the function is dependent on the inherited contract. Inheriting does not allow claiming by default. A public or external function is required in the child contract to access the Claim function. * @param wethReceiver The receiver of WETH. * @param usdbReceiver The receiver of USDB. */ From 534d0539f114da5905628eb7d036ac3cbdb3c38d Mon Sep 17 00:00:00 2001 From: stonehenge Date: Sat, 6 Jul 2024 08:36:49 +0400 Subject: [PATCH 36/39] fix: Fix _claim notice --- contracts/BlastERC20RebasingYield.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/BlastERC20RebasingYield.sol b/contracts/BlastERC20RebasingYield.sol index 7891695..0052ec0 100644 --- a/contracts/BlastERC20RebasingYield.sol +++ b/contracts/BlastERC20RebasingYield.sol @@ -38,7 +38,7 @@ contract BlastERC20RebasingYield is BlastNativeYield { } /** - * @notice Claim Blast yield. Guarding of the function is dependent on the inherited contract. Inheriting does not allow claiming by default. A public or external function is required in the child contract to access the Claim function. + * @notice Claim Blast yield. Guarding of the function is dependent on the inherited contract. Inheriting does not allow claiming by default. A public or external function is required in the child contract to access the _claim function. * @param wethReceiver The receiver of WETH. * @param usdbReceiver The receiver of USDB. */ From 39e688a2f6af6d5cabf3088edcc6e824afb21a0b Mon Sep 17 00:00:00 2001 From: stonehenge Date: Sun, 7 Jul 2024 08:41:56 +0400 Subject: [PATCH 37/39] fix: Renaming --- test/foundry/BlastERC20RebasingYield.t.sol | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/test/foundry/BlastERC20RebasingYield.t.sol b/test/foundry/BlastERC20RebasingYield.t.sol index 2b08b8c..e23abbb 100644 --- a/test/foundry/BlastERC20RebasingYield.t.sol +++ b/test/foundry/BlastERC20RebasingYield.t.sol @@ -13,7 +13,7 @@ import {MockBlastPoints} from "../mock/MockBlastPoints.sol"; import {MockBlastWETH} from "../mock/MockBlastWETH.sol"; import {MockBlastYield} from "../mock/MockBlastYield.sol"; -contract BlastERC20RebasingYieldOwnableTwoSteps is BlastERC20RebasingYield, OwnableTwoSteps { +contract BlastERC20RebasingYieldGuarded is BlastERC20RebasingYield, OwnableTwoSteps { constructor( address _blast, address _blastPoints, @@ -36,7 +36,7 @@ contract BlastERC20RebasingYield_Test is TestHelpers { MockBlastERC20 private usdb; MockBlastYield private mockBlastYield; MockBlastPoints private mockBlastPoints; - BlastERC20RebasingYieldOwnableTwoSteps private blastERC20RebasingYieldOwnableTwoSteps; + BlastERC20RebasingYieldGuarded private blastERC20RebasingYieldGuarded; address public owner = address(69); address public operator = address(420); @@ -48,7 +48,7 @@ contract BlastERC20RebasingYield_Test is TestHelpers { usdb = new MockBlastERC20("USDB", "USDB"); mockBlastYield = new MockBlastYield(); mockBlastPoints = new MockBlastPoints(); - blastERC20RebasingYieldOwnableTwoSteps = new BlastERC20RebasingYieldOwnableTwoSteps( + blastERC20RebasingYieldGuarded = new BlastERC20RebasingYieldGuarded( address(mockBlastYield), address(mockBlastPoints), operator, @@ -59,27 +59,27 @@ contract BlastERC20RebasingYield_Test is TestHelpers { } function test_setUpState() public { - assertEq(blastERC20RebasingYieldOwnableTwoSteps.WETH(), address(weth)); - assertEq(blastERC20RebasingYieldOwnableTwoSteps.USDB(), address(usdb)); + assertEq(blastERC20RebasingYieldGuarded.WETH(), address(weth)); + assertEq(blastERC20RebasingYieldGuarded.USDB(), address(usdb)); - YieldMode wethYieldMode = weth.yieldMode(address(blastERC20RebasingYieldOwnableTwoSteps)); + YieldMode wethYieldMode = weth.yieldMode(address(blastERC20RebasingYieldGuarded)); assertEq(uint8(wethYieldMode), uint8(YieldMode.CLAIMABLE)); - YieldMode usdbYieldMode = usdb.yieldMode(address(blastERC20RebasingYieldOwnableTwoSteps)); + YieldMode usdbYieldMode = usdb.yieldMode(address(blastERC20RebasingYieldGuarded)); assertEq(uint8(usdbYieldMode), uint8(YieldMode.CLAIMABLE)); } function test_claim() public asPrankedUser(owner) { - blastERC20RebasingYieldOwnableTwoSteps.claim(TREASURY, TREASURY); + blastERC20RebasingYieldGuarded.claim(TREASURY, TREASURY); - assertEq(weth.balanceOf(address(blastERC20RebasingYieldOwnableTwoSteps)), 0); - assertEq(usdb.balanceOf(address(blastERC20RebasingYieldOwnableTwoSteps)), 0); + assertEq(weth.balanceOf(address(blastERC20RebasingYieldGuarded)), 0); + assertEq(usdb.balanceOf(address(blastERC20RebasingYieldGuarded)), 0); assertEq(weth.balanceOf(TREASURY), 1 ether); assertEq(usdb.balanceOf(TREASURY), 1 ether); } function test_claim_RevertIf_NotOwner() public asPrankedUser(user1) { vm.expectRevert(IOwnableTwoSteps.NotOwner.selector); - blastERC20RebasingYieldOwnableTwoSteps.claim(TREASURY, TREASURY); + blastERC20RebasingYieldGuarded.claim(TREASURY, TREASURY); } } From 763c63da6e72657a1d8e102db78f6021a01f10df Mon Sep 17 00:00:00 2001 From: stonehenge Date: Sun, 7 Jul 2024 08:44:21 +0400 Subject: [PATCH 38/39] fix: Notice length --- contracts/BlastERC20RebasingYield.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/BlastERC20RebasingYield.sol b/contracts/BlastERC20RebasingYield.sol index 0052ec0..8b6f210 100644 --- a/contracts/BlastERC20RebasingYield.sol +++ b/contracts/BlastERC20RebasingYield.sol @@ -38,7 +38,9 @@ contract BlastERC20RebasingYield is BlastNativeYield { } /** - * @notice Claim Blast yield. Guarding of the function is dependent on the inherited contract. Inheriting does not allow claiming by default. A public or external function is required in the child contract to access the _claim function. + * @notice Claim Blast yield. Guarding of the function is dependent on the inherited contract. + * Inheriting does not allow claiming by default. + * A public or external function is required in the child contract to access the _claim function. * @param wethReceiver The receiver of WETH. * @param usdbReceiver The receiver of USDB. */ From 3cfa074e310122c46fe7374393ed7caf3fb62552 Mon Sep 17 00:00:00 2001 From: stonehenge Date: Sun, 7 Jul 2024 08:46:22 +0400 Subject: [PATCH 39/39] fix: Whitespace formatting --- contracts/BlastERC20RebasingYield.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/BlastERC20RebasingYield.sol b/contracts/BlastERC20RebasingYield.sol index 8b6f210..65bd8e9 100644 --- a/contracts/BlastERC20RebasingYield.sol +++ b/contracts/BlastERC20RebasingYield.sol @@ -38,8 +38,8 @@ contract BlastERC20RebasingYield is BlastNativeYield { } /** - * @notice Claim Blast yield. Guarding of the function is dependent on the inherited contract. - * Inheriting does not allow claiming by default. + * @notice Claim Blast yield. Guarding of the function is dependent on the inherited contract. + * Inheriting does not allow claiming by default. * A public or external function is required in the child contract to access the _claim function. * @param wethReceiver The receiver of WETH. * @param usdbReceiver The receiver of USDB.