Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
skogard committed Dec 30, 2021
0 parents commit baaf59d
Show file tree
Hide file tree
Showing 18 changed files with 29,119 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
node_modules
.env
.DS_Store
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
pids
*.pid
*.seed
*.pid.lock
artifacts
cache
store
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Stream

> create a group that splits incoming money to members in realtime
Learn more: https://stream.moneypipe.xyz

![pipe.png](pipe_poster.png)

---

# Contract

Stream is a [minimal proxy contract](https://eips.ethereum.org/EIPS/eip-1167), which makes deployments affordable ($40 ~ $90).

This repository is made up of 2 main files:

1. [Stream.sol](contracts/Stream.sol): The core "Stream" contract that handles realtime money split handling
2. [Factory.sol](contracts/Factory.sol): The factory that clones and deploys the core Stream contract

> There's an additional [Test.sol](contracts/Test.sol) but it's just for testing purpose and is not included in the deployment.
73 changes: 73 additions & 0 deletions abi/contracts/Factory.sol/Factory.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
[
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "group",
"type": "address"
},
{
"indexed": false,
"internalType": "string",
"name": "title",
"type": "string"
}
],
"name": "ContractDeployed",
"type": "event"
},
{
"inputs": [
{
"internalType": "string",
"name": "title",
"type": "string"
},
{
"components": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint32",
"name": "value",
"type": "uint32"
},
{
"internalType": "uint32",
"name": "total",
"type": "uint32"
}
],
"internalType": "struct Stream.Member[]",
"name": "members",
"type": "tuple[]"
}
],
"name": "genesis",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "function"
}
]
79 changes: 79 additions & 0 deletions abi/contracts/Stream.sol/Stream.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
[
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "src",
"type": "address"
}
],
"name": "Stored",
"type": "event"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint32",
"name": "value",
"type": "uint32"
},
{
"internalType": "uint32",
"name": "total",
"type": "uint32"
}
],
"internalType": "struct Stream.Member[]",
"name": "m",
"type": "tuple[]"
}
],
"name": "initialize",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "members",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint32",
"name": "value",
"type": "uint32"
},
{
"internalType": "uint32",
"name": "total",
"type": "uint32"
}
],
"internalType": "struct Stream.Member[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
]
45 changes: 45 additions & 0 deletions abi/contracts/Test.sol/Test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
[
{
"inputs": [
{
"internalType": "address",
"name": "addr",
"type": "address"
}
],
"name": "withdrawFail1",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "addr",
"type": "address"
}
],
"name": "withdrawFail2",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "addr",
"type": "address"
}
],
"name": "withdrawSuccess",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
]
19 changes: 19 additions & 0 deletions contracts/Factory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
//import 'hardhat/console.sol';
import "@openzeppelin/contracts/proxy/Clones.sol";
import "./Stream.sol";
contract Factory {
event ContractDeployed(address indexed owner, address indexed group, string title);
address immutable implementation;
constructor() {
implementation = address(new Stream());
}
function genesis(string calldata title, Stream.Member[] calldata members) external returns (address) {
address payable clone = payable(Clones.clone(implementation));
Stream s = Stream(clone);
s.initialize(members);
emit ContractDeployed(msg.sender, clone, title);
return clone;
}
}
29 changes: 29 additions & 0 deletions contracts/Stream.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
//import 'hardhat/console.sol';
import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
contract Stream is Initializable {
event Stored(address src);
struct Member {
address account;
uint32 value;
uint32 total;
}
Member[] private _members;
function initialize(Member[] calldata m) initializer public {
for(uint i=0; i<m.length; i++) {
_members.push(m[i]);
}
}
receive () external payable {
require(_members.length > 0, "1");
for(uint i=0; i<_members.length; i++) {
Member memory member = _members[i];
(bool sent, ) = payable(address(member.account)).call{value: msg.value*member.value/member.total}("");
require(sent, "2");
}
}
function members() external view returns (Member[] memory) {
return _members;
}
}
16 changes: 16 additions & 0 deletions contracts/Test.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract Test {
receive() external payable {}
function withdrawFail1(address addr) external payable {
bool success = payable(addr).send(address(this).balance);
require(success, "ran out of gas");
}
function withdrawFail2(address addr) external payable {
payable(addr).transfer(address(this).balance);
}
function withdrawSuccess(address addr) external payable {
(bool success,) = payable(address(addr)).call{value: address(this).balance }("");
require(success);
}
}
1 change: 1 addition & 0 deletions deployments/localhost.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"address":"0x5FbDB2315678afecb367f032d93F642f64180aa3"}
1 change: 1 addition & 0 deletions deployments/rinkeby.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"address":"0x8faBF08451B71d0Ac8859828130051C5D3f674fa"}
1 change: 1 addition & 0 deletions deployments/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"address":"0x5FbDB2315678afecb367f032d93F642f64180aa3"}
64 changes: 64 additions & 0 deletions hardhat.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* @type import('hardhat/config').HardhatUserConfig
*/
const fs = require('fs')
const path = require('path')
require('dotenv').config()
require('@nomiclabs/hardhat-waffle')
require('hardhat-abi-exporter');
require("hardhat-gas-reporter");
require('hardhat-contract-sizer');
require("@nomiclabs/hardhat-etherscan");
task("deploy", "deploys the contract", async (args, hre) => {
const [deployer] = await hre.ethers.getSigners();
let Factory = await hre.ethers.getContractFactory('Factory');
let factory = await Factory.deploy();
await factory.deployed();
console.log("factory address", factory.address);
await fs.promises.mkdir(path.resolve(__dirname, "./deployments"), { recursive: true }).catch((e) => {})
await fs.promises.writeFile(path.resolve(__dirname, `./deployments/${hre.network.name}.json`), JSON.stringify({ address: factory.address }))
return factory;
})
module.exports = {
gasReporter: {
currency: "USD",
// gasPrice: 80,
// gasPrice: 150,
coinmarketcap: process.env.COINMARKETCAP_API_KEY,
enabled: true,
},
solidity: {
version: "0.8.4",
settings: {
optimizer: {
enabled: true,
runs: 1000,
},
}
},
mocha: {
timeout: 2000000000
},
networks: {
hardhat: {
chainId: 1337,
timeout: 1000 * 60 * 60 * 24, // 1 day
gas: 12000000,
blockGasLimit: 0x1fffffffffffff,
allowUnlimitedContractSize: true,
},
rinkeby: {
url: process.env.RINKEBY,
timeout: 1000 * 60 * 60 * 24, // 1 day
accounts: [process.env.RINKEBY_PRIVATE_KEY],
},
mainnet: {
timeout: 1000 * 60 * 60 * 24, // 1 day
url: process.env.MAINNET,
accounts: [process.env.MAINNET_PRIVATE_KEY],
}
},
etherscan: {
apiKey: process.env.ETHERSCAN_API_KEY
}
};
Loading

0 comments on commit baaf59d

Please sign in to comment.