Skip to content
Open
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
56 changes: 47 additions & 9 deletions contracts/Referral.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,35 @@ import "./external/proxy/OwnedUpgradeabilityProxy.sol";
import "./external/NativeMetaTransaction.sol";
import "./interfaces/IMaster.sol";
import "./interfaces/IAllMarkets.sol";
import "./interfaces/IbPLOTToken.sol";
import "./interfaces/IToken.sol";
import "./interfaces/IAuth.sol";

contract Referral is IAuth, NativeMetaTransaction {

event ReferralLog(address indexed referrer, address indexed referee, uint256 referredOn);
event ClaimedReferralReward(address indexed user, address token, uint256 amount);
event ReferralLog(address indexed referrer, address indexed referee, uint256 referredOn, uint256 validity);
event ReferralFeeLog(address indexed referrer, address indexed referee, address token, uint256 referrerFee, uint256 refereeFee);
event ClaimedReferralReward(address indexed user, address token, uint256 referrerFee, uint256 refereeFee);

struct UserData {
mapping(address => uint256) referrerFee; // Fee earned by referring another user for a given token
mapping(address => uint256) refereeFee; // Fee earned after being referred by another user for a given token
address referrer; // Address of the referrer
address referrer; // Address of the referrer
uint validity;
}

IAllMarkets internal allMarkets;
IbPLOTToken internal bPLOTToken;
address internal masterAddress;
address internal plotToken;

uint internal predictionDecimalMultiplier;
uint public referralValidity;

mapping (address => UserData) public userData;

modifier onlyInternal {
IMaster(masterAddress).isInternal(msg.sender);
require(IMaster(masterAddress).isInternal(msg.sender));
_;
}

Expand All @@ -55,10 +61,37 @@ contract Referral is IAuth, NativeMetaTransaction {
authorized = ms.authorized();
masterAddress = _masterAddress;
allMarkets = IAllMarkets(ms.getLatestAddress("AM"));
bPLOTToken = IbPLOTToken(ms.getLatestAddress("BL"));
plotToken = ms.dAppToken();
predictionDecimalMultiplier = 10;
referralValidity = 90 days;
_initializeEIP712("RF");
}

/**
* @dev Approves Plot tokens to bPLOT contract to use PLOT for minting bPLOT
* @param _amount amount of plot tokens
*/
function approveToBPLOT(uint _amount) external onlyAuthorized {
require(IToken(plotToken).approve((address(bPLOTToken)),_amount),"ERC20 call Failed");
}

/**
* @dev Renounce this contract as minter
*/
function renounceAsMinter() public onlyAuthorized {
bPLOTToken.renounceMinter();
}

/**
* @dev Set time upto which both referrer and referee can earn fee for refferral
* @param _referralValidity Time in seconds
*/
function setReferralValidity(uint _referralValidity) public onlyAuthorized {
require(_referralValidity > 0);
referralValidity = _referralValidity;
}

/**
* @dev Set referrer address of a user, can be set only by the authorized users
* @param _referrer User who is referring new user
Expand All @@ -70,7 +103,8 @@ contract Referral is IAuth, NativeMetaTransaction {
require(allMarkets.getTotalStakedByUser(_referee) == 0);
require(_userData.referrer == address(0));
_userData.referrer = _referrer;
emit ReferralLog(_referrer, _referee, now);
_userData.validity = referralValidity.add(now);
emit ReferralLog(_referrer, _referee, now, _userData.validity);
}

/**
Expand All @@ -84,12 +118,13 @@ contract Referral is IAuth, NativeMetaTransaction {
function setReferralRewardData(address _referee, address _token, uint _referrerFee, uint _refereeFee) external onlyInternal returns(bool _isEligible) {
UserData storage _userData = userData[_referee];
address _referrer = _userData.referrer;
if(_referrer != address(0)) {
if(_referrer != address(0) && _userData.validity >= now) {
_isEligible = true;
//Commission for referee
_userData.refereeFee[_token] = _userData.refereeFee[_token].add(_refereeFee);
//Commission for referrer
userData[_referrer].referrerFee[_token] = userData[_referrer].referrerFee[_token].add(_referrerFee);
emit ReferralFeeLog(_referrer, _referee, _token, _referrerFee, _refereeFee);
}
}

Expand All @@ -115,8 +150,9 @@ contract Referral is IAuth, NativeMetaTransaction {
uint256 _refereeFee = _userData.refereeFee[_token];
delete _userData.refereeFee[_token];
uint _tokenToTransfer = (_refereeFee.add(_referrerFee)).mul(10**predictionDecimalMultiplier);
require(_tokenToTransfer > 0);
_transferAsset(_token, _user, _tokenToTransfer);
emit ClaimedReferralReward(_user, _token, _tokenToTransfer);
emit ClaimedReferralReward(_user, _token, _referrerFee, _refereeFee);
}

/**
Expand All @@ -125,8 +161,10 @@ contract Referral is IAuth, NativeMetaTransaction {
* @param _amount The amount which is transfer.
*/
function _transferAsset(address _asset, address _recipient, uint256 _amount) internal {
if(_amount > 0) {
require(IToken(_asset).transfer(_recipient, _amount));
if(_asset == plotToken) {
require(bPLOTToken.mint(_recipient, _amount));
} else {
require(IToken(_asset).transfer(_recipient, _amount));
}
}

Expand Down
1 change: 1 addition & 0 deletions contracts/interfaces/IbPLOTToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ contract IbPLOTToken {
function convertToPLOT(address _of, address _to, uint256 amount) public;
function transfer(address recipient, uint256 amount) public returns (bool);
function renounceMinter() public;
function mint(address account, uint256 amount) public returns (bool);
}
18 changes: 13 additions & 5 deletions test/10_plotusMetaTx.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const { assert } = require("chai");
const OwnedUpgradeabilityProxy = artifacts.require("OwnedUpgradeabilityProxy");
const Master = artifacts.require("Master");
const PlotusToken = artifacts.require("MockPLOT");
const BLOT = artifacts.require("BPLOT");
const AllMarkets = artifacts.require("MockAllMarkets");
const CyclicMarkets = artifacts.require("MockCyclicMarkets");
const Referral = artifacts.require("Referral");
Expand Down Expand Up @@ -50,6 +51,7 @@ contract("Rewards-Market", async function(users) {
plotusToken = await PlotusToken.deployed();
timeNow = await latestTime();

bPlotInstance = await BLOT.at(await masterInstance.getLatestAddress(web3.utils.toHex("BL")));
allMarkets = await AllMarkets.at(await masterInstance.getLatestAddress(web3.utils.toHex("AM")));
cyclicMarkets = await CyclicMarkets.at(await masterInstance.getLatestAddress(web3.utils.toHex("CM")));
referral = await Referral.deployed();
Expand Down Expand Up @@ -209,7 +211,8 @@ contract("Rewards-Market", async function(users) {

it("Check referral fee", async () => {
let referralRewardPlot = [9.932, 0.8, 0.42, 0.246, 1, 1.4, 0.4, 0.1, 0.6, 0];

await bPlotInstance.addMinter(referral.address);
await referral.approveToBPLOT(toWei(100000000));
for(i=1;i<11;i++)
{
let reward = await referral.getReferralFees(users[i], plotusToken.address);
Expand All @@ -219,16 +222,17 @@ contract("Rewards-Market", async function(users) {
reward = reward[1];
}
assert.equal(reward/1,referralRewardPlot[i-1]*1e8);
let plotBalBefore = await plotusToken.balanceOf(users[i]);
let plotBalBefore = await bPlotInstance.balanceOf(users[i]);
functionSignature = encode3("claimReferralFee(address,address)", users[i], plotusToken.address);
if(reward > 0)
await signAndExecuteMetaTx(
privateKeyList[i],
users[i],
functionSignature,
referral,
"RF"
);
let plotBalAfter = await plotusToken.balanceOf(users[i]);
let plotBalAfter = await bPlotInstance.balanceOf(users[i]);
assert.equal(Math.round((plotBalAfter/1e13-plotBalBefore/1e13)),reward/1e3);
}
})
Expand Down Expand Up @@ -348,6 +352,7 @@ contract("Rewards-Market Raise dispute and pass the proposal ", async function(u
plotusToken = await PlotusToken.deployed();
timeNow = await latestTime();

bPlotInstance = await BLOT.at(await masterInstance.getLatestAddress(web3.utils.toHex("BL")));
cyclicMarkets = await CyclicMarkets.at(await masterInstance.getLatestAddress(web3.utils.toHex("CM")));
allMarkets = await AllMarkets.at(await masterInstance.getLatestAddress(web3.utils.toHex("AM")));
disputeResolution = await DisputeResolution.at(await masterInstance.getLatestAddress(web3.utils.toHex("DR")));
Expand Down Expand Up @@ -499,6 +504,8 @@ contract("Rewards-Market Raise dispute and pass the proposal ", async function(u

it("Check referral fee", async () => {
let referralRewardPlot = [10.532, 0.8, 0.42, 0.246, 1, 1.4, 0.4, 0.1, 0.6, 0.3];
await bPlotInstance.addMinter(referral.address);
await referral.approveToBPLOT(toWei(100000000));

for(i=1;i<11;i++)
{
Expand All @@ -509,16 +516,17 @@ contract("Rewards-Market Raise dispute and pass the proposal ", async function(u
reward = reward[1];
}
assert.equal(reward/1,referralRewardPlot[i-1]*1e8);
let plotBalBefore = await plotusToken.balanceOf(users[i]);
let plotBalBefore = await bPlotInstance.balanceOf(users[i]);
functionSignature = encode3("claimReferralFee(address,address)", users[i], plotusToken.address);
if(reward > 0)
await signAndExecuteMetaTx(
privateKeyList[i],
users[i],
functionSignature,
referral,
"RF"
);
let plotBalAfter = await plotusToken.balanceOf(users[i]);
let plotBalAfter = await bPlotInstance.balanceOf(users[i]);
assert.equal(Math.round((plotBalAfter/1e13-plotBalBefore/1e13)),reward/1e3);
}
})
Expand Down
16 changes: 12 additions & 4 deletions test/18_Acyclic_testcase.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ contract("Rewards-Market", async function(users) {
BLOTInstance = await BLOT.deployed();
timeNow = await latestTime();

bPlotInstance = await BLOT.at(await masterInstance.getLatestAddress(web3.utils.toHex("BL")));
allMarkets = await AllMarkets.at(await masterInstance.getLatestAddress(web3.utils.toHex("AM")));
acyclicMarkets = await AcyclicMarkets.at(await masterInstance.getLatestAddress(web3.utils.toHex("AC")));
referral = await Referral.deployed();
Expand Down Expand Up @@ -222,6 +223,8 @@ contract("Rewards-Market", async function(users) {

it("Check referral fee", async () => {
let referralRewardPlot = [10.532, 0.8, 0.42, 0.246, 1, 1.4, 0.4, 0.1, 0.6, 0.3];
await bPlotInstance.addMinter(referral.address);
await referral.approveToBPLOT(toWei(100000000));

for(i=1;i<11;i++)
{
Expand All @@ -232,16 +235,17 @@ contract("Rewards-Market", async function(users) {
reward = reward[1];
}
assert.equal(reward/1,referralRewardPlot[i-1]*1e8);
let plotBalBefore = await plotusToken.balanceOf(users[i]);
let plotBalBefore = await bPlotInstance.balanceOf(users[i]);
functionSignature = encode3("claimReferralFee(address,address)", users[i], plotusToken.address);
if(reward > 0)
await signAndExecuteMetaTx(
privateKeyList[i],
users[i],
functionSignature,
referral,
"RF"
);
let plotBalAfter = await plotusToken.balanceOf(users[i]);
let plotBalAfter = await bPlotInstance.balanceOf(users[i]);
assert.equal(Math.round((plotBalAfter/1e13-plotBalBefore/1e13)),reward/1e3);
}
})
Expand Down Expand Up @@ -391,6 +395,7 @@ contract("Rewards-Market Raise dispute and pass the proposal ", async function(u
BLOTInstance = await BLOT.deployed();
timeNow = await latestTime();

bPlotInstance = await BLOT.at(await masterInstance.getLatestAddress(web3.utils.toHex("BL")));
acyclicMarkets = await AcyclicMarkets.at(await masterInstance.getLatestAddress(web3.utils.toHex("AC")));
allMarkets = await AllMarkets.at(await masterInstance.getLatestAddress(web3.utils.toHex("AM")));
disputeResolution = await DisputeResolution.at(await masterInstance.getLatestAddress(web3.utils.toHex("DR")));
Expand Down Expand Up @@ -543,6 +548,8 @@ contract("Rewards-Market Raise dispute and pass the proposal ", async function(u

it("Check referral fee", async () => {
let referralRewardPlot = [10.532, 0.8, 0.42, 0.246, 1, 1.4, 0.4, 0.1, 0.6, 0.3];
await bPlotInstance.addMinter(referral.address);
await referral.approveToBPLOT(toWei(100000000));

for(i=1;i<11;i++)
{
Expand All @@ -553,16 +560,17 @@ contract("Rewards-Market Raise dispute and pass the proposal ", async function(u
reward = reward[1];
}
assert.equal(reward/1,referralRewardPlot[i-1]*1e8);
let plotBalBefore = await plotusToken.balanceOf(users[i]);
let plotBalBefore = await bPlotInstance.balanceOf(users[i]);
functionSignature = encode3("claimReferralFee(address,address)", users[i], plotusToken.address);
if(reward > 0)
await signAndExecuteMetaTx(
privateKeyList[i],
users[i],
functionSignature,
referral,
"RF"
);
let plotBalAfter = await plotusToken.balanceOf(users[i]);
let plotBalAfter = await bPlotInstance.balanceOf(users[i]);
assert.equal(Math.round((plotBalAfter/1e13-plotBalBefore/1e13)),reward/1e3);
}
})
Expand Down
Loading