View Source: contracts/modules/Affiliates.sol
↗ Extends: State, AffiliatesEvents, ModuleCommonFunctionalities
Track referrals and reward referrers (affiliates) with tokens. In-detail specifications are found at https://wiki.sovryn.app/en/community/Affiliates
struct SetAffiliatesReferrerResult {
bool success,
bool alreadySet,
bool userNotFirstTradeFlag
}
Function modifier to avoid any other calls not coming from loan pools.
modifier onlyCallableByLoanPools() internal
Function modifier to avoid any other calls not coming from within protocol functions.
modifier onlyCallableInternal() internal
- constructor()
- constructor()
- initialize(address target)
- setAffiliatesReferrer(address user, address referrer)
- getReferralsList(address referrer)
- getUserNotFirstTradeFlag(address user)
- setUserNotFirstTradeFlag(address user)
- _getAffiliatesTradingFeePercentForSOV()
- _getReferrerTradingFeeForToken(uint256 feeTokenAmount)
- getAffiliateTradingTokenFeePercent()
- getMinReferralsToPayout()
- _getSovBonusAmount(address feeToken, uint256 feeAmount)
- payTradingFeeToAffiliatesReferrer(address referrer, address trader, address token, uint256 tradingFeeTokenBaseAmount)
- withdrawAffiliatesReferrerTokenFees(address token, address receiver, uint256 amount)
- withdrawAllAffiliatesReferrerTokenFees(address receiver)
- _removeAffiliatesReferrerToken(address referrer, address token)
- getAffiliatesReferrerBalances(address referrer)
- getAffiliatesTokenRewardsValueInRbtc(address referrer)
- getAffiliatesReferrerTokensList(address referrer)
- getAffiliatesReferrerTokenBalance(address referrer, address token)
- getAffiliatesUserReferrer(address user)
- getAffiliateRewardsHeld(address referrer)
Void constructor.
function () public nonpayable
Source Code
constructor() public {}
Avoid calls to this contract except for those explicitly declared.
function () external nonpayable
Source Code
function() external {
revert("Affiliates - fallback not allowed");
}
Set delegate callable functions by proxy contract.
function initialize(address target) external nonpayable onlyOwner
Arguments
Name | Type | Description |
---|---|---|
target | address | The address of a new logic implementation. |
Source Code
function initialize(address target) external onlyOwner {
address prevModuleContractAddress = logicTargets[this.setAffiliatesReferrer.selector];
_setTarget(this.setAffiliatesReferrer.selector, target);
_setTarget(this.getUserNotFirstTradeFlag.selector, target);
_setTarget(this.getReferralsList.selector, target);
_setTarget(this.setUserNotFirstTradeFlag.selector, target);
_setTarget(this.payTradingFeeToAffiliatesReferrer.selector, target);
_setTarget(this.getAffiliatesReferrerBalances.selector, target);
_setTarget(this.getAffiliatesReferrerTokenBalance.selector, target);
_setTarget(this.getAffiliatesReferrerTokensList.selector, target);
_setTarget(this.withdrawAffiliatesReferrerTokenFees.selector, target);
_setTarget(this.withdrawAllAffiliatesReferrerTokenFees.selector, target);
_setTarget(this.getMinReferralsToPayout.selector, target);
_setTarget(this.getAffiliatesUserReferrer.selector, target);
_setTarget(this.getAffiliateRewardsHeld.selector, target);
_setTarget(this.getAffiliateTradingTokenFeePercent.selector, target);
_setTarget(this.getAffiliatesTokenRewardsValueInRbtc.selector, target);
emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, "Affiliates");
}
Loan pool calls this function to tell affiliates a user coming from a referrer is trading and should be registered if not yet. Taking into account some user status flags may lead to the user and referrer become added or not to the affiliates record. *
function setAffiliatesReferrer(address user, address referrer) external nonpayable onlyCallableByLoanPools whenNotPaused
Arguments
Name | Type | Description |
---|---|---|
user | address | The address of the user that is trading on loan pools. |
referrer | address | The address of the referrer the user is coming from. |
Source Code
function setAffiliatesReferrer(address user, address referrer)
external
onlyCallableByLoanPools
whenNotPaused
{
SetAffiliatesReferrerResult memory result;
result.userNotFirstTradeFlag = getUserNotFirstTradeFlag(user);
result.alreadySet = affiliatesUserReferrer[user] != address(0);
result.success = !(result.userNotFirstTradeFlag || result.alreadySet || user == referrer);
if (result.success) {
affiliatesUserReferrer[user] = referrer;
referralsList[referrer].add(user);
emit SetAffiliatesReferrer(user, referrer);
} else {
emit SetAffiliatesReferrerFail(
user,
referrer,
result.alreadySet,
result.userNotFirstTradeFlag
);
}
}
Getter to query the referrals coming from a referrer.
function getReferralsList(address referrer) external view
returns(refList address[])
Arguments
Name | Type | Description |
---|---|---|
referrer | address | The address of a given referrer. |
Returns
The referralsList mapping value by referrer.
Source Code
function getReferralsList(address referrer) external view returns (address[] memory refList) {
refList = referralsList[referrer].enumerate();
return refList;
}
Getter to query the not-first-trade flag of a user.
function getUserNotFirstTradeFlag(address user) public view
returns(bool)
Arguments
Name | Type | Description |
---|---|---|
user | address | The address of a given user. |
Returns
The userNotFirstTradeFlag mapping value by user.
Source Code
function getUserNotFirstTradeFlag(address user) public view returns (bool) {
return userNotFirstTradeFlag[user];
}
Setter to toggle on the not-first-trade flag of a user.
function setUserNotFirstTradeFlag(address user) external nonpayable onlyCallableByLoanPools whenNotPaused
Arguments
Name | Type | Description |
---|---|---|
user | address | The address of a given user. |
Source Code
function setUserNotFirstTradeFlag(address user)
external
onlyCallableByLoanPools
whenNotPaused
{
if (!userNotFirstTradeFlag[user]) {
userNotFirstTradeFlag[user] = true;
emit SetUserNotFirstTradeFlag(user);
}
}
Internal getter to query the fee share for affiliate program.
function _getAffiliatesTradingFeePercentForSOV() internal view
returns(uint256)
Source Code
function _getAffiliatesTradingFeePercentForSOV() internal view returns (uint256) {
return affiliateFeePercent;
}
Internal to calculate the affiliates trading token fee amount. Affiliates program has 2 kind of rewards: 1. x% based on the fee of the token that is traded (in form of the token itself). 2. x% based on the fee of the token that is traded (in form of SOV). This _getReferrerTradingFeeForToken calculates the first one by applying a custom percentage multiplier.
function _getReferrerTradingFeeForToken(uint256 feeTokenAmount) internal view
returns(uint256)
Arguments
Name | Type | Description |
---|---|---|
feeTokenAmount | uint256 | The trading token fee amount. |
Returns
The affiliates share of the trading token fee amount.
Source Code
function _getReferrerTradingFeeForToken(uint256 feeTokenAmount)
internal
view
returns (uint256)
{
return feeTokenAmount.mul(getAffiliateTradingTokenFeePercent()).div(10**20);
}
Getter to query the fee share of trading token fee for affiliate program.
function getAffiliateTradingTokenFeePercent() public view
returns(uint256)
Source Code
function getAffiliateTradingTokenFeePercent() public view returns (uint256) {
return affiliateTradingTokenFeePercent;
}
Getter to query referral threshold for paying out to the referrer.
function getMinReferralsToPayout() public view
returns(uint256)
Source Code
function getMinReferralsToPayout() public view returns (uint256) {
return minReferralsToPayout;
}
Get the sovToken reward of a trade.
function _getSovBonusAmount(address feeToken, uint256 feeAmount) internal view
returns(uint256)
Arguments
Name | Type | Description |
---|---|---|
feeToken | address | The address of the token in which the trading/borrowing fee was paid. |
feeAmount | uint256 | The height of the fee. |
Returns
The reward amount.
Source Code
function _getSovBonusAmount(address feeToken, uint256 feeAmount)
internal
view
returns (uint256)
{
uint256 rewardAmount;
address _priceFeeds = priceFeeds;
/// @dev Calculate the reward amount, querying the price feed.
(bool success, bytes memory data) =
_priceFeeds.staticcall(
abi.encodeWithSelector(
IPriceFeeds(_priceFeeds).queryReturn.selector,
feeToken,
sovTokenAddress, /// dest token = SOV
feeAmount.mul(_getAffiliatesTradingFeePercentForSOV()).div(1e20)
)
);
// solhint-disable-next-line no-inline-assembly
assembly {
if eq(success, 1) {
rewardAmount := mload(add(data, 32))
}
}
return rewardAmount;
}
Protocol calls this function to pay the affiliates rewards to a user (referrer). *
function payTradingFeeToAffiliatesReferrer(address referrer, address trader, address token, uint256 tradingFeeTokenBaseAmount) external nonpayable onlyCallableInternal whenNotPaused
returns(referrerBonusSovAmount uint256, referrerBonusTokenAmount uint256)
Arguments
Name | Type | Description |
---|---|---|
referrer | address | The address of the referrer. |
trader | address | The address of the trader. |
token | address | The address of the token in which the trading/borrowing fee was paid. |
tradingFeeTokenBaseAmount | uint256 | Total trading fee amount, the base for calculating referrer's fees. * |
Returns
referrerBonusSovAmount The amount of SOV tokens paid to the referrer (through a vesting contract, lockedSOV).
Source Code
function payTradingFeeToAffiliatesReferrer(
address referrer,
address trader,
address token,
uint256 tradingFeeTokenBaseAmount
)
external
onlyCallableInternal
whenNotPaused
returns (uint256 referrerBonusSovAmount, uint256 referrerBonusTokenAmount)
{
bool isHeld = referralsList[referrer].length() < getMinReferralsToPayout();
bool bonusPaymentIsSuccess = true;
uint256 paidReferrerBonusSovAmount;
/// Process token fee rewards first.
referrerBonusTokenAmount = _getReferrerTradingFeeForToken(tradingFeeTokenBaseAmount);
if (!affiliatesReferrerTokensList[referrer].contains(token))
affiliatesReferrerTokensList[referrer].add(token);
affiliatesReferrerBalances[referrer][token] = affiliatesReferrerBalances[referrer][token]
.add(referrerBonusTokenAmount);
/// Then process SOV rewards.
referrerBonusSovAmount = _getSovBonusAmount(token, tradingFeeTokenBaseAmount);
uint256 rewardsHeldByProtocol = affiliateRewardsHeld[referrer];
if (isHeld) {
/// If referrals less than minimum, temp the rewards SOV to the storage
affiliateRewardsHeld[referrer] = rewardsHeldByProtocol.add(referrerBonusSovAmount);
} else {
/// If referrals >= minimum, directly send all of the remain rewards to locked sov
/// Call depositSOV() in LockedSov contract
/// Set the affiliaterewardsheld = 0
if (affiliateRewardsHeld[referrer] > 0) {
affiliateRewardsHeld[referrer] = 0;
}
paidReferrerBonusSovAmount = referrerBonusSovAmount.add(rewardsHeldByProtocol);
IERC20(sovTokenAddress).approve(lockedSOVAddress, paidReferrerBonusSovAmount);
(bool success, ) =
lockedSOVAddress.call(
abi.encodeWithSignature(
"depositSOV(address,uint256)",
referrer,
paidReferrerBonusSovAmount
)
);
if (!success) {
bonusPaymentIsSuccess = false;
}
}
if (bonusPaymentIsSuccess) {
emit PayTradingFeeToAffiliate(
referrer,
trader, // trader
token,
isHeld,
tradingFeeTokenBaseAmount,
referrerBonusTokenAmount,
referrerBonusSovAmount,
paidReferrerBonusSovAmount
);
} else {
emit PayTradingFeeToAffiliateFail(
referrer,
trader, // trader
token,
tradingFeeTokenBaseAmount,
referrerBonusTokenAmount,
referrerBonusSovAmount,
paidReferrerBonusSovAmount
);
}
return (referrerBonusSovAmount, referrerBonusTokenAmount);
}
Referrer calls this function to receive its reward in a given token. It will send the other (non-SOV) reward tokens from trading protocol fees, to the referrer’s wallet.
function withdrawAffiliatesReferrerTokenFees(address token, address receiver, uint256 amount) public nonpayable whenNotPaused
Arguments
Name | Type | Description |
---|---|---|
token | address | The address of the token to withdraw. |
receiver | address | The address of the withdrawal beneficiary. |
amount | uint256 | The amount of tokens to claim. If greater than balance, just sends balance. |
Source Code
nction withdrawAffiliatesReferrerTokenFees(
address token,
address receiver,
uint256 amount
) public whenNotPaused {
require(receiver != address(0), "Affiliates: cannot withdraw to zero address");
address referrer = msg.sender;
uint256 referrerTokenBalance = affiliatesReferrerBalances[referrer][token];
uint256 withdrawAmount = referrerTokenBalance > amount ? amount : referrerTokenBalance;
require(withdrawAmount > 0, "Affiliates: cannot withdraw zero amount");
require(
referralsList[referrer].length() >= getMinReferralsToPayout(),
"Your referrals has not reached the minimum request"
);
uint256 newReferrerTokenBalance = referrerTokenBalance.sub(withdrawAmount);
if (newReferrerTokenBalance == 0) {
_removeAffiliatesReferrerToken(referrer, token);
} else {
affiliatesReferrerBalances[referrer][token] = newReferrerTokenBalance;
}
IERC20(token).safeTransfer(receiver, withdrawAmount);
emit WithdrawAffiliatesReferrerTokenFees(referrer, receiver, token, withdrawAmount);
}
Withdraw to msg.sender all token fees for a referrer.
function withdrawAllAffiliatesReferrerTokenFees(address receiver) external nonpayable whenNotPaused
Arguments
Name | Type | Description |
---|---|---|
receiver | address | The address of the withdrawal beneficiary. |
Source Code
nction withdrawAllAffiliatesReferrerTokenFees(address receiver) external whenNotPaused {
require(receiver != address(0), "Affiliates: cannot withdraw to zero address");
address referrer = msg.sender;
require(
referralsList[referrer].length() >= getMinReferralsToPayout(),
"Your referrals has not reached the minimum request"
);
(address[] memory tokenAddresses, uint256[] memory tokenBalances) =
getAffiliatesReferrerBalances(referrer);
for (uint256 i; i < tokenAddresses.length; i++) {
withdrawAffiliatesReferrerTokenFees(tokenAddresses[i], receiver, tokenBalances[i]);
}
}
Internal function to delete a referrer's token balance.
function _removeAffiliatesReferrerToken(address referrer, address token) internal nonpayable
Arguments
Name | Type | Description |
---|---|---|
referrer | address | The address of the referrer. |
token | address | The address of the token specifying the balance to remove. |
Source Code
nction _removeAffiliatesReferrerToken(address referrer, address token) internal {
delete affiliatesReferrerBalances[referrer][token];
affiliatesReferrerTokensList[referrer].remove(token);
}
Get all token balances of a referrer.
function getAffiliatesReferrerBalances(address referrer) public view
returns(referrerTokensList address[], referrerTokensBalances uint256[])
Arguments
Name | Type | Description |
---|---|---|
referrer | address | The address of the referrer. |
Returns
referrerTokensList The array of available tokens (keys).
Source Code
nction getAffiliatesReferrerBalances(address referrer)
public
view
returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances)
{
referrerTokensList = getAffiliatesReferrerTokensList(referrer);
referrerTokensBalances = new uint256[](referrerTokensList.length);
for (uint256 i; i < referrerTokensList.length; i++) {
referrerTokensBalances[i] = getAffiliatesReferrerTokenBalance(
referrer,
referrerTokensList[i]
);
}
return (referrerTokensList, referrerTokensBalances);
}
Get all token rewards estimation value in rbtc. *
function getAffiliatesTokenRewardsValueInRbtc(address referrer) external view
returns(rbtcTotalAmount uint256)
Arguments
Name | Type | Description |
---|---|---|
referrer | address | Address of referrer. * |
Returns
The value estimation in rbtc.
Source Code
nction getAffiliatesTokenRewardsValueInRbtc(address referrer)
external
view
returns (uint256 rbtcTotalAmount)
{
address[] memory tokensList = getAffiliatesReferrerTokensList(referrer);
address _priceFeeds = priceFeeds;
for (uint256 i; i < tokensList.length; i++) {
// Get the value of each token in rbtc
(bool success, bytes memory data) =
_priceFeeds.staticcall(
abi.encodeWithSelector(
IPriceFeeds(_priceFeeds).queryReturn.selector,
tokensList[i], // source token
address(wrbtcToken), // dest token = SOV
affiliatesReferrerBalances[referrer][tokensList[i]] // total token rewards
)
);
assembly {
if eq(success, 1) {
rbtcTotalAmount := add(rbtcTotalAmount, mload(add(data, 32)))
}
}
}
}
Get all available tokens at the affiliates program for a given referrer.
function getAffiliatesReferrerTokensList(address referrer) public view
returns(tokensList address[])
Arguments
Name | Type | Description |
---|---|---|
referrer | address | The address of a given referrer. |
Returns
tokensList The list of available tokens.
Source Code
nction getAffiliatesReferrerTokensList(address referrer)
public
view
returns (address[] memory tokensList)
{
tokensList = affiliatesReferrerTokensList[referrer].enumerate();
return tokensList;
}
Getter to query the affiliate balance for a given referrer and token.
function getAffiliatesReferrerTokenBalance(address referrer, address token) public view
returns(uint256)
Arguments
Name | Type | Description |
---|---|---|
referrer | address | The address of the referrer. |
token | address | The address of the token to get balance for. |
Returns
The affiliatesReferrerBalances mapping value by referrer and token keys.
Source Code
nction getAffiliatesReferrerTokenBalance(address referrer, address token)
public
view
returns (uint256)
{
return affiliatesReferrerBalances[referrer][token];
}
Getter to query the address of referrer for a given user.
function getAffiliatesUserReferrer(address user) public view
returns(address)
Arguments
Name | Type | Description |
---|---|---|
user | address | The address of the user. |
Returns
The address on affiliatesUserReferrer mapping value by user key.
Source Code
nction getAffiliatesUserReferrer(address user) public view returns (address) {
return affiliatesUserReferrer[user];
}
Getter to query the reward amount held for a given referrer.
function getAffiliateRewardsHeld(address referrer) public view
returns(uint256)
Arguments
Name | Type | Description |
---|---|---|
referrer | address | The address of the referrer. |
Returns
The affiliateRewardsHeld mapping value by referrer key.
Source Code
nction getAffiliateRewardsHeld(address referrer) public view returns (uint256) {
return affiliateRewardsHeld[referrer];
}
}
- Address
- Administered
- AdminRole
- AdvancedToken
- AdvancedTokenStorage
- Affiliates
- AffiliatesEvents
- ApprovalReceiver
- BProPriceFeed
- CheckpointsShared
- Constants
- Context
- DevelopmentFund
- DummyContract
- EnumerableAddressSet
- EnumerableBytes32Set
- EnumerableBytes4Set
- ERC20
- ERC20Detailed
- ErrorDecoder
- Escrow
- EscrowReward
- FeedsLike
- FeesEvents
- FeeSharingCollector
- FeeSharingCollectorProxy
- FeeSharingCollectorStorage
- FeesHelper
- FourYearVesting
- FourYearVestingFactory
- FourYearVestingLogic
- FourYearVestingStorage
- GenericTokenSender
- GovernorAlpha
- GovernorVault
- IApproveAndCall
- IChai
- IContractRegistry
- IConverterAMM
- IERC1820Registry
- IERC20_
- IERC20
- IERC777
- IERC777Recipient
- IERC777Sender
- IFeeSharingCollector
- IFourYearVesting
- IFourYearVestingFactory
- IFunctionsList
- ILiquidityMining
- ILiquidityPoolV1Converter
- ILoanPool
- ILoanToken
- ILoanTokenLogicBeacon
- ILoanTokenLogicModules
- ILoanTokenLogicProxy
- ILoanTokenModules
- ILoanTokenWRBTC
- ILockedSOV
- IMoCState
- IModulesProxyRegistry
- Initializable
- InterestUser
- IPot
- IPriceFeeds
- IPriceFeedsExt
- IProtocol
- IRSKOracle
- ISovryn
- ISovrynSwapNetwork
- IStaking
- ISwapsImpl
- ITeamVesting
- ITimelock
- IV1PoolOracle
- IVesting
- IVestingFactory
- IVestingRegistry
- IWrbtc
- IWrbtcERC20
- LenderInterestStruct
- LiquidationHelper
- LiquidityMining
- LiquidityMiningConfigToken
- LiquidityMiningProxy
- LiquidityMiningStorage
- LoanClosingsEvents
- LoanClosingsLiquidation
- LoanClosingsRollover
- LoanClosingsShared
- LoanClosingsWith
- LoanClosingsWithoutInvariantCheck
- LoanInterestStruct
- LoanMaintenance
- LoanMaintenanceEvents
- LoanOpenings
- LoanOpeningsEvents
- LoanParamsStruct
- LoanSettings
- LoanSettingsEvents
- LoanStruct
- LoanToken
- LoanTokenBase
- LoanTokenLogicBeacon
- LoanTokenLogicLM
- LoanTokenLogicProxy
- LoanTokenLogicStandard
- LoanTokenLogicStorage
- LoanTokenLogicWrbtc
- LoanTokenSettingsLowerAdmin
- LockedSOV
- MarginTradeStructHelpers
- Medianizer
- ModuleCommonFunctionalities
- ModulesCommonEvents
- ModulesProxy
- ModulesProxyRegistry
- MultiSigKeyHolders
- MultiSigWallet
- Mutex
- Objects
- OrderStruct
- OrigingVestingCreator
- OriginInvestorsClaim
- Ownable
- Pausable
- PausableOz
- PreviousLoanToken
- PreviousLoanTokenSettingsLowerAdmin
- PriceFeedRSKOracle
- PriceFeeds
- PriceFeedsLocal
- PriceFeedsMoC
- PriceFeedV1PoolOracle
- ProtocolAffiliatesInterface
- ProtocolLike
- ProtocolSettings
- ProtocolSettingsEvents
- ProtocolSettingsLike
- ProtocolSwapExternalInterface
- ProtocolTokenUser
- Proxy
- ProxyOwnable
- ReentrancyGuard
- RewardHelper
- RSKAddrValidator
- SafeERC20
- SafeMath
- SafeMath96
- setGet
- SharedReentrancyGuard
- SignedSafeMath
- SOV
- sovrynProtocol
- StakingAdminModule
- StakingGovernanceModule
- StakingInterface
- StakingProxy
- StakingRewards
- StakingRewardsProxy
- StakingRewardsStorage
- StakingShared
- StakingStakeModule
- StakingStorageModule
- StakingStorageShared
- StakingVestingModule
- StakingWithdrawModule
- State
- SwapsEvents
- SwapsExternal
- SwapsImplLocal
- SwapsImplSovrynSwap
- SwapsUser
- TeamVesting
- Timelock
- TimelockHarness
- TimelockInterface
- TokenSender
- UpgradableProxy
- USDTPriceFeed
- Utils
- VaultController
- Vesting
- VestingCreator
- VestingFactory
- VestingLogic
- VestingRegistry
- VestingRegistry2
- VestingRegistry3
- VestingRegistryLogic
- VestingRegistryProxy
- VestingRegistryStorage
- VestingStorage
- WeightedStakingModule
- WRBTC