Contract Build Improvements (#215)

This commit is contained in:
Daniel Ternyak 2018-11-21 17:24:33 -06:00 committed by GitHub
parent 0496b58130
commit f8910b1e09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 107 additions and 30543 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
.idea .idea
contract/build

View File

@ -2,7 +2,7 @@ matrix:
include: include:
# Frontend # Frontend
- language: node_js - language: node_js
node_js: 8.11.4 node_js: 8.13.0
before_install: before_install:
- cd frontend/ - cd frontend/
install: yarn install: yarn
@ -15,17 +15,23 @@ matrix:
before_install: before_install:
- cd backend/ - cd backend/
- cp .env.example .env - cp .env.example .env
env:
- FLASK_APP=app.py FLASK_DEBUG=1 CROWD_FUND_URL=https://eip-712.herokuapp.com/contract/crowd-fund
CROWD_FUND_FACTORY_URL=https://eip-712.herokuapp.com/contract/factory
install: pip install -r requirements/dev.txt install: pip install -r requirements/dev.txt
script: script:
- flask test - flask test
# Contracts # Contracts
- language: node_js - language: node_js
node_js: 8.11.4 node_js: 8.13.0
before_install: before_install:
- cd contract/ - cd contract/
install: yarn && yarn add global truffle ganache-cli install: yarn && yarn add global truffle ganache-cli@6.1.8
before_script: before_script:
- ganache-cli > /dev/null & - ganache-cli > /dev/null &
- sleep 10 - sleep 10
script: script:
- yarn run test - yarn run test
env:
- CROWD_FUND_URL=https://eip-712.herokuapp.com/contract/crowd-fund
CROWD_FUND_FACTORY_URL=https://eip-712.herokuapp.com/contract/factory

View File

@ -9,5 +9,8 @@ SENDGRID_API_KEY="optional, but emails won't send without it"
# for ropsten use the following # for ropsten use the following
# ETHEREUM_ENDPOINT_URI = "https://ropsten.infura.io/API_KEY" # ETHEREUM_ENDPOINT_URI = "https://ropsten.infura.io/API_KEY"
ETHEREUM_ENDPOINT_URI = "http://localhost:8545" ETHEREUM_ENDPOINT_URI = "http://localhost:8545"
CROWD_FUND_URL = "https://eip-712.herokuapp.com/contract/crowd-fund"
CROWD_FUND_FACTORY_URL = "https://eip-712.herokuapp.com/contract/factory"
UPLOAD_DIRECTORY = "/tmp" UPLOAD_DIRECTORY = "/tmp"
UPLOAD_URL = "http://localhost:5000" # for constructing download url UPLOAD_URL = "http://localhost:5000" # for constructing download url

View File

@ -1,20 +0,0 @@
# Config file for automatic testing at travis-ci.org
sudo: false # http://docs.travis-ci.com/user/migrating-from-legacy/
language: python
env:
- FLASK_APP=app.py FLASK_DEBUG=1
python:
- 2.7
- 3.4
- 3.5
- 3.6
install:
- pip install -r requirements/dev.txt
- nvm install 6.10
- nvm use 6.10
- npm install
before_script:
- npm run lint
- npm run build
- flask lint
script: flask test

View File

@ -15,6 +15,8 @@ ENV = env.str("FLASK_ENV", default="production")
DEBUG = ENV == "development" DEBUG = ENV == "development"
SITE_URL = env.str('SITE_URL', default='https://grant.io') SITE_URL = env.str('SITE_URL', default='https://grant.io')
AUTH_URL = env.str('AUTH_URL', default='https://eip-712.herokuapp.com') AUTH_URL = env.str('AUTH_URL', default='https://eip-712.herokuapp.com')
CROWD_FUND_FACTORY_URL = env.str('CROWD_FUND_FACTORY_URL', default=None)
CROWD_FUND_URL = env.str('CROWD_FUND_URL', default=None)
SQLALCHEMY_DATABASE_URI = env.str("DATABASE_URL") SQLALCHEMY_DATABASE_URI = env.str("DATABASE_URL")
QUEUES = ["default"] QUEUES = ["default"]
SECRET_KEY = env.str("SECRET_KEY") SECRET_KEY = env.str("SECRET_KEY")

View File

@ -2,6 +2,8 @@ import json
import time import time
from flask_web3 import current_web3 from flask_web3 import current_web3
from .util import batch_call, call_array, RpcError from .util import batch_call, call_array, RpcError
import requests
from grant.settings import CROWD_FUND_URL
crowd_fund_abi = None crowd_fund_abi = None
@ -11,11 +13,18 @@ def get_crowd_fund_abi():
global crowd_fund_abi global crowd_fund_abi
if crowd_fund_abi: if crowd_fund_abi:
return crowd_fund_abi return crowd_fund_abi
if CROWD_FUND_URL:
crowd_fund_json = requests.get(CROWD_FUND_URL).json()
crowd_fund_abi = crowd_fund_json['abi']
return crowd_fund_abi
with open("../contract/build/contracts/CrowdFund.json", "r") as read_file: with open("../contract/build/contracts/CrowdFund.json", "r") as read_file:
crowd_fund_abi = json.load(read_file)['abi'] crowd_fund_abi = json.load(read_file)['abi']
return crowd_fund_abi return crowd_fund_abi
def read_proposal(address): def read_proposal(address):
current_web3.eth.defaultAccount = current_web3.eth.accounts[0] current_web3.eth.defaultAccount = current_web3.eth.accounts[0]
crowd_fund_abi = get_crowd_fund_abi() crowd_fund_abi = get_crowd_fund_abi()

View File

@ -1,13 +1,14 @@
import copy
import json import json
import time import time
from grant.extensions import web3
from ..config import BaseTestConfig
from grant.web3.proposal import read_proposal
from flask_web3 import current_web3
import eth_tester.backends.pyevm.main as py_evm_main import eth_tester.backends.pyevm.main as py_evm_main
from flask_web3 import current_web3
from grant.extensions import web3
from grant.settings import CROWD_FUND_URL, CROWD_FUND_FACTORY_URL
from grant.web3.proposal import read_proposal
from ..config import BaseTestConfig
import requests
# increase gas limit on eth-tester # increase gas limit on eth-tester
# https://github.com/ethereum/web3.py/issues/1013 # https://github.com/ethereum/web3.py/issues/1013
# https://gitter.im/ethereum/py-evm?at=5b7eb68c4be56c5918854337 # https://gitter.im/ethereum/py-evm?at=5b7eb68c4be56c5918854337
@ -23,10 +24,17 @@ class TestWeb3ProposalRead(BaseTestConfig):
BaseTestConfig.setUp(self) BaseTestConfig.setUp(self)
# the following will properly configure web3 with test config # the following will properly configure web3 with test config
web3.init_app(self.real_app) web3.init_app(self.real_app)
with open("../contract/build/contracts/CrowdFundFactory.json", "r") as read_file: if CROWD_FUND_FACTORY_URL:
crowd_fund_factory_json = json.load(read_file) crowd_fund_factory_json = requests.get(CROWD_FUND_FACTORY_URL).json()
with open("../contract/build/contracts/CrowdFund.json", "r") as read_file: else:
self.crowd_fund_json = json.load(read_file) with open("../frontend/client/lib/contracts/CrowdFundFactory.json", "r") as read_file:
crowd_fund_factory_json = json.load(read_file)
if CROWD_FUND_URL:
self.crowd_fund_json = requests.get(CROWD_FUND_URL).json()
else:
with open("../frontend/client/lib/contracts/CrowdFund.json", "r") as read_file:
self.crowd_fund_json = json.load(read_file)
current_web3.eth.defaultAccount = current_web3.eth.accounts[0] current_web3.eth.defaultAccount = current_web3.eth.accounts[0]
CrowdFundFactory = current_web3.eth.contract( CrowdFundFactory = current_web3.eth.contract(
abi=crowd_fund_factory_json['abi'], bytecode=crowd_fund_factory_json['bytecode']) abi=crowd_fund_factory_json['abi'], bytecode=crowd_fund_factory_json['bytecode'])
@ -78,13 +86,13 @@ class TestWeb3ProposalRead(BaseTestConfig):
def create_crowd_fund(self): def create_crowd_fund(self):
tx_hash = self.crowd_fund_factory.functions.createCrowdFund( tx_hash = self.crowd_fund_factory.functions.createCrowdFund(
5000000000000000000, # ethAmount 5000000000000000000, # ethAmount
current_web3.eth.accounts[0], # payout current_web3.eth.accounts[0], # payout
[current_web3.eth.accounts[0]], # trustees [current_web3.eth.accounts[0]], # trustees
[5000000000000000000], # milestone amounts [5000000000000000000], # milestone amounts
60, # duration (minutes) 60, # duration (minutes)
60, # voting period (minutes) 60, # voting period (minutes)
True # immediate first milestone payout True # immediate first milestone payout
).transact() ).transact()
tx_receipt = current_web3.eth.waitForTransactionReceipt(tx_hash) tx_receipt = current_web3.eth.waitForTransactionReceipt(tx_hash)
tx_events = self.crowd_fund_factory.events.ContractCreated().processReceipt(tx_receipt) tx_events = self.crowd_fund_factory.events.ContractCreated().processReceipt(tx_receipt)

3
contract/.gitignore vendored
View File

@ -2,5 +2,4 @@ node_modules
.idea/ .idea/
yarn-error.log yarn-error.log
.env .env
build/abi build
build/typedefs

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -5,4 +5,7 @@ FUND_ETH_ADDRESSES=0x4bbeEB066eD09B7AEd07bF39EEe0460DFa261520,0xDECAF9CD2367cdbb
NO_DEV_TS_CHECK=true NO_DEV_TS_CHECK=true
# Set the public host url (no trailing slash) # Set the public host url (no trailing slash)
PUBLIC_HOST_URL=https://demo.grant.io PUBLIC_HOST_URL=https://demo.grant.io
CROWD_FUND_URL = "https://eip-712.herokuapp.com/contract/crowd-fund"
CROWD_FUND_FACTORY_URL = "https://eip-712.herokuapp.com/contract/factory"

View File

@ -1 +1 @@
8.11.4 8.13.0

1
frontend/Procfile Normal file
View File

@ -0,0 +1 @@
web: yarn start

View File

@ -1,9 +1,9 @@
import axios from './axios'; import axios from './axios';
import { Proposal, TeamMember, Update } from 'types'; import { Proposal, TeamMember, Update } from 'types';
import { import {
formatProposalFromGet,
formatTeamMemberForPost, formatTeamMemberForPost,
formatTeamMemberFromGet, formatTeamMemberFromGet,
formatProposalFromGet,
} from 'utils/api'; } from 'utils/api';
import { PROPOSAL_CATEGORY } from './constants'; import { PROPOSAL_CATEGORY } from './constants';
@ -91,6 +91,16 @@ export function verifyEmail(code: string): Promise<any> {
return axios.post(`/api/v1/email/${code}/verify`); return axios.post(`/api/v1/email/${code}/verify`);
} }
export async function fetchCrowdFundFactoryJSON(): Promise<any> {
const res = await axios.get(process.env.CROWD_FUND_FACTORY_URL as string);
return res.data;
}
export async function fetchCrowdFundJSON(): Promise<any> {
const res = await axios.get(process.env.CROWD_FUND_URL as string);
return res.data;
}
export function postProposalUpdate( export function postProposalUpdate(
proposalId: number, proposalId: number,
title: string, title: string,

View File

@ -1,6 +1,6 @@
import Web3 from 'web3'; import Web3 from 'web3';
import getContractInstance from './getContract'; import getContractInstance from './getContract';
import CrowdFund from 'lib/contracts/CrowdFund.json'; import { fetchCrowdFundJSON } from 'api/api';
const contractCache = {} as { [key: string]: any }; const contractCache = {} as { [key: string]: any };
@ -9,6 +9,12 @@ export async function getCrowdFundContract(web3: Web3 | null, deployedAddress: s
throw new Error('getCrowdFundAddress: web3 was null but is required!'); throw new Error('getCrowdFundAddress: web3 was null but is required!');
} }
if (!contractCache[deployedAddress]) { if (!contractCache[deployedAddress]) {
let CrowdFund;
if (process.env.CROWD_FUND_FACTORY_URL) {
CrowdFund = await fetchCrowdFundJSON();
} else {
CrowdFund = await import('./contracts/CrowdFund.json');
}
try { try {
contractCache[deployedAddress] = await getContractInstance( contractCache[deployedAddress] = await getContractInstance(
web3, web3,

View File

@ -1,18 +1,22 @@
import { SagaIterator } from 'redux-saga'; import { SagaIterator } from 'redux-saga';
import { put, all, fork, take, takeLatest, select, call } from 'redux-saga/effects'; import { all, call, fork, put, select, take, takeLatest } from 'redux-saga/effects';
import { setWeb3, setAccounts, setContract } from './actions'; import { setAccounts, setContract, setWeb3 } from './actions';
import { selectWeb3 } from './selectors'; import { selectWeb3 } from './selectors';
import { safeEnable } from 'utils/web3'; import { safeEnable } from 'utils/web3';
import types from './types'; import types from './types';
import { fetchCrowdFundFactoryJSON } from 'api/api';
/* tslint:disable no-var-requires --- TODO: find a better way to import contract */ /* tslint:disable no-var-requires --- TODO: find a better way to import contract */
const CrowdFundFactory = require('lib/contracts/CrowdFundFactory.json'); let CrowdFundFactory = require('lib/contracts/CrowdFundFactory.json');
export function* bootstrapWeb3(): SagaIterator { export function* bootstrapWeb3(): SagaIterator {
// Don't attempt to bootstrap web3 on SSR // Don't attempt to bootstrap web3 on SSR
if (process.env.SERVER_SIDE_RENDER) { if (process.env.SERVER_SIDE_RENDER) {
return; return;
} }
if (process.env.CROWD_FUND_FACTORY_URL) {
CrowdFundFactory = yield call(fetchCrowdFundFactoryJSON);
}
yield put<any>(setWeb3()); yield put<any>(setWeb3());
yield take(types.WEB3_FULFILLED); yield take(types.WEB3_FULFILLED);

View File

@ -26,14 +26,29 @@ dotenvFiles.forEach(dotenvFile => {
} }
}); });
if (!process.env.PUBLIC_HOST_URL) { const envProductionRequiredHandler = (envVariable, fallbackValue) => {
if (process.env.NODE_ENV === 'production') { if (!process.env[envVariable]) {
throw new Error( if (process.env.NODE_ENV === 'production') {
'The process.env.PUBLIC_HOST_URL environment variable is required but was not specified.', throw new Error(
); `The process.env.${envVariable} environment variable is required but was not specified.`,
);
}
process.env[envVariable] = fallbackValue;
} }
process.env.PUBLIC_HOST_URL = 'http://localhost:' + (process.env.PORT || 3000); };
}
envProductionRequiredHandler(
'PUBLIC_HOST_URL',
'http://localhost:' + (process.env.PORT || 3000),
);
envProductionRequiredHandler(
'CROWD_FUND_URL',
'https://eip-712.herokuapp.com/contract/crowd-fund',
);
envProductionRequiredHandler(
'CROWD_FUND_FACTORY_URL',
'https://eip-712.herokuapp.com/contract/factory',
);
const appDirectory = fs.realpathSync(process.cwd()); const appDirectory = fs.realpathSync(process.cwd());
process.env.NODE_PATH = (process.env.NODE_PATH || '') process.env.NODE_PATH = (process.env.NODE_PATH || '')

View File

@ -1,6 +1,6 @@
{ {
"name": "grant", "name": "grant",
"version": "1.0.1", "version": "1.0.2",
"main": "index.js", "main": "index.js",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
@ -10,12 +10,16 @@
"lint": "tslint --project ./tsconfig.json --config ./tslint.json -e \"**/build/**\"", "lint": "tslint --project ./tsconfig.json --config ./tslint.json -e \"**/build/**\"",
"start": "NODE_ENV=production node ./build/server/server.js", "start": "NODE_ENV=production node ./build/server/server.js",
"now": "npm run build && now -e BACKEND_URL=https://grant-stage.herokuapp.com", "now": "npm run build && now -e BACKEND_URL=https://grant-stage.herokuapp.com",
"heroku-postbuild": "yarn build",
"tsc": "tsc", "tsc": "tsc",
"link-contracts": "cd client/lib && ln -s ../../build/contracts contracts", "link-contracts": "cd client/lib && ln -s ../../build/contracts contracts",
"ganache": "ganache-cli -b 5", "ganache": "ganache-cli -b 5",
"truffle": "truffle exec ./bin/init-truffle.js && cd client/lib/contracts && truffle console", "truffle": "truffle exec ./bin/init-truffle.js && cd client/lib/contracts && truffle console",
"storybook": "start-storybook -p 9001 -c .storybook" "storybook": "start-storybook -p 9001 -c .storybook"
}, },
"engines": {
"node": "8.13.0"
},
"husky": { "husky": {
"hooks": { "hooks": {
"pre-commit": "lint-staged", "pre-commit": "lint-staged",