Global Referral & Affiliate System for Rujira apps
Goal
Implement a global system that can handle both Referral & Affiliate fees across Rujira apps, helping us drive growth from integrators, KOLs and anyone willing to join our decentralized salesforce.
Specs
Exact implementation TBD based on technical constraints - desired design summarized below.
The system should support two types of fees:
- Referral Fee = fee taken from the protocol revenue (allowing partners to drive volume at no extra cost for the end user, similar to what CEXs do for KOLs; also key for integrators).
- Affiliate Fee = charged on top of the protocol fee (same model as THORChain, good for integrators that have a captive user base that is not price sensitive, e.g. Ledger Live, TrustWallet, etc.).
We should have an on-chain Partners Registry with the following entries for each partner:
- Partner code (e.g. "AB123"): Optional parameter than can either be passed with each transaction (e.g. for integrators/alternative frontends), or can be linked once to a specific address (so KOLs can have a referral link --> user visit the page and sign once a tx to link the partner code to his address and the code persist till it is replaced by another one or removed by the user. If a code is registered with an address, but an alternative code is used when submitting the tx, then the alternative code prevails for that specific tx).
- Partner payment address: The address where the Referral Fee and Affiliate Fee will be paid (one is enough, if a partner wants to split between two addresses or more, we can setup an intermediate revenue converter contract with N target addresses and custom weights).
- Referral Fee (e.g. 5%): The percentage of the protocol fee that will be redirected to the partner. The default referral_fee is a global parameter set by the admin of the registry, and it can be overwritten partner by partner if need be.
-
Referral Multiplier (e.g. 1.5x): This is a multiplier applied to the Referral Fee every time some revenue is generated by a referred user. The Referral Multiplier is calculated based on the 30-day trailing revenue generated by all the referred users associated with a given Partner code. Illustrative value:
- If trailing_revenue > 0, multiplier = 1.00x
- If trailing_revenue > 100, multiplier = 1.25x
- If trailing_revenue > 500, multiplier = 1.50x
- If trailing_revenue > 2,500, multiplier = 1.75x
- If trailing_revenue > 12,500, multiplier = 2.00x
- Trailing revenue (e.g. $1000): The total revenue (before any split) generated by the users associated with the Partner code in the last 30 days.
- Kickback (e.g. 20%): TBD if doable - The percentage of the Referral Fee that is sent back to the users. This is to allow KOLs to offer an extra incentive for users to join the platform using their code "join with code XYZ and get 2% discount on fees on all your trades". This value can be updated within a certain range (e.g. 0-50%) by the partner directly.
- Affiliate Fee (e.g. 0.5%): The percentage of the transaction value that will be charged in addition to standard protocol fee and sent to the partner. This value can be updated within a certain range (e.g. 0-3%) by the partner directly.
There should be a page in the UI allowing anyone to create partner codes. One address can have several partner codes, e.g. for KOLs to track performance across multiple channels (Youtube, X, TikTok). The code, payment_address, kickback and affiliate_fee can be updated by the partner directly. The referral_fee, multiplier and related parameters are controlled by the admin of the registry contract.
The UI should allow to create referral link which prompt the user to connect his wallet and sign a transaction to activate the referral code and benefit from the kickback.
The UI will also include a leaderboard for both Affiliates and Referrals.
The min-max valid range for kickback and affiliate_fee are global variables controlled by the admin of the registry.
We need to be able to have different registry contracts for different teams (e.g. so the Rujira team can control the parameters specific to their apps, Nami to theirs, Liquidy, Auto, etc.), if they wish reuse the same referral + affiliate model as Rujira core apps.
Potential (likely) abuse: Given partner code creation is permissionless, the likely scenario is that everyone ends up creating a partner code with and using it for themselves, effectively getting a [10%] discount on fees at perpetuity. We could try to police that, or make the code creation process permissioned, but it would add to overhead and introduce subjectivity so probably not the way to go. Instead, we can simply calibrate our fees to take that into account if we notice it's being abused. It can also have a psychological benefit for users to see a share of their own fees going back to their wallet.
Different type of fees for different type of apps - Illustration by type of fees:
Transaction-based fees (e.g. a trade on RUJI Trade or RUJI Perps, a successful bid on RUJI Liquidations, RUJI Launchpad or RUJI Collections):
-
Referral Fee: At the moment the fee is collected, check if there is a valid referral code,
- If no valid code, send 100% of the fees to the regular protocol fee address;
- If a valid code with referral_fee = 5%, multiplier = 1.5x and kickback = 20%, then
- Protocol will get gross_protocol_fee * (1 - 5% * 1.5);
- Partner will be allocated (1 - 20%) * 5% * 1.5 * gross_protocol_fee;
- User will get back 20% * 5% * 1.5 * gross_protocol_fee;
-
Affiliate Fee:
- For market orders and any one-step tx, collect the affiliate fee as a percentage of the output token at the time of the transaction.
- For limit orders or any other multi-step tx, collect the affiliate fee as a percentage of the output token at the time the order is claimed.
Continuous fees (e.g. interest paid on RUJI Lending, Management Fee and Performance fee on 3rd party RUJI Pools Vault, Nami Savers, Nami Index):
-
Referral Fee:
- Every time there is a deposit with a valid partner code, link the address that made a deposit with that code in that particular vault. The code stay linked to this address and this vault until a new deposit is made with a valid code.
- Every time a fees is collected (e.g. when the user do another deposit or a withdrawal, or when the vault is cranked to collect the fee), check if the code is still valid:
- If no valid code, send 100% of the fees to the regular protocol fee address;
- If a valid code with referral_fee = 5%, multiplier = 1.5x and kickback = 20%, then
- Protocol will get gross_protocol_fee * (1 - 5% * 1.5);
- Partner's share of the referral pool will be incremented by $ value of (1 - 20%) * 5% * 1.5 * gross_protocol_fee compared to the total $ value in the pool including the new fee;
- TBD: Can we use the $ value? Trying to avoid having a different pool for each possible fee denom.
- TBD: Can we make that the pool is also a revenu convertor swapping everything for a target denom over time? Would be super messy to distribute in multiple denoms.
- User will get back 20% * 5% * 1.5 * gross_protocol_fee in kickback (we could probably ignore the kickback entirely for this type of fees to keep things a bit simpler);
- Would be good to have a way to crank the fee distribution to avoid situations where there is a large deposit that accrues a lot of fees, but stay there for years without any fees being distributed.
- Affiliate Fee: For this type of vault products, the optional affiliate fee should be taken at the time of deposit as a percentage of the deposited balance (we could do a withdrawal fee instead, but that would delay cashflows, some people might stay deposited for years so seems suboptimal for integrators).