Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: BlastYield contract #103

Merged
merged 39 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
b93db9e
feat: BlastYield contract
stonehengeLR Jun 30, 2024
8445190
fix: Compilier error
stonehengeLR Jul 1, 2024
f9fcf92
fix: Compilier error
stonehengeLR Jul 1, 2024
2edb97e
test: BlastYield Tests
stonehengeLR Jul 2, 2024
edbe35f
test: BlastYield Test Fixes
stonehengeLR Jul 3, 2024
fe415c3
fix: Prettier and Mocks
stonehengeLR Jul 3, 2024
b7e2d0d
fix: Increase node version for github actions
stonehengeLR Jul 3, 2024
d1c8d3f
fix: Increase node version for github actions
stonehengeLR Jul 3, 2024
9ca51b7
fix: Update Access Control to OwnableTwoSteps
stonehengeLR Jul 4, 2024
6f67949
feat: Private function to allow both access control and ownable two s…
stonehengeLR Jul 4, 2024
e9cb33e
fix: Remove virtual from _claim
stonehengeLR Jul 4, 2024
cc82877
fix: Rename _owner to _governor
stonehengeLR Jul 4, 2024
e7dcbeb
fix: Fix _claim notice
stonehengeLR Jul 4, 2024
2517444
fix: Pass mockPoints
stonehengeLR Jul 4, 2024
88ee19b
fix: Remove operator role
stonehengeLR Jul 4, 2024
ce33daf
fix: Mock naming
stonehengeLR Jul 4, 2024
591cf53
fix: Get modifier from TestHelpers
stonehengeLR Jul 4, 2024
0ba5d3a
chore: Update solmate to openzeppelin
stonehengeLR Jul 4, 2024
acda72e
fix: Governor comment
stonehengeLR Jul 4, 2024
4143be9
fix: TestHelpers inheritance
stonehengeLR Jul 4, 2024
5946c5f
feat: Split BlastYield into multiple contracts
stonehengeLR Jul 5, 2024
06cebd1
fix: Remove event
stonehengeLR Jul 5, 2024
70b57dd
fix: Remove empty line
stonehengeLR Jul 5, 2024
f80299b
fix: YieldMode GasMode fix
stonehengeLR Jul 5, 2024
96c81ec
fix: Fix blast points notice
stonehengeLR Jul 5, 2024
ed78762
fix: Refix YieldMode GasMode
stonehengeLR Jul 5, 2024
bc6d3e8
fix: Test names
stonehengeLR Jul 5, 2024
3d7fac2
fix: Improve notices
stonehengeLR Jul 5, 2024
666c866
fix: Fix native yield and points tests
stonehengeLR Jul 5, 2024
c01c63d
fix: YieldMode GasMode naming BlastNativeYield_Test
stonehengeLR Jul 5, 2024
68bb39c
fix: Unused variables and imports
stonehengeLR Jul 6, 2024
1d6537f
fix: Remove variable alias
stonehengeLR Jul 6, 2024
0729c1a
fix: Another unused import
stonehengeLR Jul 6, 2024
9183289
fix: Remove variable alias
stonehengeLR Jul 6, 2024
602487e
fix: Fix _claim notice
stonehengeLR Jul 6, 2024
534d053
fix: Fix _claim notice
stonehengeLR Jul 6, 2024
39e688a
fix: Renaming
stonehengeLR Jul 7, 2024
763c63d
fix: Notice length
stonehengeLR Jul 7, 2024
3cfa074
fix: Whitespace formatting
stonehengeLR Jul 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
Expand Down
56 changes: 56 additions & 0 deletions contracts/BlastERC20RebasingYield.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import {BlastNativeYield} from "./BlastNativeYield.sol";
import {IERC20Rebasing, YieldMode as IERC20Rebasing__YieldMode} from "./interfaces/IERC20Rebasing.sol";

/**
* @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 BlastERC20RebasingYield is BlastNativeYield {
address public immutable WETH;
address public immutable USDB;

/**
* @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
* @param _usdb USDB address
* @param _weth WETH address
*/
constructor(
address _blast,
address _blastPoints,
address _blastPointsOperator,
address _governor,
address _usdb,
address _weth
) BlastNativeYield(_blast, _blastPoints, _blastPointsOperator, _governor) {
WETH = _weth;
USDB = _usdb;

IERC20Rebasing(_weth).configure(IERC20Rebasing__YieldMode.CLAIMABLE);
IERC20Rebasing(_usdb).configure(IERC20Rebasing__YieldMode.CLAIMABLE);
}

/**
* @notice Claim Blast yield. Guarding of the function is dependent on the inherited contract.
0xhiroshi marked this conversation as resolved.
Show resolved Hide resolved
* @param wethReceiver The receiver of WETH.
* @param usdbReceiver The receiver of USDB.
*/
function _claim(address wethReceiver, address usdbReceiver) internal {
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);
}
}
}
27 changes: 27 additions & 0 deletions contracts/BlastNativeYield.sol
Original file line number Diff line number Diff line change
@@ -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";
0xhiroshi marked this conversation as resolved.
Show resolved Hide resolved
import {BlastPoints} from "./BlastPoints.sol";
/**
0xhiroshi marked this conversation as resolved.
Show resolved Hide resolved
* @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);
}
}
20 changes: 20 additions & 0 deletions contracts/BlastPoints.sol
Original file line number Diff line number Diff line change
@@ -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
0xhiroshi marked this conversation as resolved.
Show resolved Hide resolved
* @author LooksRare protocol team (👀,💎)
*/
contract BlastPoints {
/**
* @param _blastPoints Blast points
* @param _blastPointsOperator Blast points operator
*/
constructor(address _blastPoints, address _blastPointsOperator) {
IBlastPoints(_blastPoints).configurePointsOperator(_blastPointsOperator);
}
}
77 changes: 77 additions & 0 deletions contracts/interfaces/IBlast.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

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);
}
6 changes: 6 additions & 0 deletions contracts/interfaces/IBlastPoints.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IBlastPoints {
function configurePointsOperator(address operator) external;
}
21 changes: 21 additions & 0 deletions contracts/interfaces/IERC20Rebasing.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

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);
}
2 changes: 1 addition & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const config: HardhatUserConfig = {
solidity: {
compilers: [
{
version: "0.8.17",
version: "0.8.20",
settings: { optimizer: { enabled: true, runs: 888888 } },
},
{
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@
"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.1.1",
"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"
Expand Down
86 changes: 86 additions & 0 deletions test/foundry/BlastERC20RebasingYield.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

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";
import {MockBlastPoints} from "../mock/MockBlastPoints.sol";
import {MockBlastWETH} from "../mock/MockBlastWETH.sol";
import {MockBlastYield} from "../mock/MockBlastYield.sol";

contract BlastERC20RebasingYieldOwnableTwoSteps is BlastERC20RebasingYield, OwnableTwoSteps {
constructor(
address _blast,
address _blastPoints,
address _blastPointsOperator,
address _owner,
address _usdb,
address _weth
)
BlastERC20RebasingYield(_blast, _blastPoints, _blastPointsOperator, _owner, _usdb, _weth)
OwnableTwoSteps(_owner)
{}

function claim(address wethReceiver, address usdbReceiver) public onlyOwner {
_claim(wethReceiver, usdbReceiver);
}
}

contract BlastERC20RebasingYieldOwnableTwoStepsOwnableTwoSteps_Test is TestHelpers {
0xhiroshi marked this conversation as resolved.
Show resolved Hide resolved
MockBlastWETH private weth;
MockBlastERC20 private usdb;
MockBlastYield private mockBlastYield;
MockBlastPoints private mockBlastPoints;
BlastERC20RebasingYieldOwnableTwoSteps private blastERC20RebasingYieldOwnableTwoSteps;

address public owner = address(69);
address public operator = address(420);
address public user1 = address(1);
address private constant TREASURY = address(69420);

function setUp() public {
weth = new MockBlastWETH();
usdb = new MockBlastERC20("USDB", "USDB");
mockBlastYield = new MockBlastYield();
mockBlastPoints = new MockBlastPoints();
blastERC20RebasingYieldOwnableTwoSteps = new BlastERC20RebasingYieldOwnableTwoSteps(
address(mockBlastYield),
address(mockBlastPoints),
operator,
owner,
address(usdb),
address(weth)
);
}

function test_setUpState() public {
assertEq(blastERC20RebasingYieldOwnableTwoSteps.WETH(), address(weth));
assertEq(blastERC20RebasingYieldOwnableTwoSteps.USDB(), address(usdb));

IERC20Rebasing__YieldMode wethYieldMode = weth.yieldMode(address(blastERC20RebasingYieldOwnableTwoSteps));
assertEq(uint8(wethYieldMode), uint8(IERC20Rebasing__YieldMode.CLAIMABLE));

IERC20Rebasing__YieldMode usdbYieldMode = usdb.yieldMode(address(blastERC20RebasingYieldOwnableTwoSteps));
assertEq(uint8(usdbYieldMode), uint8(IERC20Rebasing__YieldMode.CLAIMABLE));
}

function test_claim() public asPrankedUser(owner) {
blastERC20RebasingYieldOwnableTwoSteps.claim(TREASURY, TREASURY);

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);
blastERC20RebasingYieldOwnableTwoSteps.claim(TREASURY, TREASURY);
}
}
51 changes: 51 additions & 0 deletions test/foundry/BlastNativeYield.t.sol
Original file line number Diff line number Diff line change
@@ -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 {
0xhiroshi marked this conversation as resolved.
Show resolved Hide resolved
constructor(
address _blast,
address _blastPoints,
address _blastPointsOperator,
address _owner
) BlastNativeYield(_blast, _blastPoints, _blastPointsOperator, _owner) OwnableTwoSteps(_owner) {}
}

contract BlastNativeYieldOwnableTwoSteps_Test is TestHelpers {
0xhiroshi marked this conversation as resolved.
Show resolved Hide resolved
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);
0xhiroshi marked this conversation as resolved.
Show resolved Hide resolved

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);
}
}
Loading
Loading