Skip to content

Commit

Permalink
bribe distr
Browse files Browse the repository at this point in the history
  • Loading branch information
belbix committed Sep 6, 2023
1 parent 7590462 commit cfaf60f
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 0 deletions.
86 changes: 86 additions & 0 deletions contracts/tools/BribeDistribution.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import "../interfaces/IERC20.sol";
import "../interfaces/IBribe.sol";

contract BribeDistribution {

string public constant VERSION = "1.0.0";

address public owner;
address public pendingOwner;
address public operator;

IBribe public immutable bribe;
address public immutable vault;
address public immutable token;
uint public round;

constructor(address bribe_, address _vault, address _token) {
bribe = IBribe(bribe_);
vault = _vault;
token = _token;
owner = msg.sender;
}

modifier onlyOwner() {
require(msg.sender == owner, "NOT_OWNER");
_;
}

modifier onlyOperator() {
require(msg.sender == operator || msg.sender == owner, "NOT_OPERATOR");
_;
}

function offerOwnership(address newOwner) external onlyOwner {
require(newOwner != address(0), "ZERO_ADDRESS");
pendingOwner = newOwner;
}

function acceptOwnership() external {
require(msg.sender == pendingOwner, "NOT_OWNER");
owner = pendingOwner;
}

function setOperator(address operator_) external onlyOwner {
operator = operator_;
}

////////////////// MAIN LOGIC //////////////////////

function autoNotify() external onlyOperator {
_notify(IERC20(token).balanceOf(msg.sender), round % 2 == 0);
round++;
}

function manualNotify(uint amount, bool fresh) external onlyOperator {
_notify(amount, fresh);
}

function _notify(uint amount, bool fresh) internal {
if (amount != 0) {
IERC20(token).transferFrom(msg.sender, address(this), amount);
}

uint toBribes = IERC20(token).balanceOf(address(this));
require(toBribes != 0, "ZERO_BALANCE");

// assume we will have bribes once per 2 weeks. Need to use a half of the current balance in case of start of new 2 weeks epoch.
if (fresh) {
toBribes = toBribes / 2;
}

_approveIfNeed(token, address(bribe), toBribes);
bribe.notifyForNextEpoch(vault, token, toBribes);
}

function _approveIfNeed(address _token, address dst, uint amount) internal {
if (IERC20(_token).allowance(address(this), dst) < amount) {
IERC20(_token).approve(dst, type(uint).max);
}
}

}
1 change: 1 addition & 0 deletions scripts/addresses/polygon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export class PolygonAddresses {
public static PERF_FEE_TREASURY = "0x9Cc199D4353b5FB3e6C8EEBC99f5139e0d8eA06b".toLowerCase();
public static TETU_BRIDGED_PROCESSING = "0x1950a09fc28Dd3C36CaC89485357844Af0739C07".toLowerCase();
public static REWARDS_REDIRECTOR = "0xA9947d0815d6EA3077805E2112FB19572DD4dc9E".toLowerCase();
public static BRIBE_DISTRIBUTION = "0x1b7B8E29176CF89Cd4c04852FCff552721fC1b2e".toLowerCase();

// PROTOCOL ADRS
public static DEPOSIT_HELPER_V2 = "0xab2422A4d8Ac985AE98F5Da3713988b420f24165".toLowerCase();
Expand Down
18 changes: 18 additions & 0 deletions scripts/deploy/DeployBribeDistribution.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {ethers} from "hardhat";
import {DeployerUtils} from "../utils/DeployerUtils";
import {PolygonAddresses} from "../addresses/polygon";
import {Addresses} from "../addresses/addresses";
import {BribeDistribution} from "../../typechain";

async function main() {
const signer = (await ethers.getSigners())[0];
const core = Addresses.getCore();
await DeployerUtils.deployContract(signer, "BribeDistribution", core.bribe, PolygonAddresses.tUSDC, core.tetu);
}

main()
.then(() => process.exit(0))
.catch(error => {
console.error(error);
process.exit(1);
});
91 changes: 91 additions & 0 deletions test/tools/BribeDistributorTest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import chai from "chai";
import chaiAsPromised from "chai-as-promised";
import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers";
import {BribeDistribution, MockBribe__factory, MockGauge__factory, MockToken,} from "../../typechain";
import {TimeUtils} from "../TimeUtils";
import {ethers} from "hardhat";
import {DeployerUtils} from "../../scripts/utils/DeployerUtils";

const {expect} = chai;
chai.use(chaiAsPromised);

describe("BribeDistributorTest", function () {
let snapshotBefore: string;
let snapshot: string;
let signer: SignerWithAddress;
let signer2: SignerWithAddress;

let distr: BribeDistribution;
let token: MockToken;


before(async function () {
this.timeout(1200000);
snapshotBefore = await TimeUtils.snapshot();
[signer, signer2] = await ethers.getSigners();

const controller = await DeployerUtils.deployMockController(signer);
const mockBribe = MockBribe__factory.connect(await DeployerUtils.deployProxy(signer, 'MockBribe'), signer);
await mockBribe.init(controller.address);
const mockGauge = MockGauge__factory.connect(await DeployerUtils.deployProxy(signer, 'MockGauge'), signer);
await mockGauge.init(controller.address)

token = await DeployerUtils.deployMockToken(signer);

const vault = await DeployerUtils.deployTetuVaultV2(
signer,
controller.address,
token.address,
'TETU',
'TETU',
mockGauge.address,
0
);

distr = await DeployerUtils.deployContract(signer, "BribeDistribution", mockBribe.address, vault.address, token.address) as BribeDistribution;
})

after(async function () {
await TimeUtils.rollback(snapshotBefore);
});

beforeEach(async function () {
snapshot = await TimeUtils.snapshot();
});

afterEach(async function () {
await TimeUtils.rollback(snapshot);
});

it("set new owner test", async () => {
await expect(distr.connect(signer2).offerOwnership(signer2.address)).revertedWith('NOT_OWNER');
await distr.offerOwnership(signer2.address)
await expect(distr.acceptOwnership()).revertedWith('NOT_OWNER');
await distr.connect(signer2).acceptOwnership()
expect(await distr.owner()).eq(signer2.address)
await expect(distr.offerOwnership(signer2.address)).revertedWith('NOT_OWNER');
})

it("manualNotify test", async () => {
await token.approve(distr.address, 1000)
const bribe = await distr.bribe();

await distr.manualNotify(1000, true)
expect(await token.balanceOf(bribe)).eq(500);

await distr.manualNotify(0, false)
expect(await token.balanceOf(bribe)).eq(1000);
})

it("autoNotify test", async () => {
const bal = await token.balanceOf(signer.address);
await token.approve(distr.address, bal)
const bribe = await distr.bribe();

await distr.autoNotify()
expect(await token.balanceOf(bribe)).eq(bal.div(2));

await distr.autoNotify()
expect(await token.balanceOf(bribe)).eq(bal);
})
})

0 comments on commit cfaf60f

Please sign in to comment.