Fee splitting between relayers ; Affiliate program #12
The 0x protocol could allow relayers to split the fees with their affiliates if another agent help in the filling of one of their orders.
Currently, if an order from relayer Alice is filled by a user from relayer Bob, Alice will receive 100% of the fees. Bob benefits from this since it increases his liquidity, but the incentive is somewhat weak. In addition, there is no incentive for third parties to simply act as order aggregators, since they would never receive fees. Allowing relayers to give part of the fees to their affiliates would create a stronger incentive for relayers to share their liquidity and to borrow orders from others.
In addition of creating stronger collaboration among the 0x network, it can also allow for new, interesting strategies and profitable infrastructure. For instance, some agents could simply aggregate order from all the relayers and offer the best orders available, both price wise and fee wise, to dApps. Such a service would allow dApps to listen to communicate with a much smaller number of relayers and would still be profitable for the agent running this order aggregator system.
Another interesting application would be to create a Reserve Manager based relayer where users can contribute to the liquidity pool by being affiliates. One of the main problem of the Reserve Manager strategy is that the relayer needs large reserves if they want to fill the need of a large amount of users. One obvious solution to this would be for users to deposit their funds in a smart contract and this smart contract acts as a reserve. However, there are some complications when it comes to price control attacks and fair profit sharing. With fee splitting, you can have a simpler approach to this problem ; Liquidity providers can simply create orders at a price requested by the relayer and when these orders are filled, the liquidity provider can receive part of the fees.
There are multiple ways to allow affiliates on the 0x protocol.
Currently, both suggestions do not force an order to be attached to an affiliate in order to minimize friction from the user perspective (unless relayer sign orders for each affiliate with the affiliate address). Maker or taker would otherwise be required to either resign the order or sign the affiliate address before filling an order, respectively, both of which impair user experience. I believe there are off-chain solutions affiliates and relayers can use to make sure the affiliate reward goes to the right address.
Examining both solutions ;
However, with this solution, there is no need for an external smart contract. You need simple a new mapping variable, 1 new function (
Here as well, users could remove the
Note that modifying approach 2 slightly to act as a handshake between the relayer and affiliate could reduce
In general, allowing fees to be split between relayers and affiliates would not only significantly increase the collaboration within the 0x network, but would also open the door to more many new interesting strategies and ideas.
Note that in the current real world, affiliates are not imposed on costumers. Affiliate URLs are very common and everybody can change the URL to their own affiliate link. Changelly, for example, allow anyone to become an affiliate, which allows you to have reduced fees when you use your own referral link. Considering the affiliate market is valued in the billions of dollar, I believe these approaches are viable options.
Improvements can definitely be made, but, in my opinion, should never impair user experience .
My comments: I really like the affiliate term in this context, with the original relayer being the primary relay and the secondary ones being affiliates. I'm not too fond of the non-enforceability aspect of 1, but I like the idea of a relayer explicitly opting into several affiliates with a specified split. This opens the door for dynamic splits that rewards more productive affiliates. State channels are also an interesting approach in 2, but I'm a little weary of how much of this logic would live outside of the protocol and escape standardization.
I'd like to pitch in a variant to your approach 1. This is probably very gas heavy, but I think it would address enforceability and also keep your core ideas of setting downstream fee splits.
Alice makes her original order at Relayer A, with them as the fee recipient. The basic order format is the same as it is today, and the order hash / her signature still covers the same parameters, including one fee recipient and the total maker and taker fees.
The difference is that the call to
For example, when originally posted on Relayer A, the relay fee related parameters are:
Let's say Relayer B requests to share Alice's order from Relayer A, and Relayer A decides the maker and taker fee split based on the history of their relationship. Relayer A would respond to Relayer B with the following parameters:
Note that the first relay signature now omits the order salt in its coverage. The exchange contract will use it for verification, but won't allow it for taking an order. Also, Relayer A will supply Relayer B with
Now, let's say that Relayer B would like to share Alice's order with Relayer C. Relayer B would be allowed to sign off some of its fees to Relayer C, but no more than it would receive in total:
Relayer B would also provide Relayer C with
Finally, let's say Relayer C shares this order with Relayer D:
Again, Relayer C will provide Relayer D with
If Bob were to discover this order on Relayer D and take it, the exchange contract would verify that the maker and taker fees decrease monotonically and that each relay signature belongs to the preceding address.
The fee recipients would get paid out backwards in the table, each row subtracting the accumulated fees of prior rows. For example, for the Maker Fee, Relayer D would get 0.5 ZRX, Relayer C would get 0.5 ZRX (1 - 0.5), Relayer B would get 1 ZRX (2 - 1), Relayer A would get 3 ZRX (5 - 2), which sum to the total maker fee of 5 ZRX. Alice and Bob still pay no more than the original maker and taker fees, respectively.
The order Bob receives from Relayer D intentionally omits the previous relay signatures that cover the order salt, so Bob cannot shortchange any relayers in the chain. For example, Bob could not fill the original order paying out all the fees to Relayer A, because he doesn't have its relay signature that covers the order salt. (He could, of course, go to straight to Relayer A, but he could have always done that.)
Intermediate relayers cannot forge the fees, as they can't sign the updated hash that covers them.
The added costs are as many signature verifications as there are relayers, more complex fee calculations, and more input data in the transaction. This is all obviously expensive in terms of gas, but it would allow for trustless relaying with downstream fee splitting, while only modifying or introducing a variant of
edit: fix typos
I think @vsergeev's solution adds a lot of complexity and gas while not actually solving much. If a user is going to go to the effort of circumventing the affiliate's application, they already have the order hash and the base feeRecipient. It seems like it wouldn't take much extra effort to map the feeRecipient address back to the source relayer, then go directly to the source to get the order (given the order hash) without any affiliate signatures.
I think a simpler solution is to have the order define an affiliateFee to come out of total fee (makerFee + takerFee). If an affiliateFee is specified, but no affiliate is provided when the transaction is filled, pay the affiliate fee to the feeRecipient, but do it in two separate transactions through the token transfer proxy to ensure that gas can't be saved by not specifying an affiliate address.
This doesn't directly allow the relayer to specify different fees for different affiliates, but that's solvable too. At OpenRelay, we're developing an affiliate contract to split received fees between us and our affiliates (though without this ZEIP we're only able to split fees with the affiliate that helps create transactions, not with affiliates that help fill transactions). If a relayer wants to give different shares to different affiliates, they could have the accepted affiliate addresses be contracts that will split the affiliate fees according to different percentages for different affiliates.
I must admit my knowledge of gas consumption is somewhat limited, and it seems plausible that the EVM might reduce the gas for multiple updates to the same addresses to look like a single update, in which case this solution may not pan out.
@AusIV, the complexity is not just mitigating user circumvention, but it's also to support chained affiliates, while preventing them from stealing fees they're not entitled to. If we're only concerned with one affiliate, it could be simplified.
I just don't think the exchange contract is the right place to store affiliate relationship state -- that seems like it should be offchain.
I do like your idea of paying fees to a contract that splits between relayer and affiliate(s), but I think there are still some difficulties with supporting multiple affiliates, not to mention chained affiliates, without asking the maker to re-sign for each one.
Maybe a hybrid option is that there could be a formalized fee split contract interface, which the exchange contract could
edit: rename affiliate token to affiliate id to avoid confusion
I guess I'm not convinced of the need for affiliate chaining. I can see it being mildly useful, but I don't see it being valuable enough to justify the complexity.
Another issue with that proposal is that feeRecipients must be key pairs for that to work, and can't be contracts. Not only that, the private keys have to be on live, connected systems to be able to sign orders for specific affiliates. I'm fairly intent on keeping the keys that can withdraw my relay funds as isolated as possible, so having to have them on the system serving my orderbook rubs me the wrong way. (It doesn't help that I spent the afternoon consoling a friend who lost his life savings because his bitcoin private keys got stolen from a system that was supposed to be secure).
I'm excited to hear you guys have opened the floor for discussion on the subject of fee splitting between collaborating relayers, as it makes all the sense in the world if you really want the relayer protocol to gain momentum.
I'm not familiar with state channels so option 2 is a bit beyond my grasp at this stage, but with regards to option 1 I will just say that I'm a pragmatic entrepreneur/dev, and not too worried at this stage about the possibility of bad actors skimming a few affiliate fees here and there. I don't expect the affiliate fees to be particularly large since the relayer will likely be taking the lions share, as such bad actors can't get away with a whole lot before they're spotted and mitigated.
The gas argument on option 1 is fair but honestly, from a consumer side of it, thanks to relayer liquidity sharing you now have access to much better market deals, and so what's a little more gas expenditure?
My advice is don't overthink it and go with something practical, let it loose and see how it performs so you have some tangible data from which to drive the relayer protocol roadmap.
The perceived bad actor threat may not really be as much of a threat as you think, and the gas fee may not be as big a deal as you think... the proof is in the pudding :)
@vsergeev I do like your proposal, especially the signature from the relayer for each of their affiliate to ensure users don't remove it. Producing a signature is cheap computationally wise and relayers would be happy to sign the orders to their affiliate if it means they could earn some profit from their users filling it. I edited 1. to include this. However, as @AusIV mentioned, it might indeed have some security risks that relayers would not be willing to expose themselves to. I do agree with @AusIV however that I am not sure if the multi-layer relayer feature is necessary at the moment. From my experience, I often tend to over-engineer things while trying to solve problems that in practice actually never show up (or ends up being insignificant). We know that allowing at least one affiliate can come a long way, more is unclear. I therefore think a single affiliate-layer is a sufficient proposal for a first version of this affiliate feature. Perhaps in the future we will see that many people requests more than one layer and then we can revisit this proposal.
@AusIV Yes, I am pretty sure that updating the same address twice will result in lower gas consumption than updating two separate addresses, and it might be impossible in practice to have the same gas consumption when no or one affiliate is specified.
@avonian I do indeed agree with you that in practice most users will not try to remove the affiliate address, especially if some off-chain consequences are applied. In the end, if implemented properly, a user would need to move their funds or find another relayer if they remove the affiliate address, which is more expensive both in time and gas than simply letting the affiliate address on the order. I also do think that this simple solution might be fine for first implementation and refinement can be made in the future, especially since this introduces no substantial security risks for the users and relayers.