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
[Protocol3] New fee model and examples #197
Comments
Here are some of my feedback and questions regarding New Fee Model:
I think we should always use the maker's price, instead of the taker's price. This is how it works on CEXes.
But from a user's perspective, what he get in a trade should always satisfy the order's price, regardless if the spread is negative or positive.
This is an interesting approach. Basically if a ring is signed by the matcher, the matcher is forced to subside whatever amount needed to make the settlement price satisfy both order's prices, given the matcher still have enough balance. We may need to apply some kind of cap on the amount though. For example, 10% of the order'size, etc. One possible challange for this appoach is that the ring-matcher may not have so many altcoins to pay feesl for all rings he built. We'll proabaly need to deduct protocol fees from trading fees the ring-matcher make out of the both orders first, if the trading fees < protocol fees, then we deduct from matcher's account balance, and if the fund is insufficient, we reject the settlement request. If we do enforce ring-matcher to pay protocol fee, should we force them to pay in LRC instead of any token? And the protocol fee can be paid in fix amount instead of a percentage of the trading volume as well. |
Regarding 3. Exchange protocol fee reduction staking (Per exchange) I guess the idea is to let the exchange owner figure out how to reward people who stake LRC for his/her exchange, from the protocol level, we treat those staked tokens as a whole, is it? This type of stakes is different from type-2 staking (2. Exchange owner staking (Per exchange)) in that the weight is 50% and the tokens can be withdrawn at any time without restrictions. Correct me if I'm wrong. |
I think that's fine, because 2 order rings are symmetrical there should be no problem with making the first order the taker and the second order the maker, it should still be the same ring.
That's right, it reduces the number of constraints and makes the protocol fees/spread a lot easier because we only have to deal with 2 tokens. If we do a protocol fee on the amount traded we would also have to do that on the fee that is paid in fee token and so on...
Unless I made a mistake it's actually very simple to do. All fees are calculated as if the trade happens at the rate specified in the order. The only difference is that the second order receives tokens from not just the first order, but also the ring-matcher. Because the ring-matcher also pays the protocol fee for both orders there is no difference in who needs to pay the protocol fee on the complete
Yes, that's how it would work. It does not matter for the order owners either way. They will get their tokens at the rate specified in the order.
I though about this, and I'm not against a cap, but I think leaving this uncapped is not really dangerous. The ring-matcher needs to know what he's doing when matching orders. There's a lot of ways to lose money if you use the system incorrectly (like paying a huge fee to the operator for the settlement).
That's how it would work. If the ring-matcher balance is insufficient the settlement cannot be included in a block. There's actually no need to do any checks like 'trading fees < protocol fees' etc in the circuit... the balance is just updated for every 'token transfer' and every 'transfer' ensures that But in most normal cases the ring-matcher can pay everything using the fees he gets.
I think it makes sense to use percentages. Trading fees are percentages and people are okay with that. Otherwise the fixed protocol fee is either extremely low or makes the protocol unattractive for small trades. I think making it a very low percentage is better than making it a fixed fee, but that's just my opinion, I don't know if that's the smartest thing to do. A fixed fee in LRC will be a bit cheaper in the circuit. Doing both is also an option I guess: very low percentage + fixed fee in LRC. When we support simple token transfers we'll probably have to do the protocol fee in a percentage because users will have to pay it directly. If we use percentages that kind of rules out using LRC as the only payment because we don't know the price of LRC in tokenS/tokenB. Well, we could try and get the price in the circuits some way, but even if that is possible it would be pretty expensive to do it that way. |
Correct. Just the reduction in protocol fee could be reason enough for ring-matchers/wallets/etc... to stake for the exchange. But the exchange owner can give extra rewards if he wants.
That's the idea. 3. staking is a lot more flexible in that the LRC can be withdrawn at any time (from the protocol's perspective, the exchange owner contract can impose more restrictions). 2. stake is stuck until shutdown so is riskier for the staker, but better for the users so this staking is incentivized by giving it a larger weight for the protocol fee reduction. |
I feel comfortable moving forward. |
Regarding:
Is there a way that you can allow for the exchange to reimburse the maker to bring their effective fee down to 0%? How is there a loophole also? Can you explain please? |
Thanks for the feedback @coreycaplan3 !
Yes, the protocol fee is not paid by the order owner itself, it's completely paid by the ring-matcher. The protocol fee is not paid by the order owner by using a part of the fee. The protocol fee percentage and fee percentage are completely unrelated. If the fee is 0% the order owner will not pay any fees at all, the ring-matcher will have to pay the protocol fee. It's also very likely it will be possible for the maker fee to be reduced to 0%.
My current thinking is that there isn't any realistic loophole. My biggest fear is/was the asymmetry. You could create a ring that matches an order selling $100 worth of tokens with an order selling $0 worth of tokens, the protocol doesn't know (and should not care) about this. The ring-matcher can then decide to only pay the protocol fees for the order worth $0, effectively evading the protocol fees. The question remains how this asymmetry could be exploited. I can't think of any that are problematic but some examples:
But it's of course possible I'm missing a case that's actually a problem. :) |
Great explanation! I think one thing to keep in mind is that most exchanges operate like regular trading platforms. The idea that Dolomite could settle a trade worth $0 to avoid fees with a $100 trade is far fetched when you think about how businesses like Dolomite operate. I definitely see what you're saying but even still I don't think it's reasonably possible to setup a taker trade for effectively $0 if it's being matched logically.
So does this mean that, similar to v2 of Loopring, Dolomite needs to effectively reimburse itself via the trading fees? Last recommendation: Protocol pool staking (Global) Thanks for all of the answers. Everything seems logical otherwise :) |
Oh I definitely agree. But because the protocol fee can still be a significant loss of revenue for exchanges it may be worthwhile for them to exploit far fetched things like this.
I'm not sure what you mean with that. The ring-matcher can pay the protocol fees using his own funds. But because of the order we do the token transfers in (the ring-matcher receives the trading fees/margin first, afterwards he pays the protocol fees), he can use the trading fees he receives to do so if possible. Does that answer your question? There are 3 possible sources of income:
As a DEX you can choose to be the wallet, ring-matcher and operator all at the same time, which makes the operator fee redundant.
The exact mechanism for this still needs to worked out. But this seems reasonable, though I think the penality should be rather high if we would do this. It's a risk/reward exercise for the users, nobody is forcing you to lock up LRC for a long time. :)
Thank you! |
Yes this answers my question! I was wondering at what point in the settlement process does that occur. This makes sense. Considering DEXs (like Dolomite) can effectively cover the protocol fee for market makers and (presumably) issue rebates then too to them in "real-time".
This makes sense.
What's your thoughts on this scenario: I say I'm going to lock my LRC for 12 months. After the 6 month tranche goes by, I decide I want to withdraw, which is in-line with the other people who were going to withdraw in 6 months, but it still breaks my "agreement" of staking for 12 months. What's your thoughts on situations like this and how we should penalize the withdrawal? The same way as withdrawing at a random time? |
The only way to do rebates is by negative spreads. This was actually something I discussed with Matthew and Daniel today and may be a source of confusion (see the 'Negative fees for market makers (rebates)' part in the issue). Matt will ask market makers if they are okay with this. Having actual rebate payments for orders has the strange side effect of the same order having multiple representations that behave differently if you implement it in a straightforward way. Having the market maker simply set a higher price (combination of his expected price + rebate) is more flexible, though perhaps less traditional. If this is too confusing we will add a rebate parameter to the order, but it will simply be used to set the price higher in the protocol. I will be making some examples showcasing how the fee model works in different cases (probably tomorrow).
I would say the same as at a random time, because you're still withdrawing earlier than expected. Users are expecting the LRC to remain locked up for another 6 months and they may have made a decision to buy/lock-up LRC as a result of that. Though Matt actually came with an idea for this that may render this discussion moot (locked up LRC could be 'used' in a different way). Lots of different possibilities! |
Maybe I misunderstood what was originally written but there are circumstances in which negative fees would be given out organically and not just for negative spreads. Dolomite is using it as an incentive mechanism, no matter what the order books look like. Simply put, it's an incentive mechanism for all market makers. The way you described the rebates and the way I understood them lend them to being "conditional" on negative spreads, whereas the way Dolomite would like to use them is not conditional on anything - if you are a maker, you get the company-specified rebate. Can you elaborate if I misunderstood?
Very interesting, looking forward to learning more and I agree with the result so far. |
I added some examples in the issue how it would work. If you want to do rebates you have to use negative spreads. But I think the confusion is probably how this is currently exposed in the protocol/order. Even though not needed for the protocol, it makes sense to add a |
Yes that's a great idea and will make it clearer! |
Updated the main post:
|
This can actually be done by using a contract as the owner of the operator account. The funds are withdrawn to this account and can be split between the operator and the proving service using any logic. |
Great, then this will be like an extension to the protocol. The same approach can be used to make sure matching fees can also be split between multiple parties including the operator and wallets (therefore the protocol does not need to support a percentage operator fee). |
Updated the main post:
|
The following discussions are for beta3 and further versions. |
This comment has been minimized.
This comment has been minimized.
The summary of a discussion between Brecht and myself regarding what will likely change in our fee model:
We should also limit the crypt asset of the operator's hot wallet, because that's all that hackers can steal if they hacked into the backend. The idea is to use the hot wallet to pay Ethereum tx gas; use another account (fee-recipient) to receive trading fees and pays protocol fees. The private key of the fee-recipient can be kept in a cold wallet. |
Ring-matcher removalThe Operator now receives the fees form users but he now also pays the protocol fee/rebates. The operator didn't need to sign anything with the ring-matcher because the operator only received fees, the operator never had to pay anything using his account. The ring-matcher needed to sign the ring to authorize these payments. All the things a ring-matcher could decide are now the responsibility of the operator, but the operator will probably just do whatever the DEX wants using some non-protocol related data:
The fees earned by the operator can be withdrawn to a contract that splits the fees in a trust-less way or the operator can have complete control over the fees that were earned. The operator needs 2 online keypairs:
Having 2 different sets of online keypairs gives better security than just a single keypair set. We could also come up with a method that only uses a single ECDSA keypair:
If the attacker has access to the ECDSA private key in this scheme however he could drain both the account receiving the fees as well as the ETH in the Ethereuem account used for transactions. Token Transfers for a single ringUpdated token transfers, though not much has changed (operator simply replaces the ring-matcher). The biggest performance gain here is that we don't have to update a ring-matcher account/trade and we don't have to store ring-matcher and ring-matcher to operator fee info in DA.
SecurityBoth EdDSA and ECDSA keypairs hackedFor an attacker to successfully spend funds from the operator account he needs both the EdDSA private key and the ECDSA private key of the operator:
-> The EdDSA private key and the ECDSA private key should be stored on different servers (or some setup that is even more secure than this). Only the EdDSA keypair hackedWhen an attacker only has the EdDSA private key he can only sign offchain requests using the operator account. These requests can be blocked by the server committing blocks. Only the ECDSA keypair hackedWhen an attacker only has the ECDSA private key he could
LabelsFor labelling requests we have two options:
I think 2. this makes the most sense because we want to really limit the data that is put onchain as much as possible (as it is the main bottleneck). |
LabelsI also prefer using hashes. But we need to make sure the hash is as short as possible, hash collisions should be fine as we have some data being hashed are available as part of the onchain DA. For simplicity, should we also use Poseidon or we can use any hashing function? My understanding is the hashing function has nothing to do with circuits so we may even use murmur hash in relayer to generate an Also, infrequent hash collisions should not be a problem as many data fields of settlements are actually available on-chain. |
Keypair SchemesI prefer the 2-keypairs scheme. In the future, we may refer to these private keys as:
In our smart contract, only the 3rd private key’s corresponding address need to be registered as an operator. (Is my understanding correct? @Brechtpd ) In your 2-keypairs scheme, fee recipient (ECDSA) private key != operator (ECDSA) private key, but we don't have to enforce it on the protocol level, and instead, use as the best practices. |
I would make the label part of the order/requests, so it's part of the the data a user signs. Then all labels of all orders would be bundled together and hashed using Poseidon/Pedersen in the circuit. This way the operator cannot lie about the label data of the orders/requests used. The length of the hash is not important because it's just a single hash/block. |
Yes! Can be registered either directly as the exchange operator or indirectly using an operator contract.
Correct. |
I would assume 1) calculating the order hash will take O(n) time where n is the number of orders and 2) the calculation of hash is not part of any circuits. If my understanding is correct, I'd say go with this approach. |
That is correct. The label will just be ~1 byte/order so the hashing cost in the circuit will be very very low, maybe an extra 50-100 constraints/trade in total for hashing the extra order data for the order signature and hashing all the labels of all the orders to a single hash.
I think it should be part of the circuit, otherwise the operator can put any hash on-chain that he wants. The extra cost in the circuit will be insignificant. If we do it in the circuit the operator is forced to use the correct labels to generate the hash (so he needs to share the correct label data, otherwise it won't match the hash onchain). If we don't do it in the circuit I don't see a lot of benefit in putting anything onchain. There isn't that much data of the order onchain that someone can easily see which trade used which orders. |
What about we use 32 bytes (uint256) for the label as Poseidon takes 4N inputs? |
Poseidon can take different number of inputs, but you can only use It may make more sense to use Pedersen here because Pedersen is bit based. we just make a bitstream of all the labels of all the orders and hash it that way once for the complete block. There are ways Poseidon could also be used this way, though I'd have to check what's possible. In any case, the extra constraints/trade will be low. |
Regardless of the hash function, I don't think 1 byte is large enough for the label, we should use at least a |
Any reason why it needs to be that large? A simple DEX specific contract where people can get a short uint16/uint24/... label can be made to make these labels short and make it possible to map to some larger amount of data (like an Ethereum address). |
sorry I was massing up the label concept with the hashing. Uint24 should be enough. |
I'm not quite understanding what's meaning for the "label" in above discussion? :( |
It's just an identifier for a request e.g. an identifier for the wallet the request was created in. In previous fee models we had wallets and ring-matchers that were paid directly as part of the trade. This produces a lot of token transfers which increases the cost in the circuit (constraints) but also increases the amount of data-availability data (all transactions need to be reconstructible using this data). So instead of doing all these costly token transfers we just publish a label on-chain for the order/request that was used by the operator. The operator (who receives all the fees from users) can then make agreements with wallets/etc... outside of the protocol how they get paid for the use of their requests. |
Okay. Got it
…------------------ Original ------------------
From: Brecht Devos <notifications@github.com>
Date: Fri,Jul 26,2019 9:32 PM
To: Loopring/protocols <protocols@noreply.github.com>
Cc: Steve Guo <12143369@qq.com>, Mention <mention@noreply.github.com>
Subject: Re: [Loopring/protocols] [Protocol3] New fee model and examples (#197)
It's just an identifier for a request e.g. the wallet the request was created in.
In previous fee models we had wallets and ring-matchers that were paid directly as part of the trade. This produces a lot of token transfers which increases the cost in the circuit (constraints) but also increases the amount of data-availability data (all transactions need to be reconstructible using this data).
So instead of doing all these costly token transfers we just publish a label on-chain for the order/request that was used by the operator. The operator can then make agreements with wallets/etc... outside of the protocol how they get paid for the use of their requests.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
The label can also be used to keep any arbitrary data that can be interpreted by the DEX and their partners, entirely transparent to the protocol. |
We only need to hashes all the labels as a labelHash per off-chain block. |
All features have been implemented. |
New Fee Model Design
Protocol Fee
This fee is proportionally applied on every token transfer part of the trade. The protocol fee can be lowered by staking LRC. A different protocol fee can be used for maker orders and taker orders.
A protocol fee value is stored in a single byte in
bips/10
. This allows us to set the protocol fee up to0.255%
in steps of0.001%
(0.1 bips
).Different treatment of maker and taker orders
The ring-matcher chooses which order is the maker and which order is the taker.
The order at position 0 in the ring is always the taker order, the order at position 1 is always the maker order. We always use the rate of the second order for the trade.
Removal of the fee token
No more fee token/fee amount. The protocol fee is applied on the amount traded. A possible negative caused by this is that it's not possible to do fee payments in security tokens, NFTs, ... but we don't support these yet in protocol 3 anyway. Can be added back in a future version of the protocol when it makes sense.
Fee payments
Paid in the tokenB of the order. These are not taxed or do not have any other disadvantage. The order owner pays the fee to the ring-matcher respecting
feeBips
. These values are calculated on the complete amount bought, the protocol fee does not change this in any way.feeBips's max value is 0.63% in steps of 0.01% (1 bips).
Buy/Sell orders
Users can decide if they want to buy a fixed number of tokens (a buy order) of if they want to sell a fixed number of tokens (a sell order). A buy order contains the maximum price the user wants to spend (by increasing amountS), a sell order contains the minimum price the users wants to get (by decreasing amountB). This allows us to do market orders. It only matters if an order is a buy or a sell order when the order is used as the taker order, the price for the maker order is always the price defined in the order.
So if there is a positive spread between the taker and the maker order we either use the spread to buy more tokens (sell order) for the taker, or let the taker keep the spread (buy order).
Rebates
The ring-matcher can choose to give an order a rebate. This is a percentage of amountB.
rebateBips's max value is 0.63% in steps of 0.01% (1 bips).
Ring-matcher pays all actual costs for a trade
The ring-matcher is in the best position to decide if a trade is profitable (and if not, he can still choose to do the trade for other reasons):
So it makes sense to also let the ring-matcher pay:
By letting the ring-matcher pay the protocol fees for the orders we decouple this from the fee paid by the order owners. This is useful because the
order.feeBips
can be lower than the protocol fee. Otherwise this could give issues when the protocol fee changes or when the order is used as maker/taker and different protocol fees apply.Note that the ring-matcher normally receives fees from both orders which he can use to pay the protocol fees and/or rebates.
But if the ring-matcher pays the protocol fee, why have different protocol fee rates? You could argue that a 0.05% taker fee and a 0.01% maker fee is the same as a fixed 0.03% rate because the same entity pays the fee. That is true, but in general the ring-matcher will get a larger fee for the taker order than for the maker order so he will receive more tokens in
takerOrder.amountB
than inmakerOrder.amountB
. By having different rates it's more likely that the ring-matcher can pay the complete protocol fee just by using the tokens he receives as fee.Data
Order
The order contains the maximum fee paid by the order owner.
Ring
The ring contains the actual fee paid by the order owner (which needs to be
<= order.maxFeeBips
). This allows, for example, for DEXs to temporarily/permanently lower the fees on their DEX without having users recreate their orders so they can get the lower fee. This also allows the same order to get the taker fee and the maker fee, because the same order could be used as both.feeBips
andrebateBips
cannot both be non-zero for an order.Token Transfers for a single ring
The order we do the transfers in is important. The ring-matcher can directly pay his fees using the fees he gets from the orders.
There is little point in minimizing the number of 'token transfers' in the circuit. That's not expensive. The number of accounts and balances that need to be updated is the expensive part.
Fee Model Examples
Buy taker order
Protocol fees:
Taker order:
-> Pays: 10.0ETH (less than the 10.1ETH specified in the order)
-> Receives: 10,000LRC - 20LRC (fee)
-> Trading fee: 20LRC
-> Protocol fee: 5LRC
Maker order:
-> Pays: 10,000LRC
-> Receives: 10ETH - 0.01ETH (fee)
-> Trading fee: 0.01ETH
-> Protocol fee: 0.0025ETH
Sell taker order
Protocol fees:
Taker order:
-> Pays: 10.1ETH
-> Receives: 10,100LRC (more than the 10,000LRC specified in the order) - 20.2LRC (fee)
-> Trading fee: 20.2LRC
-> Protocol fee: 5.05LRC
Maker order:
-> Pays: 10,100LRC
-> Receives: 10.1ETH + 0.0101ETH (rebate)
-> Rebate: 0.0101ETH
-> Protocol fee: 0.002525ETH
The text was updated successfully, but these errors were encountered: