diff --git a/README.md b/README.md index e0cffec..a8a9d19 100644 --- a/README.md +++ b/README.md @@ -20,35 +20,6 @@ yarn install yarn chain ``` -> Make a copy of `.sample.env` and rename to `.env` in `packages/react-app`. Don't forget to fill in the variables. - - - - - - - - - - - - - - - - - - - - - - - - - - - -
VariableDescription
REACT_APP_NETWORKThe ethereum network to run on, by default "mainnet"
REACT_APP_INFURA_IDYour Infura project ID.
REACT_APP_ETHERSCAN_IDYour Etherscan API key token.
REACT_APP_PROVIDERProvider endpoint, typically Infura endpoint.
REACT_APP_MAINNET_RPC_ENDPOINTCan be used to override the mainnet RPC provider endpoint (typically Alchemy endpoint).
> in a second terminal window, start your 📱 frontend: ```bash @@ -57,30 +28,6 @@ yarn start ``` > Make a copy of `.sample.env` and rename to `.env` in `packages/hardhat`. Don't forget to fill in the variables. - - - - - - - - - - - - - - - - - - - - - - - -
VariableDescription
STREAM_FACTORY_OWNEROwner address of the stream factory contract packages/hardhat/contracts/StreamFactory.sol
STREAM_FACTORY_ADMINSAdmin addresses of the stream factory contract constructor arg packages/hardhat/contracts/StreamFactory.sol
DEPLOY_ENDPOINT_RINKEBYYour Infura / Alchemy endpoint for tokenstream on Rinkeby network
DEPLOY_ACCOUNT_RINKEBYYour wallet account. For metamask, the private key can be extracted by clicking on the three dots button next to the account icon, then on "Account Details" and then on "Export private key".
> in a third terminal window, 🛰 deploy your contract: ```bash diff --git a/packages/hardhat/.sample.env b/packages/hardhat/.sample.env index 0729078..368dbc5 100644 --- a/packages/hardhat/.sample.env +++ b/packages/hardhat/.sample.env @@ -1,4 +1,3 @@ -STREAM_FACTORY_OWNER=0x0000000000000000000000000000000000000000 -STREAM_FACTORY_ADMINS=["0x0000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000"] -DEPLOY_ENDPOINT_RINKEBY=https://rinkeby.infura.io/v3/[YOUR_ID] -DEPLOY_ACCOUNT_RINKEBY=my super secret key that i promise never ever to share \ No newline at end of file +DEVELOPER=0x0000000000000000000000000000000000000000 +MANAGER1=0x0000000000000000000000000000000000000000 +MANAGER2=0x0000000000000000000000000000000000000000 \ No newline at end of file diff --git a/packages/hardhat/deploy/00_deploy_stream_factory.js b/packages/hardhat/deploy/00_deploy_stream_factory.js index eb7e01f..eabd579 100644 --- a/packages/hardhat/deploy/00_deploy_stream_factory.js +++ b/packages/hardhat/deploy/00_deploy_stream_factory.js @@ -6,17 +6,18 @@ module.exports = async ({ getNamedAccounts, getChainId, deployments }) => { const { deployer } = await getNamedAccounts(); const chainId = await getChainId(); + const admins = []; const GTC = { address: "0xde30da39c46104798bb5aa3fe8b9e0e1f348163f" }; - const owner = process.env.STREAM_FACTORY_OWNER; - const admins = JSON.parse(process.env.STREAM_FACTORY_ADMINS); - admins.push(owner); // the owner is also an admin + admins[0] = process.env.MANAGER1; + admins[1] = process.env.MANAGER2; + admins[2] = process.env.MANAGER3; // // deploy dummy GTC on non-mainnet networks // if (chainId !== "1") { // GTC = await deploy("GTC", { // from: deployer, - // args: [admins], + // args: [admins[2]], // log: true, // }); // } @@ -24,7 +25,7 @@ module.exports = async ({ getNamedAccounts, getChainId, deployments }) => { // deploy the stream factory const streamFactory = await deploy("StreamFactory", { from: deployer, - args: [owner, admins], + args: [admins[1], admins], log: true, }); @@ -38,7 +39,7 @@ module.exports = async ({ getNamedAccounts, getChainId, deployments }) => { await run("verify:verify", { address: streamFactory.address, contract: "contracts/StreamFactory.sol:StreamFactory", - constructorArguments: [owner, admins], + constructorArguments: [admins[1], admins], }); } }; diff --git a/packages/hardhat/hardhat.config.js b/packages/hardhat/hardhat.config.js index e527242..733c6d9 100644 --- a/packages/hardhat/hardhat.config.js +++ b/packages/hardhat/hardhat.config.js @@ -2,7 +2,6 @@ const { utils } = require("ethers"); const fs = require("fs"); const chalk = require("chalk"); -require("dotenv").config(); require("@nomiclabs/hardhat-waffle"); require("@tenderly/hardhat-tenderly"); require("hardhat-deploy"); @@ -35,11 +34,11 @@ module.exports = { url: "http://localhost:8545", }, rinkeby: { - url: process.env.DEPLOY_ENDPOINT_RINKEBY, // <---- YOUR INFURA ID! (or it won't work) + url: "https://rinkeby.infura.io/v3/460f40a260564ac4a4f4b3fffb032dad", // <---- YOUR INFURA ID! (or it won't work) // url: "https://speedy-nodes-nyc.moralis.io/XXXXXXXXXXXXXXXXXXXXXXX/eth/rinkeby", // <---- YOUR MORALIS ID! (not limited to infura) - accounts: [ - process.env.DEPLOY_ACCOUNT_RINKEBY - ], + accounts: { + mnemonic: mnemonic(), + }, }, kovan: { url: "https://kovan.infura.io/v3/460f40a260564ac4a4f4b3fffb032dad", // <---- YOUR INFURA ID! (or it won't work) diff --git a/packages/react-app/.sample.env b/packages/react-app/.sample.env index 06fa770..f7c8fd3 100644 --- a/packages/react-app/.sample.env +++ b/packages/react-app/.sample.env @@ -1,5 +1 @@ -REACT_APP_INFURA_ID=INFURA-PROJECT-ID -REACT_APP_RINKEBY_PROVIDER=https://rinkeby.infura.io/v3/INFURA-PROJECT-ID -REACT_APP_ETHERSCAN_ID=YOUR Etherscan API key token -REACT_APP_MAINNET_RPC_ENDPOINT=https://eth-mainnet.alchemyapi.io/v2/ALCHEMY-ID -REACT_APP_NETWORK=rinkeby \ No newline at end of file +REACT_APP_PROVIDER=https://rinkeby.infura.io/v3/2717afb6bf164045b5d5468031b93f87 diff --git a/packages/react-app/src/App.jsx b/packages/react-app/src/App.jsx index af11da7..842383d 100644 --- a/packages/react-app/src/App.jsx +++ b/packages/react-app/src/App.jsx @@ -22,23 +22,22 @@ import { Home, UserStream } from "./views"; const { ethers } = require("ethers"); -const mainnetRpcEndpoint = process.env.REACT_APP_MAINNET_RPC_ENDPOINT || "https://eth-mainnet.alchemyapi.io/v2/W0XfQJvBYrDk6wxM2F3VEDns10TBTLzs"; - /// 📡 What chain are your contracts deployed to? -const targetNetwork = NETWORKS[process.env.REACT_APP_NETWORK || "mainnet"]; // <------- select your target frontend network (localhost, rinkeby, xdai, mainnet) +const targetNetwork = NETWORKS.mainnet; // <------- select your target frontend network (localhost, rinkeby, xdai, mainnet) + // 😬 Sorry for all the console logging const DEBUG = false; const NETWORKCHECK = true; // 🛰 providers -if (DEBUG) console.log("📡 Connecting to " + targetNetwork.network + " Ethereum"); +if (DEBUG) console.log("📡 Connecting to Mainnet Ethereum"); // const mainnetProvider = getDefaultProvider("mainnet", { infura: INFURA_ID, etherscan: ETHERSCAN_KEY, quorum: 1 }); // const mainnetProvider = new InfuraProvider("mainnet",INFURA_ID); // // attempt to connect to our own scaffold eth rpc and if that fails fall back to infura... // Using StaticJsonRpcProvider as the chainId won't change see https://github.com/ethers-io/ethers.js/issues/901 const scaffoldEthProvider = navigator.onLine - ? new ethers.providers.StaticJsonRpcProvider(mainnetRpcEndpoint) + ? new ethers.providers.StaticJsonRpcProvider("https://eth-mainnet.alchemyapi.io/v2/W0XfQJvBYrDk6wxM2F3VEDns10TBTLzs") : null; const poktMainnetProvider = navigator.onLine ? new ethers.providers.StaticJsonRpcProvider( @@ -46,14 +45,14 @@ const poktMainnetProvider = navigator.onLine ) : null; const mainnetInfura = navigator.onLine - ? new ethers.providers.StaticJsonRpcProvider(mainnetRpcEndpoint) + ? new ethers.providers.StaticJsonRpcProvider("https://eth-mainnet.alchemyapi.io/v2/W0XfQJvBYrDk6wxM2F3VEDns10TBTLzs") : null; // ( ⚠️ Getting "failed to meet quorum" errors? Check your INFURA_ID // 🏠 Your local provider is usually pointed at your local blockchain const localProviderUrl = targetNetwork.rpcUrl; -// as you deploy to other networks you can set REACT_APP_RINKEBY_PROVIDER=https://dai.poa.network in packages/react-app/.env -const localProviderUrlFromEnv = process.env.REACT_APP_RINKEBY_PROVIDER ? process.env.REACT_APP_RINKEBY_PROVIDER : localProviderUrl; +// as you deploy to other networks you can set REACT_APP_PROVIDER=https://dai.poa.network in packages/react-app/.env +const localProviderUrlFromEnv = process.env.REACT_APP_PROVIDER ? process.env.REACT_APP_PROVIDER : localProviderUrl; if (DEBUG) console.log("🏠 Connecting to provider:", localProviderUrlFromEnv); const localProvider = new ethers.providers.StaticJsonRpcProvider(localProviderUrlFromEnv); @@ -76,7 +75,7 @@ const walletLinkProvider = walletLink.makeWeb3Provider( Web3 modal helps us "connect" external wallets: */ const web3Modal = new SafeAppWeb3Modal({ - network: targetNetwork.network, // Optional. If using WalletConnect on xDai, change network to "xdai" and add RPC info below for xDai chain. + network: "mainnet", // Optional. If using WalletConnect on xDai, change network to "xdai" and add RPC info below for xDai chain. cacheProvider: true, // optional theme: "light", // optional. Change to "dark" for a dark theme. providerOptions: { @@ -87,7 +86,6 @@ const web3Modal = new SafeAppWeb3Modal({ infuraId: INFURA_ID, rpc: { 1: "https://eth-mainnet.alchemyapi.io/v2/oKxs-03sij-U_N0iOlrSsZFr29-IqbuF", // mainnet // For more WalletConnect providers: https://docs.walletconnect.org/quick-start/dapps/web3-provider#required - 4: `https://rinkeby.infura.io/v3/${INFURA_ID}`, 42: `https://kovan.infura.io/v3/${INFURA_ID}`, 100: "https://dai.poa.network", // xDai }, diff --git a/packages/react-app/src/constants.js b/packages/react-app/src/constants.js index 4784283..d71f2bf 100644 --- a/packages/react-app/src/constants.js +++ b/packages/react-app/src/constants.js @@ -1,8 +1,8 @@ // MY INFURA_ID, SWAP IN YOURS FROM https://infura.io/dashboard/ethereum -export const INFURA_ID = process.env.REACT_APP_INFURA_ID || "460f40a260564ac4a4f4b3fffb032dad"; +export const INFURA_ID = "460f40a260564ac4a4f4b3fffb032dad"; // MY ETHERSCAN_ID, SWAP IN YOURS FROM https://etherscan.io/myapikey -export const ETHERSCAN_KEY = process.env.REACT_APP_ETHERSCAN_ID || "PSW8C433Q667DVEX5BCRMGNAH9FSGFZ7Q8"; +export const ETHERSCAN_KEY = "PSW8C433Q667DVEX5BCRMGNAH9FSGFZ7Q8"; // BLOCKNATIVE ID FOR Notify.js: export const BLOCKNATIVE_DAPPID = "0b58206a-f3c0-4701-a62f-73c7243e8c77"; @@ -20,7 +20,7 @@ export const NETWORKS = { color: "#ff8b9e", chainId: 1, // rpcUrl: `https://mainnet.infura.io/v3/${INFURA_ID}`, - rpcUrl: process.env.REACT_APP_MAINNET_RPC_ENDPOINT || "https://eth-mainnet.alchemyapi.io/v2/W0XfQJvBYrDk6wxM2F3VEDns10TBTLzs", + rpcUrl: "https://eth-mainnet.alchemyapi.io/v2/W0XfQJvBYrDk6wxM2F3VEDns10TBTLzs", blockExplorer: "https://etherscan.io/", }, kovan: { diff --git a/packages/react-app/src/contracts/hardhat_contracts.json b/packages/react-app/src/contracts/hardhat_contracts.json index 7b6f79a..3902209 100644 --- a/packages/react-app/src/contracts/hardhat_contracts.json +++ b/packages/react-app/src/contracts/hardhat_contracts.json @@ -475,25 +475,20 @@ } } }, - "4": { - "rinkeby": { - "name": "rinkeby", - "chainId": "4", + "42": { + "kovan": { + "name": "kovan", + "chainId": "42", "contracts": { - "StreamFactory": { - "address": "0xDD72eCeC91cE12de1482c6e245514fCc2840611F", + "GTC": { + "address": "0xCE8B9A8bf0c578380bf8BfeA15dE81fe7ffD8155", "abi": [ { "inputs": [ { "internalType": "address", - "name": "owner", + "name": "admin", "type": "address" - }, - { - "internalType": "address[]", - "name": "admins", - "type": "address[]" } ], "stateMutability": "nonpayable", @@ -505,140 +500,69 @@ { "indexed": true, "internalType": "address", - "name": "previousOwner", + "name": "owner", "type": "address" }, { "indexed": true, "internalType": "address", - "name": "newOwner", + "name": "spender", "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "previousAdminRole", - "type": "bytes32" }, { - "indexed": true, - "internalType": "bytes32", - "name": "newAdminRole", - "type": "bytes32" + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" } ], - "name": "RoleAdminChanged", + "name": "Approval", "type": "event" }, { "anonymous": false, "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, { "indexed": true, "internalType": "address", - "name": "account", + "name": "from", "type": "address" }, { "indexed": true, "internalType": "address", - "name": "sender", + "name": "to", "type": "address" - } - ], - "name": "RoleGranted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" }, { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" } ], - "name": "RoleRevoked", + "name": "Transfer", "type": "event" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "address", - "name": "creator", - "type": "address" - }, - { - "indexed": false, "internalType": "address", - "name": "user", + "name": "owner", "type": "address" }, { - "indexed": false, "internalType": "address", - "name": "stream", + "name": "spender", "type": "address" } ], - "name": "StreamAdded", - "type": "event" - }, - { - "inputs": [], - "name": "DEFAULT_ADMIN_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "FACTORY_MANAGER", + "name": "allowance", "outputs": [ { - "internalType": "bytes32", + "internalType": "uint256", "name": "", - "type": "bytes32" + "type": "uint256" } ], "stateMutability": "view", @@ -648,62 +572,21 @@ "inputs": [ { "internalType": "address", - "name": "_newFactoryManager", - "type": "address" - } - ], - "name": "addFactoryManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract SimpleStream", - "name": "stream", - "type": "address" - } - ], - "name": "addStreamForUser", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address payable", - "name": "_toAddress", + "name": "spender", "type": "address" }, { "internalType": "uint256", - "name": "_cap", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_frequency", + "name": "amount", "type": "uint256" - }, - { - "internalType": "bool", - "name": "_startsFull", - "type": "bool" - }, - { - "internalType": "contract IERC20", - "name": "_gtc", - "type": "address" } ], - "name": "createStreamFor", + "name": "approve", "outputs": [ { - "internalType": "address", - "name": "streamAddress", - "type": "address" + "internalType": "bool", + "name": "", + "type": "bool" } ], "stateMutability": "nonpayable", @@ -712,36 +595,30 @@ { "inputs": [ { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" + "internalType": "address", + "name": "account", + "type": "address" } ], - "name": "getRoleAdmin", + "name": "balanceOf", "outputs": [ { - "internalType": "bytes32", + "internalType": "uint256", "name": "", - "type": "bytes32" + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "address payable", - "name": "user", - "type": "address" - } - ], - "name": "getStreamForUser", + "inputs": [], + "name": "decimals", "outputs": [ { - "internalType": "address", - "name": "streamAddress", - "type": "address" + "internalType": "uint8", + "name": "", + "type": "uint8" } ], "stateMutability": "view", @@ -749,36 +626,18 @@ }, { "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, { "internalType": "address", - "name": "account", + "name": "spender", "type": "address" - } - ], - "name": "grantRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" }, { - "internalType": "address", - "name": "account", - "type": "address" + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" } ], - "name": "hasRole", + "name": "decreaseAllowance", "outputs": [ { "internalType": "bool", @@ -786,105 +645,93 @@ "type": "bool" } ], - "stateMutability": "view", + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "faucetMint", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", - "name": "user", + "name": "spender", "type": "address" }, { "internalType": "uint256", - "name": "increase", + "name": "addedValue", "type": "uint256" } ], - "name": "increaseUserStreamCap", - "outputs": [], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "owner", + "name": "name", "outputs": [ { - "internalType": "address", + "internalType": "string", "name": "", - "type": "address" + "type": "string" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "symbol", + "outputs": [ { - "internalType": "address", - "name": "user", - "type": "address" + "internalType": "string", + "name": "", + "type": "string" } ], - "name": "releaseUserStream", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, + "name": "totalSupply", + "outputs": [ { - "internalType": "address", - "name": "account", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "renounceRole", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, { "internalType": "address", - "name": "account", + "name": "recipient", "type": "address" - } - ], - "name": "revokeRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + }, { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], - "name": "supportsInterface", + "name": "transfer", "outputs": [ { "internalType": "bool", @@ -892,19 +739,6 @@ "type": "bool" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], "stateMutability": "nonpayable", "type": "function" }, @@ -912,52 +746,35 @@ "inputs": [ { "internalType": "address", - "name": "", + "name": "sender", "type": "address" - } - ], - "name": "userStreams", - "outputs": [ + }, { "internalType": "address", - "name": "", + "name": "recipient", "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ + }, { - "internalType": "address", - "name": "", - "type": "address" + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], - "name": "users", + "name": "transferFrom", "outputs": [ { "internalType": "bool", - "name": "hasStream", + "name": "", "type": "bool" } ], - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" } ] - } - } - } - }, - "31337": { - "localhost": { - "name": "localhost", - "chainId": "31337", - "contracts": { + }, "StreamFactory": { - "address": "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "address": "0x3Ba3F6d5F9d0c821c9511b4a85C9a8397bc67195", "abi": [ { "inputs": [