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 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
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
198 changes: 198 additions & 0 deletions contracts/competition/Competition.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

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

contract Competition is Governable {
struct Team {
address leader;
string name;
address[] members;
}

struct Competition {
uint start;
uint end;
uint maxTeamSize;
uint8 competitionType;
mapping(address => Team) teams;
mapping(string => bool) teamNames;
mapping(address => address) memberTeams;
mapping(address => address) joinRequests;
mapping(address => mapping(address => bytes32)) joinRequestsReferralCodes;
}

Competition[] public competitions;
IReferralStorage public referralStorage;

event TeamCreated(uint index, address leader, string name);
event JoinRequestCreated(uint index, address member, address leader, bytes32 referralCode);
event JoinRequestCanceled(uint index, address member);
event JoinRequestApproved(uint index, address member, address leader);
event MemberRemoved(uint index, address leader, address member);
event CompetitionCreated(uint index, uint start, uint end, uint maxTeamSize, uint8 competitionType);
event CompetitionUpdated(uint index, uint start, uint end, uint maxTeamSize, uint8 competitionType);
event CompetitionRemoved(uint index);

modifier registrationIsOpen(uint competitionIndex) {
require(competitions[competitionIndex].start > block.timestamp, "Competition: Registration is closed.");
_;
}

modifier isNotMember(uint competitionIndex) {
require(competitions[competitionIndex].memberTeams[msg.sender] == address(0), "Competition: Team members are not allowed.");
_;
}

modifier competitionExists(uint index) {
require(competitions.length > index && competitions[index].start > 0, "Competition: The competition does not exist.");
_;
}

modifier teamsAreAllowed(uint index) {
require(competitions[competitionIndex].competitionType !== 0, "Competition: Team are not allowed.");
_;
}

constructor(IReferralStorage _referralStorage) public {
referralStorage = _referralStorage;
}

function createCompetition(uint start, uint end, uint maxTeamSize, uint8 competitionType) external onlyGov {
_validateCompetitionParameters(start, end, maxTeamSize);

competitions.push(Competition(start, end, maxTeamSize, competitionType));

emit CompetitionCreated(competitions.length - 1, start, end, maxTeamSize);
}

function updateCompetition(uint index, uint start, uint end, uint maxTeamSize, uint8 competitionType) external onlyGov competitionExists(index) {
_validateCompetitionParameters(start, end, maxTeamSize);

competitions[index].start = start;
competitions[index].end = end;
competitions[index].maxTeamSize = maxTeamSize;
morazzela marked this conversation as resolved.
Show resolved Hide resolved
competitions[index].competitionType = competitionType;

emit CompetitionUpdated(index, start, end, maxTeamSize, competitionType);
}

function removeCompetition(uint index) external onlyGov competitionExists(index) {
require(competitions[index].start > block.timestamp, "Competition: Competition is active.");

delete competitions[index];

emit CompetitionRemoved(index);
}

function createTeam(uint competitionIndex, string calldata name) external registrationIsOpen(competitionIndex) isNotMember(competitionIndex) teamsAreAllowed(competitionIndex) {
Competition storage competition = competitions[competitionIndex];

require(!competition.teamNames[name], "Competition: Team name already registered.");

Team storage team = competition.teams[msg.sender];
team.leader = msg.sender;
team.name = name;
team.members.push(msg.sender);

competition.teamNames[name] = true;
competition.memberTeams[msg.sender] = msg.sender;

emit TeamCreated(competitionIndex, msg.sender, name);
}

function createJoinRequest(uint competitionIndex, address leaderAddress, bytes32 referralCode) external registrationIsOpen(competitionIndex) isNotMember(competitionIndex) teamsAreAllowed(competitionIndex) {
Competition storage competition = competitions[competitionIndex];

require(competition.memberTeams[msg.sender] == address(0), "Competition: You can't join multiple teams.");
require(competition.teams[leaderAddress].leader != address(0), "Competition: The team does not exist.");

if (referralCode != bytes32(0)) {
require(referralStorage.codeOwners(referralCode) != address(0), "Competition: The referral code does not exist.");
}

competition.joinRequests[msg.sender] = leaderAddress;
competition.joinRequestsReferralCodes[msg.sender][leaderAddress] = referralCode;

emit JoinRequestCreated(competitionIndex, msg.sender, leaderAddress, referralCode);
}

function approveJoinRequest(uint competitionIndex, address[] calldata memberAddresses) external registrationIsOpen(competitionIndex) teamsAreAllowed(competitionIndex) {
Competition storage competition = competitions[competitionIndex];

for (uint i = 0; i < memberAddresses.length; i++) {
address memberAddress = memberAddresses[i];
require(competition.joinRequests[memberAddress] == msg.sender, "Competition: Member did not apply.");
require(competition.memberTeams[memberAddress] == address(0), "Competition: Member already joined a team.");
require(competition.teams[msg.sender].members.length < competition.maxTeamSize, "Competition: Team is full.");

if (competition.joinRequestsReferralCodes[memberAddress][msg.sender] != bytes32(0)) {
referralStorage.setTraderReferralCode(memberAddress, competition.joinRequestsReferralCodes[memberAddress][msg.sender]);
}

competition.teams[msg.sender].members.push(memberAddress);
competition.memberTeams[memberAddress] = msg.sender;
competition.joinRequests[memberAddress] = address(0);

emit JoinRequestApproved(competitionIndex, memberAddress, msg.sender);
}
}

function cancelJoinRequest(uint competitionIndex) external registrationIsOpen(competitionIndex) teamsAreAllowed(competitionIndex) {
competitions[competitionIndex].joinRequests[msg.sender] = address(0);
emit JoinRequestCanceled(competitionIndex, msg.sender);
}

function removeMember(uint competitionIndex, address leaderAddress, address memberAddress) external registrationIsOpen(competitionIndex) teamsAreAllowed(competitionIndex) {
Competition storage competition = competitions[competitionIndex];

require(competition.memberTeams[memberAddress] == msg.sender || memberAddress == msg.sender, "Competition: You are not allowed to remove this member.");

address[] memory oldMembers = competition.teams[leaderAddress].members;
delete competition.teams[leaderAddress].members;
for (uint i = 0; i < oldMembers.length; i++) {
if (oldMembers[i] != memberAddress) {
competition.teams[leaderAddress].members.push(oldMembers[i]);
}
}

competition.memberTeams[memberAddress] = address(0);

emit MemberRemoved(competitionIndex, leaderAddress, memberAddress);
}

function getTeam(uint competitionIndex, address _leaderAddress) external view returns (address leaderAddress, string memory name) {
Team memory team = competitions[competitionIndex].teams[_leaderAddress];
return (team.leader, team.name);
}

function getTeamMembers(uint competitionIndex, address leaderAddress, uint start, uint offset) external view returns (address[] memory members) {
address[] memory members = competitions[competitionIndex].teams[leaderAddress].members;
address[] memory result = new address[](offset);

for (uint i = start; i < start + offset && i < members.length; i++) {
result[i] = members[i];
}

return result;
}

function getMemberTeam(uint competitionIndex, address memberAddress) external view returns (address leaderAddress) {
return competitions[competitionIndex].memberTeams[memberAddress];
}

function getJoinRequest(uint competitionIndex, address memberAddress) external view returns (address leaderAddress) {
return competitions[competitionIndex].joinRequests[memberAddress];
}

function validateName(uint competitionIndex, string calldata name) external view returns (bool isValid) {
return !competitions[competitionIndex].teamNames[name];
}

function _validateCompetitionParameters(uint start, uint end, uint maxTeamSize) internal {
require(start > block.timestamp, "Competition: Start time must be in the future.");
require(end > start, "Competition: End time must be greater than start time.");
require(maxTeamSize > 0, "Competition: Max team size must be greater than zero.");
}
}
19 changes: 19 additions & 0 deletions scripts/competition/createCompetition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const { ethers } = require("hardhat");
const { contractAt, sendTxn } = require("../shared/helpers")

async function main() {
const competition = await contractAt("Competition", "0x271B8D7b97A07207BAd07dc577F6D29D6a368C56");

await sendTxn(competition.createCompetition(
1663884000,
1664488800,
5
), "competition.createCompetition(start, end, maxTeamSize)")
}

main()
.then(() => process.exit(0))
.catch(error => {
console.error(error)
process.exit(1)
})
19 changes: 19 additions & 0 deletions scripts/competition/updateCompetition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const { contractAt, sendTxn } = require("../shared/helpers")

async function main() {
const competition = await contractAt("Competition", "0x17fb5AEEF7221353B6B2D12EDDa0Dd5655Ec25b2");

await sendTxn(competition.updateCompetition(
0,
1672527599,
1704063599,
10
), "competition.updateCompetition(index, start, end, maxTeamSize)")
}

main()
.then(() => process.exit(0))
.catch(error => {
console.error(error)
process.exit(1)
})
45 changes: 45 additions & 0 deletions scripts/core/deployCompetition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
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 getArbitrumTestnetValues() {
// const positionRouter = await contractAt("PositionRouter", "0x195256074192170d1530527abC9943759c7167d8")

// return { positionRouter }
// }

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

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

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

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

main()
.then(() => process.exit(0))
.catch(error => {
console.error(error)
process.exit(1)
})
Loading