Semi-automatic contract which splits received ether equally to declared shareholders.
I was asked to create a contract which would automatically split received ether from mining pools to declared shareholders.
Mining pools tend do set low gas limit for transactions so it turned out that this contract should only receive transfer. Payout to shareholders has to be triggered manually (using payout()
method).
- truffle
- TestRPC
- (optional) Docker (with
docker-compose
) - for convenience, I'm using dedicated images
docker-compose run --rm truffle install
docker-compose up -d testrpc
docker-compose run --rm truffle test
After longer development (and test runs) it may turn out that coinbase
set in TestRPC may run out of ether which will fail tests. If this happens TestRPC server has to be restarted.
docker-compose restart testrpc
When contract is changed README
file should be updated.
I've created a simple PHP build tool which will use README template and pass to it information about compiled contract.
To use it, simply, run make docs
. This command requires docker
and docker-compose
to be installed.
If you don't want to use docker
you can compile README with this commands:
solc --combined-json "abi,bin" zeppelin/SafeMath.sol=/usr/src/app/installed_contracts/zeppelin/contracts/SafeMath.sol --optimize contracts/EthSplit.sol > build/solc.json
php docs/build.php > README.md
Note: you will need to install solc
compiler and PHP
(>= 7.0).
[
{
"constant": false,
"inputs": [],
"name": "payout",
"outputs": [
{
"name": "result",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"inputs": [
{
"name": "shareholdersList",
"type": "address[]"
},
{
"name": "donateTo",
"type": "address"
}
],
"payable": false,
"type": "constructor"
},
{
"payable": true,
"type": "fallback"
}
]
[{"constant":false,"inputs":[],"name":"payout","outputs":[{"name":"result","type":"bool"}],"payable":false,"type":"function"},{"inputs":[{"name":"shareholdersList","type":"address[]"},{"name":"donateTo","type":"address"}],"payable":false,"type":"constructor"},{"payable":true,"type":"fallback"}]
Contract was compiled by stable version of solc
compiler. It was optimized using default values.
6060604052341561000c57fe5b6040516102e13803806102e183398101604052805160208201519101905b815161003d906000906020850190610061565b5060018054600160a060020a031916600160a060020a0383161790555b50506100f2565b8280548282559060005260206000209081019282156100b6579160200282015b828111156100b65782518254600160a060020a031916600160a060020a03909116178255602090920191600190910190610081565b5b506100c39291506100c7565b5090565b6100ef91905b808211156100c3578054600160a060020a03191681556001016100cd565b5090565b90565b6101e0806101016000396000f300606060405236156100255763ffffffff60e060020a60003504166363bd1d4a811461002e575b61002c5b5b565b005b341561003657fe5b61003e610052565b604080519115158252519081900360200190f35b6000600160a060020a033016318180808315156100725760009450610159565b61008830600160a060020a0316316103e8610160565b600154909350600160a060020a0316158015906100ca5750600154604051600160a060020a039091169084156108fc029085906000818181858888f193505050505b156100d55782840393505b6000546100e3908590610160565b9150600090505b60005481101561015457600080548290811061010257fe5b906000526020600020900160005b90546040516101009290920a9004600160a060020a0316906108fc8415029084906000818181858888f19350505050151561014b5760006000fd5b5b6001016100ea565b600194505b5050505090565b60006000610170600084116101a3565b828481151561017b57fe5b049050610198838581151561018c57fe5b068285020185146101a3565b8091505b5092915050565b8015156101b05760006000fd5b5b505600a165627a7a723058204a6bb82f31f0037b61714b9cc89d6209d7aaf19401b9ae01bfb7a4152a586ac40029
const shareholdersList = [
// array of ETH wallet address
// eg. 0x0 :)
];
const donateTo = '0x0'; // don't donate
const contract = web3.eth.contract([{"constant":false,"inputs":[],"name":"payout","outputs":[{"name":"result","type":"bool"}],"payable":false,"type":"function"},{"inputs":[{"name":"shareholdersList","type":"address[]"},{"name":"donateTo","type":"address"}],"payable":false,"type":"constructor"},{"payable":true,"type":"fallback"}]);
contract.new(shareholdersList, donateTo, {
from: web3.eth.accounts[0],
gas: '4700000',
data: '0x6060604052341561000c57fe5b6040516102e13803806102e183398101604052805160208201519101905b815161003d906000906020850190610061565b5060018054600160a060020a031916600160a060020a0383161790555b50506100f2565b8280548282559060005260206000209081019282156100b6579160200282015b828111156100b65782518254600160a060020a031916600160a060020a03909116178255602090920191600190910190610081565b5b506100c39291506100c7565b5090565b6100ef91905b808211156100c3578054600160a060020a03191681556001016100cd565b5090565b90565b6101e0806101016000396000f300606060405236156100255763ffffffff60e060020a60003504166363bd1d4a811461002e575b61002c5b5b565b005b341561003657fe5b61003e610052565b604080519115158252519081900360200190f35b6000600160a060020a033016318180808315156100725760009450610159565b61008830600160a060020a0316316103e8610160565b600154909350600160a060020a0316158015906100ca5750600154604051600160a060020a039091169084156108fc029085906000818181858888f193505050505b156100d55782840393505b6000546100e3908590610160565b9150600090505b60005481101561015457600080548290811061010257fe5b906000526020600020900160005b90546040516101009290920a9004600160a060020a0316906108fc8415029084906000818181858888f19350505050151561014b5760006000fd5b5b6001016100ea565b600194505b5050505090565b60006000610170600084116101a3565b828481151561017b57fe5b049050610198838581151561018c57fe5b068285020185146101a3565b8091505b5092915050565b8015156101b05760006000fd5b5b505600a165627a7a723058204a6bb82f31f0037b61714b9cc89d6209d7aaf19401b9ae01bfb7a4152a586ac40029'
}, (e, contract) => {
console.log(e, contract);
if (contract && typeof contract.address !== 'undefined') {
console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
}
});
Deployed contract is able to do two things:
- receive ether transfers
- payout stored ether to defined shareholders (via
payout()
method)
Currently contract does not support selfdestructing.
This contract is not secured in any way. It doesn't have to.
- shareholders list can't be changed
- triggering
payout()
will give no benefit for someone who is not defined in shareholders list
# donate
If you're happy with my work feel free to donate me with some ether (0x4a03ec5e48de60048d8fd5e004b443db51d9f0f5
) :)
Update: please don't follow those instructions - I don't own the wallet anymore.
If you're very happy with my work you can set donateTo
constructor argument during contract deployment.
Every time you make a payout I'll receive 0.1% of that transfer.~~
const shareholdersList = [
// array of ETH wallet address
// eg. 0x0 :)
];
const donateTo = '0x4a03ec5e48de60048d8fd5e004b443db51d9f0f5';
const contract = web3.eth.contract([{"constant":false,"inputs":[],"name":"payout","outputs":[{"name":"result","type":"bool"}],"payable":false,"type":"function"},{"inputs":[{"name":"shareholdersList","type":"address[]"},{"name":"donateTo","type":"address"}],"payable":false,"type":"constructor"},{"payable":true,"type":"fallback"}]);
contract.new(shareholdersList, donateTo, {
from: web3.eth.accounts[0],
gas: '4700000',
data: '0x6060604052341561000c57fe5b6040516102e13803806102e183398101604052805160208201519101905b815161003d906000906020850190610061565b5060018054600160a060020a031916600160a060020a0383161790555b50506100f2565b8280548282559060005260206000209081019282156100b6579160200282015b828111156100b65782518254600160a060020a031916600160a060020a03909116178255602090920191600190910190610081565b5b506100c39291506100c7565b5090565b6100ef91905b808211156100c3578054600160a060020a03191681556001016100cd565b5090565b90565b6101e0806101016000396000f300606060405236156100255763ffffffff60e060020a60003504166363bd1d4a811461002e575b61002c5b5b565b005b341561003657fe5b61003e610052565b604080519115158252519081900360200190f35b6000600160a060020a033016318180808315156100725760009450610159565b61008830600160a060020a0316316103e8610160565b600154909350600160a060020a0316158015906100ca5750600154604051600160a060020a039091169084156108fc029085906000818181858888f193505050505b156100d55782840393505b6000546100e3908590610160565b9150600090505b60005481101561015457600080548290811061010257fe5b906000526020600020900160005b90546040516101009290920a9004600160a060020a0316906108fc8415029084906000818181858888f19350505050151561014b5760006000fd5b5b6001016100ea565b600194505b5050505090565b60006000610170600084116101a3565b828481151561017b57fe5b049050610198838581151561018c57fe5b068285020185146101a3565b8091505b5092915050565b8015156101b05760006000fd5b5b505600a165627a7a723058204a6bb82f31f0037b61714b9cc89d6209d7aaf19401b9ae01bfb7a4152a586ac40029'
}, (e, contract) => {
console.log(e, contract);
if (contract && typeof contract.address !== 'undefined') {
console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
}
});