Skip to content

Latest commit

 

History

History
1127 lines (891 loc) · 33.2 KB

Affiliates.md

File metadata and controls

1127 lines (891 loc) · 33.2 KB

Affiliates contract. (Affiliates.sol)

View Source: contracts/modules/Affiliates.sol

↗ Extends: State, AffiliatesEvents, ModuleCommonFunctionalities

Affiliates contract

Track referrals and reward referrers (affiliates) with tokens. In-detail specifications are found at https://wiki.sovryn.app/en/community/Affiliates

Structs

SetAffiliatesReferrerResult

struct SetAffiliatesReferrerResult {
 bool success,
 bool alreadySet,
 bool userNotFirstTradeFlag
}

Modifiers

onlyCallableByLoanPools

Function modifier to avoid any other calls not coming from loan pools.

modifier onlyCallableByLoanPools() internal

onlyCallableInternal

Function modifier to avoid any other calls not coming from within protocol functions.

modifier onlyCallableInternal() internal

Functions


constructor

Void constructor.

function () public nonpayable
Source Code
constructor() public {}

constructor

Avoid calls to this contract except for those explicitly declared.

function () external nonpayable
Source Code
function() external {
        revert("Affiliates - fallback not allowed");
    }

initialize

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");
    }

setAffiliatesReferrer

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
            );
        }
    }

getReferralsList

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;
    }

getUserNotFirstTradeFlag

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];
    }

setUserNotFirstTradeFlag

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);
        }
    }

_getAffiliatesTradingFeePercentForSOV

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;
    }

_getReferrerTradingFeeForToken

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);
    }

getAffiliateTradingTokenFeePercent

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;
    }

getMinReferralsToPayout

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;
    }

_getSovBonusAmount

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;
    }

payTradingFeeToAffiliatesReferrer

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);
    }

withdrawAffiliatesReferrerTokenFees

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);
    }

withdrawAllAffiliatesReferrerTokenFees

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]);
        }
    }

_removeAffiliatesReferrerToken

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);
    }

getAffiliatesReferrerBalances

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);
    }

getAffiliatesTokenRewardsValueInRbtc

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)))
                }
            }
        }
    }

getAffiliatesReferrerTokensList

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;
    }

getAffiliatesReferrerTokenBalance

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];
    }

getAffiliatesUserReferrer

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];
    }

getAffiliateRewardsHeld

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];
    }
}

Contracts