Skip to content

Commit

Permalink
KOL referral (#48)
Browse files Browse the repository at this point in the history
* forta init

* wip

* added high bnbx mint, high bnbx unstake

* wip

* rewards pct change done

* startDelegation, completeDelegation delay completed

* bot undelegation failures tracked

* readme update

* er-drop, bnbx-supply done

* README pdate

* minor changes

* small changes

* bots published

* added reorg fix

* fix: added blockNumber impl.

* updated logs

* kol initial contracts

* make contract gasless

* make contracts upgradeable

* rename

* kol not allowed as user

* info json added

* minor PR updates
  • Loading branch information
Manoj Patra authored Jan 13, 2023
1 parent 0c3f1f1 commit 0d803f3
Show file tree
Hide file tree
Showing 7 changed files with 269 additions and 0 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ NODE_ENV=main npx hardhat deployBnbXImpl --network <network>
NODE_ENV=main npx hardhat deployStakeManagerProxy <bnbX> <admin> <manager> <tokenHub> <bcDepositWallet> <bot> <feeBps> --network <network>
NODE_ENV=main npx hardhat upgradeStakeManagerProxy <proxyAddress> --network <network>
NODE_ENV=main npx hardhat deployStakeManagerImpl --network <network>

NODE_ENV=main npx hardhat deployReferralContract <admin> <trustedForwarder> --network <network>
NODE_ENV=main npx hardhat upgradeReferralContract <proxyAddress> --network <network>
```

## Verifying on etherscan
Expand Down
139 changes: 139 additions & 0 deletions contracts/campaigns/KOLReferral.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@opengsn/contracts/src/ERC2771Recipient.sol";

contract KOLReferral is Initializable, ERC2771Recipient {
address public admin;

mapping(address => string) public walletToReferralId;
mapping(string => address) public referralIdToWallet;
mapping(address => string) public userReferredBy;
mapping(address => address[]) private _kolToUsers;

address[] private _users;
address[] private _kols;

modifier onlyAdmin() {
require(_msgSender() == admin, "Only Admin");
_;
}

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}

function initialize(address admin_, address trustedForwarder_)
external
initializer
{
require(admin_ != address(0), "zero address");
require(trustedForwarder_ != address(0), "zero address");
admin = admin_;
_setTrustedForwarder(trustedForwarder_);
}

function registerKOL(address wallet, string memory referralId)
external
onlyAdmin
{
require(
referralIdToWallet[referralId] == address(0),
"ReferralId is already taken"
);
require(
bytes(walletToReferralId[wallet]).length == 0,
"ReferralId is already assigned for this wallet"
);
walletToReferralId[wallet] = referralId;
referralIdToWallet[referralId] = wallet;
_kols.push(wallet);
}

function storeUserInfo(string memory referralId) external {
require(
referralIdToWallet[referralId] != address(0),
"Invalid ReferralId"
);
require(
bytes(userReferredBy[_msgSender()]).length == 0,
"User is already referred before"
);
userReferredBy[_msgSender()] = referralId;
_users.push(_msgSender());

address kolWallet = referralIdToWallet[referralId];

require(_msgSender() != kolWallet, "kol not allowed as user");
_kolToUsers[kolWallet].push(_msgSender());
}

function queryUserReferrer(address user)
external
view
returns (address _referrer)
{
string memory referralId = userReferredBy[user];
return referralIdToWallet[referralId];
}

function getKOLUserList(address kol)
external
view
returns (address[] memory)
{
return _kolToUsers[kol];
}

function getKOLs() external view returns (address[] memory) {
return _kols;
}

function getUsers(uint256 startIdx, uint256 maxNumUsers)
external
view
returns (uint256 numUsers, address[] memory userList)
{
require(startIdx < _users.length, "invalid startIdx");

if (startIdx + maxNumUsers > _users.length) {
maxNumUsers = _users.length - startIdx;
}

userList = new address[](maxNumUsers);
for (
numUsers = 0;
startIdx < _users.length && numUsers < maxNumUsers;
numUsers++
) {
userList[numUsers] = _users[startIdx++];
}

return (numUsers, userList);
}

function getKOLCount() external view returns (uint256) {
return _kols.length;
}

function getUserCount() external view returns (uint256) {
return _users.length;
}

function getKOLRefCount(address kol) external view returns (uint256) {
return _kolToUsers[kol].length;
}

function setAdmin(address admin_) external onlyAdmin {
require(admin_ != address(0), "zero address");
require(admin_ != admin, "old admin == new admin");
admin = admin_;
}

function setTrustedForwarder(address trustedForwarder_) external onlyAdmin {
require(trustedForwarder_ != address(0), "zero address");
_setTrustedForwarder(trustedForwarder_);
}
}
15 changes: 15 additions & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,21 @@ task(
await deployDirect(hre, "StakeManager");
});

task("deployReferralContract", "Deploy KOL Referral Contract")
.addPositionalParam("admin")
.addPositionalParam("trustedForwarder")
.setAction(
async ({ admin, trustedForwarder }, hre: HardhatRuntimeEnvironment) => {
await deployProxy(hre, "KOLReferral", admin, trustedForwarder);
}
);

task("upgradeReferralContract", "Upgrade KOL Referral Contract")
.addPositionalParam("proxyAddress")
.setAction(async ({ proxyAddress }, hre: HardhatRuntimeEnvironment) => {
await upgradeProxy(hre, "KOLReferral", proxyAddress);
});

const config: HardhatUserConfig = {
defaultNetwork: "hardhat",
solidity: {
Expand Down
13 changes: 13 additions & 0 deletions kol-referral-info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"testnet": {
"contract": "0x50C15cb832dcBFB9ee4b95d101608b664F06D7f7",
"admin": "0x8e39FBBA48014E8a36b36dad183d2A00E9c750cC",
"trustedForwarder": "0x61456BF1715C1415730076BB79ae118E806E74d2"
},
"beta": {
"contract": "0x3629787a59418732B388ED398928c5Bb9f4E74f1",
"proxyAdmin": "0xcb507d421540f1ec1b8adcaf81995c7c89f4213e",
"admin": "0x8e39FBBA48014E8a36b36dad183d2A00E9c750cC",
"trustedForwarder": "0x86C80a8aa58e0A4fa09A69624c31Ab2a6CAD56b8"
}
}
29 changes: 29 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,8 @@
"ts-node": "^10.8.1",
"typechain": "^5.2.0",
"typescript": "^4.7.3"
},
"dependencies": {
"@opengsn/contracts": "^3.0.0-beta.1"
}
}
67 changes: 67 additions & 0 deletions test/KOLReferral.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
import { expect } from "chai";
import { ethers, upgrades } from "hardhat";
import { KOLReferral } from "../typechain";

describe("KOL referral Contract", () => {
let admin: SignerWithAddress;
let kol1: SignerWithAddress;
let trustedForwarder: SignerWithAddress;
let users: SignerWithAddress[];
let kolContract: KOLReferral;

beforeEach(async () => {
[admin, kol1, trustedForwarder, ...users] = await ethers.getSigners();

kolContract = (await upgrades.deployProxy(
await ethers.getContractFactory("KOLReferral"),
[admin.address, trustedForwarder.address]
)) as KOLReferral;
await kolContract.deployed();
});

it("register a kol", async () => {
let referralId1: string = "kol_1_ref_id";

expect(await kolContract.walletToReferralId(kol1.address)).be.eq("");
expect(await kolContract.referralIdToWallet(referralId1)).be.eq(
ethers.constants.AddressZero
);
expect(await kolContract.getKOLCount()).be.eq(0);

await kolContract.registerKOL(kol1.address, referralId1);
expect(await kolContract.walletToReferralId(kol1.address)).be.eq(
referralId1
);
expect(await kolContract.referralIdToWallet(referralId1)).be.eq(
kol1.address
);
expect(await kolContract.getKOLCount()).be.eq(1);
});

it("store user info", async () => {
let referralId1: string = "kol_1_ref_id";
await kolContract.registerKOL(kol1.address, referralId1);

expect(await kolContract.getUserCount()).to.be.eq(0);
expect(await kolContract.getKOLRefCount(kol1.address)).be.eq(0);

let u1kolContract = kolContract.connect(users[0]);
await u1kolContract.storeUserInfo(referralId1);

expect(await kolContract.queryUserReferrer(users[0].address)).to.be.eq(
kol1.address
);
expect(await kolContract.getKOLRefCount(kol1.address)).be.eq(1);

const totalUsers = await kolContract.getUserCount();
const { numUsers, userList } = await kolContract.getUsers(0, totalUsers);
expect(userList[0]).to.be.eq(users[0].address);
expect(numUsers).to.be.eq(1);
expect(numUsers).to.be.eq(totalUsers);

await expect(
kolContract.connect(kol1).storeUserInfo(referralId1)
).be.revertedWith("kol not allowed as user");
});
});

0 comments on commit 0d803f3

Please sign in to comment.