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

Integrate $BB in YieldDistributor #94

Merged
merged 12 commits into from
Sep 22, 2024
2 changes: 2 additions & 0 deletions script/deploy/DeployYieldDistributor.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ contract DeployYieldDistributor is Script {
string public deployConfigPath = string(bytes("./script/deploy/config/deployYD.json"));
string config_data = vm.readFile(deployConfigPath);
address _bread = stdJson.readAddress(config_data, "._bread");
address _butteredBread = stdJson.readAddress(config_data, "._butteredBread");
uint256 _minRequiredVotingPower = stdJson.readUint(config_data, "._minRequiredVotingPower");
uint256 _cycleLength = stdJson.readUint(config_data, "._cycleLength");
uint256 _maxPoints = stdJson.readUint(config_data, "._maxPoints");
Expand All @@ -24,6 +25,7 @@ contract DeployYieldDistributor is Script {
bytes initData = abi.encodeWithSelector(
YieldDistributor.initialize.selector,
_bread,
_butteredBread,
_precision,
_minRequiredVotingPower,
_maxPoints,
Expand Down
8 changes: 6 additions & 2 deletions script/deploy/config/deployBB.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
{
"_owner": "0x918dEf5d593F46735f74F9E2B280Fe51AF3A99ad",
"_liquidityPools": ["0xa555d5344f6FB6c65da19e403Cb4c1eC4a1a5Ee3"],
"_scalingFactors": ["100"],
"_liquidityPools": [
"0xf3d8f3de71657d342db60dd714c8a2ae37eac6b4"
],
"_scalingFactors": [
"100"
],
"_name": "ButteredBread",
"_symbol": "BB"
}
3 changes: 2 additions & 1 deletion script/deploy/config/deployYD.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"_bread": "0xa555d5344f6FB6c65da19e403Cb4c1eC4a1a5Ee3",
"_butteredbread": "0x123456789abcdef123456789abcdef123456789a",
"_owner": "0x918dEf5d593F46735f74F9E2B280Fe51AF3A99ad",
"_projectNames": [
"laborDao",
Expand All @@ -19,7 +20,7 @@
"_maxPoints": 10000,
"_cycleLength": 518400,
"_minRequiredVotingPower": 1728000000000000000000000,
"_lastClaimedBlockNumber": 0,
"_lastClaimedBlockNumber": 1,
"_precision": 1000000000000000000,
"_yieldFixedSplitDivisor": 2
}
27 changes: 25 additions & 2 deletions src/YieldDistributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ contract YieldDistributor is IYieldDistributor, OwnableUpgradeable {
mapping(address => uint256[]) voterDistributions;
/// @notice How much of the yield is divided equally among projects
uint256 public yieldFixedSplitDivisor;
/// @notice The address of the `ButteredBread` token contract
ERC20VotesUpgradeable public BUTTERED_BREAD;

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
Expand All @@ -57,6 +59,7 @@ contract YieldDistributor is IYieldDistributor, OwnableUpgradeable {

function initialize(
address _bread,
address _butteredBread,
uint256 _precision,
uint256 _minRequiredVotingPower,
uint256 _maxPoints,
Expand All @@ -66,8 +69,16 @@ contract YieldDistributor is IYieldDistributor, OwnableUpgradeable {
address[] memory _projects
) public initializer {
__Ownable_init(msg.sender);
if (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is more readable personally

if (
    _bread == address(0) ||
    _butteredBread == address(0) ||
    _precision == 0 ||
    _minRequiredVotingPower == 0 ||
    _maxPoints == 0 ||
    _cycleLength == 0 ||
    _yieldFixedSplitDivisor == 0 ||
    _lastClaimedBlockNumber == 0 ||
    _projects.length == 0
) {
    revert MustBeGreaterThanZero();
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

formatter overrides this.. do you know if there's a comment I can add for it to ignore this?

Copy link
Contributor

@bagelface bagelface Sep 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aside from changing line_length, which i wouldn't recommend, not really. all good

_bread == address(0) || _butteredBread == address(0) || _precision == 0 || _minRequiredVotingPower == 0
|| _maxPoints == 0 || _cycleLength == 0 || _yieldFixedSplitDivisor == 0 || _lastClaimedBlockNumber == 0
|| _projects.length == 0
) {
revert MustBeGreaterThanZero();
}
RonTuretzky marked this conversation as resolved.
Show resolved Hide resolved

BREAD = Bread(_bread);
BUTTERED_BREAD = ERC20VotesUpgradeable(_butteredBread);
PRECISION = _precision;
minRequiredVotingPower = _minRequiredVotingPower;
maxPoints = _maxPoints;
Expand Down Expand Up @@ -97,8 +108,12 @@ contract YieldDistributor is IYieldDistributor, OwnableUpgradeable {
* @return uint256 The voting power of the user
*/
function getCurrentVotingPower(address _account) public view returns (uint256) {
return
this.getVotingPowerForPeriod(BREAD, lastClaimedBlockNumber - cycleLength, lastClaimedBlockNumber, _account);
return this.getVotingPowerForPeriod(
RonTuretzky marked this conversation as resolved.
Show resolved Hide resolved
BREAD, lastClaimedBlockNumber - cycleLength, lastClaimedBlockNumber, _account
)
+ this.getVotingPowerForPeriod(
RonTuretzky marked this conversation as resolved.
Show resolved Hide resolved
BUTTERED_BREAD, lastClaimedBlockNumber - cycleLength, lastClaimedBlockNumber, _account
);
}

/**
Expand Down Expand Up @@ -373,4 +388,12 @@ contract YieldDistributor is IYieldDistributor, OwnableUpgradeable {

yieldFixedSplitDivisor = _yieldFixedSplitDivisor;
}

/**
* @notice Set the ButteredBread token contract
* @param _butteredBread Address of the ButteredBread token contract
*/
function setButteredBread(address _butteredBread) public onlyOwner {
BUTTERED_BREAD = ERC20VotesUpgradeable(_butteredBread);
}
}
77 changes: 77 additions & 0 deletions test/ButteredBread.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {ButteredBread, IButteredBread} from "src/ButteredBread.sol";
import {ICurveStableSwap} from "src/interfaces/ICurveStableSwap.sol";
import {IERC20Votes} from "src/interfaces/IERC20Votes.sol";
import {YieldDistributorTestWrapper} from "src/test/YieldDistributorTestWrapper.sol";
import {YieldDistributor, IYieldDistributor} from "src/YieldDistributor.sol";
import {IBread} from "bread-token/src/interfaces/IBread.sol";
import {OwnableUpgradeable} from "openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol";
import {ERC20Mock} from "openzeppelin-contracts/contracts/mocks/token/ERC20Mock.sol";

uint256 constant XDAI_FACTOR = 700; // 700% scaling factor; 7X
uint256 constant TOKEN_AMOUNT = 1000 ether;
Expand All @@ -23,6 +28,21 @@ contract ButteredBreadTest is Test {

uint256 public fixedPointPercent;
address[] public userList;
YieldDistributorTestWrapper public yieldDistributor;
string public deployConfigPath = string(bytes("./test/test_deploy.json"));
string config_data = vm.readFile(deployConfigPath);
bytes projectsRaw = stdJson.parseRaw(config_data, "._projects");
address[] projects = abi.decode(projectsRaw, (address[]));
uint256 _blocktime = stdJson.readUint(config_data, "._blocktime");
uint256 _maxPoints = stdJson.readUint(config_data, "._maxPoints");
uint256 _precision = stdJson.readUint(config_data, "._precision");
uint256 _minVotingAmount = stdJson.readUint(config_data, "._minVotingAmount");
uint256 _cycleLength = stdJson.readUint(config_data, "._cycleLength");
uint256 _minHoldingDuration = stdJson.readUint(config_data, "._minHoldingDuration");
uint256 _lastClaimedBlockNumber = stdJson.readUint(config_data, "._lastClaimedBlockNumber");
uint256 _yieldFixedSplitDivisor = stdJson.readUint(config_data, "._yieldFixedSplitDivisor");
// See test/YieldDistributor.t.sol for explanation of these values
uint256 _minRequiredVotingPower = stdJson.readUint(config_data, "._minRequiredVotingPower");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i recommend in the future, inheriting the deployment script from the Scripts folder into the test setup, which will also inherit the stdJson datas. but for now, this works


function setUp() public virtual {
vm.createSelectFork(vm.rpcUrl("gnosis"));
Expand Down Expand Up @@ -54,6 +74,25 @@ contract ButteredBreadTest is Test {
vm.label(GNOSIS_CURVE_POOL_XDAI_BREAD, "CurveLP_XDAI_BREAD");

userList.push(ALICE);

YieldDistributorTestWrapper yieldDistributorImplementation = new YieldDistributorTestWrapper();
address[] memory projects1 = new address[](1);
projects1[0] = address(this);
bytes memory ydinitData = abi.encodeWithSelector(
YieldDistributor.initialize.selector,
address(GNOSIS_BREAD),
address(bb),
_precision,
_minRequiredVotingPower,
_maxPoints,
_cycleLength,
_yieldFixedSplitDivisor,
_lastClaimedBlockNumber,
projects1
);
yieldDistributor = YieldDistributorTestWrapper(
address(new TransparentUpgradeableProxy(address(yieldDistributorImplementation), address(this), ydinitData))
);
}

function _helperAddLiquidity(address _account, uint256 _amountT0, uint256 _amountT1) internal {
Expand Down Expand Up @@ -490,3 +529,41 @@ contract ButteredBreadTest_Delegation is ButteredBreadTest {
assertEq(bb.delegates(ALICE), DELEGATEE);
}
}

interface Mintable {
function mint(address account) external payable;
}

contract ButteredBreadTest_Integration is ButteredBreadTest {
uint256 public start = 32_323_232_323;

function setUp() public virtual override {
super.setUp();
_helperAddLiquidity(ALICE, TOKEN_AMOUNT, TOKEN_AMOUNT);
}

function setUpForCycle(YieldDistributorTestWrapper _yieldDistributor) public {
vm.roll(start - (_cycleLength));
address yieldDistributorOwner = OwnableUpgradeable(_yieldDistributor).owner();
vm.prank(yieldDistributorOwner);
_yieldDistributor.setLastClaimedBlockNumber(vm.getBlockNumber());
address breadOwner = OwnableUpgradeable(GNOSIS_BREAD).owner();
vm.prank(breadOwner);
IBread(GNOSIS_BREAD).setYieldClaimer(address(_yieldDistributor));
vm.roll(start - (_cycleLength + 1));
vm.deal(ALICE, _minVotingAmount);
vm.startPrank(ALICE);
bb.deposit(GNOSIS_CURVE_POOL_XDAI_BREAD, TOKEN_AMOUNT);
Mintable(GNOSIS_BREAD).mint{value: _minVotingAmount}(ALICE);
vm.roll(start);
}

function testIntegration() public {
setUpForCycle(yieldDistributor);
assertEq(bb.balanceOf(ALICE), TOKEN_AMOUNT * XDAI_FACTOR / fixedPointPercent);
assertEq(bb.accountToLPBalance(ALICE, GNOSIS_CURVE_POOL_XDAI_BREAD), TOKEN_AMOUNT);
uint256 bbBalance = bb.balanceOf(ALICE);
uint256 bBalance = IERC20(GNOSIS_BREAD).balanceOf(ALICE);
assertEq(yieldDistributor.getCurrentVotingPower(ALICE), bbBalance + bBalance);
}
}
5 changes: 5 additions & 0 deletions test/YieldDistributor.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {TransparentUpgradeableProxy} from
import {YieldDistributor, IYieldDistributor} from "src/YieldDistributor.sol";
import {YieldDistributorTestWrapper} from "src/test/YieldDistributorTestWrapper.sol";

import {ButteredBread} from "src/ButteredBread.sol";

abstract contract Bread is ERC20VotesUpgradeable, OwnableUpgradeable {
function claimYield(uint256 amount, address receiver) public virtual;
function yieldAccrued() external view virtual returns (uint256);
Expand Down Expand Up @@ -43,6 +45,7 @@ contract YieldDistributorTest is Test {
uint256 _lastClaimedBlockNumber = stdJson.readUint(config_data, "._lastClaimedBlockNumber");
uint256 _yieldFixedSplitDivisor = stdJson.readUint(config_data, "._yieldFixedSplitDivisor");
Bread public bread = Bread(address(_bread));
ButteredBread public butteredBread = ButteredBread(address(_bread));
uint256 minHoldingDurationInBlocks = _minHoldingDuration / _blocktime;

// For testing purposes, these values were used in the following way to configure _minRequiredVotingPower
Expand All @@ -61,6 +64,7 @@ contract YieldDistributorTest is Test {
bytes memory initData = abi.encodeWithSelector(
YieldDistributor.initialize.selector,
address(bread),
address(butteredBread),
_precision,
_minRequiredVotingPower,
_maxPoints,
Expand All @@ -79,6 +83,7 @@ contract YieldDistributorTest is Test {
initData = abi.encodeWithSelector(
YieldDistributor.initialize.selector,
address(bread),
address(butteredBread),
_precision,
_minRequiredVotingPower,
_maxPoints,
Expand Down
3 changes: 2 additions & 1 deletion test/test_deploy.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"_bread": "0xa555d5344f6FB6c65da19e403Cb4c1eC4a1a5Ee3",
"_butteredbread": "0x123456789abcdef123456789abcdef123456789a",
"_projectNames": [
"laborDao",
"Dandelion",
Expand All @@ -17,7 +18,7 @@
"_blocktime": 5,
"_cycleLength": 10,
"_maxPoints": 10000,
"_lastClaimedBlockNumber": 0,
"_lastClaimedBlockNumber": 1,
"_minRequiredVotingPower": 10000000000000000000,
"_minVotingAmount": 10000000000000000000,
"_minHoldingDuration": 864000,
Expand Down