Open miladmostavi opened 8 years ago
Another potential way is to track when an address has withdrawn revenue, and then transfer that along each time. This way, every time a token is transferred it does not have to withdraw revenue.
See how theDAO did it. It tracked "paidOut" (https://github.com/slockit/DAO/blob/bdb1cf0af929d81862e5a801ad85b3765fda4f18/DAO.sol#L806).
EG, addresses A - C, each holding 25% of tokens totalSupply -> 100.
A: balance: 25. paidOut: 0. B: balance: 25. paidOut: 0. C: balance: 25. paidOut: 0. D: balance: 25. paidOut: 0. TotalRevenue: 0. Outstanding Revenue: 0.
10 ether comes in as revenue.
A withdraws revenue:
value = singularDTVToken.balanceOf(forAddress) * (totalRevenue / singularDTVToken.totalSupply() - paidOut[forAddress];
ether owed to A = 25 * (10) / 100 - 0 = 2.5 ether.
Now you also do: paidOut[A] = 2.5 ether.
Thus after withdraw:
totalRevenue = 10 balanceOf(A) = 25 revAtWithdraw[A] = 10 totalSupply = 100
A tries to withdraw again:
value = singularDTVToken.balanceOf(forAddress) * (totalRevenue / singularDTVToken.totalSupply() - paidOut[forAddress];
ether owed to A = 25 * 10/100 - 2.5 = 0.
Now. A send 25 tokens to B. During transfer, paidOut[A] is also transferred to paidOut[B]. Ledgers are thus:
A: balance 0. paidOut. 0 B: balance 50. paidOut. 2.5 ether. C: balance 25. paidOut. 0. D: balance 25. paidOut. 0. TotalRevenue: 10. Outstanding Revenue: 7.5
B withdraws revenue:
value = singularDTVToken.balanceOf(forAddress) * (totalRevenue) / singularDTVToken.totalSupply() - paidOut[forAddress];
ether owed to B = 50 * (10)/100 - 2.5 = 2.5 ether.
Thus ledger:
A: balance 0. paidOut. 0 B: balance 50. paidOut. 5 ether. C: balance 25. paidOut. 0. D: balance 25. paidOut. 0. TotalRevenue: 10. Outstanding Revenue: 5
Another 10 ether revenue comes in.
C withdraw revenue:
value = singularDTVToken.balanceOf(forAddress) * (totalRevenue) / singularDTVToken.totalSupply() - paidOut[forAddress];
ether owed to C = 25 * 20/100 - 0 = 5 ether.
Thus ledger:
A: balance 0. paidOut. 0 (owed 0) B: balance 50. paidOut. 5 ether (owed 5) C: balance 25. paidOut. 5 ether (owed 0) D: balance 25. paidOut. 0. (owed 5) TotalRevenue: 20. Outstanding Revenue: 10
And correct me, if I'm wrong, wouldn't this solve this then? https://github.com/ConsenSys/singulardtv-contracts/issues/35. You can then call withdrawRevenueFor for msg.sender. Not upon every token transfer.
Is my thinking correct here, or is there some another reason to opt to withdraw upon every token transfer?
Thanks for referring to this approach Simon. It is a good way to tackle issue #35. I wonder how exchanges thought about handling potential revenue withdraws with DAO tokens. Since paidOut may be different for different DAO tokens, exchanging them is more difficult.
I like this approach too, since it removes the need to move ether in a token transfer. It's like a soft revenue withdraw: instead of transferring ether right away, we add to a owed
list.
But exchanges will still need to account for revenue attached to tokens.
But exchanges will still need to account for revenue attached to tokens.
In this method, they just should not call withdraw on behalf of their users. If users want to withdraw their revenue they can take it out of the exchange and execute it themselves? Unless exchanges want to offer the functionality to withdraw revenue?
Exchanges would have to make sure, that at the time of trading on an exchange, tokens have the same value otherwise it would get messy. With both solutions ("thaDao" and current implementation) an exchange would have to take care of this, because they trade off-chain.
A slight advantage of the current implementation is, that there is a guarantee for on-chain transactions, that the additional token attribute (revenue) has always the same value of 0, what makes token a little more fungible.
Good point. Not all tokens would be equal, since it depends how much paidOut it is dragging along. Hmmm
I suggest we do it similar to our current implementation, with the following modifications:
We add a list to the SingularDTVFund
named owed
, and a function named softWithdrawRevenueFor(forAddress)
that calculates the revenue share the same way as withdrawRevenueFor(forAddress)
does currently, but instead of send
ing it right away, it adds the calculated value to the owed[forAddress]
.
withdrawRevenueFor()
will be modified to use msg.sender
instead of forAddress
, add owed[msg.sender]
to its calculated revenue share and then reset owed[msg.sender]
.
transfer
function in SingularDTVToken
will then use the new softWithdrawRevenueFor
function.
This approach removes the side effect of actually sending ETH in a token transfer and also makes all tokens equal at the time of transfer. It also solves https://github.com/ConsenSys/singulardtv-contracts/issues/35.
Exchanges will still need to account for revenue attached to tokens.
I was about to suggest a similar modification. Keeping the tokens equal at the time of transfer is very important in my opinion. It makes trading significantly easier and removes the risk for users to accidentally transfer revenue along with their shares. I will implement this modification now.
+1. Seems most elegant.
Implemented softWithdrawl in 087aa17708b16dfc5fb5b406ea4b57d2eb1abe81
Also updated test accordingly. This issue will remain open as the actual issue remains. But I will close #35.
I think we should discuss how the exchanges will handle the revenue share attached to our tokens. Right now, right before a token transfer happens, revenue for both parties are automatically withdrawn. This solution is very clean and straightforward. It also means that all tokens have the same value when transferred.
The issue is with the users that keep their tokens on exchanges. If a user withdraws SNGLS from an exchange, revenue share is sent to exchange's address. It is the exchange's responsibility to assign that reward to the user's balance.