Only Runtime Contracts (#225)
This commit is contained in:
parent
8a97142d82
commit
00219e65c8
|
@ -4,7 +4,7 @@ matrix:
|
|||
- language: node_js
|
||||
node_js: 8.13.0
|
||||
before_install:
|
||||
- cd frontend/
|
||||
- cd frontend
|
||||
install: yarn
|
||||
script:
|
||||
- yarn run lint
|
||||
|
@ -16,8 +16,7 @@ matrix:
|
|||
- cd backend/
|
||||
- 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
|
||||
- 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
|
||||
script:
|
||||
- flask test
|
||||
|
|
|
@ -6,12 +6,18 @@ DATABASE_URL="sqlite:////tmp/dev.db"
|
|||
REDISTOGO_URL="redis://localhost:6379"
|
||||
SECRET_KEY="not-so-secret"
|
||||
SENDGRID_API_KEY="optional, but emails won't send without it"
|
||||
|
||||
# for ropsten use the following
|
||||
# ETHEREUM_ENDPOINT_URI = "https://ropsten.infura.io/API_KEY"
|
||||
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"
|
||||
|
||||
# CROWD_FUND_URL = "https://eip-712.herokuapp.com/contract/crowd-fund"
|
||||
# CROWD_FUND_FACTORY_URL = "https://eip-712.herokuapp.com/contract/factory"
|
||||
CROWD_FUND_URL = "http://localhost:5000/dev-contracts/CrowdFund.json"
|
||||
CROWD_FUND_FACTORY_URL = "http://localhost:5000/dev-contracts/CrowdFundFactory.json"
|
||||
|
||||
# SENTRY_DSN="https://PUBLICKEY@sentry.io/PROJECTID"
|
||||
# SENTRY_RELEASE="optional, overrides git hash"
|
||||
|
||||
UPLOAD_DIRECTORY = "/tmp"
|
||||
UPLOAD_URL = "http://localhost:5000" # for constructing download url
|
||||
|
|
|
@ -5,7 +5,7 @@ from flask_cors import CORS
|
|||
from sentry_sdk.integrations.flask import FlaskIntegration
|
||||
import sentry_sdk
|
||||
|
||||
from grant import commands, proposal, user, comment, milestone, admin, email
|
||||
from grant import commands, proposal, user, comment, milestone, admin, email, web3 as web3module
|
||||
from grant.extensions import bcrypt, migrate, db, ma, mail, web3
|
||||
from grant.settings import SENTRY_RELEASE, ENV
|
||||
|
||||
|
@ -46,6 +46,9 @@ def register_blueprints(app):
|
|||
app.register_blueprint(milestone.views.blueprint)
|
||||
app.register_blueprint(admin.views.blueprint)
|
||||
app.register_blueprint(email.views.blueprint)
|
||||
# Only add these routes locally
|
||||
if ENV == 'development':
|
||||
app.register_blueprint(web3module.dev_contracts.blueprint)
|
||||
|
||||
|
||||
def register_shellcontext(app):
|
||||
|
|
|
@ -19,6 +19,7 @@ from .models import(
|
|||
proposal_contribution_schema,
|
||||
db
|
||||
)
|
||||
import traceback
|
||||
|
||||
blueprint = Blueprint("proposal", __name__, url_prefix="/api/v1/proposals")
|
||||
|
||||
|
@ -88,12 +89,16 @@ def get_proposals(stage):
|
|||
else:
|
||||
proposals = Proposal.query.order_by(Proposal.date_created.desc()).all()
|
||||
dumped_proposals = proposals_schema.dump(proposals)
|
||||
for p in dumped_proposals:
|
||||
proposal_contract = read_proposal(p['proposal_address'])
|
||||
p['crowd_fund'] = proposal_contract
|
||||
filtered_proposals = list(filter(lambda p: p['crowd_fund'] is not None, dumped_proposals))
|
||||
return filtered_proposals
|
||||
|
||||
try:
|
||||
for p in dumped_proposals:
|
||||
proposal_contract = read_proposal(p['proposal_address'])
|
||||
p['crowd_fund'] = proposal_contract
|
||||
filtered_proposals = list(filter(lambda p: p['crowd_fund'] is not None, dumped_proposals))
|
||||
return filtered_proposals
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print(traceback.format_exc())
|
||||
return {"message": "Oops! Something went wrong."}, 500
|
||||
|
||||
@blueprint.route("/", methods=["POST"])
|
||||
@requires_sm
|
||||
|
|
|
@ -9,7 +9,11 @@ environment variables.
|
|||
import subprocess
|
||||
from environs import Env
|
||||
|
||||
git_revision_short_hash = subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD'])
|
||||
def git_revision_short_hash():
|
||||
try:
|
||||
return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD'])
|
||||
except subprocess.CalledProcessError:
|
||||
return 0
|
||||
|
||||
env = Env()
|
||||
env.read_env()
|
||||
|
@ -33,7 +37,7 @@ SENDGRID_DEFAULT_FROM = "noreply@grant.io"
|
|||
ETHEREUM_PROVIDER = "http"
|
||||
ETHEREUM_ENDPOINT_URI = env.str("ETHEREUM_ENDPOINT_URI")
|
||||
SENTRY_DSN = env.str("SENTRY_DSN", default=None)
|
||||
SENTRY_RELEASE = env.str("SENTRY_RELEASE", default=git_revision_short_hash)
|
||||
SENTRY_RELEASE = env.str("SENTRY_RELEASE", default=git_revision_short_hash())
|
||||
UPLOAD_DIRECTORY = env.str("UPLOAD_DIRECTORY")
|
||||
UPLOAD_URL = env.str("UPLOAD_URL")
|
||||
MAX_CONTENT_LENGTH = 5 * 1024 * 1024 # 5MB (limits file uploads, raises RequestEntityTooLarge)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
from . import dev_contracts
|
|
@ -0,0 +1,19 @@
|
|||
import json
|
||||
|
||||
from flask import Blueprint, jsonify
|
||||
|
||||
blueprint = Blueprint('dev-contracts', __name__, url_prefix='/dev-contracts')
|
||||
|
||||
|
||||
@blueprint.route("/CrowdFundFactory.json", methods=["GET"])
|
||||
def factory():
|
||||
with open("../contract/build/contracts/CrowdFundFactory.json", "r") as read_file:
|
||||
crowd_fund_factory_json = json.load(read_file)
|
||||
return jsonify(crowd_fund_factory_json)
|
||||
|
||||
|
||||
@blueprint.route("/CrowdFund.json", methods=["GET"])
|
||||
def crowd_find():
|
||||
with open("../contract/build/contracts/CrowdFund.json", "r") as read_file:
|
||||
crowd_fund_json = json.load(read_file)
|
||||
return jsonify(crowd_fund_json)
|
|
@ -1,10 +1,10 @@
|
|||
import json
|
||||
import time
|
||||
from flask_web3 import current_web3
|
||||
from .util import batch_call, call_array, RpcError
|
||||
import requests
|
||||
from grant.settings import CROWD_FUND_URL
|
||||
|
||||
import requests
|
||||
from flask_web3 import current_web3
|
||||
|
||||
from grant.settings import CROWD_FUND_URL
|
||||
from .util import batch_call, call_array, RpcError
|
||||
|
||||
crowd_fund_abi = None
|
||||
|
||||
|
@ -14,19 +14,14 @@ def get_crowd_fund_abi():
|
|||
if 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:
|
||||
crowd_fund_abi = json.load(read_file)['abi']
|
||||
return crowd_fund_abi
|
||||
|
||||
crowd_fund_json = requests.get(CROWD_FUND_URL).json()
|
||||
crowd_fund_abi = crowd_fund_json['abi']
|
||||
return crowd_fund_abi
|
||||
|
||||
|
||||
def read_proposal(address):
|
||||
current_web3.eth.defaultAccount = current_web3.eth.accounts[0]
|
||||
current_web3.eth.defaultAccount = '0x537680D921C000fC52Af9962ceEb4e359C50F424' if not current_web3.eth.accounts else \
|
||||
current_web3.eth.accounts[0]
|
||||
crowd_fund_abi = get_crowd_fund_abi()
|
||||
contract = current_web3.eth.contract(address=address, abi=crowd_fund_abi)
|
||||
|
||||
|
@ -106,6 +101,7 @@ def read_proposal(address):
|
|||
|
||||
def get_no_vote(i):
|
||||
return derived_results['getContributorMilestoneVote' + contrib_address + str(i)]
|
||||
|
||||
no_votes = list(map(get_no_vote, range(len(crowd_fund['milestones']))))
|
||||
|
||||
contrib = {
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import json
|
||||
import time
|
||||
|
||||
import eth_tester.backends.pyevm.main as py_evm_main
|
||||
import requests
|
||||
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
|
||||
# https://github.com/ethereum/web3.py/issues/1013
|
||||
# https://gitter.im/ethereum/py-evm?at=5b7eb68c4be56c5918854337
|
||||
|
@ -24,17 +24,8 @@ class TestWeb3ProposalRead(BaseTestConfig):
|
|||
BaseTestConfig.setUp(self)
|
||||
# the following will properly configure web3 with test config
|
||||
web3.init_app(self.real_app)
|
||||
if CROWD_FUND_FACTORY_URL:
|
||||
crowd_fund_factory_json = requests.get(CROWD_FUND_FACTORY_URL).json()
|
||||
else:
|
||||
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)
|
||||
crowd_fund_factory_json = requests.get(CROWD_FUND_FACTORY_URL).json()
|
||||
self.crowd_fund_json = requests.get(CROWD_FUND_URL).json()
|
||||
current_web3.eth.defaultAccount = current_web3.eth.accounts[0]
|
||||
CrowdFundFactory = current_web3.eth.contract(
|
||||
abi=crowd_fund_factory_json['abi'], bytecode=crowd_fund_factory_json['bytecode'])
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
8.13.0
|
|
@ -4,14 +4,19 @@ FUND_ETH_ADDRESSES=0x4bbeEB066eD09B7AEd07bF39EEe0460DFa261520,0xDECAF9CD2367cdbb
|
|||
# Disable typescript checking for dev building (reduce build time & resource usage)
|
||||
NO_DEV_TS_CHECK=true
|
||||
|
||||
NODE_ENV=development
|
||||
|
||||
# Set the public host url (no trailing slash)
|
||||
PUBLIC_HOST_URL=https://demo.grant.io
|
||||
|
||||
BACKEND_URL=http://localhost:5000
|
||||
|
||||
# sentry
|
||||
SENTRY_DSN="https://PUBLICKEY@sentry.io/PROJECTID"
|
||||
SENTRY_DSN=https://PUBLICKEY@sentry.io/PROJECTID
|
||||
SENTRY_RELEASE="optional, overrides git hash"
|
||||
|
||||
CROWD_FUND_URL = "https://eip-712.herokuapp.com/contract/crowd-fund"
|
||||
CROWD_FUND_FACTORY_URL = "https://eip-712.herokuapp.com/contract/factory"
|
||||
# CROWD_FUND_URL=https://eip-712.herokuapp.com/contract/crowd-fund
|
||||
# CROWD_FUND_FACTORY_URL=https://eip-712.herokuapp.com/contract/factory
|
||||
|
||||
CROWD_FUND_URL=http://localhost:5000/dev-contracts/CrowdFund.json
|
||||
CROWD_FUND_FACTORY_URL=http://localhost:5000/dev-contracts/CrowdFundFactory.json
|
|
@ -12,16 +12,30 @@ require('../config/env');
|
|||
|
||||
module.exports = {};
|
||||
|
||||
const CHECK_CONTRACT_IDS = ['CrowdFundFactory.json']
|
||||
|
||||
const clean = (module.exports.clean = () => {
|
||||
rimraf.sync(paths.contractsBuild);
|
||||
});
|
||||
|
||||
const compile = (module.exports.compile = () => {
|
||||
childProcess.execSync('yarn build', { cwd: paths.contractsBase });
|
||||
logMessage('truffle compile, please wait...', 'info');
|
||||
try {
|
||||
childProcess.execSync('yarn build', { cwd: paths.contractsBase });
|
||||
} catch (e) {
|
||||
logMessage(e.stdout.toString('utf8'), 'error');
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
const migrate = (module.exports.migrate = () => {
|
||||
childProcess.execSync('truffle migrate', { cwd: paths.contractsBase });
|
||||
logMessage('truffle migrate, please wait...', 'info');
|
||||
try {
|
||||
childProcess.execSync('truffle migrate', { cwd: paths.contractsBase });
|
||||
} catch (e) {
|
||||
logMessage(e.stdout.toString('utf8'), 'error');
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
const makeWeb3Conn = () => {
|
||||
|
@ -62,20 +76,41 @@ const getGanacheNetworkId = (module.exports.getGanacheNetworkId = () => {
|
|||
.catch(() => -1);
|
||||
});
|
||||
|
||||
const checkContractsNetworkIds = (module.exports.checkContractsNetworkIds = id =>
|
||||
const checkContractsNetworkIds = (module.exports.checkContractsNetworkIds = (
|
||||
id,
|
||||
retry = false,
|
||||
) =>
|
||||
new Promise((res, rej) => {
|
||||
const buildDir = paths.contractsBuild;
|
||||
fs.readdir(buildDir, (err, names) => {
|
||||
fs.readdir(buildDir, (err) => {
|
||||
if (err) {
|
||||
logMessage(`No contracts build directory @ ${buildDir}`, 'error');
|
||||
res(false);
|
||||
} else {
|
||||
const allHaveId = names.reduce((ok, name) => {
|
||||
const allHaveId = CHECK_CONTRACT_IDS.reduce((ok, name) => {
|
||||
const contract = require(path.join(buildDir, name));
|
||||
if (Object.keys(contract.networks).length > 0 && !contract.networks[id]) {
|
||||
const actual = Object.keys(contract.networks).join(', ');
|
||||
logMessage(`${name} should have networks[${id}], it has ${actual}`, 'error');
|
||||
return false;
|
||||
const contractHasKeys = Object.keys(contract.networks).length > 0;
|
||||
if (!contractHasKeys) {
|
||||
if (retry) {
|
||||
logMessage(
|
||||
'Contract does not contain network keys after retry. Exiting. Please manually debug Contract JSON.',
|
||||
'error',
|
||||
);
|
||||
process.exit(1);
|
||||
} else {
|
||||
logMessage('Contract does not contain any keys. Will migrate.');
|
||||
migrate();
|
||||
return checkContractsNetworkIds(id, true);
|
||||
}
|
||||
} else {
|
||||
if (contractHasKeys && !contract.networks[id]) {
|
||||
const actual = Object.keys(contract.networks).join(', ');
|
||||
logMessage(
|
||||
`${name} should have networks[${id}], it has ${actual}`,
|
||||
'error',
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true && ok;
|
||||
}, true);
|
||||
|
@ -128,9 +163,7 @@ module.exports.ethereumCheck = () =>
|
|||
if (!allHaveId) {
|
||||
logMessage('Contract problems, will compile & migrate.', 'warning');
|
||||
clean();
|
||||
logMessage('truffle compile, please wait...', 'info');
|
||||
compile();
|
||||
logMessage('truffle migrate, please wait...', 'info');
|
||||
migrate();
|
||||
fundWeb3v1();
|
||||
} else {
|
||||
|
|
|
@ -10,11 +10,7 @@ export async function getCrowdFundContract(web3: Web3 | null, deployedAddress: s
|
|||
}
|
||||
if (!contractCache[deployedAddress]) {
|
||||
let CrowdFund;
|
||||
if (process.env.CROWD_FUND_FACTORY_URL) {
|
||||
CrowdFund = await fetchCrowdFundJSON();
|
||||
} else {
|
||||
CrowdFund = await import('./contracts/CrowdFund.json');
|
||||
}
|
||||
CrowdFund = await fetchCrowdFundJSON();
|
||||
try {
|
||||
contractCache[deployedAddress] = await getContractInstance(
|
||||
web3,
|
||||
|
|
|
@ -10,7 +10,11 @@ const getContractInstance = async (
|
|||
// get network ID and the deployed address
|
||||
const networkId = await web3.eth.net.getId();
|
||||
if (!deployedAddress && !contractDefinition.networks[networkId]) {
|
||||
throw new WrongNetworkError('Wrong web3 network configured');
|
||||
throw new WrongNetworkError(
|
||||
`Wrong web3 network configured. Deployed address: ${deployedAddress}; networkId: ${networkId}, contractDefinitionNetworks: ${JSON.stringify(
|
||||
contractDefinition.networks,
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
|
||||
deployedAddress = deployedAddress || contractDefinition.networks[networkId].address;
|
||||
|
|
|
@ -6,18 +6,12 @@ import { safeEnable } from 'utils/web3';
|
|||
import types from './types';
|
||||
import { fetchCrowdFundFactoryJSON } from 'api/api';
|
||||
|
||||
/* tslint:disable no-var-requires --- TODO: find a better way to import contract */
|
||||
let CrowdFundFactory = require('lib/contracts/CrowdFundFactory.json');
|
||||
|
||||
export function* bootstrapWeb3(): SagaIterator {
|
||||
// Don't attempt to bootstrap web3 on SSR
|
||||
if (process.env.SERVER_SIDE_RENDER) {
|
||||
return;
|
||||
}
|
||||
if (process.env.CROWD_FUND_FACTORY_URL) {
|
||||
CrowdFundFactory = yield call(fetchCrowdFundFactoryJSON);
|
||||
}
|
||||
|
||||
const CrowdFundFactory = yield call(fetchCrowdFundFactoryJSON);
|
||||
yield put<any>(setWeb3());
|
||||
yield take(types.WEB3_FULFILLED);
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@ const fs = require('fs');
|
|||
const path = require('path');
|
||||
const paths = require('./paths');
|
||||
const childProcess = require('child_process');
|
||||
const dotenv = require('dotenv');
|
||||
const { logMessage } = require('../bin/utils');
|
||||
|
||||
delete require.cache[require.resolve('./paths')];
|
||||
|
||||
|
@ -11,21 +13,17 @@ if (!process.env.NODE_ENV) {
|
|||
);
|
||||
}
|
||||
|
||||
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
|
||||
const dotenvFiles = [
|
||||
`${paths.dotenv}.${process.env.NODE_ENV}.local`,
|
||||
`${paths.dotenv}.${process.env.NODE_ENV}`,
|
||||
process.env.NODE_ENV !== 'test' && `${paths.dotenv}.local`,
|
||||
paths.dotenv,
|
||||
].filter(Boolean);
|
||||
|
||||
dotenvFiles.forEach(dotenvFile => {
|
||||
if (fs.existsSync(dotenvFile)) {
|
||||
require('dotenv').config({
|
||||
path: dotenvFile,
|
||||
});
|
||||
// Override local ENV variables with .env
|
||||
if (fs.existsSync(paths.dotenv)) {
|
||||
const envConfig = dotenv.parse(fs.readFileSync(paths.dotenv));
|
||||
// tslint:disable-next-line
|
||||
for (const k in envConfig) {
|
||||
if (process.env[k]) {
|
||||
logMessage(`Warning! Over-writing existing ENV Variable ${k}`);
|
||||
}
|
||||
process.env[k] = envConfig[k];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const envProductionRequiredHandler = (envVariable, fallbackValue) => {
|
||||
if (!process.env[envVariable]) {
|
||||
|
@ -72,6 +70,8 @@ process.env.NODE_PATH = (process.env.NODE_PATH || '')
|
|||
module.exports = () => {
|
||||
const raw = {
|
||||
BACKEND_URL: process.env.BACKEND_URL,
|
||||
CROWD_FUND_FACTORY_URL: process.env.CROWD_FUND_FACTORY_URL,
|
||||
CROWD_FUND_URL: process.env.CROWD_FUND_URL,
|
||||
NODE_ENV: process.env.NODE_ENV || 'development',
|
||||
PORT: process.env.PORT || 3000,
|
||||
PUBLIC_HOST_URL: process.env.PUBLIC_HOST_URL,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const ModuleDependencyWarning = require('webpack/lib/ModuleDependencyWarning');
|
||||
|
||||
// supress unfortunate warnings due to transpileOnly=true and certain ts export patterns
|
||||
// suppress unfortunate warnings due to transpileOnly=true and certain ts export patterns
|
||||
// https://github.com/TypeStrong/ts-loader/issues/653#issuecomment-390889335
|
||||
// https://github.com/TypeStrong/ts-loader/issues/751
|
||||
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"analyze": "NODE_ENV=production ANALYZE=true next build ./client",
|
||||
"build": "cross-env NODE_ENV=production node bin/build.js",
|
||||
"dev": "rm -rf ./node_modules/.cache && cross-env NODE_ENV=development BACKEND_URL=http://localhost:5000 node bin/dev.js",
|
||||
"lint": "tslint --project ./tsconfig.json --config ./tslint.json -e \"**/build/**\"",
|
||||
"build": "node bin/build.js",
|
||||
"dev": "rm -rf ./node_modules/.cache && node bin/dev.js",
|
||||
"lint": "tslint --project ./tsconfig.json --config ./tslint.json -e \"**/build/**\" -e \"**/bin/**\"",
|
||||
"start": "NODE_ENV=production node ./build/server/server.js",
|
||||
"now": "npm run build && now -e BACKEND_URL=https://grant-stage.herokuapp.com",
|
||||
"heroku-postbuild": "yarn build",
|
||||
|
@ -90,7 +89,6 @@
|
|||
"copy-webpack-plugin": "^4.6.0",
|
||||
"core-js": "^2.5.7",
|
||||
"cors": "^2.8.4",
|
||||
"cross-env": "^5.2.0",
|
||||
"css-loader": "^1.0.0",
|
||||
"dotenv": "^6.0.0",
|
||||
"ethereum-blockies-base64": "1.0.2",
|
||||
|
|
|
@ -4838,13 +4838,6 @@ cropperjs@v1.0.0-rc.3:
|
|||
version "1.0.0-rc.3"
|
||||
resolved "https://registry.yarnpkg.com/cropperjs/-/cropperjs-1.0.0-rc.3.tgz#50a7c7611befc442702f845ede77d7df4572e82b"
|
||||
|
||||
cross-env@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.2.0.tgz#6ecd4c015d5773e614039ee529076669b9d126f2"
|
||||
dependencies:
|
||||
cross-spawn "^6.0.5"
|
||||
is-windows "^1.0.0"
|
||||
|
||||
cross-spawn@5.1.0, cross-spawn@^5.0.1:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
|
||||
|
@ -8459,7 +8452,7 @@ is-utf8@^0.2.0:
|
|||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
|
||||
|
||||
is-windows@^1.0.0, is-windows@^1.0.1, is-windows@^1.0.2:
|
||||
is-windows@^1.0.1, is-windows@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
|
||||
|
||||
|
|
Loading…
Reference in New Issue