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

start leaderboard contract #27

Draft
wants to merge 21 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ data/snapshotBalance
data/holders
flattened
distribution-data*.json
.DS_Store

#Hardhat files
cache
Expand Down
135 changes: 135 additions & 0 deletions contracts/competition/Competition.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import "../referrals/interfaces/IReferralStorage.sol";
import "../access/Governable.sol";

contract Competition is Governable
morazzela marked this conversation as resolved.
Show resolved Hide resolved
{
morazzela marked this conversation as resolved.
Show resolved Hide resolved
struct Team {
address leader;
string name;
bytes32 referral;
address[] members;
address[] joinRequests;
}

uint public start;
uint public end;
uint public registrationStart;
uint public registrationEnd;
IReferralStorage private referralStorage;
address[] private leaders;
morazzela marked this conversation as resolved.
Show resolved Hide resolved
mapping(address => Team) private teams;
mapping(string => bool) private teamNames;
mapping(address => address) private membersToTeam;
mapping(address => mapping(address => bool)) private requests;
morazzela marked this conversation as resolved.
Show resolved Hide resolved

modifier registrationIsOpen()
morazzela marked this conversation as resolved.
Show resolved Hide resolved
{
require(block.timestamp >= registrationStart && block.timestamp < registrationEnd, "Registration is closed.");
_;
}

modifier isNotMember()
{
require(membersToTeam[msg.sender] == address(0), "Team members are not allowed.");
_;
}

constructor(
uint start_,
uint end_,
uint registrationStart_,
uint registrationEnd_,
IReferralStorage referralStorage_
morazzela marked this conversation as resolved.
Show resolved Hide resolved
) public {
start = start_;
end = end_;
registrationStart = registrationStart_;
registrationEnd = registrationEnd_;
referralStorage = referralStorage_;
}

function registerTeam(string calldata name, bytes32 referral) external registrationIsOpen {
require(referralStorage.codeOwners(referral) != address(0), "Referral code does not exist.");
require(teamNames[name] == false, "Team name already registered.");

Team storage team;
morazzela marked this conversation as resolved.
Show resolved Hide resolved

team.leader = msg.sender;
team.name = name;
team.referral = referral;
team.members.push(msg.sender);

teams[msg.sender] = team;
leaders.push(msg.sender);
teamNames[name] = true;
}

function createJoinRequest(address leaderAddress) external registrationIsOpen isNotMember {
require(membersToTeam[msg.sender] == address(0), "You can't join multiple teams.");
require(teams[msg.sender].leader != address(0), "The team does not exist.");
require(requests[leaderAddress][msg.sender] == false, "You already applied for this team.");

teams[leaderAddress].joinRequests.push(msg.sender);
requests[leaderAddress][msg.sender] = true;
}

function approveJoinRequest(address memberAddress) external registrationIsOpen isNotMember {
require(requests[msg.sender][memberAddress] == false, "This member did not apply.");
require(membersToTeam[memberAddress] == address(0), "This member already joined a team.");

referralStorage.setTraderReferralCode(memberAddress, teams[msg.sender].referral);
teams[msg.sender].members.push(msg.sender);
membersToTeam[memberAddress] = msg.sender;
}

function getLeaders(uint start_, uint offset) external view returns (address[] memory) {
address[] memory res;

for (uint i = start_; i < leaders.length && i < start_ + offset; i++) {
res[i] = leaders[i];
}

return res;
}

function getTeam(address leaderAddr) external view returns (address leader, string memory name, bytes32 referral) {
Team memory team = teams[leaderAddr];
return (team.leader, team.name, team.referral);
}

function getTeamMembers(address leaderAddr) external view returns (address[] memory) {
return teams[leaderAddr].members;
}

function getTeamJoinRequests(address leaderAddr) external view returns (address[] memory) {
address[] memory res;

for (uint i = 0; i < teams[leaderAddr].joinRequests.length; i++) {
address jr = teams[leaderAddr].joinRequests[i];
if (membersToTeam[jr] == address(0)) {
res[i] = jr;
}
}

return res;
}

function setStart(uint start_) external onlyGov {
start = start_;
}

function setEnd(uint end_) external onlyGov {
end = end_;
}

function setRegistrationStart(uint registrationStart_) external onlyGov {
registrationStart = registrationStart_;
}

function setRegistrationEnd(uint registrationEnd_) external onlyGov {
registrationEnd = registrationEnd_;
}
}
52 changes: 52 additions & 0 deletions scripts/core/deployCompetition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const { deployContract, contractAt } = require("../shared/helpers")

const network = (process.env.HARDHAT_NETWORK || 'mainnet');

async function getArbValues() {
const positionRouter = await contractAt("PositionRouter", "0x3D6bA331e3D9702C5e8A8d254e5d8a285F223aba")

return { positionRouter }
}

async function getAvaxValues() {
const positionRouter = await contractAt("PositionRouter", "0x195256074192170d1530527abC9943759c7167d8")

return { positionRouter }
}

async function getValues() {
if (network === "arbitrum") {
return getArbValues()
}

if (network === "avax") {
return getAvaxValues()
}

if (network === "testnet") {
return getTestnetValues()
}
}

async function main() {
const { positionRouter } = await getValues()
const referralStorage = await contractAt("ReferralStorage", await positionRouter.referralStorage())

const startTime = Math.round(Date.now() / 1000)
const endTime = startTime + 100000000000

await deployContract("Competition", [
startTime,
endTime,
startTime,
endTime,
referralStorage.address,
]);
}

main()
.then(() => process.exit(0))
.catch(error => {
console.error(error)
process.exit(1)
})
88 changes: 88 additions & 0 deletions test/competition/Competition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
const { expect, use } = require("chai")
const { solidity } = require("ethereum-waffle")
const { deployContract } = require("../shared/fixtures")
const { getBlockTime } = require("../shared/utilities")

use(solidity)

const { keccak256 } = ethers.utils

// Tier0 (5% discount, 5% rebate) = Tier {totalRebate = 1000, defaultTradersDiscountShare = 5000}
// Tier1 (12% discount, 8% rebate) = Tier {totalRebate = 2000, defaultTradersDiscountShare = 6000}
// Tier2 (12% discount, 15% rebate) = Tier {totalRebate = 2700, defaultTradersDiscountShare = 4444}
// for the last tier extra EsGMX incentives will be handled off-chain
describe("Competition", function () {
const provider = waffle.provider
const [wallet, user0, user1, user2] = provider.getWallets()
let competition
let referralStorage

beforeEach(async () => {
const ts = await getBlockTime(provider)

referralStorage = await deployContract("ReferralStorage", [])
competition = await deployContract("Competition", [
ts + 60, // start
ts + 120, // end
ts - 60, // registrationStart
ts + 60, // registrationEnd
referralStorage.address
]);
})

it("allows owner to set times", async () => {
await competition.connect(wallet).setStart(1)
await competition.connect(wallet).setEnd(1)
await competition.connect(wallet).setRegistrationStart(1)
await competition.connect(wallet).setRegistrationEnd(1)
})

it("disable non owners to set times", async () => {
await expect(competition.connect(user0).setStart(1)).to.be.revertedWith("Governable: forbidden")
await expect(competition.connect(user0).setEnd(1)).to.be.revertedWith("Governable: forbidden")
await expect(competition.connect(user0).setRegistrationStart(1)).to.be.revertedWith("Governable: forbidden")
await expect(competition.connect(user0).setRegistrationEnd(1)).to.be.revertedWith("Governable: forbidden")
})

it("disable people to register teams before registration time", async () => {
const code = keccak256("0xFF")
await referralStorage.connect(user0).registerCode(code)
await competition.connect(wallet).setRegistrationStart((await getBlockTime(provider)) + 10)
await expect(competition.connect(user0).registerTeam("1", code)).to.be.revertedWith("Registration is closed.")
})

it("disable people to register teams after registration time", async () => {
const code = keccak256("0xFF")
await referralStorage.connect(user0).registerCode(code)
await competition.connect(wallet).setRegistrationEnd((await getBlockTime(provider)) - 10)
await expect(competition.connect(user0).registerTeam("1", code)).to.be.revertedWith("Registration is closed.")
})

it("allows people to register teams in times", async () => {
const code = keccak256("0xFF")
await referralStorage.connect(user0).registerCode(code)
try {
await competition.connect(user0).registerTeam("1", code)
} catch (e) {
console.log(e)
}
})

it("disabled people to register multiple teams", async () => {
const code = keccak256("0xFF")
await referralStorage.connect(user0).registerCode(code)
await competition.connect(user0).registerTeam("1", code)
await expect(competition.connect(user0).registerTeam("1", code)).to.be.revertedWith("Team members are not allowed.")
})

it("disabled people to register a team with non existing referral code", async () => {
const code = keccak256("0xFF")
await expect(competition.connect(user0).registerTeam("1", code)).to.be.revertedWith("Referral code does not exist.")
})

it("disabled multiple teams with the same name", async () => {
const code = keccak256("0xFF")
await competition.connect(user0).registerTeam("1", code)
await expect(competition.connect(user1).registerTeam("1", code)).to.be.revertedWith("Team name already registered.")
})
});