@expandorg/app-web3
Advanced tools
Comparing version 0.0.32 to 0.0.33
{ | ||
"name": "@expandorg/app-web3", | ||
"version": "0.0.32", | ||
"version": "0.0.33", | ||
"description": "web3 app", | ||
@@ -21,7 +21,7 @@ "main": "index.js", | ||
"dependencies": { | ||
"@expandorg/app-utils": "^0.0.36", | ||
"@expandorg/app-utils": "^0.0.37", | ||
"@expandorg/utils": "^0.0.8", | ||
"@gemsorg/gems-token": "^1.0.0" | ||
}, | ||
"gitHead": "610bca6faa505b76fa8c7916ed4344380573b61f" | ||
"gitHead": "32124066122cb67ee261472b69f4993331538e31" | ||
} |
// @flow | ||
import { | ||
web3StateSelector, | ||
metamaskStateSelector, | ||
initGemsStateSelector, | ||
} from './src/selectors'; | ||
import { web3StateSelector, metamaskStateSelector } from './src/selectors'; | ||
export { web3StateSelector, metamaskStateSelector, initGemsStateSelector }; | ||
export { web3StateSelector, metamaskStateSelector }; |
@@ -5,10 +5,6 @@ // @flow | ||
const web3ActionTypes = createActionTypes('web3', { | ||
INIT_WEB3_COMPLETE: null, | ||
INIT_WEB3_FAILED: null, | ||
INIT_GEMS: null, | ||
INIT_GEMS_COMPLETE: null, | ||
INIT_GEMS_FAILED: null, | ||
INIT_METAMASK: null, | ||
CHANGE_STATE: null, | ||
}); | ||
export default web3ActionTypes; |
@@ -9,12 +9,14 @@ import React from 'react'; | ||
const Actions = ({ onHide, children, className }) => ( | ||
<div className={cn(styles.actions, className)}> | ||
{children} | ||
{onHide && ( | ||
<Button theme="grey" className={styles.back} onClick={onHide}> | ||
no, go back | ||
</Button> | ||
)} | ||
</div> | ||
); | ||
export default function Actions({ onHide, children, className }) { | ||
return ( | ||
<div className={cn(styles.actions, className)}> | ||
{children} | ||
{onHide && ( | ||
<Button theme="grey" className={styles.back} onClick={onHide}> | ||
no, go back | ||
</Button> | ||
)} | ||
</div> | ||
); | ||
} | ||
@@ -30,3 +32,1 @@ Actions.propTypes = { | ||
}; | ||
export default Actions; |
@@ -1,5 +0,5 @@ | ||
import React, { Component } from 'react'; | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { Button, ErrorMessage } from '@expandorg/components'; | ||
import { Button, ErrorMessage } from '@expandorg/components'; | ||
import Actions from './Actions'; | ||
@@ -9,31 +9,34 @@ | ||
export default class Form extends Component { | ||
static propTypes = { | ||
action: PropTypes.string.isRequired, | ||
headline: PropTypes.string.isRequired, | ||
description: PropTypes.string.isRequired, | ||
error: PropTypes.string, | ||
onAction: PropTypes.func.isRequired, | ||
}; | ||
export default function Form({ | ||
onAction, | ||
action, | ||
headline, | ||
description, | ||
error, | ||
}) { | ||
return ( | ||
<div className={styles.container}> | ||
<div className={styles.headline}>{headline}</div> | ||
<div className={styles.description}>{description}- </div> | ||
<div className={styles.screenshot} /> | ||
<ErrorMessage errors={error} className={styles.error} /> | ||
<Actions className={styles.actions}> | ||
<Button className={styles.action} onClick={onAction}> | ||
{action} | ||
</Button> | ||
</Actions> | ||
</div> | ||
); | ||
} | ||
static defaultProps = { | ||
error: null, | ||
}; | ||
Form.propTypes = { | ||
action: PropTypes.string.isRequired, | ||
headline: PropTypes.string.isRequired, | ||
description: PropTypes.string.isRequired, | ||
error: PropTypes.oneOfType(PropTypes.object, PropTypes.string), | ||
onAction: PropTypes.func.isRequired, | ||
}; | ||
render() { | ||
const { onAction, action, headline, description, error } = this.props; | ||
return ( | ||
<div className={styles.container}> | ||
<div className={styles.headline}>{headline}</div> | ||
<div className={styles.description}>{description}- </div> | ||
<div className={styles.screenshot} /> | ||
<ErrorMessage errors={error} className={styles.error} /> | ||
<Actions className={styles.actions}> | ||
<Button className={styles.action} onClick={onAction}> | ||
{action} | ||
</Button> | ||
</Actions> | ||
</div> | ||
); | ||
} | ||
} | ||
Form.defaultProps = { | ||
error: null, | ||
}; |
@@ -1,7 +0,11 @@ | ||
import React, { Component } from 'react'; | ||
import React, { useEffect } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { useSelector, useDispatch } from 'react-redux'; | ||
import { Dialog } from '@expandorg/components'; | ||
import MetamaskState from '../../MetamaskState'; | ||
import { metamaskStateSelector } from '../../selectors'; | ||
import { initMetamask } from '../../sagas'; | ||
@@ -14,52 +18,58 @@ import Install from './Install'; | ||
export default class MetamaskPromt extends Component { | ||
static propTypes = { | ||
metamaskState: PropTypes.string.isRequired, | ||
action: PropTypes.string, | ||
headline: PropTypes.string, | ||
description: PropTypes.string, | ||
error: PropTypes.object, // eslint-disable-line react/forbid-prop-types | ||
onLogin: PropTypes.func.isRequired, | ||
onHide: PropTypes.func.isRequired, | ||
}; | ||
export default function MetamaskPromt({ | ||
onAction, | ||
onHide, | ||
action, | ||
error, | ||
headline, | ||
description, | ||
}) { | ||
const dispatch = useDispatch(); | ||
const mmask = useSelector(metamaskStateSelector); | ||
static defaultProps = { | ||
action: 'Sign in', | ||
error: null, | ||
headline: 'You’ll need to sign in using MetaMask', | ||
description: '(similar to the above). Click below to log in.', | ||
}; | ||
useEffect(() => { | ||
dispatch(initMetamask()); | ||
}, [dispatch]); | ||
render() { | ||
const { | ||
metamaskState, | ||
onLogin, | ||
onHide, | ||
action, | ||
error, | ||
headline, | ||
description, | ||
} = this.props; | ||
return ( | ||
<Dialog onHide={onHide} hideButton visible contentLabel="matamask"> | ||
<div className={styles.container}> | ||
{metamaskState === MetamaskState.NotInstalled && ( | ||
<Install onHide={onHide} /> | ||
)} | ||
{metamaskState === MetamaskState.NotAuthorized && ( | ||
<Unlock onHide={onHide} /> | ||
)} | ||
{metamaskState === MetamaskState.Authorized && ( | ||
<Form | ||
onAction={onLogin} | ||
description={description} | ||
headline={headline} | ||
action={action} | ||
error={error} | ||
/> | ||
)} | ||
</div> | ||
</Dialog> | ||
); | ||
} | ||
const install = | ||
mmask.state === MetamaskState.NotInstalled || | ||
mmask.state === MetamaskState.Installing; | ||
const auth = | ||
mmask.state === MetamaskState.NotAuthorized || | ||
mmask.state === MetamaskState.Authorizing; | ||
return ( | ||
<Dialog onHide={onHide} hideButton visible contentLabel="matamask"> | ||
<div className={styles.container}> | ||
{install && <Install onHide={onHide} />} | ||
{auth && <Unlock onHide={onHide} />} | ||
{mmask.state === MetamaskState.Authorized && ( | ||
<Form | ||
onAction={onAction} | ||
description={description} | ||
headline={headline} | ||
action={action} | ||
error={error} | ||
/> | ||
)} | ||
</div> | ||
</Dialog> | ||
); | ||
} | ||
MetamaskPromt.propTypes = { | ||
action: PropTypes.string, | ||
headline: PropTypes.string, | ||
description: PropTypes.string, | ||
error: PropTypes.object, // eslint-disable-line react/forbid-prop-types | ||
onAction: PropTypes.func.isRequired, | ||
onHide: PropTypes.func.isRequired, | ||
}; | ||
MetamaskPromt.defaultProps = { | ||
action: 'Sign in', | ||
error: null, | ||
headline: 'You’ll need to sign in using MetaMask', | ||
description: '(similar to the above). Click below to log in.', | ||
}; |
@@ -11,2 +11,9 @@ // @flow | ||
function calculateGasPrice(average: number) { | ||
return Math.min( | ||
Math.max(average * GAS_PRICE_FACTOR, GAS_PRICE_MIN), | ||
GAS_PRICE_MAX | ||
); | ||
} | ||
export default class GemsService { | ||
@@ -46,6 +53,2 @@ vault: string; | ||
initGemTokens = async () => { | ||
this.gemsTokens = await this.getGemTokensInstance(); | ||
}; | ||
getGemTokensInstance = async () => { | ||
const instance = new GemsToken( | ||
@@ -56,11 +59,5 @@ this.web3.currentProvider, | ||
await instance.init(); | ||
return instance; | ||
this.gemsTokens = instance; | ||
}; | ||
calculateGasPrice = (average: number) => | ||
Math.min( | ||
Math.max(average * GAS_PRICE_FACTOR, GAS_PRICE_MIN), | ||
GAS_PRICE_MAX | ||
); | ||
approve = async (value: number, average: number) => { | ||
@@ -70,12 +67,13 @@ if (!this.gemsTokens) { | ||
} | ||
const gasPrice = this.calculateGasPrice(average); | ||
await this.gemsTokens.approve(this.vault, value * 1e18, { | ||
gasPrice, | ||
}); | ||
const props = { gasPrice: calculateGasPrice(average) }; | ||
await this.gemsTokens.approve(this.vault, value * 1e18, props); | ||
}; | ||
getDefaultAccount = () => this.web3.eth.accounts[0]; | ||
getDefaultAccount = () => { | ||
return this.web3.eth.accounts[0]; | ||
}; | ||
verifyAccount = async (accountId: string) => { | ||
const accounts = await this.getAccounts(); | ||
const getAccounts = promisify(this.web3.eth.getAccounts, this.web3.eth); | ||
const accounts = await getAccounts(); | ||
if (`0x${accountId}` !== accounts[0]) { | ||
@@ -96,7 +94,2 @@ throw new Error('Invalid account'); | ||
getAccounts = async () => { | ||
const call = promisify(this.web3.eth.getAccounts, this.web3.eth); | ||
return call(); | ||
}; | ||
sendAsync = async (data: any) => { | ||
@@ -103,0 +96,0 @@ const call = promisify( |
import MetamaskState from './MetamaskState'; | ||
import web3ActionTypes from './actionTypes'; | ||
const initialState = MetamaskState.NotInstalled; | ||
const initialState = { state: MetamaskState.NotInstalled }; | ||
export default function metamaskReducer(state = initialState, action) { | ||
switch (action.type) { | ||
case web3ActionTypes.INIT_WEB3_FAILED: | ||
return initialState; | ||
case web3ActionTypes.INIT_WEB3_COMPLETE: | ||
return MetamaskState.NotAuthorized; | ||
case web3ActionTypes.INIT_GEMS: | ||
return MetamaskState.NotAuthorized; | ||
case web3ActionTypes.INIT_GEMS_COMPLETE: | ||
return MetamaskState.Authorized; | ||
case web3ActionTypes.CHANGE_STATE: | ||
return action.payload; | ||
default: | ||
@@ -17,0 +11,0 @@ break; |
// @flow | ||
const MetamaskState = { | ||
NotInstalled: 'NotInstalled', | ||
NotAuthorized: 'NotAuthorized', | ||
Authorized: 'Authorized', | ||
NotInstalled: 0, | ||
Installing: 1, | ||
NotAuthorized: 2, | ||
Authorizing: 3, | ||
Authorized: 4, | ||
}; | ||
export default MetamaskState; |
@@ -1,27 +0,32 @@ | ||
import { takeEvery, put, call, getContext } from 'redux-saga/effects'; | ||
import { takeEvery, put, call, getContext, select } from 'redux-saga/effects'; | ||
import { delay } from '@expandorg/utils'; | ||
import { appActionTypes } from '@expandorg/app-utils/app'; | ||
import web3ActionTypes from './actionTypes'; | ||
import { metamaskStateSelector } from './selectors'; | ||
function* handleInitWeb3() { | ||
import MetamaskState from './MetamaskState'; | ||
export const initMetamask = () => ({ | ||
type: web3ActionTypes.INIT_METAMASK, | ||
payload: null, | ||
}); | ||
const changeMetamaskState = (state, error) => ({ | ||
type: web3ActionTypes.CHANGE_STATE, | ||
payload: { state, error }, | ||
}); | ||
function* ensureInstalled(gemsService) { | ||
try { | ||
const services = yield getContext('services'); | ||
const gemsService = services.resolve('gems'); | ||
yield put(changeMetamaskState(MetamaskState.Installing)); | ||
yield call(gemsService.initWeb3); | ||
yield put({ type: web3ActionTypes.INIT_WEB3_COMPLETE, payload: null }); | ||
} catch (error) { | ||
yield put({ type: web3ActionTypes.INIT_WEB3_FAILED, payload: error }); | ||
yield put(changeMetamaskState(MetamaskState.NotAuthorized)); | ||
} catch (e) { | ||
yield put(changeMetamaskState(MetamaskState.NotInstalled, e)); | ||
} | ||
} | ||
function* initGemsInstance() { | ||
function* ensureAuthorized(gemsService) { | ||
try { | ||
yield put({ type: web3ActionTypes.INIT_GEMS, payload: null }); | ||
const services = yield getContext('services'); | ||
const gemsService = services.resolve('gems'); | ||
yield put(changeMetamaskState(MetamaskState.Authorizing)); | ||
yield call(gemsService.ensureEnable); | ||
@@ -37,12 +42,32 @@ | ||
yield call(gemsService.initGemTokens); | ||
yield put({ type: web3ActionTypes.INIT_GEMS_COMPLETE, payload: null }); | ||
yield put(changeMetamaskState(MetamaskState.Authorized)); | ||
} catch (e) { | ||
yield put({ type: web3ActionTypes.INIT_GEMS_FAILED, payload: e }); | ||
yield put(changeMetamaskState(MetamaskState.NotAuthorized, e)); | ||
} | ||
} | ||
/* eslint-disable import/prefer-default-export */ | ||
function* runInitMetamask() { | ||
const services = yield getContext('services'); | ||
const gemsService = services.resolve('gems'); | ||
let mmask = yield select(metamaskStateSelector); | ||
if (mmask.state === MetamaskState.Installing) { | ||
return; | ||
} | ||
if (mmask.state === MetamaskState.NotInstalled) { | ||
yield ensureInstalled(gemsService); | ||
} | ||
mmask = yield select(metamaskStateSelector); | ||
if (mmask.state === MetamaskState.Installing) { | ||
return; | ||
} | ||
if (mmask.state === MetamaskState.NotAuthorized) { | ||
yield ensureAuthorized(gemsService); | ||
} | ||
} | ||
export function* web3Sagas() { | ||
yield takeEvery(appActionTypes.INIT, handleInitWeb3); | ||
yield takeEvery(web3ActionTypes.INIT_WEB3_COMPLETE, initGemsInstance); | ||
yield takeEvery(web3ActionTypes.INIT_METAMASK, runInitMetamask); | ||
} |
// @flow | ||
import { createSelector } from 'reselect'; | ||
import { uiStateSelector } from '@expandorg/app-utils/app'; | ||
@@ -11,6 +10,1 @@ export const web3StateSelector = (state: Object) => state.web3; | ||
); | ||
export const initGemsStateSelector = createSelector( | ||
uiStateSelector, | ||
state => state.initGems | ||
); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
215512
382
+ Added@expandorg/api-client@0.0.21(transitive)
+ Added@expandorg/app-utils@0.0.37(transitive)
- Removed@expandorg/api-client@0.0.20(transitive)
- Removed@expandorg/app-utils@0.0.36(transitive)
Updated@expandorg/app-utils@^0.0.37