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

Affiliates v2 #233

Merged
merged 68 commits into from
Jun 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
be5c69e
Affiliates before testing
dasaveliev Dec 28, 2020
d3ae2e6
Merge remote-tracking branch 'origin/development' into affiliates
dasaveliev Dec 28, 2020
879bafc
Affiliates module pre-testing tuning
dasaveliev Dec 30, 2020
4955d66
Housekeeping: solved audits, refactoring
dasaveliev Jan 2, 2021
89622a5
python spaces
dasaveliev Jan 3, 2021
d93b4e1
minor changes
dasaveliev Jan 4, 2021
91411df
Split LoanClosings EIP-170; affiliates test script
dasaveliev Jan 4, 2021
b9a4b88
Merge local with remote 'affiliates' branches
tjcloa Jan 17, 2021
36c71b1
upgrade solidity plugins; no husky hook
tjcloa Jan 17, 2021
2d70b1f
Affiliates tests pre-initial
tjcloa Jan 18, 2021
a9c1080
Merge branch 'development' of into affiliates
tjcloa Jan 18, 2021
e2bf527
prettier formatter (no logic change)
tjcloa Jan 18, 2021
1adc14f
hardhat initial environment settings
tjcloa Jan 22, 2021
a30b59e
hardhat config
tjcloa Jan 26, 2021
5e6382d
Hardhat vs Brownie: ISovryn interface conflict
tjcloa Jan 26, 2021
70eb3e2
Preserve Affiliates working test 90% coverage
tjcloa Jan 27, 2021
26389cb
Affiliates referral final touches before merge
tjcloa Jan 28, 2021
b3e8922
Removed yarn.lock
tjcloa Jan 28, 2021
6eecd0f
Merge development branch into affiliates
tjcloa Jan 28, 2021
9570f3a
Adaptation to LoanClosings contract split
tjcloa Jan 28, 2021
7bdd3c4
Tests hardhat adapt. & LoanClosings split
tjcloa Jan 28, 2021
b8b0593
Housekeeping: removed legacy LoanTokenLogicDai.sol
tjcloa Jan 29, 2021
4a2b46b
node_modules removed from repo
tjcloa Feb 3, 2021
f45c659
flash loan whitelisting before tests
tjcloa Feb 3, 2021
5e23132
restoring earlyAccessToken (#130)
tjcloa Feb 3, 2021
8dd4351
Merge 'origin/development' into affiliates
tjcloa Feb 3, 2021
c7861e7
Merge remote-tracking branch 'origin/development' into affiliates_fix…
tjcloa Apr 7, 2021
e3efeec
sync with development branch
tjcloa Apr 8, 2021
d3687bc
merged with development, fixed tests
tjcloa Apr 9, 2021
c574aa9
No need to define the protocol address, only need in the affiliates t…
cwsnt Apr 9, 2021
3f681f7
Fixed for deployment
cwsnt Apr 13, 2021
65e49bd
Fix the protocol address not registered for module interaction in dep…
cwsnt Apr 15, 2021
7e86285
Add integration testing for margin trade with affiliate
cwsnt Apr 16, 2021
3047d41
Add integration test for affiliates withdrawal
cwsnt Apr 19, 2021
12a0a9b
Add standalone affiliates deployment
cwsnt Apr 21, 2021
2ec96bb
Add public function to withdraw all affiliates token
cwsnt Apr 22, 2021
ed3c8c4
Add feature bonus SOV on referral commissions
cwsnt Apr 23, 2021
1478f0e
Fix affiliates test - changing swap impl local to sovryn's
cwsnt Apr 23, 2021
9bddd27
Add unit test for sov bonus amount in affiliates
cwsnt Apr 26, 2021
0b02c61
Fix conflict
cwsnt Apr 26, 2021
d205b36
Set sov token address while deploying protocol
cwsnt Apr 26, 2021
14d476e
Merge and fix conflict with development branch
cwsnt Apr 27, 2021
b9e2248
Add replace protocol settings, set affiliate bonus SOV percent, set m…
cwsnt Apr 28, 2021
fa82f91
Merge latest development (after bzx merged)
cwsnt Apr 28, 2021
a50bedc
Create a whole affiliate deployment script
cwsnt Apr 29, 2021
357d08c
Initialize affiliates v2 with mockup locked SOV
cwsnt May 4, 2021
bf8c875
Untied lockedSOV contract from sovryn protocol
cwsnt May 6, 2021
499043d
Add scenario where lockedSOV deposit may failed
cwsnt May 6, 2021
a1a1bf2
Merge with latest development branch after lockedSOV is implemented
cwsnt May 15, 2021
586a3d5
Sync package lock
cwsnt May 17, 2021
73718f7
Merge with latest development branch
cwsnt May 18, 2021
18b7767
Fix deployment script for affiliates v2
cwsnt May 18, 2021
66d9d72
Add new test for coverage
cwsnt May 21, 2021
458511e
refactor code to achive 100% coverage for affiliates modules
cwsnt May 21, 2021
2933553
1/Enchancement based on code review
cwsnt May 21, 2021
975c3bc
Exclude enumerableAddressSet from test coverage
cwsnt May 21, 2021
296cb4d
Merge branch 'development' into affiliates_v2
cwsnt May 21, 2021
56ccc8c
Add integration testing for affiliates in test script
cwsnt May 24, 2021
55e9e75
Change LockedSOVMockup to the real LockedSOV in affiliates test
cwsnt May 25, 2021
603a3f5
Add fee token rewards to affiliates
cwsnt May 28, 2021
2cdf34d
Fix missing return parameters
cwsnt May 31, 2021
20c5bb5
Fix releaseTime issue in escrow test
cwsnt May 31, 2021
5b330ef
Upgrade feeshelper when deploy affiliates
cwsnt Jun 1, 2021
5cd8c36
Include the affiliates setting into 1 deployment script
cwsnt Jun 3, 2021
9d3c1e3
Enable getter for additional state in protocol
cwsnt Jun 5, 2021
1a7b438
Improve test coverage
cwsnt Jun 6, 2021
921ffda
Enchancement based on the pr review
cwsnt Jun 8, 2021
71e7287
Merge and fix conflict with latest development branch
cwsnt Jun 8, 2021
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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ __pycache__
build/
reports/
node_modules/
node_modules
ignore/
.*
!.gitignore
!.gitattributes
!.solhint.json
Expand All @@ -22,7 +24,10 @@ coverage.json
.vscode
yarn.lock
solc-select
artifacts
cache
.idea/
workspace.code-workspace
.env
node_modules
artifacts/
Expand Down
4 changes: 2 additions & 2 deletions .solcover.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module.exports = {
skipFiles: ['mockup', 'testhelpers', 'openzeppelin']
};
skipFiles: ['mockup', 'testhelpers', 'openzeppelin', 'mixins/EnumerableAddressSet.sol']
};
11 changes: 8 additions & 3 deletions .solhint.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
{
"extends": "solhint:default",
"plugins": ["prettier"],
"plugins": [
"prettier"
],
"rules": {
"prettier/prettier": "error",
"max-line-length": ["warn",140]
"max-line-length": [
"warn",
140
]
}
}
}
28 changes: 27 additions & 1 deletion contracts/connectors/loantoken/LoanTokenLogicStandard.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pragma experimental ABIEncoderV2;
import "./LoanTokenSettingsLowerAdmin.sol";
import "./interfaces/ProtocolLike.sol";
import "./interfaces/FeedsLike.sol";
import "../../modules/interfaces/ProtocolAffiliatesInterface.sol";

/**
* @title Loan Token Logic Standard contract.
Expand Down Expand Up @@ -369,6 +370,28 @@ contract LoanTokenLogicStandard is LoanTokenSettingsLowerAdmin {
);
}

function marginTradeAffiliate(
bytes32 loanId, // 0 if new loan
uint256 leverageAmount, // expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5)
uint256 loanTokenSent,
uint256 collateralTokenSent,
address collateralTokenAddress,
address trader,
address affiliateReferrer, // the user was brought by the affiliate (referrer)
bytes calldata loanDataBytes // arbitrary order data
)
external
payable
returns (
uint256,
uint256 // returns new principal and new collateral added to trade
)
{
if (affiliateReferrer != address(0))
ProtocolAffiliatesInterface(sovrynContractAddress).setAffiliatesReferrer(trader, affiliateReferrer);
return marginTrade(loanId, leverageAmount, loanTokenSent, collateralTokenSent, collateralTokenAddress, trader, loanDataBytes);
}

/**
* @notice Transfer tokens wrapper.
* Sets token owner the msg.sender.
Expand Down Expand Up @@ -1027,7 +1050,10 @@ contract LoanTokenLogicStandard is LoanTokenSettingsLowerAdmin {
);
require(sentAmounts[1] != 0, "25");

return (sentAmounts[1], sentAmounts[4]); /// newPrincipal, newCollateral
//REFACTOR: move to a general interface: ProtocolSettingsLike?
ProtocolAffiliatesInterface(sovrynContractAddress).setUserNotFirstTradeFlag(sentAddresses[1]);

return (sentAmounts[1], sentAmounts[4]); // newPrincipal, newCollateral
}

/// sentAddresses[0]: lender
Expand Down
26 changes: 23 additions & 3 deletions contracts/core/State.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
pragma solidity 0.5.17;

import "./Objects.sol";
import "../mixins/EnumerableAddressSet.sol";
tjcloa marked this conversation as resolved.
Show resolved Hide resolved
import "../mixins/EnumerableBytes32Set.sol";
import "../openzeppelin/ReentrancyGuard.sol";
import "../openzeppelin/Ownable.sol";
Expand All @@ -21,7 +22,8 @@ import "../interfaces/IWrbtcERC20.sol";
* */
contract State is Objects, ReentrancyGuard, Ownable {
using SafeMath for uint256;
using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;
using EnumerableAddressSet for EnumerableAddressSet.AddressSet; // enumerable map of addresses
tjcloa marked this conversation as resolved.
Show resolved Hide resolved
using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses

/// Handles asset reference price lookups.
address public priceFeeds;
Expand Down Expand Up @@ -118,8 +120,8 @@ contract State is Objects, ReentrancyGuard, Ownable {
/// Lifetime total payout of protocol token.
uint256 public protocolTokenPaid;

/// 30% fee share /// Fee share for affiliate program.
uint256 public affiliateFeePercent = 30 * 10**18;
/// 5% fee share in form of SOV /// Fee share for affiliate program.
uint256 public affiliateFeePercent = 5 * 10**18;

/// 5% collateral discount /// Discount on collateral for liquidators.
uint256 public liquidationIncentivePercent = 5 * 10**18;
Expand Down Expand Up @@ -160,6 +162,24 @@ contract State is Objects, ReentrancyGuard, Ownable {

address public admin;

address public protocolAddress; // for modules interaction

mapping(address => bool) public userNotFirstTradeFlag; // The flag is set on the user's first trade or borrowing

mapping(address => address) public affiliatesUserReferrer; // User => referrer (affiliate)
mapping(address => EnumerableAddressSet.AddressSet) internal referralsList; // list of referral addresses that owned by the referrer

uint256 public minReferralsToPayout = 3;
mapping(address => uint256) public affiliateRewardsHeld; // Total affiliate SOV rewards that held in the protocol (Because the minimum referrals is less than the rule)
address public sovTokenAddress; // For affiliates SOV Bonus proccess
address public lockedSOVAddress;

/// 20% fee share of trading token fee /// Fee share of trading token fee for affiliate program.
uint256 public affiliateTradingTokenFeePercent = 20 * 10**18;

mapping(address => EnumerableAddressSet.AddressSet) internal affiliatesReferrerTokensList; // addresses of tokens in which commissions were paid to referrers
mapping(address => mapping(address => uint256)) public affiliatesReferrerBalances; // [referrerAddress][tokenAddress] is a referrer's token balance of accrued fees

/**
* @notice Add signature and target to storage.
* */
Expand Down
40 changes: 40 additions & 0 deletions contracts/events/AffiliatesEvents.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.
tjcloa marked this conversation as resolved.
Show resolved Hide resolved
* Licensed under the Apache License, Version 2.0.
*/

pragma solidity 0.5.17;

contract AffiliatesEvents {
event SetAffiliatesReferrer(address indexed user, address indexed referrer);

event SetAffiliatesReferrerFail(address indexed user, address indexed referrer, bool alreadySet, bool userNotFirstTrade);

event SetUserNotFirstTradeFlag(address indexed user);

event PayTradingFeeToAffiliate(
address indexed referrer,
address indexed token,
bool indexed isHeld,
uint256 tradingFeeTokenAmount,
uint256 tokenBonusAmount,
uint256 sovBonusAmount,
uint256 sovBonusAmountPaid
);

event PayTradingFeeToAffiliateFail(
address indexed referrer,
address indexed token,
uint256 tradingFeeTokenAmount,
uint256 tokenBonusAmount,
uint256 sovBonusAmount,
uint256 sovBonusAmountTryingToPaid
);

event WithdrawAffiliatesReferrerTokenFees(
address indexed referrer,
address indexed receiver,
address indexed tokenAddress,
uint256 amount
);
}
10 changes: 10 additions & 0 deletions contracts/events/ProtocolSettingsEvents.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ contract ProtocolSettingsEvents {

event SetAffiliateFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);

event SetAffiliateTradingTokenFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);

event SetLiquidationIncentivePercent(address indexed sender, uint256 oldValue, uint256 newValue);

event SetMaxSwapSize(address indexed sender, uint256 oldValue, uint256 newValue);
Expand Down Expand Up @@ -63,4 +65,12 @@ contract ProtocolSettingsEvents {
event SetRolloverBaseReward(address indexed sender, uint256 oldValue, uint256 newValue);

event SetRebatePercent(address indexed sender, uint256 oldRebatePercent, uint256 newRebatePercent);

event SetProtocolAddress(address indexed sender, address indexed oldProtocol, address indexed newProtocol);

event SetMinReferralsToPayoutAffiliates(address indexed sender, uint256 oldMinReferrals, uint256 newMinReferrals);

event SetSOVTokenAddress(address indexed sender, address indexed oldTokenAddress, address indexed newTokenAddress);

event SetLockedSOVAddress(address indexed sender, address indexed oldAddress, address indexed newAddress);
}
67 changes: 64 additions & 3 deletions contracts/interfaces/ISovryn.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

pragma solidity >=0.5.0 <0.6.0;
pragma experimental ABIEncoderV2;
//TODO: stored in ./interfaces only while brownie isn't removed
//TODO: move to contracts/interfaces after with brownie is removed

import "../core/State.sol";
import "../events/ProtocolSettingsEvents.sol";
Expand All @@ -14,6 +16,8 @@ import "../events/LoanMaintenanceEvents.sol";
import "../events/LoanClosingsEvents.sol";
import "../events/FeesEvents.sol";
import "../events/SwapsEvents.sol";
import "../events/AffiliatesEvents.sol";
import "../events/FeesEvents.sol";

contract ISovryn is
State,
Expand All @@ -22,7 +26,9 @@ contract ISovryn is
LoanOpeningsEvents,
LoanMaintenanceEvents,
LoanClosingsEvents,
SwapsEvents
SwapsEvents,
AffiliatesEvents,
FeesEvents
{
////// Protocol //////

Expand All @@ -34,6 +40,14 @@ contract ISovryn is

////// Protocol Settings //////

function setSovrynProtocolAddress(address newProtocolAddress) external;

function setSOVTokenAddress(address newSovTokenAddress) external;

function setLockedSOVAddress(address newSOVLockedAddress) external;

function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals) external;

function setPriceFeedContract(address newContract) external;

function setSwapsImplContract(address newContract) external;
Expand All @@ -50,6 +64,8 @@ contract ISovryn is

function setAffiliateFeePercent(uint256 newValue) external;

function setAffiliateTradingTokenFeePercent(uint256 newValue) external;

function setLiquidationIncentivePercent(uint256 newAmount) external;

function setMaxDisagreement(uint256 newAmount) external;
Expand All @@ -60,8 +76,6 @@ contract ISovryn is

function setFeesController(address newController) external;

function withdrawFees(address token, address receiver) external returns (uint256);

function withdrawLendingFees(
address token,
address receiver,
Expand Down Expand Up @@ -302,4 +316,51 @@ contract ISovryn is
function setLegacyOracles(address[] calldata refs, address[] calldata oracles) external;

function getLegacyOracle(address ref) external view returns (address);

////// Affiliates Module //////

function getUserNotFirstTradeFlag(address user) external view returns (bool);

function setUserNotFirstTradeFlag(address user) external view returns (bool);

function payTradingFeeToAffiliatesReferrer(
address referrer,
address token,
uint256 tradingFeeTokenBaseAmount
) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);

function setAffiliatesReferrer(address user, address referrer) external; //onlyCallableByLoanPools

function getReferralsList(address referrer) external view returns (address[] memory refList);

function getAffiliatesReferrerBalances(address referrer)
external
view
returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances);

function getAffiliatesReferrerTokensList(address referrer) external view returns (address[] memory tokensList);

function getAffiliatesReferrerTokenBalance(address referrer, address token) external view returns (uint256);

function withdrawAffiliatesReferrerTokenFees(
address token,
address receiver,
uint256 amount
) external returns (uint256 withdrawAmount);

function withdrawAllAffiliatesReferrerTokenFees(address receiver) external;

function getProtocolAddress() external view returns (address);

function getSovTokenAddress() external view returns (address);

function getLockedSOVAddress() external view returns (address);

function getMinReferralsToPayout() external view returns (uint256);

function getAffiliatesUserReferrer(address user) external view returns (address referrer);

function getAffiliateRewardsHeld(address referrer) external view returns (uint256);

function getAffiliateTradingTokenFeePercent() external view returns (uint256 affiliateTradingTokenFeePercent);
}
Loading