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

ERC20 Splitter #153

Merged
merged 2 commits into from
Sep 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 0 additions & 10 deletions contracts/bondingcurve/BondingCurve.sol
Original file line number Diff line number Diff line change
Expand Up @@ -151,14 +151,6 @@ contract BondingCurve is IBondingCurve, OracleRef, PCVSplitter, Timed, Incentivi
_setMintCap(_mintCap);
}

/// @notice sets the allocation of incoming PCV
function setAllocation(
address[] calldata allocations,
uint256[] calldata ratios
) external override onlyGovernor {
_setAllocation(allocations, ratios);
}

/// @notice batch allocate held PCV
function allocate() external override whenNotPaused {
uint256 amount = balance();
Expand All @@ -176,8 +168,6 @@ contract BondingCurve is IBondingCurve, OracleRef, PCVSplitter, Timed, Incentivi
_initTimed(); // reset window
_incentivize();
}

emit Allocate(msg.sender, amount);
}

/// @notice a boolean signalling whether Scale has been reached
Expand Down
7 changes: 0 additions & 7 deletions contracts/bondingcurve/IBondingCurve.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ interface IBondingCurve {

event Purchase(address indexed to, uint256 amountIn, uint256 amountOut);

event Allocate(address indexed caller, uint256 amount);

event Reset(uint256 oldTotalPurchased);

// ----------- State changing Api -----------
Expand All @@ -40,11 +38,6 @@ interface IBondingCurve {

function setScale(uint256 newScale) external;

function setAllocation(
address[] calldata pcvDeposits,
uint256[] calldata ratios
) external;

function setIncentiveFrequency(uint256 newFrequency) external;

function setMintCap(uint256 newMintCap) external;
Expand Down
38 changes: 38 additions & 0 deletions contracts/pcv/utils/ERC20Splitter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
pragma solidity ^0.8.0;

import "./PCVSplitter.sol";

/// @title ERC20Splitter
/// @notice a contract to split token held to multiple locations
contract ERC20Splitter is PCVSplitter {

/// @notice token to split
IERC20 public token;

/**
@notice constructor for ERC20Splitter
@param _core the Core address to reference
@param _pcvDeposits the locations to send tokens
@param _ratios the relative ratios of how much tokens to send each location, in basis points
*/
constructor(
address _core,
IERC20 _token,
address[] memory _pcvDeposits,
uint256[] memory _ratios
)
CoreRef(_core)
PCVSplitter(_pcvDeposits, _ratios)
{
token = _token;
}

/// @notice distribute held TRIBE
function allocate() external whenNotPaused {
_allocate(token.balanceOf(address(this)));
}

function _allocateSingle(uint256 amount, address pcvDeposit) internal override {
token.transfer(pcvDeposit, amount);
}
}
14 changes: 13 additions & 1 deletion contracts/pcv/utils/PCVSplitter.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.4;

import "../../refs/CoreRef.sol";

/// @title abstract contract for splitting PCV into different deposits
/// @author Fei Protocol
abstract contract PCVSplitter {
abstract contract PCVSplitter is CoreRef {

/// @notice total allocation allowed representing 100%
uint256 public constant ALLOCATION_GRANULARITY = 10_000;
Expand All @@ -12,6 +14,7 @@ abstract contract PCVSplitter {
address[] private pcvDeposits;

event AllocationUpdate(address[] oldPCVDeposits, uint256[] oldRatios, address[] newPCVDeposits, uint256[] newRatios);
event Allocate(address indexed caller, uint256 amount);

/// @notice PCVSplitter constructor
/// @param _pcvDeposits list of PCV Deposits to split to
Expand Down Expand Up @@ -52,6 +55,14 @@ abstract contract PCVSplitter {
return (pcvDeposits, ratios);
}

/// @notice sets the allocation of held PCV
function setAllocation(
address[] calldata _allocations,
uint256[] calldata _ratios
) external onlyGovernorOrAdmin {
_setAllocation(_allocations, _ratios);
}

/// @notice distribute funds to single PCV deposit
/// @param amount amount of funds to send
/// @param pcvDeposit the pcv deposit to send funds
Expand Down Expand Up @@ -85,5 +96,6 @@ abstract contract PCVSplitter {
uint256 amount = total * ratios[i] / granularity;
_allocateSingle(amount, pcvDeposits[i]);
}
emit Allocate(msg.sender, total);
}
}
2 changes: 1 addition & 1 deletion test/pcv/ERC20Dripper.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const dripAmount = new BN(4000000).mul(new BN(10).pow(new BN(18)));
// this is 1 week in seconds
const dripFrequency = 604800;

describe.only('ERC20Dripper', () => {
describe('ERC20Dripper', () => {
before(async () => {
({
userAddress,
Expand Down
52 changes: 52 additions & 0 deletions test/pcv/ERC20Splitter.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const {
expectEvent,
expectRevert,
expect,
getAddresses,
getCore,
} = require('../helpers');

const ERC20Splitter = artifacts.require('ERC20Splitter');
const Tribe = artifacts.require('Tribe');

describe('ERC20Splitter', function () {
let userAddress;
let secondUserAddress;
let governorAddress;

beforeEach(async function () {
({
userAddress,
secondUserAddress,
governorAddress,
} = await getAddresses());
this.core = await getCore(true);
this.tribe = await Tribe.at(await this.core.tribe());
this.erc20Splitter = await ERC20Splitter.new(
this.core.address,
this.tribe.address,
[userAddress, secondUserAddress],
[9000, 1000]
);

await this.core.allocateTribe(this.erc20Splitter.address, '100000', {from: governorAddress});
});

it('Unpaused allocates TRIBE successfully', async function() {
expect(await this.tribe.balanceOf(this.erc20Splitter.address)).to.be.bignumber.equal('100000');

expectEvent(await this.erc20Splitter.allocate({from: userAddress}), 'Allocate', {
caller: userAddress,
amount: '100000'
});

expect(await this.tribe.balanceOf(this.erc20Splitter.address)).to.be.bignumber.equal('0');
expect(await this.tribe.balanceOf(userAddress)).to.be.bignumber.equal('90000');
expect(await this.tribe.balanceOf(secondUserAddress)).to.be.bignumber.equal('10000');
});

it('Paused reverts', async function() {
await this.erc20Splitter.pause({from: governorAddress});
await expectRevert(this.erc20Splitter.allocate(), 'Pausable: paused');
});
});