This epic handles all the smart contract design work for the PayoutEngine component.
The basic idea with the payout engine is to be able to take in a payment (in tokens or ether) and then distribute it out to a series of addresses. We use the RangeVote in our use case to “set” the distribution. Since this is going to be a single application we’ll need to have an array of different payouts. Each payout will have an ID that relates to a single payout. In order to work with the RangeVote all we need to do is connect an ACL role to the function that “sets” a payout. We also need a way to put funds into a payout. It would be possible to setup the PayoutEngine so that you could “pre-load” it but for the initial use case all we need is to create a pass through. The user story looks something like this:
A DAO creates initiated a distributed payout which forwards a vote to RangeVote to determine how a budget will be set.
Depending on how the vote is setup elligible voters will cast their votes. Once the vote expires somebody can call the external function executeVote()
The RangeVote will call _executeVote() which calls runScript passing the results of the vote as input to runScript
The PayoutEngine needs to have a function that receives the runScript input.
Once the payout distribution has been set there needs to be a way to authorize the PayoutEngine to distribute ether or tokens based on the distribution that was previously set.
For ERC20 this means that there needs to be a push/pull mechanism. For Ether, ERC777 and ERC721 this can all be handled in a single function.
There are still some questions with how the vault is going to be handled in it’s final form so we should watch the repo and circle back on this. To start we’ll implement just the Ether functions. The other implementations should be pretty close to the ether implementation.
So our functions will look like this:
function startPayout(string[] _candidateKeys, address[] _candidateAddresses, string _metadata ) external auth(START_PAYOUT_ROLE) returns(uint256 payoutId)
This is the function that setups who the candidates will be, and where the funds will go for the payout. This is where the payout object needs to be created in the payouts array.
function setDistribution(uint256 _payoutId, string[] _candidateKeys, uint256[] _supports) external auth(SET_DISTRIBUTION_ROLE)
This is the function that the RangeVote will call. It doesn’t need to be called by a RangeVote but for our use case the “SET_DISTRIBUTION_ROLE” will be given to the RangeVote.
function runPayout(uint256 _payoutId) external payable
This function is how a payout is used. When ether is fed into the runPayout function it’s sent out based on the distribution that’s been set.
In order to get those functions to do their thaaaaang we’ll need the following data structures:
struct Payout{
string[] candidateKeys,
address[] candidate addresses,
uint256[] supports
}
Payout[] payouts
All in all I think this will be a pretty straight forward contract. It does something simple and it does it in the most versatile way possible. Additional runPayout functions will need to be added for different token types but again this needs to wait on the vote.